aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c73
-rw-r--r--shell/hush_test/hush-psubst/tick3.right6
-rwxr-xr-xshell/hush_test/hush-psubst/tick3.tests11
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
1224static 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
3Q
4a\bc
5a"c
6done: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
2TEST=Q
3# \` is special
4echo `echo '\'TEST\`echo ZZ\`BEST`
5# \$ and \\ are special
6echo `echo \\$TEST`
7echo `echo \$TEST`
8echo a`echo \\\\b`c
9# \" etc are NOT special (passed verbatim WITH \)!
10echo a`echo \"`c
11echo done:$?