diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-13 03:43:43 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-13 03:43:43 +0200 |
commit | d5fa1a0f49c4872f614a4674922f4362b114fece (patch) | |
tree | 64d0af64712f546499a165f5997b569ed890d9ee | |
parent | d2d327db6d38d5a6e8e253c54d3e97466ce3bc79 (diff) | |
download | busybox-w32-d5fa1a0f49c4872f614a4674922f4362b114fece.tar.gz busybox-w32-d5fa1a0f49c4872f614a4674922f4362b114fece.tar.bz2 busybox-w32-d5fa1a0f49c4872f614a4674922f4362b114fece.zip |
xargs: code shrink -15 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | findutils/xargs.c | 154 | ||||
-rwxr-xr-x | testsuite/xargs.tests | 5 |
2 files changed, 79 insertions, 80 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c index 9133b8f6c..25a785336 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -122,53 +122,49 @@ typedef struct xlist_t { | |||
122 | char xstr[1]; | 122 | char xstr[1]; |
123 | } xlist_t; | 123 | } xlist_t; |
124 | 124 | ||
125 | static smallint eof_stdin_detected; | 125 | /* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space. |
126 | 126 | * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. | |
127 | #define ISBLANK(c) ((c) == ' ' || (c) == '\t') | 127 | */ |
128 | #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ | 128 | #define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); }) |
129 | || (c) == '\f' || (c) == '\v') | ||
130 | 129 | ||
131 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES | 130 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES |
132 | static xlist_t *process_stdin(xlist_t *list_arg, | 131 | static xlist_t* process_stdin(xlist_t *list_arg, |
133 | const char *eof_str, size_t mc, char *buf) | 132 | const char *eof_str, size_t mc, char *buf) |
134 | { | 133 | { |
135 | #define NORM 0 | 134 | #define NORM 0 |
136 | #define QUOTE 1 | 135 | #define QUOTE 1 |
137 | #define BACKSLASH 2 | 136 | #define BACKSLASH 2 |
138 | #define SPACE 4 | 137 | #define SPACE 4 |
139 | 138 | char *s = NULL; /* start of the word */ | |
140 | char *s = NULL; /* start word */ | 139 | char *p = NULL; /* pointer to end of the word */ |
141 | char *p = NULL; /* pointer to end word */ | ||
142 | char q = '\0'; /* quote char */ | 140 | char q = '\0'; /* quote char */ |
143 | char state = NORM; | 141 | char state = NORM; |
144 | char eof_str_detected = 0; | 142 | char eof_str_detected = 0; |
145 | size_t line_l = 0; /* size loaded args line */ | 143 | size_t line_l = 0; /* size of loaded args */ |
146 | int c; /* current char */ | ||
147 | xlist_t *cur; | 144 | xlist_t *cur; |
148 | xlist_t *prev; | 145 | xlist_t *prev; |
149 | 146 | ||
150 | prev = cur = list_arg; | 147 | prev = cur = list_arg; |
151 | while (1) { | 148 | while (cur) { |
152 | if (!cur) break; | ||
153 | prev = cur; | 149 | prev = cur; |
154 | line_l += cur->length; | 150 | line_l += cur->length; |
155 | cur = cur->link; | 151 | cur = cur->link; |
156 | } | 152 | } |
157 | 153 | ||
158 | while (!eof_stdin_detected) { | 154 | while (1) { |
159 | c = getchar(); | 155 | int c = getchar(); |
160 | if (c == EOF) { | 156 | if (c == EOF) { |
161 | eof_stdin_detected = 1; | ||
162 | if (s) | 157 | if (s) |
163 | goto unexpected_eof; | 158 | goto unexpected_eof; |
164 | break; | 159 | break; |
165 | } | 160 | } |
166 | if (eof_str_detected) | 161 | if (eof_str_detected) /* skip till EOF */ |
167 | continue; | 162 | continue; |
168 | if (state == BACKSLASH) { | 163 | if (state == BACKSLASH) { |
169 | state = NORM; | 164 | state = NORM; |
170 | goto set; | 165 | goto set; |
171 | } else if (state == QUOTE) { | 166 | } |
167 | if (state == QUOTE) { | ||
172 | if (c != q) | 168 | if (c != q) |
173 | goto set; | 169 | goto set; |
174 | q = '\0'; | 170 | q = '\0'; |
@@ -202,7 +198,7 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
202 | bb_error_msg_and_die("unmatched %s quote", | 198 | bb_error_msg_and_die("unmatched %s quote", |
203 | q == '\'' ? "single" : "double"); | 199 | q == '\'' ? "single" : "double"); |
204 | } | 200 | } |
205 | /* word loaded */ | 201 | /* A full word is loaded */ |
206 | if (eof_str) { | 202 | if (eof_str) { |
207 | eof_str_detected = (strcmp(s, eof_str) == 0); | 203 | eof_str_detected = (strcmp(s, eof_str) == 0); |
208 | } | 204 | } |
@@ -220,10 +216,8 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
220 | } | 216 | } |
221 | prev = cur; | 217 | prev = cur; |
222 | line_l += length; | 218 | line_l += length; |
223 | if (line_l > mc) { | 219 | if (line_l > mc) /* limit stop memory usage */ |
224 | /* stop memory usage :-) */ | ||
225 | break; | 220 | break; |
226 | } | ||
227 | } | 221 | } |
228 | s = NULL; | 222 | s = NULL; |
229 | state = NORM; | 223 | state = NORM; |
@@ -233,33 +227,32 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
233 | } | 227 | } |
234 | #else | 228 | #else |
235 | /* The variant does not support single quotes, double quotes or backslash */ | 229 | /* The variant does not support single quotes, double quotes or backslash */ |
236 | static xlist_t *process_stdin(xlist_t *list_arg, | 230 | static xlist_t* process_stdin(xlist_t *list_arg, |
237 | const char *eof_str, size_t mc, char *buf) | 231 | const char *eof_str, size_t mc, char *buf) |
238 | { | 232 | { |
239 | |||
240 | int c; /* current char */ | ||
241 | char eof_str_detected = 0; | 233 | char eof_str_detected = 0; |
242 | char *s = NULL; /* start word */ | 234 | char *s = NULL; /* start of the word */ |
243 | char *p = NULL; /* pointer to end word */ | 235 | char *p = NULL; /* pointer to end of the word */ |
244 | size_t line_l = 0; /* size loaded args line */ | 236 | size_t line_l = 0; /* size of loaded args */ |
245 | xlist_t *cur; | 237 | xlist_t *cur; |
246 | xlist_t *prev; | 238 | xlist_t *prev; |
247 | 239 | ||
248 | prev = cur = list_arg; | 240 | prev = cur = list_arg; |
249 | while (1) { | 241 | while (cur) { |
250 | if (!cur) break; | ||
251 | prev = cur; | 242 | prev = cur; |
252 | line_l += cur->length; | 243 | line_l += cur->length; |
253 | cur = cur->link; | 244 | cur = cur->link; |
254 | } | 245 | } |
255 | 246 | ||
256 | while (!eof_stdin_detected) { | 247 | while (1) { |
257 | c = getchar(); | 248 | int c = getchar(); |
258 | if (c == EOF) { | 249 | if (c == EOF) { |
259 | eof_stdin_detected = 1; | 250 | if (s == NULL) |
251 | break; | ||
260 | } | 252 | } |
261 | if (eof_str_detected) | 253 | if (eof_str_detected) { /* skip till EOF */ |
262 | continue; | 254 | continue; |
255 | } | ||
263 | if (c == EOF || ISSPACE(c)) { | 256 | if (c == EOF || ISSPACE(c)) { |
264 | if (s == NULL) | 257 | if (s == NULL) |
265 | continue; | 258 | continue; |
@@ -271,7 +264,7 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
271 | bb_error_msg_and_die("argument line too long"); | 264 | bb_error_msg_and_die("argument line too long"); |
272 | *p++ = (c == EOF ? '\0' : c); | 265 | *p++ = (c == EOF ? '\0' : c); |
273 | if (c == EOF) { /* word's delimiter or EOF detected */ | 266 | if (c == EOF) { /* word's delimiter or EOF detected */ |
274 | /* word loaded */ | 267 | /* A full word is loaded */ |
275 | if (eof_str) { | 268 | if (eof_str) { |
276 | eof_str_detected = (strcmp(s, eof_str) == 0); | 269 | eof_str_detected = (strcmp(s, eof_str) == 0); |
277 | } | 270 | } |
@@ -289,12 +282,10 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
289 | } | 282 | } |
290 | prev = cur; | 283 | prev = cur; |
291 | line_l += length; | 284 | line_l += length; |
292 | if (line_l > mc) { | 285 | if (line_l > mc) /* limit stop memory usage */ |
293 | /* stop memory usage :-) */ | ||
294 | break; | 286 | break; |
295 | } | ||
296 | s = NULL; | ||
297 | } | 287 | } |
288 | s = NULL; | ||
298 | } | 289 | } |
299 | } | 290 | } |
300 | return list_arg; | 291 | return list_arg; |
@@ -325,28 +316,25 @@ static int xargs_ask_confirmation(void) | |||
325 | #endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */ | 316 | #endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */ |
326 | 317 | ||
327 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | 318 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM |
328 | static xlist_t *process0_stdin(xlist_t *list_arg, | 319 | static xlist_t* process0_stdin(xlist_t *list_arg, |
329 | const char *eof_str UNUSED_PARAM, size_t mc, char *buf) | 320 | const char *eof_str UNUSED_PARAM, size_t mc, char *buf) |
330 | { | 321 | { |
331 | int c; /* current char */ | 322 | char *s = NULL; /* start of the word */ |
332 | char *s = NULL; /* start word */ | 323 | char *p = NULL; /* pointer to end of the word */ |
333 | char *p = NULL; /* pointer to end word */ | 324 | size_t line_l = 0; /* size of loaded args */ |
334 | size_t line_l = 0; /* size loaded args line */ | ||
335 | xlist_t *cur; | 325 | xlist_t *cur; |
336 | xlist_t *prev; | 326 | xlist_t *prev; |
337 | 327 | ||
338 | prev = cur = list_arg; | 328 | prev = cur = list_arg; |
339 | while (1) { | 329 | while (cur) { |
340 | if (!cur) break; | ||
341 | prev = cur; | 330 | prev = cur; |
342 | line_l += cur->length; | 331 | line_l += cur->length; |
343 | cur = cur->link; | 332 | cur = cur->link; |
344 | } | 333 | } |
345 | 334 | ||
346 | while (!eof_stdin_detected) { | 335 | while (1) { |
347 | c = getchar(); | 336 | int c = getchar(); |
348 | if (c == EOF) { | 337 | if (c == EOF) { |
349 | eof_stdin_detected = 1; | ||
350 | if (s == NULL) | 338 | if (s == NULL) |
351 | break; | 339 | break; |
352 | c = '\0'; | 340 | c = '\0'; |
@@ -357,7 +345,7 @@ static xlist_t *process0_stdin(xlist_t *list_arg, | |||
357 | bb_error_msg_and_die("argument line too long"); | 345 | bb_error_msg_and_die("argument line too long"); |
358 | *p++ = c; | 346 | *p++ = c; |
359 | if (c == '\0') { /* word's delimiter or EOF detected */ | 347 | if (c == '\0') { /* word's delimiter or EOF detected */ |
360 | /* word loaded */ | 348 | /* A full word is loaded */ |
361 | size_t length = (p - buf); | 349 | size_t length = (p - buf); |
362 | /* Dont xzalloc - it can be quite big */ | 350 | /* Dont xzalloc - it can be quite big */ |
363 | cur = xmalloc(offsetof(xlist_t, xstr) + length); | 351 | cur = xmalloc(offsetof(xlist_t, xstr) + length); |
@@ -371,10 +359,8 @@ static xlist_t *process0_stdin(xlist_t *list_arg, | |||
371 | } | 359 | } |
372 | prev = cur; | 360 | prev = cur; |
373 | line_l += length; | 361 | line_l += length; |
374 | if (line_l > mc) { | 362 | if (line_l > mc) /* limit stop memory usage */ |
375 | /* stop memory usage :-) */ | ||
376 | break; | 363 | break; |
377 | } | ||
378 | s = NULL; | 364 | s = NULL; |
379 | } | 365 | } |
380 | } | 366 | } |
@@ -412,12 +398,11 @@ enum { | |||
412 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 398 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
413 | int xargs_main(int argc, char **argv) | 399 | int xargs_main(int argc, char **argv) |
414 | { | 400 | { |
415 | char **args; | ||
416 | int i, n; | ||
417 | xlist_t *list = NULL; | 401 | xlist_t *list = NULL; |
418 | xlist_t *cur; | ||
419 | int child_error = 0; | 402 | int child_error = 0; |
420 | char *max_args, *max_chars; | 403 | char *max_args; |
404 | char *max_chars; | ||
405 | char *buf; | ||
421 | int n_max_arg; | 406 | int n_max_arg; |
422 | const char *eof_str = NULL; | 407 | const char *eof_str = NULL; |
423 | unsigned opt; | 408 | unsigned opt; |
@@ -441,15 +426,12 @@ int xargs_main(int argc, char **argv) | |||
441 | 426 | ||
442 | argv += optind; | 427 | argv += optind; |
443 | argc -= optind; | 428 | argc -= optind; |
444 | if (!argc) { | 429 | if (!argv[0]) { |
445 | /* default behavior is to echo all the filenames */ | 430 | /* default behavior is to echo all the filenames */ |
446 | *argv = (char*)"echo"; | 431 | *--argv = (char*)"echo"; |
447 | argc++; | 432 | argc++; |
448 | } | 433 | } |
449 | 434 | ||
450 | n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ | ||
451 | if (n_max_chars < 4*1024); /* paranoia */ | ||
452 | n_max_chars = LONG_MAX; | ||
453 | /* The Open Group Base Specifications Issue 6: | 435 | /* The Open Group Base Specifications Issue 6: |
454 | * "The xargs utility shall limit the command line length such that | 436 | * "The xargs utility shall limit the command line length such that |
455 | * when the command line is invoked, the combined argument | 437 | * when the command line is invoked, the combined argument |
@@ -457,27 +439,32 @@ int xargs_main(int argc, char **argv) | |||
457 | * in the System Interfaces volume of IEEE Std 1003.1-2001) | 439 | * in the System Interfaces volume of IEEE Std 1003.1-2001) |
458 | * shall not exceed {ARG_MAX}-2048 bytes". | 440 | * shall not exceed {ARG_MAX}-2048 bytes". |
459 | */ | 441 | */ |
442 | n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ | ||
443 | if (n_max_chars < 4*1024); /* paranoia */ | ||
444 | n_max_chars = 4*1024; | ||
460 | n_max_chars -= 2048; | 445 | n_max_chars -= 2048; |
461 | /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which | 446 | /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which |
462 | * have it at 1 meg). Things will work fine with a large ARG_MAX but it | 447 | * have it at 1 meg). Things will work fine with a large ARG_MAX |
463 | * will probably hurt the system more than it needs to; an array of this | 448 | * but it will probably hurt the system more than it needs to; |
464 | * size is allocated. | 449 | * an array of this size is allocated. |
465 | */ | 450 | */ |
466 | if (n_max_chars > 20 * 1024) | 451 | if (n_max_chars > 20 * 1024) |
467 | n_max_chars = 20 * 1024; | 452 | n_max_chars = 20 * 1024; |
468 | 453 | ||
469 | if (opt & OPT_UPTO_SIZE) { | 454 | if (opt & OPT_UPTO_SIZE) { |
455 | int i; | ||
470 | size_t n_chars = 0; | 456 | size_t n_chars = 0; |
471 | n_max_chars = xatoul_range(max_chars, 1, n_max_chars); | 457 | n_max_chars = xatoul_range(max_chars, 1, n_max_chars); |
472 | for (i = 0; i < argc; i++) { | 458 | for (i = 0; argv[i]; i++) { |
473 | n_chars += strlen(*argv) + 1; | 459 | n_chars += strlen(argv[i]) + 1; |
474 | } | 460 | } |
475 | if (n_max_chars <= n_chars) { | 461 | n_max_chars -= n_chars; |
462 | if ((ssize_t)n_max_chars <= 0) { | ||
476 | bb_error_msg_and_die("can't fit single argument within argument list size limit"); | 463 | bb_error_msg_and_die("can't fit single argument within argument list size limit"); |
477 | } | 464 | } |
478 | n_max_chars -= n_chars; | ||
479 | } | 465 | } |
480 | max_chars = xmalloc(n_max_chars); | 466 | |
467 | buf = xmalloc(n_max_chars); | ||
481 | 468 | ||
482 | if (opt & OPT_UPTO_NUMBER) { | 469 | if (opt & OPT_UPTO_NUMBER) { |
483 | n_max_arg = xatoul_range(max_args, 1, INT_MAX); | 470 | n_max_arg = xatoul_range(max_args, 1, INT_MAX); |
@@ -485,10 +472,14 @@ int xargs_main(int argc, char **argv) | |||
485 | n_max_arg = n_max_chars; | 472 | n_max_arg = n_max_chars; |
486 | } | 473 | } |
487 | 474 | ||
488 | while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || | 475 | while ((list = read_args(list, eof_str, n_max_chars, buf)) != NULL |
489 | !(opt & OPT_NO_EMPTY)) | 476 | || !(opt & OPT_NO_EMPTY) |
490 | { | 477 | ) { |
478 | char **args; | ||
479 | xlist_t *cur; | ||
480 | int i, n; | ||
491 | size_t n_chars = 0; | 481 | size_t n_chars = 0; |
482 | |||
492 | opt |= OPT_NO_EMPTY; | 483 | opt |= OPT_NO_EMPTY; |
493 | n = 0; | 484 | n = 0; |
494 | #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT | 485 | #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT |
@@ -510,15 +501,14 @@ int xargs_main(int argc, char **argv) | |||
510 | break; | 501 | break; |
511 | } | 502 | } |
512 | } | 503 | } |
513 | #endif /* FEATURE_XARGS_SUPPORT_TERMOPT */ | 504 | #endif |
514 | 505 | ||
515 | /* allocate pointers for execvp: | 506 | /* allocate pointers for execvp */ |
516 | argc*arg, n*arg from stdin, NULL */ | 507 | args = xzalloc(sizeof(args[0]) * (argc + n + 1)); |
517 | args = xzalloc((n + argc + 1) * sizeof(char *)); | ||
518 | 508 | ||
519 | /* store the command to be executed | 509 | /* store the command to be executed |
520 | (taken from the command line) */ | 510 | * (taken from the command line) */ |
521 | for (i = 0; i < argc; i++) | 511 | for (i = 0; argv[i]; i++) |
522 | args[i] = argv[i]; | 512 | args[i] = argv[i]; |
523 | /* (taken from stdin) */ | 513 | /* (taken from stdin) */ |
524 | for (cur = list; n; cur = cur->link) { | 514 | for (cur = list; n; cur = cur->link) { |
@@ -535,6 +525,7 @@ int xargs_main(int argc, char **argv) | |||
535 | if (!(opt & OPT_INTERACTIVE)) | 525 | if (!(opt & OPT_INTERACTIVE)) |
536 | bb_putchar_stderr('\n'); | 526 | bb_putchar_stderr('\n'); |
537 | } | 527 | } |
528 | |||
538 | if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { | 529 | if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { |
539 | child_error = xargs_exec(args); | 530 | child_error = xargs_exec(args); |
540 | } | 531 | } |
@@ -546,12 +537,15 @@ int xargs_main(int argc, char **argv) | |||
546 | free(cur); | 537 | free(cur); |
547 | } | 538 | } |
548 | free(args); | 539 | free(args); |
540 | |||
549 | if (child_error > 0 && child_error != 123) { | 541 | if (child_error > 0 && child_error != 123) { |
550 | break; | 542 | break; |
551 | } | 543 | } |
552 | } /* while */ | 544 | } /* while */ |
545 | |||
553 | if (ENABLE_FEATURE_CLEAN_UP) | 546 | if (ENABLE_FEATURE_CLEAN_UP) |
554 | free(max_chars); | 547 | free(buf); |
548 | |||
555 | return child_error; | 549 | return child_error; |
556 | } | 550 | } |
557 | 551 | ||
diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests index 17f4e7a1b..c73363038 100755 --- a/testsuite/xargs.tests +++ b/testsuite/xargs.tests | |||
@@ -26,4 +26,9 @@ testing "xargs does not stop on underscore ('new' GNU behavior)" \ | |||
26 | "a _ b\n" \ | 26 | "a _ b\n" \ |
27 | "" "a\n_\nb\n" | 27 | "" "a\n_\nb\n" |
28 | 28 | ||
29 | testing "xargs -s7 can take one-char input" \ | ||
30 | "xargs -s7" \ | ||
31 | "a\n" \ | ||
32 | "" "a\n" | ||
33 | |||
29 | exit $FAILCOUNT | 34 | exit $FAILCOUNT |