diff --git a/coreutils/sort.c b/coreutils/sort.c index e2e7983a1..5c3fa1a71 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -278,27 +278,32 @@ static unsigned str2u(char **str) int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sort_main(int argc UNUSED_PARAM, char **argv) { - FILE *fp, *outfile = stdout; - char *line, **lines = NULL; + char *line, **lines; char *str_ignored, *str_o, *str_t; llist_t *lst_k = NULL; int i, flag; - int linecount = 0; + int linecount; + unsigned opts; xfunc_error_retval = 2; /* Parse command line options */ /* -o and -t can be given at most once */ - opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */ + opt_complementary = "o--o:t--t:" /* -t, -o: at most one of each */ "k::"; /* -k takes list */ - getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); + opts = getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); + /* global b strips leading and trailing spaces */ + if (opts & FLAG_b) + option_mask32 |= FLAG_bb; #if ENABLE_FEATURE_SORT_BIG - if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o); - if (option_mask32 & FLAG_t) { + if (opts & FLAG_t) { if (!str_t[0] || str_t[1]) bb_error_msg_and_die("bad -t parameter"); key_separator = str_t[0]; } + /* note: below this point we use option_mask32, not opts, + * since that reduces register pressure and makes code smaller */ + /* parse sort key */ while (lst_k) { enum { @@ -315,7 +320,6 @@ int sort_main(int argc UNUSED_PARAM, char **argv) }; struct sort_key *key = add_key(); char *str_k = llist_pop(&lst_k); - const char *temp2; i = 0; /* i==0 before comma, 1 after (-k3,6) */ while (*str_k) { @@ -327,11 +331,13 @@ int sort_main(int argc UNUSED_PARAM, char **argv) key->range[2*i+1] = str2u(&str_k); } while (*str_k) { + const char *temp2; + if (*str_k == ',' && !i++) { str_k++; break; } /* no else needed: fall through to syntax error - because comma isn't in OPT_STR */ + because comma isn't in OPT_STR */ temp2 = strchr(OPT_STR, *str_k); if (!temp2) bb_error_msg_and_die("unknown key option"); @@ -339,27 +345,29 @@ int sort_main(int argc UNUSED_PARAM, char **argv) if (flag & ~FLAG_allowed_for_k) bb_error_msg_and_die("unknown sort type"); /* b after ',' means strip _trailing_ space */ - if (i && flag == FLAG_b) flag = FLAG_bb; + if (i && flag == FLAG_b) + flag = FLAG_bb; key->flags |= flag; str_k++; } } } #endif - /* global b strips leading and trailing spaces */ - if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb; /* Open input files and read data */ argv += optind; if (!*argv) *--argv = (char*)"-"; + linecount = 0; + lines = NULL; do { /* coreutils 6.9 compat: abort on first open error, * do not continue to next file: */ - fp = xfopen_stdin(*argv); + FILE *fp = xfopen_stdin(*argv); for (;;) { line = GET_LINE(fp); - if (!line) break; + if (!line) + break; lines = xrealloc_vector(lines, 6, linecount); lines[linecount++] = line; } @@ -373,16 +381,17 @@ int sort_main(int argc UNUSED_PARAM, char **argv) /* handle -c */ if (option_mask32 & FLAG_c) { int j = (option_mask32 & FLAG_u) ? -1 : 0; - for (i = 1; i < linecount; i++) + for (i = 1; i < linecount; i++) { if (compare_keys(&lines[i-1], &lines[i]) > j) { - fprintf(stderr, "Check line %d\n", i); + fprintf(stderr, "Check line %u\n", i); return EXIT_FAILURE; } + } return EXIT_SUCCESS; } #endif /* Perform the actual sort */ - qsort(lines, linecount, sizeof(char *), compare_keys); + qsort(lines, linecount, sizeof(lines[0]), compare_keys); /* handle -u */ if (option_mask32 & FLAG_u) { flag = 0; @@ -390,17 +399,24 @@ int sort_main(int argc UNUSED_PARAM, char **argv) /* -- disabling last-resort compare... */ option_mask32 |= FLAG_s; for (i = 1; i < linecount; i++) { - if (!compare_keys(&lines[flag], &lines[i])) + if (compare_keys(&lines[flag], &lines[i]) == 0) free(lines[i]); else lines[++flag] = lines[i]; } - if (linecount) linecount = flag+1; + if (linecount) + linecount = flag+1; } + /* Print it */ +#if ENABLE_FEATURE_SORT_BIG + /* Open output file _after_ we read all input ones */ + if (option_mask32 & FLAG_o) + xmove_fd(xopen3(str_o, O_WRONLY, 0666), STDOUT_FILENO); +#endif flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; for (i = 0; i < linecount; i++) - fprintf(outfile, "%s%c", lines[i], flag); + printf("%s%c", lines[i], flag); fflush_stdout_and_exit(EXIT_SUCCESS); } diff --git a/testsuite/sort.tests b/testsuite/sort.tests index 5ed29fb12..72df80b1f 100755 --- a/testsuite/sort.tests +++ b/testsuite/sort.tests @@ -27,6 +27,8 @@ egg 1 2 papyrus 999 3 0 algebra " +# testing "description" "command(s)" "result" "infile" "stdin" + # Sorting with keys testing "sort one key" "sort -k4,4 input" \ @@ -115,4 +117,15 @@ one\0two\0three\0\ testing "sort key doesn't strip leading blanks, disables fallback global sort" \ "sort -n -k2 -t ' '" " a \n 1 \n 2 \n" "" " 2 \n 1 \n a \n" +testing "sort file in place" \ +"strace -oZZZ sort -o input input && cat input" "\ +111 +222 +" "\ +222 +111 +" "" + +# testing "description" "command(s)" "result" "infile" "stdin" + exit $FAILCOUNT