Skip to content

Commit 8215ec0

Browse files
committed
feat: add alphanumeric sort
1 parent f70c7b7 commit 8215ec0

File tree

1 file changed

+62
-9
lines changed

1 file changed

+62
-9
lines changed

src/ls.c

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -432,13 +432,14 @@ static enum time_type time_type;
432432

433433
enum sort_type
434434
{
435-
sort_none = -1, /* -U */
436-
sort_name, /* default */
437-
sort_extension, /* -X */
438-
sort_size, /* -S */
439-
sort_version, /* -v */
440-
sort_time, /* -t */
441-
sort_numtypes /* the number of elements of this enum */
435+
sort_none = -1, /* -U */
436+
sort_name, /* default */
437+
sort_extension, /* -X */
438+
sort_size, /* -S */
439+
sort_version, /* -v */
440+
sort_time, /* -t */
441+
sort_alphanumeric, /* -Y */
442+
sort_numtypes /* the number of elements of this enum */
442443
};
443444

444445
static enum sort_type sort_type;
@@ -853,11 +854,11 @@ ARGMATCH_VERIFY (format_args, format_types);
853854

854855
static char const *const sort_args[] =
855856
{
856-
"none", "time", "size", "extension", "version", NULL
857+
"none", "time", "size", "extension", "version", "alphanumeric", NULL
857858
};
858859
static enum sort_type const sort_types[] =
859860
{
860-
sort_none, sort_time, sort_size, sort_extension, sort_version
861+
sort_none, sort_time, sort_size, sort_extension, sort_version, sort_alphanumeric
861862
};
862863
ARGMATCH_VERIFY (sort_args, sort_types);
863864

@@ -1838,6 +1839,11 @@ decode_switches (int argc, char **argv)
18381839
sort_type_specified = true;
18391840
break;
18401841

1842+
case 'Y':
1843+
sort_type = sort_alphanumeric;
1844+
sort_type_specified = true;
1845+
break;
1846+
18411847
case '1':
18421848
/* -1 has no effect after -l. */
18431849
if (format != long_format)
@@ -3265,12 +3271,58 @@ cmp_extension (struct fileinfo const *a, struct fileinfo const *b,
32653271
return diff ? diff : cmp (a->name, b->name);
32663272
}
32673273

3274+
/* Compare alphanumerically. That is, strings are sorted by their
3275+
alphanumeric components, with numeric components sorted numerically.
3276+
For example, "foo9" comes before "foo10".
3277+
3278+
Sort code from https://stackoverflow.com/a/1344056/338803 */
3279+
3280+
static inline bool
3281+
isdigit(char c)
3282+
{
3283+
return '0' <= c && c <= '9';
3284+
}
3285+
3286+
static inline int
3287+
cmp_alphanumeric (struct fileinfo const *a, struct fileinfo const *b,
3288+
int (*cmp) (char const *, char const *))
3289+
{
3290+
char *s1 = a->name;
3291+
char *s2 = b->name;
3292+
3293+
for (;;) {
3294+
if (*s2 == '\0')
3295+
return *s1 != '\0';
3296+
else if (*s1 == '\0')
3297+
return 1;
3298+
else if (!(isdigit(*s1) && isdigit(*s2))) {
3299+
if (*s1 != *s2) {
3300+
char str1[2] = {*s1, '\0'};
3301+
char str2[2] = {*s2, '\0'};
3302+
return cmp (str1, str2);
3303+
} else
3304+
(++s1, ++s2);
3305+
} else {
3306+
char *lim1, *lim2;
3307+
unsigned long n1 = strtoul(s1, &lim1, 10);
3308+
unsigned long n2 = strtoul(s2, &lim2, 10);
3309+
if (n1 > n2)
3310+
return 1;
3311+
else if (n1 < n2)
3312+
return -1;
3313+
s1 = lim1;
3314+
s2 = lim2;
3315+
}
3316+
}
3317+
}
3318+
32683319
DEFINE_SORT_FUNCTIONS (ctime, cmp_ctime)
32693320
DEFINE_SORT_FUNCTIONS (mtime, cmp_mtime)
32703321
DEFINE_SORT_FUNCTIONS (atime, cmp_atime)
32713322
DEFINE_SORT_FUNCTIONS (size, cmp_size)
32723323
DEFINE_SORT_FUNCTIONS (name, cmp_name)
32733324
DEFINE_SORT_FUNCTIONS (extension, cmp_extension)
3325+
DEFINE_SORT_FUNCTIONS (alphanumeric, cmp_alphanumeric)
32743326

32753327
/* Compare file versions.
32763328
Unlike all other compare functions above, cmp_version depends only
@@ -4700,6 +4752,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
47004752
-w, --width=COLS assume screen width instead of current value\n\
47014753
-x list entries by lines instead of by columns\n\
47024754
-X sort alphabetically by entry extension\n\
4755+
-Y sort alphanumerically\n\
47034756
-Z, --context print any SELinux security context of each file\n\
47044757
-1 list one file per line\n\
47054758
"), stdout);

0 commit comments

Comments
 (0)