sort: make sort -o FILE FILE (same FILE) work. Closes bug 785. -3 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
1_16_stable
Denys Vlasenko 2009-12-13 02:09:22 +01:00
parent 31e2e7b863
commit aa42d13e32
2 changed files with 49 additions and 20 deletions

View 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, char **argv) MAIN_EXTERNALLY_VISIBLE;
int sort_main(int argc UNUSED_PARAM, char **argv) int sort_main(int argc UNUSED_PARAM, char **argv)
{ {
FILE *fp, *outfile = stdout; char *line, **lines;
char *line, **lines = NULL;
char *str_ignored, *str_o, *str_t; char *str_ignored, *str_o, *str_t;
llist_t *lst_k = NULL; llist_t *lst_k = NULL;
int i, flag; int i, flag;
int linecount = 0; int linecount;
unsigned opts;
xfunc_error_retval = 2; xfunc_error_retval = 2;
/* Parse command line options */ /* Parse command line options */
/* -o and -t can be given at most once */ /* -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 */ "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 ENABLE_FEATURE_SORT_BIG
if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o); if (opts & FLAG_t) {
if (option_mask32 & FLAG_t) {
if (!str_t[0] || str_t[1]) if (!str_t[0] || str_t[1])
bb_error_msg_and_die("bad -t parameter"); bb_error_msg_and_die("bad -t parameter");
key_separator = str_t[0]; 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 */ /* parse sort key */
while (lst_k) { while (lst_k) {
enum { enum {
@ -315,7 +320,6 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
}; };
struct sort_key *key = add_key(); struct sort_key *key = add_key();
char *str_k = llist_pop(&lst_k); char *str_k = llist_pop(&lst_k);
const char *temp2;
i = 0; /* i==0 before comma, 1 after (-k3,6) */ i = 0; /* i==0 before comma, 1 after (-k3,6) */
while (*str_k) { while (*str_k) {
@ -327,11 +331,13 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
key->range[2*i+1] = str2u(&str_k); key->range[2*i+1] = str2u(&str_k);
} }
while (*str_k) { while (*str_k) {
const char *temp2;
if (*str_k == ',' && !i++) { if (*str_k == ',' && !i++) {
str_k++; str_k++;
break; break;
} /* no else needed: fall through to syntax error } /* 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); temp2 = strchr(OPT_STR, *str_k);
if (!temp2) if (!temp2)
bb_error_msg_and_die("unknown key option"); 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) if (flag & ~FLAG_allowed_for_k)
bb_error_msg_and_die("unknown sort type"); bb_error_msg_and_die("unknown sort type");
/* b after ',' means strip _trailing_ space */ /* 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; key->flags |= flag;
str_k++; str_k++;
} }
} }
} }
#endif #endif
/* global b strips leading and trailing spaces */
if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb;
/* Open input files and read data */ /* Open input files and read data */
argv += optind; argv += optind;
if (!*argv) if (!*argv)
*--argv = (char*)"-"; *--argv = (char*)"-";
linecount = 0;
lines = NULL;
do { do {
/* coreutils 6.9 compat: abort on first open error, /* coreutils 6.9 compat: abort on first open error,
* do not continue to next file: */ * do not continue to next file: */
fp = xfopen_stdin(*argv); FILE *fp = xfopen_stdin(*argv);
for (;;) { for (;;) {
line = GET_LINE(fp); line = GET_LINE(fp);
if (!line) break; if (!line)
break;
lines = xrealloc_vector(lines, 6, linecount); lines = xrealloc_vector(lines, 6, linecount);
lines[linecount++] = line; lines[linecount++] = line;
} }
@ -373,16 +381,17 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
/* handle -c */ /* handle -c */
if (option_mask32 & FLAG_c) { if (option_mask32 & FLAG_c) {
int j = (option_mask32 & FLAG_u) ? -1 : 0; 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) { 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_FAILURE;
} }
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
#endif #endif
/* Perform the actual sort */ /* Perform the actual sort */
qsort(lines, linecount, sizeof(char *), compare_keys); qsort(lines, linecount, sizeof(lines[0]), compare_keys);
/* handle -u */ /* handle -u */
if (option_mask32 & FLAG_u) { if (option_mask32 & FLAG_u) {
flag = 0; flag = 0;
@ -390,17 +399,24 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
/* -- disabling last-resort compare... */ /* -- disabling last-resort compare... */
option_mask32 |= FLAG_s; option_mask32 |= FLAG_s;
for (i = 1; i < linecount; i++) { for (i = 1; i < linecount; i++) {
if (!compare_keys(&lines[flag], &lines[i])) if (compare_keys(&lines[flag], &lines[i]) == 0)
free(lines[i]); free(lines[i]);
else else
lines[++flag] = lines[i]; lines[++flag] = lines[i];
} }
if (linecount) linecount = flag+1; if (linecount)
linecount = flag+1;
} }
/* Print it */ /* 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'; flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
for (i = 0; i < linecount; i++) 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); fflush_stdout_and_exit(EXIT_SUCCESS);
} }

View File

@ -27,6 +27,8 @@ egg 1 2 papyrus
999 3 0 algebra 999 3 0 algebra
" "
# testing "description" "command(s)" "result" "infile" "stdin"
# Sorting with keys # Sorting with keys
testing "sort one key" "sort -k4,4 input" \ 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" \ 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" "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 exit $FAILCOUNT