mirror of https://github.com/mirror/busybox.git
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
parent
31e2e7b863
commit
aa42d13e32
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue