aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-02-21 20:08:54 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-02-21 20:08:54 +0100
commit7d285c78a35b1e745f7c6f27e31d73677ad2943a (patch)
treea830b467422c1ad3dbd2d419e11c1c003111a106
parente789c3bea18181723c4ae7d761ec30926d182cfb (diff)
downloadbusybox-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.c69
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)
368int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 393int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
369int sort_main(int argc UNUSED_PARAM, char **argv) 394int 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]);