sort: make sort -o FILE FILE (same FILE) work. Closes bug 785. -3 bytes
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 13 Dec 2009 01:09:22 +0000 (02:09 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 13 Dec 2009 01:09:22 +0000 (02:09 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/sort.c
testsuite/sort.tests

index e2e7983a1ebd173f1a6b62343cac88c3ce03091a..5c3fa1a718e1cd14efa90c84b26540ca46f0d5b4 100644 (file)
@@ -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);
 }
index 5ed29fb12cd33e7ae5fe5e3577129961e934633d..72df80b1f3b61d06cf8e70e80f49f2ebeb937ba3 100755 (executable)
@@ -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