diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-04 18:46:14 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-04 18:46:14 +0100 |
commit | 672a55e606fc50e4ffe7810bd0d9cd1cf9b980a3 (patch) | |
tree | dd1805a175268a0e16ba578e095627e90e73f5fb /shell | |
parent | 06b114900fc57cac0e422d26228f4d0aaf5d2288 (diff) | |
download | busybox-w32-672a55e606fc50e4ffe7810bd0d9cd1cf9b980a3.tar.gz busybox-w32-672a55e606fc50e4ffe7810bd0d9cd1cf9b980a3.tar.bz2 busybox-w32-672a55e606fc50e4ffe7810bd0d9cd1cf9b980a3.zip |
hush: allow { cmd } to not be terminated by semicolon in some cases
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash_test/ash-misc/group_in_braces.right | 5 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/group_in_braces.tests | 11 | ||||
-rw-r--r-- | shell/hush.c | 32 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/group_in_braces.right | 5 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/group_in_braces.tests | 11 |
5 files changed, 58 insertions, 6 deletions
diff --git a/shell/ash_test/ash-misc/group_in_braces.right b/shell/ash_test/ash-misc/group_in_braces.right new file mode 100644 index 000000000..a7064499b --- /dev/null +++ b/shell/ash_test/ash-misc/group_in_braces.right | |||
@@ -0,0 +1,5 @@ | |||
1 | Zero:0 | ||
2 | Zero:0 | ||
3 | Zero:0 | ||
4 | Zero:0 | ||
5 | Zero:0 | ||
diff --git a/shell/ash_test/ash-misc/group_in_braces.tests b/shell/ash_test/ash-misc/group_in_braces.tests new file mode 100755 index 000000000..f6571c35d --- /dev/null +++ b/shell/ash_test/ash-misc/group_in_braces.tests | |||
@@ -0,0 +1,11 @@ | |||
1 | # Test cases where { cmd } does not require semicolon after "cmd" | ||
2 | (exit 2); { { true; } } | ||
3 | echo Zero:$? | ||
4 | (exit 2); {(true)} | ||
5 | echo Zero:$? | ||
6 | (exit 2); { true | { true; } } | ||
7 | echo Zero:$? | ||
8 | (exit 2); { while false; do :; done } | ||
9 | echo Zero:$? | ||
10 | (exit 2); { case a in b) ;; esac } | ||
11 | echo Zero:$? | ||
diff --git a/shell/hush.c b/shell/hush.c index 7c2f157b8..336de75ad 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -3915,12 +3915,17 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3915 | command->cmd_type = CMD_SUBSHELL; | 3915 | command->cmd_type = CMD_SUBSHELL; |
3916 | } else { | 3916 | } else { |
3917 | /* bash does not allow "{echo...", requires whitespace */ | 3917 | /* bash does not allow "{echo...", requires whitespace */ |
3918 | ch = i_getch(input); | 3918 | ch = i_peek(input); |
3919 | if (ch != ' ' && ch != '\t' && ch != '\n') { | 3919 | if (ch != ' ' && ch != '\t' && ch != '\n' |
3920 | && ch != '(' /* but "{(..." is allowed (without whitespace) */ | ||
3921 | ) { | ||
3920 | syntax_error_unexpected_ch(ch); | 3922 | syntax_error_unexpected_ch(ch); |
3921 | return 1; | 3923 | return 1; |
3922 | } | 3924 | } |
3923 | nommu_addchr(&ctx->as_string, ch); | 3925 | if (ch != '(') { |
3926 | ch = i_getch(input); | ||
3927 | nommu_addchr(&ctx->as_string, ch); | ||
3928 | } | ||
3924 | } | 3929 | } |
3925 | 3930 | ||
3926 | { | 3931 | { |
@@ -4575,6 +4580,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4575 | || dest.has_quoted_part /* ""{... - non-special */ | 4580 | || dest.has_quoted_part /* ""{... - non-special */ |
4576 | || (next != ';' /* }; - special */ | 4581 | || (next != ';' /* }; - special */ |
4577 | && next != ')' /* }) - special */ | 4582 | && next != ')' /* }) - special */ |
4583 | && next != '(' /* {( - special */ | ||
4578 | && next != '&' /* }& and }&& ... - special */ | 4584 | && next != '&' /* }& and }&& ... - special */ |
4579 | && next != '|' /* }|| ... - special */ | 4585 | && next != '|' /* }|| ... - special */ |
4580 | && !strchr(defifs, next) /* {word - non-special */ | 4586 | && !strchr(defifs, next) /* {word - non-special */ |
@@ -4657,17 +4663,31 @@ static struct pipe *parse_stream(char **pstring, | |||
4657 | * Pathological example: { ""}; } should exec "}" cmd | 4663 | * Pathological example: { ""}; } should exec "}" cmd |
4658 | */ | 4664 | */ |
4659 | if (ch == '}') { | 4665 | if (ch == '}') { |
4660 | if (!IS_NULL_CMD(ctx.command) /* cmd } */ | 4666 | if (dest.length != 0 /* word} */ |
4661 | || dest.length != 0 /* word} */ | ||
4662 | || dest.has_quoted_part /* ""} */ | 4667 | || dest.has_quoted_part /* ""} */ |
4663 | ) { | 4668 | ) { |
4664 | goto ordinary_char; | 4669 | goto ordinary_char; |
4665 | } | 4670 | } |
4671 | if (!IS_NULL_CMD(ctx.command)) { /* cmd } */ | ||
4672 | /* Generally, there should be semicolon: "cmd; }" | ||
4673 | * However, bash allows to omit it if "cmd" is | ||
4674 | * a group. Examples: | ||
4675 | * { { echo 1; } } | ||
4676 | * {(echo 1)} | ||
4677 | * { echo 0 >&2 | { echo 1; } } | ||
4678 | * { while false; do :; done } | ||
4679 | * { case a in b) ;; esac } | ||
4680 | */ | ||
4681 | if (ctx.command->group) | ||
4682 | goto term_group; | ||
4683 | goto ordinary_char; | ||
4684 | } | ||
4666 | if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */ | 4685 | if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */ |
4686 | /* Can't be an end of {cmd}, skip the check */ | ||
4667 | goto skip_end_trigger; | 4687 | goto skip_end_trigger; |
4668 | /* else: } does terminate a group */ | 4688 | /* else: } does terminate a group */ |
4669 | } | 4689 | } |
4670 | 4690 | term_group: | |
4671 | if (end_trigger && end_trigger == ch | 4691 | if (end_trigger && end_trigger == ch |
4672 | && (ch != ';' || heredoc_cnt == 0) | 4692 | && (ch != ';' || heredoc_cnt == 0) |
4673 | #if ENABLE_HUSH_CASE | 4693 | #if ENABLE_HUSH_CASE |
diff --git a/shell/hush_test/hush-misc/group_in_braces.right b/shell/hush_test/hush-misc/group_in_braces.right new file mode 100644 index 000000000..a7064499b --- /dev/null +++ b/shell/hush_test/hush-misc/group_in_braces.right | |||
@@ -0,0 +1,5 @@ | |||
1 | Zero:0 | ||
2 | Zero:0 | ||
3 | Zero:0 | ||
4 | Zero:0 | ||
5 | Zero:0 | ||
diff --git a/shell/hush_test/hush-misc/group_in_braces.tests b/shell/hush_test/hush-misc/group_in_braces.tests new file mode 100755 index 000000000..f6571c35d --- /dev/null +++ b/shell/hush_test/hush-misc/group_in_braces.tests | |||
@@ -0,0 +1,11 @@ | |||
1 | # Test cases where { cmd } does not require semicolon after "cmd" | ||
2 | (exit 2); { { true; } } | ||
3 | echo Zero:$? | ||
4 | (exit 2); {(true)} | ||
5 | echo Zero:$? | ||
6 | (exit 2); { true | { true; } } | ||
7 | echo Zero:$? | ||
8 | (exit 2); { while false; do :; done } | ||
9 | echo Zero:$? | ||
10 | (exit 2); { case a in b) ;; esac } | ||
11 | echo Zero:$? | ||