diff options
-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:$? | ||