hush: fix expansion of quoted $VAR, $* and $@
authorDenis Vlasenko <vda.linux@googlemail.com>
Wed, 16 May 2007 10:39:24 +0000 (10:39 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Wed, 16 May 2007 10:39:24 +0000 (10:39 -0000)
shell/hush.c
shell/hush_test/hush-bugs/quote3.right
shell/hush_test/hush-bugs/quote3.tests
shell/hush_test/hush-bugs/starquoted.right [deleted file]
shell/hush_test/hush-bugs/starquoted.tests [deleted file]
shell/hush_test/hush-parsing/quote4.right [new file with mode: 0644]
shell/hush_test/hush-parsing/quote4.tests [new file with mode: 0755]
shell/hush_test/hush-parsing/starquoted.right [new file with mode: 0644]
shell/hush_test/hush-parsing/starquoted.tests [new file with mode: 0755]

index e49c0c9..e3dd666 100644 (file)
@@ -2425,6 +2425,7 @@ static int expand_on_ifs(char **list, int n, char **posp, const char *str)
 static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
 {
        char first_ch, ored_ch;
+       int i;
        const char *val;
        char *p;
        char *pos = *posp;
@@ -2462,8 +2463,8 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
                        break;
                case '*':
                case '@':
+                       i = 1;
                        if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
-                               int i = 1;
                                while (i < global_argc) {
                                        n = expand_on_ifs(list, n, &pos, global_argv[i]);
                                        debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1);
@@ -2478,16 +2479,33 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
                                        }
                                }
                        } else if (first_ch == ('@'|0x80)) { /* quoted $@ */
-                               /* TODO */
-                       } else { /* quoted $* */
-                               /* TODO */
+                               while (1) {
+                                       strcpy(pos, global_argv[i]);
+                                       pos += strlen(global_argv[i]);
+                                       if (++i >= global_argc)
+                                               break;
+                                       *pos++ = '\0';
+                                       if (n) debug_printf_expand("expand_vars_to_list 3 finalized list[%d]=%p '%s' "
+                                               "strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
+                                                       strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
+                                       list[n++] = pos;
+                               }
+                       } else { /* quoted $*: add as one word */
+                               while (1) {
+                                       strcpy(pos, global_argv[i]);
+                                       pos += strlen(global_argv[i]);
+                                       if (++i >= global_argc)
+                                               break;
+                                       if (ifs[0])
+                                               *pos++ = ifs[0];
+                               }
                        }
                        break;
                default:
                        *p = '\0';
                        arg[0] = first_ch & 0x7f;
                        if (isdigit(arg[0])) {
-                               int i = xatoi_u(arg);
+                               i = xatoi_u(arg);
                                val = NULL;
                                if (i < global_argc)
                                        val = global_argv[i];
@@ -2495,12 +2513,12 @@ static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
                                val = lookup_param(arg);
                        arg[0] = first_ch;
                        *p = SPECIAL_VAR_SYMBOL;
-                       if (!(first_ch & 0x80)) { /* unquoted var */
+                       if (!(first_ch & 0x80)) { /* unquoted $VAR */
                                if (val) {
                                        n = expand_on_ifs(list, n, &pos, val);
                                        val = NULL;
                                }
-                       }
+                       } /* else: quoted $VAR, val will be appended at pos */
                }
                if (val) {
                        strcpy(pos, val);
@@ -3268,18 +3286,18 @@ static char* make_string(char **inp)
 /* return code: 0 for OK, 1 for syntax error */
 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
 {
-//     int i;
-//     char sep[] = " ";
        int ch = b_peek(input);  /* first character after the $ */
+       unsigned char quote_mask = dest->quote ? 0x80 : 0;
 
        debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
-       if (isalpha(ch) || ch == '?') {
+       if (isalpha(ch)) {
                b_addchr(dest, SPECIAL_VAR_SYMBOL);
                ctx->child->sp++;
                while (1) {
                        debug_printf_parse(": '%c'\n", ch);
                        b_getch(input);
-                       b_addchr(dest, ch);
+                       b_addchr(dest, ch | quote_mask);
+                       quote_mask = 0;
                        ch = b_peek(input);
                        if (!isalnum(ch) && ch != '_')
                                break;
@@ -3291,7 +3309,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
                ctx->child->sp++;
                debug_printf_parse(": '%c'\n", ch);
                b_getch(input);
-               b_addchr(dest, ch);
+               b_addchr(dest, ch | quote_mask);
                b_addchr(dest, SPECIAL_VAR_SYMBOL);
        } else switch (ch) {
                case '$': /* pid */
@@ -3316,7 +3334,8 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
                                if (ch == '}')
                                        break;
                                debug_printf_parse(": '%c'\n", ch);
-                               b_addchr(dest, ch);
+                               b_addchr(dest, ch | quote_mask);
+                               quote_mask = 0;
                        }
                        b_addchr(dest, SPECIAL_VAR_SYMBOL);
                        break;
index 11443f5..069a46e 100644 (file)
@@ -1,8 +1,3 @@
 Testing: in $empty""
 ..
-Testing: in "$*"
-.abc d e.
-Testing: in "$@"
-.abc.
-.d e.
 Finished
index c52e040..075e785 100755 (executable)
@@ -5,8 +5,4 @@ fi
 echo 'Testing: in $empty""'
 empty=''
 for a in $empty""; do echo ".$a."; done
-echo 'Testing: in "$*"'
-for a in "$*"; do echo ".$a."; done
-echo 'Testing: in "$@"'
-for a in "$@"; do echo ".$a."; done
 echo Finished
diff --git a/shell/hush_test/hush-bugs/starquoted.right b/shell/hush_test/hush-bugs/starquoted.right
deleted file mode 100644 (file)
index fedaf48..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.1 abc d e f.
diff --git a/shell/hush_test/hush-bugs/starquoted.tests b/shell/hush_test/hush-bugs/starquoted.tests
deleted file mode 100755 (executable)
index 3be2026..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-if test $# = 0; then
-    exec "$THIS_SH" starquoted.tests 1 abc 'd e f'
-fi
-for a in "$*"; do echo ".$a."; done
diff --git a/shell/hush_test/hush-parsing/quote4.right b/shell/hush_test/hush-parsing/quote4.right
new file mode 100644 (file)
index 0000000..b2901ea
--- /dev/null
@@ -0,0 +1 @@
+a b
diff --git a/shell/hush_test/hush-parsing/quote4.tests b/shell/hush_test/hush-parsing/quote4.tests
new file mode 100755 (executable)
index 0000000..f1dabfa
--- /dev/null
@@ -0,0 +1,2 @@
+a_b='a b'
+echo "$a_b"
diff --git a/shell/hush_test/hush-parsing/starquoted.right b/shell/hush_test/hush-parsing/starquoted.right
new file mode 100644 (file)
index 0000000..b56323f
--- /dev/null
@@ -0,0 +1,8 @@
+.1 abc d e f.
+.1.
+.abc.
+.d e f.
+.-1 abc d e f-.
+.-1.
+.abc.
+.d e f-.
diff --git a/shell/hush_test/hush-parsing/starquoted.tests b/shell/hush_test/hush-parsing/starquoted.tests
new file mode 100755 (executable)
index 0000000..2fe49b1
--- /dev/null
@@ -0,0 +1,8 @@
+if test $# = 0; then
+    exec "$THIS_SH" "$0" 1 abc 'd e f'
+fi
+
+for a in "$*"; do echo ".$a."; done
+for a in "$@"; do echo ".$a."; done
+for a in "-$*-"; do echo ".$a."; done
+for a in "-$@-"; do echo ".$a."; done