diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-10 22:39:37 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-10 22:39:37 +0000 |
| commit | 87f40bac149dcaf1025abd745decafb3a8ac4e0c (patch) | |
| tree | 2ba28b5e62f88070cd6bfbda7486ab2125954bb3 /shell | |
| parent | 43360e51781942730f91bb19821e3f8f1087e4fa (diff) | |
| download | busybox-w32-87f40bac149dcaf1025abd745decafb3a8ac4e0c.tar.gz busybox-w32-87f40bac149dcaf1025abd745decafb3a8ac4e0c.tar.bz2 busybox-w32-87f40bac149dcaf1025abd745decafb3a8ac4e0c.zip | |
hush: more backtick and quoting fixes...
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 73 | ||||
| -rw-r--r-- | shell/hush_test/hush-psubst/tick3.right | 6 | ||||
| -rwxr-xr-x | shell/hush_test/hush-psubst/tick3.tests | 11 |
3 files changed, 71 insertions, 19 deletions
diff --git a/shell/hush.c b/shell/hush.c index e57f6e371..735526a1d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -1221,6 +1221,23 @@ static void o_addqchr(o_string *o, int ch, int quote) | |||
| 1221 | o_addchr(o, ch); | 1221 | o_addchr(o, ch); |
| 1222 | } | 1222 | } |
| 1223 | 1223 | ||
| 1224 | static void o_addqstr(o_string *o, const char *str, int len, int quote) | ||
| 1225 | { | ||
| 1226 | char ch; | ||
| 1227 | if (!quote || str[strcspn(str, "*?[\\")] == '\0') { | ||
| 1228 | o_addstr(o, str, len); | ||
| 1229 | return; | ||
| 1230 | } | ||
| 1231 | while (len) { | ||
| 1232 | ch = *str++; | ||
| 1233 | if (ch && strchr("*?[\\", ch)) { | ||
| 1234 | o_addchr(o, '\\'); | ||
| 1235 | } | ||
| 1236 | o_addchr(o, ch); | ||
| 1237 | len--; | ||
| 1238 | } | ||
| 1239 | } | ||
| 1240 | |||
| 1224 | /* A special kind of o_string for $VAR and `cmd` expansion. | 1241 | /* A special kind of o_string for $VAR and `cmd` expansion. |
| 1225 | * It contains char* list[] at the beginning, which is grown in 16 element | 1242 | * It contains char* list[] at the beginning, which is grown in 16 element |
| 1226 | * increments. Actual string data starts at the next multiple of 16. | 1243 | * increments. Actual string data starts at the next multiple of 16. |
| @@ -2445,7 +2462,7 @@ static int run_and_free_list(struct pipe *pi) | |||
| 2445 | * In the long run that function can be merged with run_list, | 2462 | * In the long run that function can be merged with run_list, |
| 2446 | * but doing that now would hobble the debugging effort. */ | 2463 | * but doing that now would hobble the debugging effort. */ |
| 2447 | free_pipe_list(pi, /* indent: */ 0); | 2464 | free_pipe_list(pi, /* indent: */ 0); |
| 2448 | debug_printf_exec("run_nad_free_list return %d\n", rcode); | 2465 | debug_printf_exec("run_and_free_list return %d\n", rcode); |
| 2449 | return rcode; | 2466 | return rcode; |
| 2450 | } | 2467 | } |
| 2451 | 2468 | ||
| @@ -2549,7 +2566,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
| 2549 | while (1) { | 2566 | while (1) { |
| 2550 | int word_len = strcspn(str, ifs); | 2567 | int word_len = strcspn(str, ifs); |
| 2551 | if (word_len) { | 2568 | if (word_len) { |
| 2552 | o_addstr(output, str, word_len); /* store non-ifs chars */ | 2569 | o_addqstr(output, str, word_len, output->o_quote); |
| 2553 | str += word_len; | 2570 | str += word_len; |
| 2554 | } | 2571 | } |
| 2555 | if (!*str) /* EOL - do not finalize word */ | 2572 | if (!*str) /* EOL - do not finalize word */ |
| @@ -2590,7 +2607,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2590 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { | 2607 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { |
| 2591 | o_string subst_result = NULL_O_STRING; | 2608 | o_string subst_result = NULL_O_STRING; |
| 2592 | 2609 | ||
| 2593 | o_addstr(output, arg, p - arg); | 2610 | o_addqstr(output, arg, p - arg, output->o_quote); |
| 2594 | o_debug_list("expand_vars_to_list[1]", output, n); | 2611 | o_debug_list("expand_vars_to_list[1]", output, n); |
| 2595 | arg = ++p; | 2612 | arg = ++p; |
| 2596 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 2613 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
| @@ -2636,7 +2653,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2636 | * and in this case should treat it like '$*' - see 'else...' below */ | 2653 | * and in this case should treat it like '$*' - see 'else...' below */ |
| 2637 | if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ | 2654 | if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ |
| 2638 | while (1) { | 2655 | while (1) { |
| 2639 | o_addstr(output, global_argv[i], strlen(global_argv[i])); | 2656 | o_addqstr(output, global_argv[i], strlen(global_argv[i]), output->o_quote); |
| 2640 | if (++i >= global_argc) | 2657 | if (++i >= global_argc) |
| 2641 | break; | 2658 | break; |
| 2642 | o_addchr(output, '\0'); | 2659 | o_addchr(output, '\0'); |
| @@ -2645,7 +2662,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2645 | } | 2662 | } |
| 2646 | } else { /* quoted $*: add as one word */ | 2663 | } else { /* quoted $*: add as one word */ |
| 2647 | while (1) { | 2664 | while (1) { |
| 2648 | o_addstr(output, global_argv[i], strlen(global_argv[i])); | 2665 | o_addqstr(output, global_argv[i], strlen(global_argv[i]), output->o_quote); |
| 2649 | if (!global_argv[++i]) | 2666 | if (!global_argv[++i]) |
| 2650 | break; | 2667 | break; |
| 2651 | if (ifs[0]) | 2668 | if (ifs[0]) |
| @@ -2684,8 +2701,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2684 | } | 2701 | } |
| 2685 | } /* else: quoted $VAR, val will be appended below */ | 2702 | } /* else: quoted $VAR, val will be appended below */ |
| 2686 | } | 2703 | } |
| 2687 | if (val) | 2704 | if (val) { |
| 2688 | o_addstr(output, val, strlen(val)); | 2705 | o_addqstr(output, val, strlen(val), output->o_quote); |
| 2706 | } | ||
| 2689 | 2707 | ||
| 2690 | o_free(&subst_result); | 2708 | o_free(&subst_result); |
| 2691 | arg = ++p; | 2709 | arg = ++p; |
| @@ -2693,7 +2711,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2693 | 2711 | ||
| 2694 | if (arg[0]) { | 2712 | if (arg[0]) { |
| 2695 | o_debug_list("expand_vars_to_list[a]", output, n); | 2713 | o_debug_list("expand_vars_to_list[a]", output, n); |
| 2696 | o_addstr(output, arg, strlen(arg) + 1); | 2714 | o_addqstr(output, arg, strlen(arg) + 1, output->o_quote); |
| 2697 | o_debug_list("expand_vars_to_list[b]", output, n); | 2715 | o_debug_list("expand_vars_to_list[b]", output, n); |
| 2698 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ | 2716 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ |
| 2699 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ | 2717 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ |
| @@ -3389,7 +3407,7 @@ static void add_till_single_quote(o_string *dest, struct in_str *input) | |||
| 3389 | break; | 3407 | break; |
| 3390 | if (ch == '\'') | 3408 | if (ch == '\'') |
| 3391 | break; | 3409 | break; |
| 3392 | o_addchr(dest, ch); | 3410 | o_addqchr(dest, ch, 1); |
| 3393 | } | 3411 | } |
| 3394 | } | 3412 | } |
| 3395 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ | 3413 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ |
| @@ -3400,15 +3418,15 @@ static void add_till_double_quote(o_string *dest, struct in_str *input) | |||
| 3400 | if (ch == '"') | 3418 | if (ch == '"') |
| 3401 | break; | 3419 | break; |
| 3402 | if (ch == '\\') { /* \x. Copy both chars. */ | 3420 | if (ch == '\\') { /* \x. Copy both chars. */ |
| 3403 | o_addchr(dest, ch); | 3421 | o_addqchr(dest, ch, 1); |
| 3404 | ch = i_getch(input); | 3422 | ch = i_getch(input); |
| 3405 | } | 3423 | } |
| 3406 | if (ch == EOF) | 3424 | if (ch == EOF) |
| 3407 | break; | 3425 | break; |
| 3408 | o_addchr(dest, ch); | 3426 | o_addqchr(dest, ch, 1); |
| 3409 | if (ch == '`') { | 3427 | if (ch == '`') { |
| 3410 | add_till_backquote(dest, input); | 3428 | add_till_backquote(dest, input); |
| 3411 | o_addchr(dest, ch); | 3429 | o_addqchr(dest, ch, 1); |
| 3412 | continue; | 3430 | continue; |
| 3413 | } | 3431 | } |
| 3414 | // if (ch == '$') ... | 3432 | // if (ch == '$') ... |
| @@ -3432,18 +3450,17 @@ static void add_till_backquote(o_string *dest, struct in_str *input) | |||
| 3432 | { | 3450 | { |
| 3433 | while (1) { | 3451 | while (1) { |
| 3434 | int ch = i_getch(input); | 3452 | int ch = i_getch(input); |
| 3435 | //bb_error_msg("ADD '%c'", ch); | ||
| 3436 | if (ch == '`') | 3453 | if (ch == '`') |
| 3437 | break; | 3454 | break; |
| 3438 | if (ch == '\\') { /* \x. Copy both chars unless it is \` */ | 3455 | if (ch == '\\') { /* \x. Copy both chars unless it is \` */ |
| 3439 | int ch2 = i_getch(input); | 3456 | int ch2 = i_getch(input); |
| 3440 | if (ch2 != '`' && ch2 != '$' && ch2 != '\\') | 3457 | if (ch2 != '`' && ch2 != '$' && ch2 != '\\') |
| 3441 | o_addchr(dest, ch); | 3458 | o_addqchr(dest, ch, 1); |
| 3442 | ch = ch2; | 3459 | ch = ch2; |
| 3443 | } | 3460 | } |
| 3444 | if (ch == EOF) | 3461 | if (ch == EOF) |
| 3445 | break; | 3462 | break; |
| 3446 | o_addchr(dest, ch); | 3463 | o_addqchr(dest, ch, 1); |
| 3447 | } | 3464 | } |
| 3448 | } | 3465 | } |
| 3449 | /* Process $(cmd) - copy contents until ")" is seen. Complicated by | 3466 | /* Process $(cmd) - copy contents until ")" is seen. Complicated by |
| @@ -3470,15 +3487,15 @@ static void add_till_closing_curly_brace(o_string *dest, struct in_str *input) | |||
| 3470 | if (ch == ')') | 3487 | if (ch == ')') |
| 3471 | if (--count < 0) | 3488 | if (--count < 0) |
| 3472 | break; | 3489 | break; |
| 3473 | o_addchr(dest, ch); | 3490 | o_addqchr(dest, ch, 1); |
| 3474 | if (ch == '\'') { | 3491 | if (ch == '\'') { |
| 3475 | add_till_single_quote(dest, input); | 3492 | add_till_single_quote(dest, input); |
| 3476 | o_addchr(dest, ch); | 3493 | o_addqchr(dest, ch, 1); |
| 3477 | continue; | 3494 | continue; |
| 3478 | } | 3495 | } |
| 3479 | if (ch == '"') { | 3496 | if (ch == '"') { |
| 3480 | add_till_double_quote(dest, input); | 3497 | add_till_double_quote(dest, input); |
| 3481 | o_addchr(dest, ch); | 3498 | o_addqchr(dest, ch, 1); |
| 3482 | continue; | 3499 | continue; |
| 3483 | } | 3500 | } |
| 3484 | } | 3501 | } |
| @@ -3638,7 +3655,25 @@ static int parse_stream(o_string *dest, struct p_context *ctx, | |||
| 3638 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); | 3655 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); |
| 3639 | return 1; | 3656 | return 1; |
| 3640 | } | 3657 | } |
| 3641 | o_addqchr(dest, i_getch(input), dest->o_quote); | 3658 | /* bash: |
| 3659 | * "The backslash retains its special meaning [in "..."] | ||
| 3660 | * only when followed by one of the following characters: | ||
| 3661 | * $, `, ", \, or <newline>. A double quote may be quoted | ||
| 3662 | * within double quotes by preceding it with a backslash. | ||
| 3663 | * If enabled, history expansion will be performed unless | ||
| 3664 | * an ! appearing in double quotes is escaped using | ||
| 3665 | * a backslash. The backslash preceding the ! is not removed." | ||
| 3666 | */ | ||
| 3667 | if (dest->o_quote) { | ||
| 3668 | if (strchr("$`\"\\", next) != NULL) { | ||
| 3669 | o_addqchr(dest, i_getch(input), 1); | ||
| 3670 | } else { | ||
| 3671 | o_addqchr(dest, '\\', 1); | ||
| 3672 | } | ||
| 3673 | } else { | ||
| 3674 | o_addchr(dest, '\\'); | ||
| 3675 | o_addchr(dest, i_getch(input)); | ||
| 3676 | } | ||
| 3642 | break; | 3677 | break; |
| 3643 | case '$': | 3678 | case '$': |
| 3644 | if (handle_dollar(dest, input) != 0) { | 3679 | if (handle_dollar(dest, input) != 0) { |
diff --git a/shell/hush_test/hush-psubst/tick3.right b/shell/hush_test/hush-psubst/tick3.right new file mode 100644 index 000000000..dc84e9263 --- /dev/null +++ b/shell/hush_test/hush-psubst/tick3.right | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | \TESTZZBEST | ||
| 2 | $TEST | ||
| 3 | Q | ||
| 4 | a\bc | ||
| 5 | a"c | ||
| 6 | done:0 | ||
diff --git a/shell/hush_test/hush-psubst/tick3.tests b/shell/hush_test/hush-psubst/tick3.tests new file mode 100755 index 000000000..97b45e4b4 --- /dev/null +++ b/shell/hush_test/hush-psubst/tick3.tests | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | TEST=Q | ||
| 3 | # \` is special | ||
| 4 | echo `echo '\'TEST\`echo ZZ\`BEST` | ||
| 5 | # \$ and \\ are special | ||
| 6 | echo `echo \\$TEST` | ||
| 7 | echo `echo \$TEST` | ||
| 8 | echo a`echo \\\\b`c | ||
| 9 | # \" etc are NOT special (passed verbatim WITH \)! | ||
| 10 | echo a`echo \"`c | ||
| 11 | echo done:$? | ||
