diff options
-rw-r--r-- | shell/hush.c | 53 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/export.right | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/group1.right | 1 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/group1.tests | 1 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_posix1.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_posix1.tests | 4 |
6 files changed, 45 insertions, 18 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 | ||
diff --git a/shell/hush_test/hush-misc/export.right b/shell/hush_test/hush-misc/export.right index 4df2e3858..b93e503f8 100644 --- a/shell/hush_test/hush-misc/export.right +++ b/shell/hush_test/hush-misc/export.right | |||
@@ -1,5 +1,5 @@ | |||
1 | export aaa1="'''" | 1 | export aaa1="'''" |
2 | export aaa2= | 2 | export aaa2='' |
3 | export aaa3="'''"'abc' | 3 | export aaa3="'''"'abc' |
4 | export aaa4='def'"'''" | 4 | export aaa4='def'"'''" |
5 | export aaa5="'''"'abc'"'''"'def'"'''" | 5 | export aaa5="'''"'abc'"'''"'def'"'''" |
diff --git a/shell/hush_test/hush-parsing/group1.right b/shell/hush_test/hush-parsing/group1.right new file mode 100644 index 000000000..6a7c4be0a --- /dev/null +++ b/shell/hush_test/hush-parsing/group1.right | |||
@@ -0,0 +1 @@ | |||
word} } | |||
diff --git a/shell/hush_test/hush-parsing/group1.tests b/shell/hush_test/hush-parsing/group1.tests new file mode 100644 index 000000000..f063fbcb3 --- /dev/null +++ b/shell/hush_test/hush-parsing/group1.tests | |||
@@ -0,0 +1 @@ | |||
{ echo word} }; } | |||
diff --git a/shell/hush_test/hush-vars/var_posix1.right b/shell/hush_test/hush-vars/var_posix1.right index 373b16ca5..47d52a6c2 100644 --- a/shell/hush_test/hush-vars/var_posix1.right +++ b/shell/hush_test/hush-vars/var_posix1.right | |||
@@ -22,6 +22,7 @@ babcdcd | |||
22 | babcdcd | 22 | babcdcd |
23 | ababcdcd | 23 | ababcdcd |
24 | Empty: | 24 | Empty: |
25 | ababcdcd}_tail | ||
25 | ababcd | 26 | ababcd |
26 | ababcd | 27 | ababcd |
27 | ababcd | 28 | ababcd |
@@ -30,4 +31,5 @@ ababcdc | |||
30 | ababcdc | 31 | ababcdc |
31 | ababcdcd | 32 | ababcdcd |
32 | Empty: | 33 | Empty: |
34 | ababcdcd}_tail | ||
33 | end | 35 | end |
diff --git a/shell/hush_test/hush-vars/var_posix1.tests b/shell/hush_test/hush-vars/var_posix1.tests index 0ce531d69..3069360e1 100755 --- a/shell/hush_test/hush-vars/var_posix1.tests +++ b/shell/hush_test/hush-vars/var_posix1.tests | |||
@@ -30,6 +30,8 @@ echo ${var#?} | |||
30 | echo ${var##?} | 30 | echo ${var##?} |
31 | echo ${var#*} | 31 | echo ${var#*} |
32 | echo Empty:${var##*} | 32 | echo Empty:${var##*} |
33 | echo ${var#}}_tail | ||
34 | # UNFIXED BUG: echo ${var#\}}_tail | ||
33 | 35 | ||
34 | echo ${var%cd} | 36 | echo ${var%cd} |
35 | echo ${var%%cd} | 37 | echo ${var%%cd} |
@@ -39,5 +41,7 @@ echo ${var%?} | |||
39 | echo ${var%%?} | 41 | echo ${var%%?} |
40 | echo ${var%*} | 42 | echo ${var%*} |
41 | echo Empty:${var%%*} | 43 | echo Empty:${var%%*} |
44 | echo ${var#}}_tail | ||
45 | # UNFIXED BUG: echo ${var#\}}_tail | ||
42 | 46 | ||
43 | echo end | 47 | echo end |