diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-02-21 20:08:54 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-02-21 20:08:54 +0100 |
commit | 7d285c78a35b1e745f7c6f27e31d73677ad2943a (patch) | |
tree | a830b467422c1ad3dbd2d419e11c1c003111a106 | |
parent | e789c3bea18181723c4ae7d761ec30926d182cfb (diff) | |
download | busybox-w32-7d285c78a35b1e745f7c6f27e31d73677ad2943a.tar.gz busybox-w32-7d285c78a35b1e745f7c6f27e31d73677ad2943a.tar.bz2 busybox-w32-7d285c78a35b1e745f7c6f27e31d73677ad2943a.zip |
sort: fix -s. Closes 10671
function old new delta
sort_main 786 862 +76
compare_keys 720 794 +74
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 150/0) Total: 150 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/sort.c | 69 |
1 files changed, 57 insertions, 12 deletions
diff --git a/coreutils/sort.c b/coreutils/sort.c index ceea24491..8ffd0cf44 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c | |||
@@ -62,9 +62,9 @@ | |||
62 | //usage: "\n -u Suppress duplicate lines" | 62 | //usage: "\n -u Suppress duplicate lines" |
63 | //usage: IF_FEATURE_SORT_BIG( | 63 | //usage: IF_FEATURE_SORT_BIG( |
64 | //usage: "\n -z Lines are terminated by NUL, not newline" | 64 | //usage: "\n -z Lines are terminated by NUL, not newline" |
65 | ////usage: "\n -m Ignored for GNU compatibility" | 65 | ///////: "\n -m Ignored for GNU compatibility" |
66 | ////usage: "\n -S BUFSZ Ignored for GNU compatibility" | 66 | ///////: "\n -S BUFSZ Ignored for GNU compatibility" |
67 | ////usage: "\n -T TMPDIR Ignored for GNU compatibility" | 67 | ///////: "\n -T TMPDIR Ignored for GNU compatibility" |
68 | //usage: ) | 68 | //usage: ) |
69 | //usage: | 69 | //usage: |
70 | //usage:#define sort_example_usage | 70 | //usage:#define sort_example_usage |
@@ -117,6 +117,7 @@ enum { | |||
117 | FLAG_k = 0x10000, | 117 | FLAG_k = 0x10000, |
118 | FLAG_t = 0x20000, | 118 | FLAG_t = 0x20000, |
119 | FLAG_bb = 0x80000000, /* Ignore trailing blanks */ | 119 | FLAG_bb = 0x80000000, /* Ignore trailing blanks */ |
120 | FLAG_no_tie_break = 0x40000000, | ||
120 | }; | 121 | }; |
121 | 122 | ||
122 | #if ENABLE_FEATURE_SORT_BIG | 123 | #if ENABLE_FEATURE_SORT_BIG |
@@ -340,10 +341,34 @@ static int compare_keys(const void *xarg, const void *yarg) | |||
340 | #endif | 341 | #endif |
341 | } /* for */ | 342 | } /* for */ |
342 | 343 | ||
343 | /* Perform fallback sort if necessary */ | 344 | if (retval == 0) { |
344 | if (!retval && !(option_mask32 & FLAG_s)) { | 345 | /* So far lines are "the same" */ |
345 | flags = option_mask32; | 346 | |
346 | retval = strcmp(*(char **)xarg, *(char **)yarg); | 347 | if (option_mask32 & FLAG_s) { |
348 | /* "Stable sort": later line is "smaller", | ||
349 | * IOW: do not allow qsort() to swap equal lines. | ||
350 | */ | ||
351 | uint32_t *p32; | ||
352 | uint32_t x32, y32; | ||
353 | char *line; | ||
354 | unsigned len; | ||
355 | |||
356 | line = *(char**)xarg; | ||
357 | len = (strlen(line) + 4) & (~3u); | ||
358 | p32 = (void*)(line + len); | ||
359 | x32 = *p32; | ||
360 | line = *(char**)yarg; | ||
361 | len = (strlen(line) + 4) & (~3u); | ||
362 | p32 = (void*)(line + len); | ||
363 | y32 = *p32; | ||
364 | |||
365 | retval = x32 > y32; | ||
366 | } else | ||
367 | if (!(option_mask32 & FLAG_no_tie_break)) { | ||
368 | /* fallback sort */ | ||
369 | flags = option_mask32; | ||
370 | retval = strcmp(*(char **)xarg, *(char **)yarg); | ||
371 | } | ||
347 | } | 372 | } |
348 | 373 | ||
349 | if (flags & FLAG_r) | 374 | if (flags & FLAG_r) |
@@ -368,7 +393,7 @@ static unsigned str2u(char **str) | |||
368 | int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 393 | int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
369 | int sort_main(int argc UNUSED_PARAM, char **argv) | 394 | int sort_main(int argc UNUSED_PARAM, char **argv) |
370 | { | 395 | { |
371 | char *line, **lines; | 396 | char **lines; |
372 | char *str_ignored, *str_o, *str_t; | 397 | char *str_ignored, *str_o, *str_t; |
373 | llist_t *lst_k = NULL; | 398 | llist_t *lst_k = NULL; |
374 | int i; | 399 | int i; |
@@ -457,7 +482,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv) | |||
457 | * do not continue to next file: */ | 482 | * do not continue to next file: */ |
458 | FILE *fp = xfopen_stdin(*argv); | 483 | FILE *fp = xfopen_stdin(*argv); |
459 | for (;;) { | 484 | for (;;) { |
460 | line = GET_LINE(fp); | 485 | char *line = GET_LINE(fp); |
461 | if (!line) | 486 | if (!line) |
462 | break; | 487 | break; |
463 | lines = xrealloc_vector(lines, 6, linecount); | 488 | lines = xrealloc_vector(lines, 6, linecount); |
@@ -482,15 +507,35 @@ int sort_main(int argc UNUSED_PARAM, char **argv) | |||
482 | return EXIT_SUCCESS; | 507 | return EXIT_SUCCESS; |
483 | } | 508 | } |
484 | #endif | 509 | #endif |
510 | |||
511 | /* For stable sort, store original line position beyond terminating NUL */ | ||
512 | if (option_mask32 & FLAG_s) { | ||
513 | for (i = 0; i < linecount; i++) { | ||
514 | uint32_t *p32; | ||
515 | char *line; | ||
516 | unsigned len; | ||
517 | |||
518 | line = lines[i]; | ||
519 | len = (strlen(line) + 4) & (~3u); | ||
520 | lines[i] = line = xrealloc(line, len + 4); | ||
521 | p32 = (void*)(line + len); | ||
522 | *p32 = i; | ||
523 | } | ||
524 | /*option_mask32 |= FLAG_no_tie_break;*/ | ||
525 | /* ^^^redundant: if FLAG_s, compare_keys() does no tie break */ | ||
526 | } | ||
527 | |||
485 | /* Perform the actual sort */ | 528 | /* Perform the actual sort */ |
486 | qsort(lines, linecount, sizeof(lines[0]), compare_keys); | 529 | qsort(lines, linecount, sizeof(lines[0]), compare_keys); |
487 | 530 | ||
488 | /* Handle -u */ | 531 | /* Handle -u */ |
489 | if (option_mask32 & FLAG_u) { | 532 | if (option_mask32 & FLAG_u) { |
490 | int j = 0; | 533 | int j = 0; |
491 | /* coreutils 6.3 drop lines for which only key is the same */ | 534 | /* coreutils 6.3 drop lines for which only key is the same |
492 | /* -- disabling last-resort compare... */ | 535 | * -- disabling last-resort compare, or else compare_keys() |
493 | option_mask32 |= FLAG_s; | 536 | * will be the same only for completely identical lines. |
537 | */ | ||
538 | option_mask32 |= FLAG_no_tie_break; | ||
494 | for (i = 1; i < linecount; i++) { | 539 | for (i = 1; i < linecount; i++) { |
495 | if (compare_keys(&lines[j], &lines[i]) == 0) | 540 | if (compare_keys(&lines[j], &lines[i]) == 0) |
496 | free(lines[i]); | 541 | free(lines[i]); |