From 8deb5891fb4c4baedf5f2e7a36d5464053a10224 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 15 Aug 2023 15:56:42 -0500 Subject: [PATCH] Make negative sort offsets in -k keys count right to left. --- tests/sort.test | 14 ++++++++++- toys/posix/sort.c | 61 ++++++++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/tests/sort.test b/tests/sort.test index dbb6ca08..a04f0009 100755 --- a/tests/sort.test +++ b/tests/sort.test @@ -109,7 +109,19 @@ testcmd "-uc" "-uc 2>&1 | grep -o [0-9]*" "3\n" "" "a\nb\nb\nc" testcmd "-C 1" "-C || echo yes" "yes\n" "" "one\ntwo\nthree" testcmd "-C 2" "-C && echo yes" "yes\n" "" "a\nb\nc\n" -optional SORT_FLOAT +toyonly testcmd 'negative -k' '-k-2,-2 -k-1r' 'a b z\nd e q\nx e a\nb m n\n' \ + '' 'a b z\nd e q\nb m n\nx e a\n' +toyonly testcmd 'negative -k2' '-k-2' 'a b z\nx e a\nd e q\nb m n\n' \ + '' 'a b z\nd e q\nb m n\nx e a\n' + +testcmd 'missing key becomes ""' '-k3r' 'm n o\ng h i\na b c\nd e\nj k\n' \ + '' 'a b c\nd e\ng h i\nj k\nm n o\n' +toyonly testcmd 'negative straddle' '-k-1r' 'm n o\nj k\ng h i\nd e\na b c\n' \ + '' 'a b c\nd e\ng h i\nj k\nm n o\n' +toyonly testcmd 'missing negative' '-k-3r' 'm n o\ng h i\na b c\nd e\nj k\n' \ + '' 'a b c\nd e\ng h i\nj k\nm n o\n' + +optional TOYBOX_FLOAT # not numbers < NaN < -infinity < numbers < +infinity testing "-g" "sort -g" \ diff --git a/toys/posix/sort.c b/toys/posix/sort.c index c0d312de..13fefef9 100644 --- a/toys/posix/sort.c +++ b/toys/posix/sort.c @@ -39,9 +39,9 @@ config SORT second word to the end of the line, -k2,2 looks at only the second word, -k2,4 looks from the start of the second to the end of the fourth word. -k2.4,5 starts from the fourth character of the second word, to the end - of the fifth word. Specifying multiple keys uses the later keys as tie - breakers, in order. A type specifier appended to a sort key (such as -2,2n) - applies only to sorting that key. + of the fifth word. Negative values count from the end. Specifying multiple + keys uses the later keys as tie breakers, in order. A type specifier + appended to a sort key (such as -2,2n) applies only to sorting that key. config SORT_FLOAT bool @@ -75,45 +75,53 @@ GLOBALS( struct sort_key { struct sort_key *next_key; // linked list - unsigned range[4]; // start word, start char, end word, end char + long range[4]; // start word, start char, end word, end char int flags; }; +static int skip_key(char *str) +{ + int end = 0; + + // Skip leading blanks + if (str[end] && !TT.t) while (isspace(str[end])) end++; + + // Skip body of key + for (; str[end]; end++) { + if (TT.t) { + if (str[end]==*TT.t) { + end++; + break; + } + } else if (isspace(str[end])) break; + } + + return end; +} + // Copy of the part of this string corresponding to a key/flags. static char *get_key_data(char *str, struct sort_key *key, int flags) { - int start = 0, end, len, i, j; + long start = 0, end, len, h, i, j, k; // Special case whole string, so we don't have to make a copy - if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3] && !(flags&(FLAG_b|FLAG_d|FLAG_i|FLAG_bb))) return str; // Find start of key on first pass, end on second pass - len = strlen(str); for (j=0; j<2; j++) { - if (!key->range[2*j]) end=len; + if (!(k = key->range[2*j])) end=len; // Loop through fields else { - end = 0; - for (i = 1; i < key->range[2*j]+j; i++) { - - // Skip leading blanks - if (str[end] && !TT.t) while (isspace(str[end])) end++; - - // Skip body of key - for (; str[end]; end++) { - if (TT.t) { - if (str[end]==*TT.t) { - end++; - break; - } - } else if (isspace(str[end])) break; - } + if (k<1) for (end = h = 0;; end += h) { + ++k; + if (!(h = skip_key(str+end))) break; } + if (k<1) end = len*!j; + else for (end = 0, i = 1; istart && isspace(str[end-1])) end--; // Handle offsets on start and end - if (key->range[3]) { + if (key->range[3]>0) { end += key->range[3]-1; if (end>len) end=len; } - if (key->range[1]) { + if (key->range[1]>0) { start += key->range[1]-1; if (start>len) start=len; } @@ -161,8 +169,7 @@ static char *get_key_data(char *str, struct sort_key *key, int flags) static struct sort_key *add_key(void) { - void **stupid_compiler = &TT.key_list; - struct sort_key **pkey = (struct sort_key **)stupid_compiler; + struct sort_key **pkey = (struct sort_key **)&TT.key_list; while (*pkey) pkey = &((*pkey)->next_key); return *pkey = xzalloc(sizeof(struct sort_key)); -- 2.39.2