diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 11 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/control_char3.right | 1 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/control_char3.tests | 2 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/control_char4.right | 1 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/control_char4.tests | 2 | ||||
-rw-r--r-- | shell/ash_test/ash-parsing/bkslash_newline4.right | 4 | ||||
-rwxr-xr-x | shell/ash_test/ash-parsing/bkslash_newline4.tests | 14 | ||||
-rw-r--r-- | shell/hush.c | 47 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/control_char3.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/control_char3.tests | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/control_char4.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/control_char4.tests | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/bkslash_newline4.right | 4 | ||||
-rwxr-xr-x | shell/hush_test/hush-parsing/bkslash_newline4.tests | 14 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var6.right | 2 |
15 files changed, 97 insertions, 11 deletions
diff --git a/shell/ash.c b/shell/ash.c index bab6138da..4ae42595d 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -13572,7 +13572,7 @@ parsesub: { | |||
13572 | do { | 13572 | do { |
13573 | STPUTC(c, out); | 13573 | STPUTC(c, out); |
13574 | c = pgetc_eatbnl(); | 13574 | c = pgetc_eatbnl(); |
13575 | } while (!subtype && isdigit(c)); | 13575 | } while ((subtype == 0 || subtype == VSLENGTH) && isdigit(c)); |
13576 | } else if (c != '}') { | 13576 | } else if (c != '}') { |
13577 | /* $[{[#]]<specialchar>[}] */ | 13577 | /* $[{[#]]<specialchar>[}] */ |
13578 | int cc = c; | 13578 | int cc = c; |
@@ -13602,11 +13602,6 @@ parsesub: { | |||
13602 | } else | 13602 | } else |
13603 | goto badsub; | 13603 | goto badsub; |
13604 | 13604 | ||
13605 | if (c != '}' && subtype == VSLENGTH) { | ||
13606 | /* ${#VAR didn't end with } */ | ||
13607 | goto badsub; | ||
13608 | } | ||
13609 | |||
13610 | if (subtype == 0) { | 13605 | if (subtype == 0) { |
13611 | static const char types[] ALIGN1 = "}-+?="; | 13606 | static const char types[] ALIGN1 = "}-+?="; |
13612 | /* ${VAR...} but not $VAR or ${#VAR} */ | 13607 | /* ${VAR...} but not $VAR or ${#VAR} */ |
@@ -13663,6 +13658,8 @@ parsesub: { | |||
13663 | #endif | 13658 | #endif |
13664 | } | 13659 | } |
13665 | } else { | 13660 | } else { |
13661 | if (subtype == VSLENGTH && c != '}') | ||
13662 | subtype = 0; | ||
13666 | badsub: | 13663 | badsub: |
13667 | pungetc(); | 13664 | pungetc(); |
13668 | } | 13665 | } |
@@ -15358,7 +15355,7 @@ init(void) | |||
15358 | 15355 | ||
15359 | 15356 | ||
15360 | //usage:#define ash_trivial_usage | 15357 | //usage:#define ash_trivial_usage |
15361 | //usage: "[-il] [-/+Cabefmnuvx] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" | 15358 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE [ARGS] | -s [ARGS]]" |
15362 | //////// comes from ^^^^^^^^^^optletters | 15359 | //////// comes from ^^^^^^^^^^optletters |
15363 | //usage:#define ash_full_usage "\n\n" | 15360 | //usage:#define ash_full_usage "\n\n" |
15364 | //usage: "Unix shell interpreter" | 15361 | //usage: "Unix shell interpreter" |
diff --git a/shell/ash_test/ash-misc/control_char3.right b/shell/ash_test/ash-misc/control_char3.right new file mode 100644 index 000000000..283e02cbb --- /dev/null +++ b/shell/ash_test/ash-misc/control_char3.right | |||
@@ -0,0 +1 @@ | |||
SHELL: line 1: : not found | |||
diff --git a/shell/ash_test/ash-misc/control_char3.tests b/shell/ash_test/ash-misc/control_char3.tests new file mode 100755 index 000000000..4359db3f3 --- /dev/null +++ b/shell/ash_test/ash-misc/control_char3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '\' SHELL | ||
diff --git a/shell/ash_test/ash-misc/control_char4.right b/shell/ash_test/ash-misc/control_char4.right new file mode 100644 index 000000000..2bf18e684 --- /dev/null +++ b/shell/ash_test/ash-misc/control_char4.right | |||
@@ -0,0 +1 @@ | |||
SHELL: line 1: -: not found | |||
diff --git a/shell/ash_test/ash-misc/control_char4.tests b/shell/ash_test/ash-misc/control_char4.tests new file mode 100755 index 000000000..48010f154 --- /dev/null +++ b/shell/ash_test/ash-misc/control_char4.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '"-"' SHELL | ||
diff --git a/shell/ash_test/ash-parsing/bkslash_newline4.right b/shell/ash_test/ash-parsing/bkslash_newline4.right new file mode 100644 index 000000000..2110716d1 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline4.right | |||
@@ -0,0 +1,4 @@ | |||
1 | 1:1 | ||
2 | 22:22 | ||
3 | 3:3 | ||
4 | Ok:0 | ||
diff --git a/shell/ash_test/ash-parsing/bkslash_newline4.tests b/shell/ash_test/ash-parsing/bkslash_newline4.tests new file mode 100755 index 000000000..c8f5037c4 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline4.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | set -- 1 22 333 | ||
2 | echo 1:$\ | ||
3 | 1 | ||
4 | echo 22:$\ | ||
5 | {\ | ||
6 | 2\ | ||
7 | } | ||
8 | echo 3:$\ | ||
9 | {\ | ||
10 | #\ | ||
11 | 3\ | ||
12 | } | ||
13 | echo Ok:$\ | ||
14 | ? | ||
diff --git a/shell/hush.c b/shell/hush.c index 77921e11c..1aa0a400d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -339,7 +339,7 @@ | |||
339 | * therefore we don't show them either. | 339 | * therefore we don't show them either. |
340 | */ | 340 | */ |
341 | //usage:#define hush_trivial_usage | 341 | //usage:#define hush_trivial_usage |
342 | //usage: "[-enxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" | 342 | //usage: "[-enxl] [-c 'SCRIPT' [ARG0 ARGS] | FILE [ARGS] | -s [ARGS]]" |
343 | //usage:#define hush_full_usage "\n\n" | 343 | //usage:#define hush_full_usage "\n\n" |
344 | //usage: "Unix shell interpreter" | 344 | //usage: "Unix shell interpreter" |
345 | 345 | ||
@@ -3696,9 +3696,10 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
3696 | 3696 | ||
3697 | pin = 0; | 3697 | pin = 0; |
3698 | while (pi) { | 3698 | while (pi) { |
3699 | fdprintf(2, "%*spipe %d %sres_word=%s followup=%d %s\n", | 3699 | fdprintf(2, "%*spipe %d #cmds:%d %sres_word=%s followup=%d %s\n", |
3700 | lvl*2, "", | 3700 | lvl*2, "", |
3701 | pin, | 3701 | pin, |
3702 | pi->num_cmds, | ||
3702 | (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""), | 3703 | (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""), |
3703 | RES[pi->res_word], | 3704 | RES[pi->res_word], |
3704 | pi->followup, PIPE[pi->followup] | 3705 | pi->followup, PIPE[pi->followup] |
@@ -3841,6 +3842,9 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
3841 | #endif | 3842 | #endif |
3842 | /* Replace all pipes in ctx with one newly created */ | 3843 | /* Replace all pipes in ctx with one newly created */ |
3843 | ctx->list_head = ctx->pipe = pi; | 3844 | ctx->list_head = ctx->pipe = pi; |
3845 | /* for cases like "cmd && &", do not be tricked by last command | ||
3846 | * being null - the entire {...} & is NOT null! */ | ||
3847 | not_null = 1; | ||
3844 | } else { | 3848 | } else { |
3845 | no_conv: | 3849 | no_conv: |
3846 | ctx->pipe->followup = type; | 3850 | ctx->pipe->followup = type; |
@@ -4994,6 +4998,32 @@ static int parse_dollar(o_string *as_string, | |||
4994 | * which check invalid constructs like ${%}. | 4998 | * which check invalid constructs like ${%}. |
4995 | * Oh well... let's check that the var name part is fine... */ | 4999 | * Oh well... let's check that the var name part is fine... */ |
4996 | 5000 | ||
5001 | if (isdigit(len_single_ch) | ||
5002 | || (len_single_ch == '#' && isdigit(i_peek_and_eat_bkslash_nl(input))) | ||
5003 | ) { | ||
5004 | /* Execution engine uses plain xatoi_positive() | ||
5005 | * to interpret ${NNN} and {#NNN}, | ||
5006 | * check syntax here in the parser. | ||
5007 | * (bash does not support expressions in ${#NN}, | ||
5008 | * e.g. ${#$var} and {#1:+WORD} are not supported). | ||
5009 | */ | ||
5010 | unsigned cnt = 9; /* max 9 digits for ${NN} and 8 for {#NN} */ | ||
5011 | while (1) { | ||
5012 | o_addchr(dest, ch); | ||
5013 | debug_printf_parse(": '%c'\n", ch); | ||
5014 | ch = i_getch_and_eat_bkslash_nl(input); | ||
5015 | nommu_addchr(as_string, ch); | ||
5016 | if (ch == '}') | ||
5017 | break; | ||
5018 | if (--cnt == 0) | ||
5019 | goto bad_dollar_syntax; | ||
5020 | if (len_single_ch != '#' && strchr(VAR_SUBST_OPS, ch)) | ||
5021 | /* ${NN<op>...} is valid */ | ||
5022 | goto eat_until_closing; | ||
5023 | if (!isdigit(ch)) | ||
5024 | goto bad_dollar_syntax; | ||
5025 | } | ||
5026 | } else | ||
4997 | while (1) { | 5027 | while (1) { |
4998 | unsigned pos; | 5028 | unsigned pos; |
4999 | 5029 | ||
@@ -5004,7 +5034,6 @@ static int parse_dollar(o_string *as_string, | |||
5004 | nommu_addchr(as_string, ch); | 5034 | nommu_addchr(as_string, ch); |
5005 | if (ch == '}') | 5035 | if (ch == '}') |
5006 | break; | 5036 | break; |
5007 | |||
5008 | if (!isalnum(ch) && ch != '_') { | 5037 | if (!isalnum(ch) && ch != '_') { |
5009 | unsigned end_ch; | 5038 | unsigned end_ch; |
5010 | unsigned char last_ch; | 5039 | unsigned char last_ch; |
@@ -5023,6 +5052,7 @@ static int parse_dollar(o_string *as_string, | |||
5023 | * special var name, e.g. ${#!}. | 5052 | * special var name, e.g. ${#!}. |
5024 | */ | 5053 | */ |
5025 | } | 5054 | } |
5055 | eat_until_closing: | ||
5026 | /* Eat everything until closing '}' (or ':') */ | 5056 | /* Eat everything until closing '}' (or ':') */ |
5027 | end_ch = '}'; | 5057 | end_ch = '}'; |
5028 | if (BASH_SUBSTR | 5058 | if (BASH_SUBSTR |
@@ -5237,6 +5267,11 @@ static int encode_string(o_string *as_string, | |||
5237 | } | 5267 | } |
5238 | #endif | 5268 | #endif |
5239 | o_addQchr(dest, ch); | 5269 | o_addQchr(dest, ch); |
5270 | if (ch == SPECIAL_VAR_SYMBOL) { | ||
5271 | /* Convert "^C" to corresponding special variable reference */ | ||
5272 | o_addchr(dest, SPECIAL_VAR_QUOTED_SVS); | ||
5273 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
5274 | } | ||
5240 | goto again; | 5275 | goto again; |
5241 | #undef as_string | 5276 | #undef as_string |
5242 | } | 5277 | } |
@@ -5348,6 +5383,11 @@ static struct pipe *parse_stream(char **pstring, | |||
5348 | if (ch == '\n') | 5383 | if (ch == '\n') |
5349 | continue; /* drop \<newline>, get next char */ | 5384 | continue; /* drop \<newline>, get next char */ |
5350 | nommu_addchr(&ctx.as_string, '\\'); | 5385 | nommu_addchr(&ctx.as_string, '\\'); |
5386 | if (ch == SPECIAL_VAR_SYMBOL) { | ||
5387 | nommu_addchr(&ctx.as_string, ch); | ||
5388 | /* Convert \^C to corresponding special variable reference */ | ||
5389 | goto case_SPECIAL_VAR_SYMBOL; | ||
5390 | } | ||
5351 | o_addchr(&ctx.word, '\\'); | 5391 | o_addchr(&ctx.word, '\\'); |
5352 | if (ch == EOF) { | 5392 | if (ch == EOF) { |
5353 | /* Testcase: eval 'echo Ok\' */ | 5393 | /* Testcase: eval 'echo Ok\' */ |
@@ -5672,6 +5712,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5672 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ | 5712 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ |
5673 | 5713 | ||
5674 | switch (ch) { | 5714 | switch (ch) { |
5715 | case_SPECIAL_VAR_SYMBOL: | ||
5675 | case SPECIAL_VAR_SYMBOL: | 5716 | case SPECIAL_VAR_SYMBOL: |
5676 | /* Convert raw ^C to corresponding special variable reference */ | 5717 | /* Convert raw ^C to corresponding special variable reference */ |
5677 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); | 5718 | o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL); |
diff --git a/shell/hush_test/hush-misc/control_char3.right b/shell/hush_test/hush-misc/control_char3.right new file mode 100644 index 000000000..94b4f8699 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char3.right | |||
@@ -0,0 +1 @@ | |||
hush: can't execute '': No such file or directory | |||
diff --git a/shell/hush_test/hush-misc/control_char3.tests b/shell/hush_test/hush-misc/control_char3.tests new file mode 100755 index 000000000..4359db3f3 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char3.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '\' SHELL | ||
diff --git a/shell/hush_test/hush-misc/control_char4.right b/shell/hush_test/hush-misc/control_char4.right new file mode 100644 index 000000000..698e21427 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char4.right | |||
@@ -0,0 +1 @@ | |||
hush: can't execute '-': No such file or directory | |||
diff --git a/shell/hush_test/hush-misc/control_char4.tests b/shell/hush_test/hush-misc/control_char4.tests new file mode 100755 index 000000000..48010f154 --- /dev/null +++ b/shell/hush_test/hush-misc/control_char4.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | # (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) | ||
2 | $THIS_SH -c '"-"' SHELL | ||
diff --git a/shell/hush_test/hush-parsing/bkslash_newline4.right b/shell/hush_test/hush-parsing/bkslash_newline4.right new file mode 100644 index 000000000..2110716d1 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline4.right | |||
@@ -0,0 +1,4 @@ | |||
1 | 1:1 | ||
2 | 22:22 | ||
3 | 3:3 | ||
4 | Ok:0 | ||
diff --git a/shell/hush_test/hush-parsing/bkslash_newline4.tests b/shell/hush_test/hush-parsing/bkslash_newline4.tests new file mode 100755 index 000000000..c8f5037c4 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline4.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | set -- 1 22 333 | ||
2 | echo 1:$\ | ||
3 | 1 | ||
4 | echo 22:$\ | ||
5 | {\ | ||
6 | 2\ | ||
7 | } | ||
8 | echo 3:$\ | ||
9 | {\ | ||
10 | #\ | ||
11 | 3\ | ||
12 | } | ||
13 | echo Ok:$\ | ||
14 | ? | ||
diff --git a/shell/hush_test/hush-vars/var6.right b/shell/hush_test/hush-vars/var6.right index 40e67fdf5..5e28d2fab 100644 --- a/shell/hush_test/hush-vars/var6.right +++ b/shell/hush_test/hush-vars/var6.right | |||
@@ -1,2 +1,2 @@ | |||
1 | hush: invalid number '1q' | 1 | hush: syntax error: unterminated ${name} |
2 | hush: syntax error: unterminated ${name} | 2 | hush: syntax error: unterminated ${name} |