diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-19 13:57:51 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-19 13:57:51 +0000 |
commit | bf25fbccb9b2641c77685ac0a537e8068b6b354a (patch) | |
tree | 8be416c9a03d440259007697664566f50f21f93e /shell/hush.c | |
parent | a29c935442869310c4af45c78446b34d370ff53c (diff) | |
download | busybox-w32-bf25fbccb9b2641c77685ac0a537e8068b6b354a.tar.gz busybox-w32-bf25fbccb9b2641c77685ac0a537e8068b6b354a.tar.bz2 busybox-w32-bf25fbccb9b2641c77685ac0a537e8068b6b354a.zip |
hush: fix handling of } which is not a closing one in { cmd; }
function old new delta
parse_stream 2176 2302 +126
builtin_unset 381 387 +6
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/shell/hush.c b/shell/hush.c index ecacd96ed..62b1d48b4 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1822,7 +1822,7 @@ static int o_glob(o_string *o, int n) | |||
1822 | goto literal; | 1822 | goto literal; |
1823 | } | 1823 | } |
1824 | if (gr != 0) { /* GLOB_ABORTED ? */ | 1824 | if (gr != 0) { /* GLOB_ABORTED ? */ |
1825 | //TODO: testcase for bad glob pattern behavior | 1825 | /* TODO: testcase for bad glob pattern behavior */ |
1826 | bb_error_msg("glob(3) error %d on '%s'", gr, pattern); | 1826 | bb_error_msg("glob(3) error %d on '%s'", gr, pattern); |
1827 | } | 1827 | } |
1828 | if (globdata.gl_pathv && globdata.gl_pathv[0]) { | 1828 | if (globdata.gl_pathv && globdata.gl_pathv[0]) { |
@@ -2339,7 +2339,8 @@ static char* expand_strvec_to_string(char **argv) | |||
2339 | if (HUSH_DEBUG) | 2339 | if (HUSH_DEBUG) |
2340 | if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) | 2340 | if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) |
2341 | bb_error_msg_and_die("BUG in varexp3"); | 2341 | bb_error_msg_and_die("BUG in varexp3"); |
2342 | list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */ | 2342 | /* bash uses ' ' regardless of $IFS contents */ |
2343 | list[n][-1] = ' '; | ||
2343 | n++; | 2344 | n++; |
2344 | } | 2345 | } |
2345 | } | 2346 | } |
@@ -5128,14 +5129,16 @@ static int handle_dollar(o_string *as_string, | |||
5128 | while (1) { | 5129 | while (1) { |
5129 | ch = i_getch(input); | 5130 | ch = i_getch(input); |
5130 | nommu_addchr(as_string, ch); | 5131 | nommu_addchr(as_string, ch); |
5131 | if (ch == '}') | 5132 | if (ch == '}') { |
5132 | break; | 5133 | break; |
5134 | } | ||
5133 | 5135 | ||
5134 | if (first_char) { | 5136 | if (first_char) { |
5135 | if (ch == '#') | 5137 | if (ch == '#') { |
5136 | /* ${#var}: length of var contents */ | 5138 | /* ${#var}: length of var contents */ |
5137 | goto char_ok; | 5139 | goto char_ok; |
5138 | else if (isdigit(ch)) { | 5140 | } |
5141 | if (isdigit(ch)) { | ||
5139 | all_digits = true; | 5142 | all_digits = true; |
5140 | goto char_ok; | 5143 | goto char_ok; |
5141 | } | 5144 | } |
@@ -5186,7 +5189,7 @@ static int handle_dollar(o_string *as_string, | |||
5186 | o_addchr(dest, ch | quote_mask); | 5189 | o_addchr(dest, ch | quote_mask); |
5187 | quote_mask = 0; | 5190 | quote_mask = 0; |
5188 | first_char = false; | 5191 | first_char = false; |
5189 | } | 5192 | } /* while (1) */ |
5190 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 5193 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
5191 | break; | 5194 | break; |
5192 | } | 5195 | } |
@@ -5432,6 +5435,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5432 | , ch); | 5435 | , ch); |
5433 | 5436 | ||
5434 | if (!is_special && !is_ifs) { /* ordinary char */ | 5437 | if (!is_special && !is_ifs) { /* ordinary char */ |
5438 | ordinary_char: | ||
5435 | o_addQchr(&dest, ch); | 5439 | o_addQchr(&dest, ch); |
5436 | if ((dest.o_assignment == MAYBE_ASSIGNMENT | 5440 | if ((dest.o_assignment == MAYBE_ASSIGNMENT |
5437 | || dest.o_assignment == WORD_IS_KEYWORD) | 5441 | || dest.o_assignment == WORD_IS_KEYWORD) |
@@ -5475,6 +5479,19 @@ static struct pipe *parse_stream(char **pstring, | |||
5475 | if (end_trigger && end_trigger == ch | 5479 | if (end_trigger && end_trigger == ch |
5476 | && (heredoc_cnt == 0 || end_trigger != ';') | 5480 | && (heredoc_cnt == 0 || end_trigger != ';') |
5477 | ) { | 5481 | ) { |
5482 | /* "{ cmd}" or "{ cmd }..." without semicolon or &: | ||
5483 | * } is an ordinary char in this case. | ||
5484 | * Pathological example: { ""}; } should exec "}" cmd | ||
5485 | */ | ||
5486 | if (ch == '}' | ||
5487 | && !(IS_NULL_PIPE(ctx.pipe) | ||
5488 | && IS_NULL_CMD(ctx.command) | ||
5489 | && dest.length == 0 | ||
5490 | && !dest.o_quoted | ||
5491 | ) | ||
5492 | ) { | ||
5493 | goto ordinary_char; | ||
5494 | } | ||
5478 | if (heredoc_cnt) { | 5495 | if (heredoc_cnt) { |
5479 | /* This is technically valid: | 5496 | /* This is technically valid: |
5480 | * { cat <<HERE; }; echo Ok | 5497 | * { cat <<HERE; }; echo Ok |
@@ -5491,15 +5508,6 @@ static struct pipe *parse_stream(char **pstring, | |||
5491 | if (done_word(&dest, &ctx)) { | 5508 | if (done_word(&dest, &ctx)) { |
5492 | goto parse_error; | 5509 | goto parse_error; |
5493 | } | 5510 | } |
5494 | /* Disallow "{ cmd }" without semicolon or & */ | ||
5495 | //debug_printf_parse("null pi %d\n", IS_NULL_PIPE(ctx.pipe)) | ||
5496 | //debug_printf_parse("null cmd %d\n", IS_NULL_CMD(ctx.command)) | ||
5497 | if (ch == '}' | ||
5498 | && !(IS_NULL_PIPE(ctx.pipe) && IS_NULL_CMD(ctx.command)) | ||
5499 | ) { | ||
5500 | syntax_error_unexpected_ch(ch); | ||
5501 | goto parse_error; | ||
5502 | } | ||
5503 | done_pipe(&ctx, PIPE_SEQ); | 5511 | done_pipe(&ctx, PIPE_SEQ); |
5504 | dest.o_assignment = MAYBE_ASSIGNMENT; | 5512 | dest.o_assignment = MAYBE_ASSIGNMENT; |
5505 | /* Do we sit outside of any if's, loops or case's? */ | 5513 | /* Do we sit outside of any if's, loops or case's? */ |
@@ -5749,6 +5757,16 @@ static struct pipe *parse_stream(char **pstring, | |||
5749 | goto case_semi; | 5757 | goto case_semi; |
5750 | #endif | 5758 | #endif |
5751 | case '}': | 5759 | case '}': |
5760 | if (!(IS_NULL_PIPE(ctx.pipe) | ||
5761 | && IS_NULL_CMD(ctx.command) | ||
5762 | && dest.length == 0 | ||
5763 | && !dest.o_quoted | ||
5764 | ) | ||
5765 | ) { | ||
5766 | /* } not preceded by ; or & is an ordinary | ||
5767 | * char, example: "echo }" */ | ||
5768 | goto ordinary_char; | ||
5769 | } | ||
5752 | /* proper use of this character is caught by end_trigger: | 5770 | /* proper use of this character is caught by end_trigger: |
5753 | * if we see {, we call parse_group(..., end_trigger='}') | 5771 | * if we see {, we call parse_group(..., end_trigger='}') |
5754 | * and it will match } earlier (not here). */ | 5772 | * and it will match } earlier (not here). */ |
@@ -6858,7 +6876,8 @@ static int builtin_unset(char **argv) | |||
6858 | 6876 | ||
6859 | var = 0; | 6877 | var = 0; |
6860 | while ((arg = *argv) != NULL && arg[0] == '-') { | 6878 | while ((arg = *argv) != NULL && arg[0] == '-') { |
6861 | while (*++arg) { | 6879 | arg++; |
6880 | do { | ||
6862 | switch (*arg) { | 6881 | switch (*arg) { |
6863 | case 'v': | 6882 | case 'v': |
6864 | case 'f': | 6883 | case 'f': |
@@ -6872,7 +6891,7 @@ static int builtin_unset(char **argv) | |||
6872 | bb_error_msg("unset: %s: invalid option", *argv); | 6891 | bb_error_msg("unset: %s: invalid option", *argv); |
6873 | return EXIT_FAILURE; | 6892 | return EXIT_FAILURE; |
6874 | } | 6893 | } |
6875 | } | 6894 | } while (*++arg); |
6876 | argv++; | 6895 | argv++; |
6877 | } | 6896 | } |
6878 | 6897 | ||