diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2014-02-27 11:17:06 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-02-27 11:17:06 +0100 |
commit | 6f068904dc142657bb596f91196f9113f1838cbe (patch) | |
tree | ac02741b3c8b74bf3a078aeb13ef7ff1c5e1e23f | |
parent | 6885e49ba596239a0b0d3631fd72fc2692fbb65c (diff) | |
download | busybox-w32-6f068904dc142657bb596f91196f9113f1838cbe.tar.gz busybox-w32-6f068904dc142657bb596f91196f9113f1838cbe.tar.bz2 busybox-w32-6f068904dc142657bb596f91196f9113f1838cbe.zip |
xargs: add support for -I and -i. Closes 493
function old new delta
process_stdin_with_replace - 195 +195
xmalloc_substitute_string - 145 +145
xargs_main 808 884 +76
count_strstr - 45 +45
packed_usage 29580 29571 -9
parse_params 1445 1416 -29
func_exec 285 138 -147
------------------------------------------------------------------------------
(add/remove: 4/0 grow/shrink: 1/3 up/down: 461/-185) Total: 276 bytes
text data bss dec hex filename
922156 932 17692 940780 e5aec busybox_old
922440 932 17692 941064 e5c08 busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | findutils/find.c | 32 | ||||
-rw-r--r-- | findutils/xargs.c | 153 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/replace.c | 45 |
4 files changed, 176 insertions, 56 deletions
diff --git a/findutils/find.c b/findutils/find.c index 044f010b0..6d34f4d68 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -402,34 +402,6 @@ struct globals { | |||
402 | G.recurse_flags = ACTION_RECURSE; \ | 402 | G.recurse_flags = ACTION_RECURSE; \ |
403 | } while (0) | 403 | } while (0) |
404 | 404 | ||
405 | #if ENABLE_FEATURE_FIND_EXEC | ||
406 | static unsigned count_subst(const char *str) | ||
407 | { | ||
408 | unsigned count = 0; | ||
409 | while ((str = strstr(str, "{}")) != NULL) { | ||
410 | count++; | ||
411 | str++; | ||
412 | } | ||
413 | return count; | ||
414 | } | ||
415 | |||
416 | |||
417 | static char* subst(const char *src, unsigned count, const char* filename) | ||
418 | { | ||
419 | char *buf, *dst, *end; | ||
420 | size_t flen = strlen(filename); | ||
421 | /* we replace each '{}' with filename: growth by strlen-2 */ | ||
422 | buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1); | ||
423 | while ((end = strstr(src, "{}")) != NULL) { | ||
424 | dst = mempcpy(dst, src, end - src); | ||
425 | dst = mempcpy(dst, filename, flen); | ||
426 | src = end + 2; | ||
427 | } | ||
428 | strcpy(dst, src); | ||
429 | return buf; | ||
430 | } | ||
431 | #endif | ||
432 | |||
433 | /* Return values of ACTFs ('action functions') are a bit mask: | 405 | /* Return values of ACTFs ('action functions') are a bit mask: |
434 | * bit 1=1: prune (use SKIP constant for setting it) | 406 | * bit 1=1: prune (use SKIP constant for setting it) |
435 | * bit 0=1: matched successfully (TRUE) | 407 | * bit 0=1: matched successfully (TRUE) |
@@ -613,7 +585,7 @@ ACTF(exec) | |||
613 | char *argv[ap->exec_argc + 1]; | 585 | char *argv[ap->exec_argc + 1]; |
614 | #endif | 586 | #endif |
615 | for (i = 0; i < ap->exec_argc; i++) | 587 | for (i = 0; i < ap->exec_argc; i++) |
616 | argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); | 588 | argv[i] = xmalloc_substitute_string(ap->exec_argv[i], ap->subst_count[i], "{}", fileName); |
617 | argv[i] = NULL; /* terminate the list */ | 589 | argv[i] = NULL; /* terminate the list */ |
618 | 590 | ||
619 | rc = spawn_and_wait(argv); | 591 | rc = spawn_and_wait(argv); |
@@ -1091,7 +1063,7 @@ static action*** parse_params(char **argv) | |||
1091 | ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); | 1063 | ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); |
1092 | i = ap->exec_argc; | 1064 | i = ap->exec_argc; |
1093 | while (i--) | 1065 | while (i--) |
1094 | ap->subst_count[i] = count_subst(ap->exec_argv[i]); | 1066 | ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}"); |
1095 | } | 1067 | } |
1096 | #endif | 1068 | #endif |
1097 | #if ENABLE_FEATURE_FIND_PAREN | 1069 | #if ENABLE_FEATURE_FIND_PAREN |
diff --git a/findutils/xargs.c b/findutils/xargs.c index 0d1bb43fc..ed6dbd33e 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -53,6 +53,13 @@ | |||
53 | //config: Support -0: input items are terminated by a NUL character | 53 | //config: Support -0: input items are terminated by a NUL character |
54 | //config: instead of whitespace, and the quotes and backslash | 54 | //config: instead of whitespace, and the quotes and backslash |
55 | //config: are not special. | 55 | //config: are not special. |
56 | //config: | ||
57 | //config:config FEATURE_XARGS_SUPPORT_REPL_STR | ||
58 | //config: bool "Enable -I STR: string to replace" | ||
59 | //config: default y | ||
60 | //config: depends on XARGS | ||
61 | //config: help | ||
62 | //config: Support -I STR and -i[STR] options. | ||
56 | 63 | ||
57 | //applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs)) | 64 | //applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs)) |
58 | 65 | ||
@@ -85,19 +92,22 @@ | |||
85 | 92 | ||
86 | struct globals { | 93 | struct globals { |
87 | char **args; | 94 | char **args; |
95 | #if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR | ||
96 | char **argv; | ||
97 | const char *repl_str; | ||
98 | char eol_ch; | ||
99 | #endif | ||
88 | const char *eof_str; | 100 | const char *eof_str; |
89 | int idx; | 101 | int idx; |
90 | } FIX_ALIASING; | 102 | } FIX_ALIASING; |
91 | #define G (*(struct globals*)&bb_common_bufsiz1) | 103 | #define G (*(struct globals*)&bb_common_bufsiz1) |
92 | #define INIT_G() do { \ | 104 | #define INIT_G() do { \ |
93 | G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ | 105 | G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ |
106 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \ | ||
107 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \ | ||
94 | } while (0) | 108 | } while (0) |
95 | 109 | ||
96 | 110 | ||
97 | /* | ||
98 | * This function has special algorithm. | ||
99 | * Don't use fork and include to main! | ||
100 | */ | ||
101 | static int xargs_exec(void) | 111 | static int xargs_exec(void) |
102 | { | 112 | { |
103 | int status; | 113 | int status; |
@@ -301,7 +311,7 @@ static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf) | |||
301 | c = '\0'; | 311 | c = '\0'; |
302 | } | 312 | } |
303 | *p++ = c; | 313 | *p++ = c; |
304 | if (c == '\0') { /* word's delimiter or EOF detected */ | 314 | if (c == '\0') { /* NUL or EOF detected */ |
305 | /* A full word is loaded */ | 315 | /* A full word is loaded */ |
306 | store_param(s); | 316 | store_param(s); |
307 | dbg_msg("args[]:'%s'", s); | 317 | dbg_msg("args[]:'%s'", s); |
@@ -323,10 +333,71 @@ static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf) | |||
323 | } | 333 | } |
324 | #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ | 334 | #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ |
325 | 335 | ||
336 | #if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR | ||
337 | /* | ||
338 | * Used if -I<repl> was specified. | ||
339 | * In this mode, words aren't appended to PROG ARGS. | ||
340 | * Instead, entire input line is read, then <repl> string | ||
341 | * in every PROG and ARG is replaced with the line: | ||
342 | * echo -e "ho ho\nhi" | xargs -I_ cmd __ _ | ||
343 | * results in "cmd 'ho hoho ho' 'ho ho'"; "cmd 'hihi' 'hi'". | ||
344 | * -n MAX_ARGS seems to be ignored. | ||
345 | * Tested with GNU findutils 4.5.10. | ||
346 | */ | ||
347 | //FIXME: n_max_chars is not handled the same way as in GNU findutils. | ||
348 | //FIXME: quoting is not implemented. | ||
349 | static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg UNUSED_PARAM, char *buf) | ||
350 | { | ||
351 | int i; | ||
352 | char *end, *p; | ||
353 | |||
354 | /* Free strings from last invocation, if any */ | ||
355 | for (i = 0; G.args && G.args[i]; i++) | ||
356 | if (G.args[i] != G.argv[i]) | ||
357 | free(G.args[i]); | ||
358 | |||
359 | end = buf + n_max_chars; | ||
360 | p = buf; | ||
361 | |||
362 | while (1) { | ||
363 | int c = getchar(); | ||
364 | if (c == EOF || c == G.eol_ch) { | ||
365 | if (p == buf) | ||
366 | goto ret; /* empty line */ | ||
367 | c = '\0'; | ||
368 | } | ||
369 | *p++ = c; | ||
370 | if (c == '\0') { /* EOL or EOF detected */ | ||
371 | i = 0; | ||
372 | while (G.argv[i]) { | ||
373 | char *arg = G.argv[i]; | ||
374 | int count = count_strstr(arg, G.repl_str); | ||
375 | if (count != 0) | ||
376 | arg = xmalloc_substitute_string(arg, count, G.repl_str, s); | ||
377 | store_param(arg); | ||
378 | dbg_msg("args[]:'%s'", arg); | ||
379 | i++; | ||
380 | } | ||
381 | p = buf; | ||
382 | goto ret; | ||
383 | } | ||
384 | if (p == end) { | ||
385 | goto ret; | ||
386 | } | ||
387 | } | ||
388 | ret: | ||
389 | *p = '\0'; | ||
390 | /* store_param(NULL) - caller will do it */ | ||
391 | dbg_msg("return:'%s'", buf); | ||
392 | return buf; | ||
393 | } | ||
394 | #endif | ||
395 | |||
326 | #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION | 396 | #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION |
327 | /* Prompt the user for a response, and | 397 | /* Prompt the user for a response, and |
328 | if the user responds affirmatively, return true; | 398 | * if user responds affirmatively, return true; |
329 | otherwise, return false. Uses "/dev/tty", not stdin. */ | 399 | * otherwise, return false. Uses "/dev/tty", not stdin. |
400 | */ | ||
330 | static int xargs_ask_confirmation(void) | 401 | static int xargs_ask_confirmation(void) |
331 | { | 402 | { |
332 | FILE *tty_stream; | 403 | FILE *tty_stream; |
@@ -360,6 +431,9 @@ static int xargs_ask_confirmation(void) | |||
360 | //usage: "\n -e[STR] STR stops input processing" | 431 | //usage: "\n -e[STR] STR stops input processing" |
361 | //usage: "\n -n N Pass no more than N args to PROG" | 432 | //usage: "\n -n N Pass no more than N args to PROG" |
362 | //usage: "\n -s N Pass command line of no more than N bytes" | 433 | //usage: "\n -s N Pass command line of no more than N bytes" |
434 | //usage: IF_FEATURE_XARGS_SUPPORT_REPL_STR( | ||
435 | //usage: "\n -I STR Replace STR within PROG ARGS with input line" | ||
436 | //usage: ) | ||
363 | //usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT( | 437 | //usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT( |
364 | //usage: "\n -x Exit if size is exceeded" | 438 | //usage: "\n -x Exit if size is exceeded" |
365 | //usage: ) | 439 | //usage: ) |
@@ -378,6 +452,8 @@ enum { | |||
378 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) | 452 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) |
379 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) | 453 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) |
380 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) | 454 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) |
455 | IF_FEATURE_XARGS_SUPPORT_REPL_STR( OPTBIT_REPLSTR ,) | ||
456 | IF_FEATURE_XARGS_SUPPORT_REPL_STR( OPTBIT_REPLSTR1 ,) | ||
381 | 457 | ||
382 | OPT_VERBOSE = 1 << OPTBIT_VERBOSE , | 458 | OPT_VERBOSE = 1 << OPTBIT_VERBOSE , |
383 | OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY , | 459 | OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY , |
@@ -388,11 +464,14 @@ enum { | |||
388 | OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, | 464 | OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, |
389 | OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, | 465 | OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, |
390 | OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, | 466 | OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, |
467 | OPT_REPLSTR = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR )) + 0, | ||
468 | OPT_REPLSTR1 = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR1 )) + 0, | ||
391 | }; | 469 | }; |
392 | #define OPTION_STR "+trn:s:e::E:" \ | 470 | #define OPTION_STR "+trn:s:e::E:" \ |
393 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ | 471 | IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ |
394 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ | 472 | IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ |
395 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") | 473 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") \ |
474 | IF_FEATURE_XARGS_SUPPORT_REPL_STR( "I:i::") | ||
396 | 475 | ||
397 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 476 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
398 | int xargs_main(int argc, char **argv) | 477 | int xargs_main(int argc, char **argv) |
@@ -405,7 +484,8 @@ int xargs_main(int argc, char **argv) | |||
405 | unsigned opt; | 484 | unsigned opt; |
406 | int n_max_chars; | 485 | int n_max_chars; |
407 | int n_max_arg; | 486 | int n_max_arg; |
408 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | 487 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \ |
488 | || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR | ||
409 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; | 489 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; |
410 | #else | 490 | #else |
411 | #define read_args process_stdin | 491 | #define read_args process_stdin |
@@ -419,7 +499,10 @@ int xargs_main(int argc, char **argv) | |||
419 | "no-run-if-empty\0" No_argument "r" | 499 | "no-run-if-empty\0" No_argument "r" |
420 | ; | 500 | ; |
421 | #endif | 501 | #endif |
422 | opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str); | 502 | opt = getopt32(argv, OPTION_STR, |
503 | &max_args, &max_chars, &G.eof_str, &G.eof_str | ||
504 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(, &G.repl_str, &G.repl_str) | ||
505 | ); | ||
423 | 506 | ||
424 | /* -E ""? You may wonder why not just omit -E? | 507 | /* -E ""? You may wonder why not just omit -E? |
425 | * This is used for portability: | 508 | * This is used for portability: |
@@ -427,8 +510,10 @@ int xargs_main(int argc, char **argv) | |||
427 | if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0') | 510 | if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0') |
428 | G.eof_str = NULL; | 511 | G.eof_str = NULL; |
429 | 512 | ||
430 | if (opt & OPT_ZEROTERM) | 513 | if (opt & OPT_ZEROTERM) { |
431 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); | 514 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin;) |
515 | IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\0';) | ||
516 | } | ||
432 | 517 | ||
433 | argv += optind; | 518 | argv += optind; |
434 | argc -= optind; | 519 | argc -= optind; |
@@ -486,20 +571,36 @@ int xargs_main(int argc, char **argv) | |||
486 | /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */ | 571 | /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */ |
487 | } | 572 | } |
488 | 573 | ||
489 | /* Allocate pointers for execvp */ | 574 | #if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR |
490 | /* We can statically allocate (argc + n_max_arg + 1) elements | 575 | if (opt & (OPT_REPLSTR | OPT_REPLSTR1)) { |
491 | * and do not bother with resizing args[], but on 64-bit machines | 576 | /* |
492 | * this results in args[] vector which is ~8 times bigger | 577 | * -I<str>: |
493 | * than n_max_chars! That is, with n_max_chars == 20k, | 578 | * Unmodified args are kept in G.argv[i], |
494 | * args[] will take 160k (!), which will most likely be | 579 | * G.args[i] receives malloced G.argv[i] with <str> replaced |
495 | * almost entirely unused. | 580 | * with input line. Setting this up: |
496 | */ | 581 | */ |
497 | /* See store_param() for matching 256-step growth logic */ | 582 | G.args = NULL; |
498 | G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff)); | 583 | G.argv = argv; |
499 | 584 | argc = 0; | |
500 | /* Store the command to be executed, part 1 */ | 585 | read_args = process_stdin_with_replace; |
501 | for (i = 0; argv[i]; i++) | 586 | } else |
502 | G.args[i] = argv[i]; | 587 | #endif |
588 | { | ||
589 | /* Allocate pointers for execvp. | ||
590 | * We can statically allocate (argc + n_max_arg + 1) elements | ||
591 | * and do not bother with resizing args[], but on 64-bit machines | ||
592 | * this results in args[] vector which is ~8 times bigger | ||
593 | * than n_max_chars! That is, with n_max_chars == 20k, | ||
594 | * args[] will take 160k (!), which will most likely be | ||
595 | * almost entirely unused. | ||
596 | * | ||
597 | * See store_param() for matching 256-step growth logic | ||
598 | */ | ||
599 | G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff)); | ||
600 | /* Store the command to be executed, part 1 */ | ||
601 | for (i = 0; argv[i]; i++) | ||
602 | G.args[i] = argv[i]; | ||
603 | } | ||
503 | 604 | ||
504 | while (1) { | 605 | while (1) { |
505 | char *rem; | 606 | char *rem; |
diff --git a/include/libbb.h b/include/libbb.h index 96f33340e..1cbe2c8b4 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -650,6 +650,8 @@ char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC; | |||
650 | void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; | 650 | void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; |
651 | char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; | 651 | char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; |
652 | char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; | 652 | char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; |
653 | unsigned count_strstr(const char *str, const char *sub) FAST_FUNC; | ||
654 | char *xmalloc_substitute_string(const char *src, int count, const char *sub, const char *repl) FAST_FUNC; | ||
653 | /* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc. | 655 | /* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc. |
654 | * But potentially slow, don't use in one-billion-times loops */ | 656 | * But potentially slow, don't use in one-billion-times loops */ |
655 | int bb_putchar(int ch) FAST_FUNC; | 657 | int bb_putchar(int ch) FAST_FUNC; |
diff --git a/libbb/replace.c b/libbb/replace.c new file mode 100644 index 000000000..8711f957d --- /dev/null +++ b/libbb/replace.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | |||
10 | //kbuild:lib-y += replace.o | ||
11 | |||
12 | #include "libbb.h" | ||
13 | |||
14 | unsigned FAST_FUNC count_strstr(const char *str, const char *sub) | ||
15 | { | ||
16 | size_t sub_len = strlen(sub); | ||
17 | unsigned count = 0; | ||
18 | |||
19 | while ((str = strstr(str, sub)) != NULL) { | ||
20 | count++; | ||
21 | str += sub_len; | ||
22 | } | ||
23 | return count; | ||
24 | } | ||
25 | |||
26 | char* FAST_FUNC xmalloc_substitute_string(const char *src, int count, const char *sub, const char *repl) | ||
27 | { | ||
28 | char *buf, *dst, *end; | ||
29 | size_t sub_len = strlen(sub); | ||
30 | size_t repl_len = strlen(repl); | ||
31 | |||
32 | //dbg_msg("subst(s:'%s',count:%d,sub:'%s',repl:'%s'", src, count, sub, repl); | ||
33 | |||
34 | buf = dst = xmalloc(strlen(src) + count * ((int)repl_len - (int)sub_len) + 1); | ||
35 | /* we replace each sub with repl */ | ||
36 | while ((end = strstr(src, sub)) != NULL) { | ||
37 | dst = mempcpy(dst, src, end - src); | ||
38 | dst = mempcpy(dst, repl, repl_len); | ||
39 | /*src = end + 1; - GNU findutils 4.5.10 doesn't do this... */ | ||
40 | src = end + sub_len; /* but this. Try "xargs -Iaa echo aaa" */ | ||
41 | } | ||
42 | strcpy(dst, src); | ||
43 | //dbg_msg("subst9:'%s'", buf); | ||
44 | return buf; | ||
45 | } | ||