Add sort -h (human readable), have -u imply -s, and general cleanup.

This commit is contained in:
Rob Landley 2021-12-29 18:42:54 -06:00
parent 9e0547cb94
commit e28e5bb465
2 changed files with 50 additions and 37 deletions

View File

@ -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'

View File

@ -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 : (dx<dy ? -1 : 0);
return dx<dy ? -1 : dx>dy;
} 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 : (dx<dy ? -1 : 0);
do {
dxy[i] = estrtol(xx, &xx, 0);
if (flags & FLAG_h) {
if (isspace(*xx)) xx++;
if (*xx && (xx = strchr(units, tolower(*xx))))
do dxy[i] *= 1024; while (xx-->units);
}
xx = y;
} while (!i++);
return dxy[0]<dxy[1] ? -1 : 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<TT.linecount; idx++) {
if (!compare_keys(&TT.lines[jdx], &TT.lines[idx]))
free(TT.lines[idx]);
if (!compare_keys(&TT.lines[jdx], &TT.lines[idx])) free(TT.lines[idx]);
else TT.lines[++jdx] = TT.lines[idx];
}
if (TT.linecount) TT.linecount = jdx+1;