From e28e5bb465f7f559f19763903c6a462c4c42c11e Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Wed, 29 Dec 2021 18:42:54 -0600 Subject: [PATCH] Add sort -h (human readable), have -u imply -s, and general cleanup. --- tests/sort.test | 19 ++++++++++--- toys/posix/sort.c | 68 ++++++++++++++++++++++++----------------------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/tests/sort.test b/tests/sort.test index dd2b8263..1d9ecc44 100755 --- a/tests/sort.test +++ b/tests/sort.test @@ -88,7 +88,7 @@ testing "key edge case with -t" "sort -n -k4 -t/" \ /usr/lib/prebaseconfig.d/6 " -testing "-x" "sort -x" "010\na0\n 0c0\n" "" "a0\n010\n 0c0\n" +toyonly testing "-x" "sort -x" "010\na0\n 0c0\n" "" "a0\n010\n 0c0\n" # Test that -f applies to key or fallback independently @@ -97,10 +97,12 @@ testing "" "sort -k2,2" "a B C\na B a\nA b b\n" "" "a B a\nA b b\na B C\n" testing "" "sort -f -k2,2" "A b b\na B C\na B a\n" "" "a B a\nA b b\na B C\n" 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" +toyonly 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" +# This has irredeemable version skew on the host and no standard defining it. +# testing "-V" "LANG=c 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 @@ -108,3 +110,12 @@ optional SORT_FLOAT testing "-g" "sort -g" \ "bork\nNaN\n-inf\n0.4\n1.222\n01.37\n2.1\n+infinity\n" "" \ "01.37\n1.222\n2.1\n0.4\nNaN\nbork\n-inf\n+infinity\n" + +# -n without number sorts as leading zero, but fallback is whole string +testcmd '-n without number sorts as leading zero' '-n' \ + '-1\n0A\n0D\nC\n1z\n3b\n' '' '1z\n0D\n3b\nC\n-1\n0A\n' + +testcmd '-u implies -s' '-uk2,2n' 'zero 1\nthree 2\nfour 3\n' '' \ + 'zero 1\none 1\nfour 3\ntwo 1\nthree 2\nalso 1' +testcmd '-h' '-h' '1bx\n1by\n1x\n1x\n1y\n1Ky\n1Ky\n1ky\n1My\n1Gx\n1Gx\n' '' \ + '1bx\n1y\n1by\n1x\n1ky\n1x\n1Ky\n1Gx\n1Ky\n1Gx\n1My' diff --git a/toys/posix/sort.c b/toys/posix/sort.c index 9f38be82..574063ea 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:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2))) +USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("gh")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2))) config SORT bool "sort" @@ -24,6 +24,7 @@ config SORT -c Check whether input is sorted -d Dictionary order (use alphanumeric and whitespace chars only) -f Force uppercase (case insensitive sort) + -h Human readable numbers -i Ignore nonprinting characters -M Month sort (jan, feb, etc) -x Hexadecimal numerical sort @@ -61,7 +62,7 @@ GLOBALS( char *o, *T, S; void *key_list; - int linecount; + unsigned linecount; char **lines, *name; ) @@ -72,8 +73,7 @@ GLOBALS( #define FLAG_bb (1<<31) // Ignore trailing blanks -struct sort_key -{ +struct sort_key { struct sort_key *next_key; // linked list unsigned range[4]; // start word, start char, end word, end char int flags; @@ -115,7 +115,7 @@ static char *get_key_data(char *str, struct sort_key *key, int flags) } } } - if (!j) start=end; + if (!j) start = end; } // Key with explicit separator starts after the separator @@ -194,7 +194,7 @@ static int compare_values(int flags, char *x, char *y) } if (yinf) return dy<0 ? 1 : -1; - return dx>dy ? 1 : (dxdy; } else if (flags & FLAG_M) { struct tm thyme; int dx; @@ -227,12 +227,24 @@ static int compare_values(int flags, char *x, char *y) } } return *x ? !!*y : -1; - } else if (flags & FLAG_n) { + } else if (flags & (FLAG_n|FLAG_h)) { // Full floating point version of -n if (CFG_SORT_FLOAT) { - double dx = atof(x), dy = atof(y); + char *xx = x, *units = "kmgtpez"; + double dxy[2]; + int i = 0; - return dx>dy ? 1 : (dxunits); + } + xx = y; + } while (!i++); + + return dxy[0]dxy[1]; // Integer version of -n for tiny systems } else return atoi(x)-atoi(y); @@ -247,8 +259,8 @@ static int compare_keys(const void *xarg, const void *yarg) char *x, *y, *xx = *(char **)xarg, *yy = *(char **)yarg; struct sort_key *key; - for (key=(struct sort_key *)TT.key_list; !retval && key; key = key->next_key){ - flags = key->flags ? key->flags : toys.optflags; + for (key=(void *)TT.key_list; !retval && key; key = key->next_key) { + flags = key->flags ? : toys.optflags; // Chop out and modify key chunks, handling -dfib @@ -287,10 +299,8 @@ static void sort_lines(char **pline, long len) // handle -c here so we don't allocate more memory than necessary. if (FLAG(c)) { - int j = FLAG(u) ? -1 : 0; - - if (TT.lines && compare_keys((void *)&TT.lines, &line)>j) - error_exit("%s: Check line %d\n", TT.name, TT.linecount); + if (TT.lines && compare_keys((void *)&TT.lines, &line)>-!!FLAG(u)) + error_exit("%s: Check line %u\n", TT.name, TT.linecount); free(TT.lines); TT.lines = (void *)line; } else { @@ -310,7 +320,9 @@ static void sort_read(int fd, char *name) void sort_main(void) { - int idx, fd = 1; + int idx, jdx, fd = 1; + + if (FLAG(u)) toys.optflags |= FLAG_s; // Parse -k sort keys. if (TT.k) { @@ -318,39 +330,32 @@ void sort_main(void) for (arg = TT.k; arg; arg = arg->next) { struct sort_key *key = add_key(); - char *temp; + char *temp, *temp2, *optlist; int flag; idx = 0; temp = arg->arg; while (*temp) { // Start of range - key->range[2*idx] = (unsigned)strtol(temp, &temp, 10); - if (*temp=='.') - key->range[(2*idx)+1] = (unsigned)strtol(temp+1, &temp, 10); + key->range[2*idx] = strtol(temp, &temp, 10); + if (*temp=='.') key->range[(2*idx)+1] = strtol(temp+1, &temp, 10); // Handle flags appended to a key type. for (;*temp;temp++) { - char *temp2, *optlist; - - // Note that a second comma becomes an "Unknown key" error. + // Second comma becomes an "Unknown key" error. if (*temp==',' && !idx++) { temp++; break; } // Which flag is this? - optlist = toys.which->options; temp2 = strchr(optlist, *temp); - flag = (1<<(optlist-temp2+strlen(optlist)-1)); + flag = 1<<(optlist-temp2+strlen(optlist)-1); // Was it a flag that can apply to a key? - - if (!temp2 || flag>FLAG_x - || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) - { + if (!temp2 || flag>FLAG_x || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) { toys.exitval = 2; error_exit("Unknown key option."); } @@ -380,11 +385,8 @@ void sort_main(void) // handle unique (-u) if (FLAG(u)) { - int jdx; - for (jdx=0, idx=1; idx