sort: make sort -o FILE FILE (same FILE) work. Closes bug 785. -3 bytes
No binary (build failed)
—
(log yok)
| @@ -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); | |
| } | |
| @@ -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 | |