From 9f3042ccac355e50c281b7ba6e69fa5726438785 Mon Sep 17 00:00:00 2001 From: nova Date: Thu, 28 Aug 2025 23:00:54 +0200 Subject: [PATCH] improvenments to natural sort --- defines.h | 20 ++++++------- sorting.c | 85 ++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 75 insertions(+), 30 deletions(-) diff --git a/defines.h b/defines.h index d9c2ee1..26d5f58 100644 --- a/defines.h +++ b/defines.h @@ -39,16 +39,16 @@ #define COLOR_ORPHAN 9 #define COLOR_PATH 10 -#define FILE_TYPE_UNKNOWN COLOR_UNKNOWN -#define FILE_TYPE_DIR COLOR_DIR -#define FILE_TYPE_EXEC COLOR_EXEC -#define FILE_TYPE_REGULAR COLOR_REGULAR -#define FILE_TYPE_SYMLINK COLOR_SYMLINK -#define FILE_TYPE_BLOCK COLOR_BLOCK -#define FILE_TYPE_CHARDEV COLOR_CHARDEV -#define FILE_TYPE_SOCK COLOR_SOCK -#define FILE_TYPE_FIFO COLOR_FIFO -#define FILE_TYPE_ORPHAN COLOR_ORPHAN +#define FILE_TYPE_UNKNOWN 0 +#define FILE_TYPE_EXEC 1 +#define FILE_TYPE_REGULAR 2 +#define FILE_TYPE_BLOCK 3 +#define FILE_TYPE_CHARDEV 4 +#define FILE_TYPE_SOCK 5 +#define FILE_TYPE_FIFO 6 +#define FILE_TYPE_ORPHAN 7 +#define FILE_TYPE_DIR 32 +#define FILE_TYPE_SYMLINK 64 #define FILE_TYPE_OPEN_FILE 128 /* this is only used in rgt_content to print a file preview, not the dir */ #define YANK_IS_USED 1 diff --git a/sorting.c b/sorting.c index f331483..b4aae47 100644 --- a/sorting.c +++ b/sorting.c @@ -4,6 +4,8 @@ #include #include +#include "defines.h" + extern unsigned int settings; extern unsigned int file_modifiers; @@ -20,31 +22,74 @@ int skip_dot(const struct dirent *entry){ return 1; } -int sort_natural(const void *file0, const void *file1){ - unsigned char file_type0 = ((file*)file0)->file_type; - unsigned char file_type1 = ((file*)file1)->file_type; - - char weight = 0; - if (file_type0 == FILE_TYPE_DIR || file_type0 == FILE_TYPE_SYMLINK) { - weight |= 1; - } - if (file_type1 == FILE_TYPE_DIR || file_type1 == FILE_TYPE_SYMLINK) { - weight |= 2; +int sort_natural(const void *file0_, const void *file1_){ + file *file0 = (file*)file0_; + file *file1 = (file*)file1_; + + unsigned char *a = file0->file_name; + unsigned char *b = file1->file_name; + + if (file0->file_type & (FILE_TYPE_SYMLINK | FILE_TYPE_DIR) && !(file1->file_type & (FILE_TYPE_SYMLINK | FILE_TYPE_DIR))) { + return -1; } - if (weight == 0 || weight == 3) { - char *file_name0 = ((file*)file0)->file_name; - char *file_name1 = ((file*)file1)->file_name; - return strcasecmp(file_name0, file_name1); - } else { - if (file_type0 > file_type1) { + if (!(file0->file_type & (FILE_TYPE_SYMLINK | FILE_TYPE_DIR)) && file1->file_type & (FILE_TYPE_SYMLINK | FILE_TYPE_DIR)) { return 1; - } else if (file_type0 < file_type1) { + } + unsigned long num0 = 0; + unsigned long num1 = 0; + /* bitwise OR a with ' ' turns turns caps into small letters + * while doing this on all chars may cause unexpected behaviour on the extended ascii set, + * for now i dont care */ + while ((*a | ' ') == (*b | ' ') && *a != '\0') { + if ((*a >= '0') && (*a <= '9')) { + while((*a >= '0') && (*a <= '9')) { + num0 = (num0 * 10) + (*a - '0'); + a++; + } + while((*b >= '0') && (*b <= '9')) { + num1 = (num1 * 10) + (*b - '0'); + b++; + } + if (num0 != num1) { + break; + } + } else { + a++; + b++; + } + } + if (num0 == num1) { + if (*a == '\0') { + a--; + } + if (*b == '\0') { + b--; + } + + unsigned char c0; + unsigned char c1; + /* in this case we actually check for a through z as otherwise unicode characters get ordered wrongly */ + if (*a >= 'A' && *a <= 'Z') { + c0 = (*a | ' '); + } else { + c0 = *a; + } + if (*b >= 'A' && *b <= 'Z') { + c1 = (*b | ' '); + } else { + c1 = *b; + } + if (c0 > c1) { + return 1; + } else if (c0 < c1) { return -1; } else { - char *file_name0 = ((file*)file0)->file_name; - char *file_name1 = ((file*)file1)->file_name; - return strcasecmp(file_name0, file_name1); + return 0; } + } else if (num0 > num1) { + return 1; + } else { + return -1; } } int sort_alpha(const void *file0, const void *file1){