Skip to content

Commit

Permalink
Make negative sort offsets in -k keys count right to left.
Browse files Browse the repository at this point in the history
  • Loading branch information
landley committed Aug 15, 2023
1 parent c214dcd commit 8deb589
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 28 deletions.
14 changes: 13 additions & 1 deletion tests/sort.test
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
61 changes: 34 additions & 27 deletions toys/posix/sort.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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; i<k+j; i++) end += skip_key(str+end);
}
if (!j) start = end;
}
Expand All @@ -127,11 +135,11 @@ static char *get_key_data(char *str, struct sort_key *key, int flags)
if (flags&FLAG_bb) while (end>start && 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;
}
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit 8deb589

Please sign in to comment.