X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=coreutils%2Fsort.c;h=a1625fc9cdb30a6d332ba023ef901ff6abac172d;hb=1b49c25e0a719ec3051eafa2329e68012c815abb;hp=dad542964680d175fe5b20d37ae3b6b3e365275e;hpb=8d9f495d68664017e0b87f2c0c2d0eae9f3c4836;p=oweals%2Fbusybox.git diff --git a/coreutils/sort.c b/coreutils/sort.c index dad542964..a1625fc9c 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -6,13 +6,63 @@ * * MAINTAINER: Rob Landley * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * See SuS3 sort standard at: * http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html */ -#include "busybox.h" +//usage:#define sort_trivial_usage +//usage: "[-nru" +//usage: IF_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") +//usage: "] [FILE]..." +//usage:#define sort_full_usage "\n\n" +//usage: "Sort lines of text\n" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -b Ignore leading blanks" +//usage: "\n -c Check whether input is sorted" +//usage: "\n -d Dictionary order (blank or alphanumeric only)" +//usage: "\n -f Ignore case" +//usage: "\n -g General numerical sort" +//usage: "\n -i Ignore unprintable characters" +//usage: "\n -k Sort key" +//usage: "\n -M Sort month" +//usage: ) +//usage: "\n -n Sort numbers" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -o Output to file" +//usage: "\n -k Sort by key" +//usage: "\n -t CHAR Key separator" +//usage: ) +//usage: "\n -r Reverse sort order" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -s Stable (don't sort ties alphabetically)" +//usage: ) +//usage: "\n -u Suppress duplicate lines" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -z Lines are terminated by NUL, not newline" +//usage: "\n -mST Ignored for GNU compatibility") +//usage: +//usage:#define sort_example_usage +//usage: "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" +//usage: "a\n" +//usage: "b\n" +//usage: "c\n" +//usage: "d\n" +//usage: "e\n" +//usage: "f\n" +//usage: IF_FEATURE_SORT_BIG( +//usage: "$ echo -e \"c 3\\nb 2\\nd 2\" | $SORT -k 2,2n -k 1,1r\n" +//usage: "d 2\n" +//usage: "b 2\n" +//usage: "c 3\n" +//usage: ) +//usage: "" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + /* sort [-m][-o output][-bdfinru][-t char][-k keydef]... [file...] @@ -20,7 +70,7 @@ */ /* These are sort types */ -static const char OPT_STR[] = "ngMucszbrdfimS:T:o:k:t:"; +static const char OPT_STR[] ALIGN1 = "ngMucszbrdfimS:T:o:k:t:"; enum { FLAG_n = 1, /* Numeric sort */ FLAG_g = 2, /* Sort using strtod() */ @@ -29,7 +79,7 @@ enum { FLAG_u = 8, /* Unique */ FLAG_c = 0x10, /* Check: no output, exit(!ordered) */ FLAG_s = 0x20, /* Stable sort, no ascii fallback at end */ - FLAG_z = 0x40, /* Input is null terminated, not \n */ + FLAG_z = 0x40, /* Input and output is NUL terminated, not \n */ /* These can be applied to search keys, the previous four can't */ FLAG_b = 0x80, /* Ignore leading blanks */ FLAG_r = 0x100, /* Reverse */ @@ -49,14 +99,15 @@ enum { static char key_separator; static struct sort_key { - struct sort_key *next_key; /* linked list */ - unsigned range[4]; /* start word, start char, end word, end char */ + struct sort_key *next_key; /* linked list */ + unsigned range[4]; /* start word, start char, end word, end char */ unsigned flags; } *key_list; static char *get_key(char *str, struct sort_key *key, int flags) { - int start = 0, end = 0, len, i, j; + int start = 0, end = 0, len, j; + unsigned i; /* Special case whole string, so we don't have to make a copy */ if (key->range[0] == 1 && !key->range[1] && !key->range[2] && !key->range[3] @@ -124,7 +175,7 @@ static char *get_key(char *str, struct sort_key *key, int flags) /* Handle -i */ if (flags & FLAG_i) { for (start = end = 0; str[end]; end++) - if (isprint(str[end])) + if (isprint_asciionly(str[end])) str[start++] = str[end]; str[start] = '\0'; } @@ -147,9 +198,9 @@ static struct sort_key *add_key(void) #define GET_LINE(fp) \ ((option_mask32 & FLAG_z) \ ? bb_get_chunk_from_file(fp, NULL) \ - : xmalloc_getline(fp)) + : xmalloc_fgetline(fp)) #else -#define GET_LINE(fp) xmalloc_getline(fp) +#define GET_LINE(fp) xmalloc_fgetline(fp) #endif /* Iterate through keys list and perform comparisons */ @@ -168,7 +219,7 @@ static int compare_keys(const void *xarg, const void *yarg) y = get_key(*(char **)yarg, key, flags); #else /* This curly bracket serves no purpose but to match the nesting - level of the for () loop we're not using */ + * level of the for () loop we're not using */ { x = *(char **)xarg; y = *(char **)yarg; @@ -271,30 +322,35 @@ static unsigned str2u(char **str) } #endif -int sort_main(int argc, char **argv); -int sort_main(int argc, char **argv) +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(argc, 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(str_o, "w"); - 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 { @@ -310,8 +366,7 @@ int sort_main(int argc, char **argv) 0 }; struct sort_key *key = add_key(); - char *str_k = lst_k->data; - const char *temp2; + char *str_k = llist_pop(&lst_k); i = 0; /* i==0 before comma, 1 after (-k3,6) */ while (*str_k) { @@ -323,11 +378,13 @@ int sort_main(int argc, 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"); @@ -335,32 +392,35 @@ int sort_main(int argc, 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++; } } - /* leaking lst_k... */ - lst_k = lst_k->link; } #endif - /* global b strips leading and trailing spaces */ - if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb; /* Open input files and read data */ - for (i = argv[optind] ? optind : optind-1; argv[i]; i++) { - fp = stdin; - if (i >= optind && NOT_LONE_DASH(argv[i])) - fp = xfopen(argv[i], "r"); + 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: */ + FILE *fp = xfopen_stdin(*argv); for (;;) { line = GET_LINE(fp); - if (!line) break; - if (!(linecount & 63)) - lines = xrealloc(lines, sizeof(char *) * (linecount + 64)); + if (!line) + break; + lines = xrealloc_vector(lines, 6, linecount); lines[linecount++] = line; } - fclose(fp); - } + fclose_if_not_stdin(fp); + } while (*++argv); + #if ENABLE_FEATURE_SORT_BIG /* if no key, perform alphabetic sort */ if (!key_list) @@ -368,16 +428,17 @@ int sort_main(int argc, 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); - return 1; + fprintf(stderr, "Check line %u\n", i); + return EXIT_FAILURE; } - return 0; + } + 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; @@ -385,16 +446,24 @@ int sort_main(int argc, 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(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO); +#endif + flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; for (i = 0; i < linecount; i++) - fprintf(outfile, "%s\n", lines[i]); + printf("%s%c", lines[i], flag); fflush_stdout_and_exit(EXIT_SUCCESS); }