128 |
/* Handle -i */ |
/* Handle -i */ |
129 |
if (flags & FLAG_i) { |
if (flags & FLAG_i) { |
130 |
for (start = end = 0; str[end]; end++) |
for (start = end = 0; str[end]; end++) |
131 |
if (isprint(str[end])) |
if (isprint_asciionly(str[end])) |
132 |
str[start++] = str[end]; |
str[start++] = str[end]; |
133 |
str[start] = '\0'; |
str[start] = '\0'; |
134 |
} |
} |
278 |
int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
279 |
int sort_main(int argc UNUSED_PARAM, char **argv) |
int sort_main(int argc UNUSED_PARAM, char **argv) |
280 |
{ |
{ |
281 |
FILE *fp, *outfile = stdout; |
char *line, **lines; |
|
char *line, **lines = NULL; |
|
282 |
char *str_ignored, *str_o, *str_t; |
char *str_ignored, *str_o, *str_t; |
283 |
llist_t *lst_k = NULL; |
llist_t *lst_k = NULL; |
284 |
int i, flag; |
int i, flag; |
285 |
int linecount = 0; |
int linecount; |
286 |
|
unsigned opts; |
287 |
|
|
288 |
xfunc_error_retval = 2; |
xfunc_error_retval = 2; |
289 |
|
|
290 |
/* Parse command line options */ |
/* Parse command line options */ |
291 |
/* -o and -t can be given at most once */ |
/* -o and -t can be given at most once */ |
292 |
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 */ |
293 |
"k::"; /* -k takes list */ |
"k::"; /* -k takes list */ |
294 |
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); |
295 |
|
/* global b strips leading and trailing spaces */ |
296 |
|
if (opts & FLAG_b) |
297 |
|
option_mask32 |= FLAG_bb; |
298 |
#if ENABLE_FEATURE_SORT_BIG |
#if ENABLE_FEATURE_SORT_BIG |
299 |
if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o); |
if (opts & FLAG_t) { |
|
if (option_mask32 & FLAG_t) { |
|
300 |
if (!str_t[0] || str_t[1]) |
if (!str_t[0] || str_t[1]) |
301 |
bb_error_msg_and_die("bad -t parameter"); |
bb_error_msg_and_die("bad -t parameter"); |
302 |
key_separator = str_t[0]; |
key_separator = str_t[0]; |
303 |
} |
} |
304 |
|
/* note: below this point we use option_mask32, not opts, |
305 |
|
* since that reduces register pressure and makes code smaller */ |
306 |
|
|
307 |
/* parse sort key */ |
/* parse sort key */ |
308 |
while (lst_k) { |
while (lst_k) { |
309 |
enum { |
enum { |
320 |
}; |
}; |
321 |
struct sort_key *key = add_key(); |
struct sort_key *key = add_key(); |
322 |
char *str_k = llist_pop(&lst_k); |
char *str_k = llist_pop(&lst_k); |
|
const char *temp2; |
|
323 |
|
|
324 |
i = 0; /* i==0 before comma, 1 after (-k3,6) */ |
i = 0; /* i==0 before comma, 1 after (-k3,6) */ |
325 |
while (*str_k) { |
while (*str_k) { |
331 |
key->range[2*i+1] = str2u(&str_k); |
key->range[2*i+1] = str2u(&str_k); |
332 |
} |
} |
333 |
while (*str_k) { |
while (*str_k) { |
334 |
|
const char *temp2; |
335 |
|
|
336 |
if (*str_k == ',' && !i++) { |
if (*str_k == ',' && !i++) { |
337 |
str_k++; |
str_k++; |
338 |
break; |
break; |
339 |
} /* no else needed: fall through to syntax error |
} /* no else needed: fall through to syntax error |
340 |
because comma isn't in OPT_STR */ |
because comma isn't in OPT_STR */ |
341 |
temp2 = strchr(OPT_STR, *str_k); |
temp2 = strchr(OPT_STR, *str_k); |
342 |
if (!temp2) |
if (!temp2) |
343 |
bb_error_msg_and_die("unknown key option"); |
bb_error_msg_and_die("unknown key option"); |
345 |
if (flag & ~FLAG_allowed_for_k) |
if (flag & ~FLAG_allowed_for_k) |
346 |
bb_error_msg_and_die("unknown sort type"); |
bb_error_msg_and_die("unknown sort type"); |
347 |
/* b after ',' means strip _trailing_ space */ |
/* b after ',' means strip _trailing_ space */ |
348 |
if (i && flag == FLAG_b) flag = FLAG_bb; |
if (i && flag == FLAG_b) |
349 |
|
flag = FLAG_bb; |
350 |
key->flags |= flag; |
key->flags |= flag; |
351 |
str_k++; |
str_k++; |
352 |
} |
} |
353 |
} |
} |
354 |
} |
} |
355 |
#endif |
#endif |
|
/* global b strips leading and trailing spaces */ |
|
|
if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb; |
|
356 |
|
|
357 |
/* Open input files and read data */ |
/* Open input files and read data */ |
358 |
argv += optind; |
argv += optind; |
359 |
if (!*argv) |
if (!*argv) |
360 |
*--argv = (char*)"-"; |
*--argv = (char*)"-"; |
361 |
|
linecount = 0; |
362 |
|
lines = NULL; |
363 |
do { |
do { |
364 |
/* coreutils 6.9 compat: abort on first open error, |
/* coreutils 6.9 compat: abort on first open error, |
365 |
* do not continue to next file: */ |
* do not continue to next file: */ |
366 |
fp = xfopen_stdin(*argv); |
FILE *fp = xfopen_stdin(*argv); |
367 |
for (;;) { |
for (;;) { |
368 |
line = GET_LINE(fp); |
line = GET_LINE(fp); |
369 |
if (!line) break; |
if (!line) |
370 |
|
break; |
371 |
lines = xrealloc_vector(lines, 6, linecount); |
lines = xrealloc_vector(lines, 6, linecount); |
372 |
lines[linecount++] = line; |
lines[linecount++] = line; |
373 |
} |
} |
381 |
/* handle -c */ |
/* handle -c */ |
382 |
if (option_mask32 & FLAG_c) { |
if (option_mask32 & FLAG_c) { |
383 |
int j = (option_mask32 & FLAG_u) ? -1 : 0; |
int j = (option_mask32 & FLAG_u) ? -1 : 0; |
384 |
for (i = 1; i < linecount; i++) |
for (i = 1; i < linecount; i++) { |
385 |
if (compare_keys(&lines[i-1], &lines[i]) > j) { |
if (compare_keys(&lines[i-1], &lines[i]) > j) { |
386 |
fprintf(stderr, "Check line %d\n", i); |
fprintf(stderr, "Check line %u\n", i); |
387 |
return EXIT_FAILURE; |
return EXIT_FAILURE; |
388 |
} |
} |
389 |
|
} |
390 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
391 |
} |
} |
392 |
#endif |
#endif |
393 |
/* Perform the actual sort */ |
/* Perform the actual sort */ |
394 |
qsort(lines, linecount, sizeof(char *), compare_keys); |
qsort(lines, linecount, sizeof(lines[0]), compare_keys); |
395 |
/* handle -u */ |
/* handle -u */ |
396 |
if (option_mask32 & FLAG_u) { |
if (option_mask32 & FLAG_u) { |
397 |
flag = 0; |
flag = 0; |
399 |
/* -- disabling last-resort compare... */ |
/* -- disabling last-resort compare... */ |
400 |
option_mask32 |= FLAG_s; |
option_mask32 |= FLAG_s; |
401 |
for (i = 1; i < linecount; i++) { |
for (i = 1; i < linecount; i++) { |
402 |
if (!compare_keys(&lines[flag], &lines[i])) |
if (compare_keys(&lines[flag], &lines[i]) == 0) |
403 |
free(lines[i]); |
free(lines[i]); |
404 |
else |
else |
405 |
lines[++flag] = lines[i]; |
lines[++flag] = lines[i]; |
406 |
} |
} |
407 |
if (linecount) linecount = flag+1; |
if (linecount) |
408 |
|
linecount = flag+1; |
409 |
} |
} |
410 |
|
|
411 |
/* Print it */ |
/* Print it */ |
412 |
|
#if ENABLE_FEATURE_SORT_BIG |
413 |
|
/* Open output file _after_ we read all input ones */ |
414 |
|
if (option_mask32 & FLAG_o) |
415 |
|
xmove_fd(xopen3(str_o, O_WRONLY, 0666), STDOUT_FILENO); |
416 |
|
#endif |
417 |
flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; |
flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; |
418 |
for (i = 0; i < linecount; i++) |
for (i = 0; i < linecount; i++) |
419 |
fprintf(outfile, "%s%c", lines[i], flag); |
printf("%s%c", lines[i], flag); |
420 |
|
|
421 |
fflush_stdout_and_exit(EXIT_SUCCESS); |
fflush_stdout_and_exit(EXIT_SUCCESS); |
422 |
} |
} |