diff options
-rwxr-xr-x | tests/sort.test | 3 | ||||
-rw-r--r-- | toys/posix/sort.c | 41 |
2 files changed, 31 insertions, 13 deletions
diff --git a/tests/sort.test b/tests/sort.test index 2070d10c..c71012f0 100755 --- a/tests/sort.test +++ b/tests/sort.test @@ -96,6 +96,9 @@ testing "" "sort -t, -k3n" "3,4,1,2\n4,1,2,3\n1,2,3,4\n2,3,4,1\n" "" \ "1,2,3,4\n2,3,4,1\n4,1,2,3\n3,4,1,2\n" testing "-kx" "sort -k1,1x" "3\na\n0c\n" "" "0c\na\n3\n" +testing "" "sort -V" "toy-2.37.tar.gz\ntoy-3.4.tar.gz\ntoy-3.12.tar.gz\ntoy-4.16-rc2.tar.gz\ntoy-4.16.tar.gz\n" "" \ + "toy-3.12.tar.gz\ntoy-2.37.tar.gz\ntoy-3.4.tar.gz\ntoy-4.16-rc2.tar.gz\ntoy-4.16.tar.gz" + optional SORT_FLOAT # not numbers < NaN < -infinity < numbers < +infinity diff --git a/toys/posix/sort.c b/toys/posix/sort.c index 4c9452eb..6f5467e1 100644 --- a/toys/posix/sort.c +++ b/toys/posix/sort.c @@ -7,7 +7,7 @@ * Deviations from POSIX: Lots. * We invented -x -USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:xbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN)) +USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN)) config SORT bool "sort" @@ -32,6 +32,7 @@ config SORT -k Sort by "key" (see below) -t Use a key separator other than whitespace -o Output to FILE instead of stdout + -V Version numbers (name-1.234-rc6.5b.tgz) Sorting by key looks at a subset of the words on each line. -k2 uses the second word to the end of the line, -k2,2 looks at only @@ -168,12 +169,7 @@ static struct sort_key *add_key(void) // Perform actual comparison static int compare_values(int flags, char *x, char *y) { - int ff = flags & (FLAG_n|FLAG_g|FLAG_M|FLAG_x); - - // Ascii sort - if (!ff) return ((flags&FLAG_f) ? strcasecmp : strcmp)(x, y); - - if (CFG_SORT_FLOAT && ff == FLAG_g) { + if (CFG_SORT_FLOAT && (flags & FLAG_g)) { char *xx,*yy; double dx = strtod(x,&xx), dy = strtod(y,&yy); int xinf, yinf; @@ -197,7 +193,7 @@ static int compare_values(int flags, char *x, char *y) if (yinf) return dy<0 ? 1 : -1; return dx>dy ? 1 : (dx<dy ? -1 : 0); - } else if (ff == FLAG_M) { + } else if (flags & FLAG_M) { struct tm thyme; int dx; char *xx,*yy; @@ -209,10 +205,27 @@ static int compare_values(int flags, char *x, char *y) else if (!yy) return 1; else return dx==thyme.tm_mon ? 0 : dx-thyme.tm_mon; - } else if (ff == FLAG_x) { - return strtol(x, NULL, 16)-strtol(y, NULL, 16); - // This has to be ff == FLAG_n - } else { + } else if (flags & FLAG_x) return strtol(x, NULL, 16)-strtol(y, NULL, 16); + else if (flags & FLAG_V) { + while (*x && *y) { + while (*x && *x == *y) x++, y++; + if (isdigit(*x) && isdigit(*y)) { + long long xx = strtoll(x, &x, 10), yy = strtoll(y, &y, 10); + + if (xx<yy) return -1; + if (xx>yy) return 1; + } else { + char xx = *x ? *x : x[-1], yy = *y ? *y : y[-1]; + + // -rc/-pre hack so abc-123 > abc-123-rc1 (other way already - < 0-9) + if (xx != yy) { + if (xx<yy && !strstart(&y, "-rc") && !strstart(&y, "-pre")) return -1; + else return 1; + } + } + } + return *x ? !!*y : -1; + } else if (flags & FLAG_n) { // Full floating point version of -n if (CFG_SORT_FLOAT) { double dx = atof(x), dy = atof(y); @@ -220,7 +233,9 @@ static int compare_values(int flags, char *x, char *y) return dx>dy ? 1 : (dx<dy ? -1 : 0); // Integer version of -n for tiny systems } else return atoi(x)-atoi(y); - } + + // Ascii sort + } else return ((flags&FLAG_f) ? strcasecmp : strcmp)(x, y); } // Callback from qsort(): Iterate through key_list and perform comparisons. |