aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-06-13 03:43:43 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-06-13 03:43:43 +0200
commitd5fa1a0f49c4872f614a4674922f4362b114fece (patch)
tree64d0af64712f546499a165f5997b569ed890d9ee
parentd2d327db6d38d5a6e8e253c54d3e97466ce3bc79 (diff)
downloadbusybox-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.c154
-rwxr-xr-xtestsuite/xargs.tests5
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
125static 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
132static xlist_t *process_stdin(xlist_t *list_arg, 131static 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 */
236static xlist_t *process_stdin(xlist_t *list_arg, 230static 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
328static xlist_t *process0_stdin(xlist_t *list_arg, 319static 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 {
412int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 398int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
413int xargs_main(int argc, char **argv) 399int 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
29testing "xargs -s7 can take one-char input" \
30 "xargs -s7" \
31 "a\n" \
32 "" "a\n"
33
29exit $FAILCOUNT 34exit $FAILCOUNT