diff options
-rw-r--r-- | shell/hush.c | 26 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/starquoted2.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-parsing/starquoted2.tests | 14 |
3 files changed, 36 insertions, 6 deletions
diff --git a/shell/hush.c b/shell/hush.c index 5b5a54241..2c1d31c6d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2380,7 +2380,10 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2380 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 2380 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
2381 | 2381 | ||
2382 | first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ | 2382 | first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ |
2383 | ored_ch |= first_ch; | 2383 | /* "$@" is special. Even if quoted, it can still |
2384 | * expand to nothing (not even an empty string) */ | ||
2385 | if ((first_ch & 0x7f) != '@') | ||
2386 | ored_ch |= first_ch; | ||
2384 | val = NULL; | 2387 | val = NULL; |
2385 | switch (first_ch & 0x7f) { | 2388 | switch (first_ch & 0x7f) { |
2386 | /* Highest bit in first_ch indicates that var is double-quoted */ | 2389 | /* Highest bit in first_ch indicates that var is double-quoted */ |
@@ -2401,6 +2404,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
2401 | i = 1; | 2404 | i = 1; |
2402 | if (!global_argv[i]) | 2405 | if (!global_argv[i]) |
2403 | break; | 2406 | break; |
2407 | ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ | ||
2404 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ | 2408 | if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ |
2405 | smallint sv = output->o_quote; | 2409 | smallint sv = output->o_quote; |
2406 | /* unquoted var's contents should be globbed, so don't quote */ | 2410 | /* unquoted var's contents should be globbed, so don't quote */ |
@@ -2932,15 +2936,25 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
2932 | } | 2936 | } |
2933 | } | 2937 | } |
2934 | #endif | 2938 | #endif |
2935 | if (word->nonnull /* we saw "xx" or 'xx' */ | 2939 | if (word->nonnull /* word had "xx" or 'xx' at least as part of it */ |
2936 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ | 2940 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ |
2937 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) | 2941 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) |
2938 | /* (otherwise it's "abc".... and is already safe) */ | 2942 | /* (otherwise it's "abc".... and is already safe) */ |
2939 | ) { | 2943 | ) { |
2940 | /* Insert "empty variable" reference, this makes | 2944 | /* but exclude "$@"! it expands to no word despite "" */ |
2941 | * e.g. "", $empty"" etc to not disappear */ | 2945 | char *p = word->data; |
2942 | o_addchr(word, SPECIAL_VAR_SYMBOL); | 2946 | while (p[0] == SPECIAL_VAR_SYMBOL |
2943 | o_addchr(word, SPECIAL_VAR_SYMBOL); | 2947 | && (p[1] & 0x7f) == '@' |
2948 | && p[2] == SPECIAL_VAR_SYMBOL | ||
2949 | ) { | ||
2950 | p += 3; | ||
2951 | } | ||
2952 | if (p == word->data || p[0] != '\0') { | ||
2953 | /* Insert "empty variable" reference, this makes | ||
2954 | * e.g. "", $empty"" etc to not disappear */ | ||
2955 | o_addchr(word, SPECIAL_VAR_SYMBOL); | ||
2956 | o_addchr(word, SPECIAL_VAR_SYMBOL); | ||
2957 | } | ||
2944 | } | 2958 | } |
2945 | child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data)); | 2959 | child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data)); |
2946 | debug_print_strings("word appended to argv", child->argv); | 2960 | debug_print_strings("word appended to argv", child->argv); |
diff --git a/shell/hush_test/hush-parsing/starquoted2.right b/shell/hush_test/hush-parsing/starquoted2.right new file mode 100644 index 000000000..46f24369e --- /dev/null +++ b/shell/hush_test/hush-parsing/starquoted2.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Should be printed | ||
2 | Should be printed | ||
diff --git a/shell/hush_test/hush-parsing/starquoted2.tests b/shell/hush_test/hush-parsing/starquoted2.tests new file mode 100755 index 000000000..782d71b88 --- /dev/null +++ b/shell/hush_test/hush-parsing/starquoted2.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | if test $# != 0; then | ||
2 | exec "$THIS_SH" "$0" | ||
3 | fi | ||
4 | |||
5 | # No params! | ||
6 | for a in "$*"; do echo Should be printed; done | ||
7 | for a in "$@"; do echo Should not be printed; done | ||
8 | # Yes, believe it or not, bash is mesmerized by "$@" and stops | ||
9 | # treating "" as "this word cannot be expanded to nothing, | ||
10 | # but must be at least null string". Now it can be expanded to nothing. | ||
11 | for a in "$@"""; do echo Should not be printed; done | ||
12 | for a in """$@"; do echo Should not be printed; done | ||
13 | for a in """$@"''"$@"''; do echo Should not be printed; done | ||
14 | for a in ""; do echo Should be printed; done | ||