int sort_main(int argc, char **argv) { FILE *fp, *outfile = stdout; char *line, **lines = NULL; char *str_ignored, *str_o, *str_t; llist_t *lst_k = NULL; int i, flag; int linecount = 0; 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 */ "k::"; /* -k takes list */ getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t); #if ENABLE_FEATURE_SORT_BIG if (option_mask32 & FLAG_o) outfile = xfopen(str_o, "w"); if (option_mask32 & FLAG_t) { if (!str_t[0] || str_t[1]) bb_error_msg_and_die("bad -t parameter"); key_separator = str_t[0]; } /* parse sort key */ while (lst_k) { enum { FLAG_allowed_for_k = FLAG_n | /* Numeric sort */ FLAG_g | /* Sort using strtod() */ FLAG_M | /* Sort date */ FLAG_b | /* Ignore leading blanks */ FLAG_r | /* Reverse */ FLAG_d | /* Ignore !(isalnum()|isspace()) */ FLAG_f | /* Force uppercase */ FLAG_i | /* Ignore !isprint() */ 0 }; struct sort_key *key = add_key(); char *str_k = lst_k->data; const char *temp2; i = 0; /* i==0 before comma, 1 after (-k3,6) */ while (*str_k) { /* Start of range */ /* Cannot use bb_strtou - suffix can be a letter */ key->range[2*i] = str2u(&str_k); if (*str_k == '.') { str_k++; key->range[2*i+1] = str2u(&str_k); } while (*str_k) { if (*str_k == ',' && !i++) { str_k++; break; } /* no else needed: fall through to syntax error because comma isn't in OPT_STR */ temp2 = strchr(OPT_STR, *str_k); if (!temp2) bb_error_msg_and_die("unknown key option"); flag = 1 << (temp2 - OPT_STR); 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; 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"); for (;;) { line = GET_LINE(fp); if (!line) break; if (!(linecount & 63)) lines = xrealloc(lines, sizeof(char *) * (linecount + 64)); lines[linecount++] = line; } fclose(fp); } #if ENABLE_FEATURE_SORT_BIG /* if no key, perform alphabetic sort */ if (!key_list) add_key()->range[0] = 1; /* handle -c */ if (option_mask32 & FLAG_c) { int j = (option_mask32 & FLAG_u) ? -1 : 0; for (i = 1; i < linecount; i++) if (compare_keys(&lines[i-1], &lines[i]) > j) { fprintf(stderr, "Check line %d\n", i); return 1; } return 0; } #endif /* Perform the actual sort */ qsort(lines, linecount, sizeof(char *), compare_keys); /* handle -u */ if (option_mask32 & FLAG_u) { flag = 0; /* coreutils 6.3 drop lines for which only key is the same */ /* -- disabling last-resort compare... */ option_mask32 |= FLAG_s; for (i = 1; i < linecount; i++) { if (!compare_keys(&lines[flag], &lines[i])) free(lines[i]); else lines[++flag] = lines[i]; } if (linecount) linecount = flag+1; } /* Print it */ for (i = 0; i < linecount; i++) fprintf(outfile, "%s\n", lines[i]); fflush_stdout_and_exit(EXIT_SUCCESS); }
int sort_main(int argc UNUSED_PARAM, char **argv) { char *line, **lines; char *str_ignored, *str_o, *str_t; llist_t *lst_k = NULL; int i, flag; 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: at most one of each */ "k::"; /* -k takes list */ 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 (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 { FLAG_allowed_for_k = FLAG_n | /* Numeric sort */ FLAG_g | /* Sort using strtod() */ FLAG_M | /* Sort date */ FLAG_b | /* Ignore leading blanks */ FLAG_r | /* Reverse */ FLAG_d | /* Ignore !(isalnum()|isspace()) */ FLAG_f | /* Force uppercase */ FLAG_i | /* Ignore !isprint() */ 0 }; struct sort_key *key = add_key(); char *str_k = llist_pop(&lst_k); i = 0; /* i==0 before comma, 1 after (-k3,6) */ while (*str_k) { /* Start of range */ /* Cannot use bb_strtou - suffix can be a letter */ key->range[2*i] = str2u(&str_k); if (*str_k == '.') { str_k++; 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 */ temp2 = strchr(OPT_STR, *str_k); if (!temp2) bb_error_msg_and_die("unknown key option"); flag = 1 << (temp2 - OPT_STR); 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; key->flags |= flag; str_k++; } } } #endif /* 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: */ FILE *fp = xfopen_stdin(*argv); for (;;) { line = GET_LINE(fp); if (!line) break; lines = xrealloc_vector(lines, 6, linecount); lines[linecount++] = line; } fclose_if_not_stdin(fp); } while (*++argv); #if ENABLE_FEATURE_SORT_BIG /* if no key, perform alphabetic sort */ if (!key_list) add_key()->range[0] = 1; /* handle -c */ if (option_mask32 & FLAG_c) { int j = (option_mask32 & FLAG_u) ? -1 : 0; for (i = 1; i < linecount; i++) { if (compare_keys(&lines[i-1], &lines[i]) > j) { fprintf(stderr, "Check line %u\n", i); return EXIT_FAILURE; } } return EXIT_SUCCESS; } #endif /* Perform the actual sort */ qsort(lines, linecount, sizeof(lines[0]), compare_keys); /* handle -u */ if (option_mask32 & FLAG_u) { flag = 0; /* coreutils 6.3 drop lines for which only key is the same */ /* -- disabling last-resort compare... */ option_mask32 |= FLAG_s; for (i = 1; i < linecount; i++) { if (compare_keys(&lines[flag], &lines[i]) == 0) free(lines[i]); else lines[++flag] = lines[i]; } 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++) printf("%s%c", lines[i], flag); fflush_stdout_and_exit(EXIT_SUCCESS); }