diff options
| author | Ron Yorston <rmy@pobox.com> | 2024-06-23 09:35:35 +0100 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2024-06-23 09:44:03 +0100 |
| commit | b07c177b446498ccd739b367f9e80337c3dfa55a (patch) | |
| tree | 8230bce5f937e46ae1a6f18677904d2eccc4ae9e /shell | |
| parent | 1b094d366f808a2ebc4824004f0d6f75f13c09cb (diff) | |
| parent | a6ce017a8a2db09c6f23aa6abf7ce21fd00c2fdf (diff) | |
| download | busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.tar.gz busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.tar.bz2 busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.zip | |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 5 | ||||
| -rw-r--r-- | shell/ash_test/ash-parsing/nodone1.right | 1 | ||||
| -rwxr-xr-x | shell/ash_test/ash-parsing/nodone1.tests | 1 | ||||
| -rw-r--r-- | shell/ash_test/ash-parsing/nodone2.right | 1 | ||||
| -rwxr-xr-x | shell/ash_test/ash-parsing/nodone2.tests | 3 | ||||
| -rw-r--r-- | shell/ash_test/ash-quoting/dollar_repl_bash2.right | 4 | ||||
| -rwxr-xr-x | shell/ash_test/ash-quoting/dollar_repl_bash2.tests | 8 | ||||
| -rw-r--r-- | shell/hush.c | 73 | ||||
| -rw-r--r-- | shell/hush_test/hush-parsing/nodone1.right | 1 | ||||
| -rwxr-xr-x | shell/hush_test/hush-parsing/nodone1.tests | 1 | ||||
| -rw-r--r-- | shell/hush_test/hush-parsing/nodone2.right | 1 | ||||
| -rwxr-xr-x | shell/hush_test/hush-parsing/nodone2.tests | 3 | ||||
| -rw-r--r-- | shell/hush_test/hush-quoting/dollar_repl_bash2.right | 4 | ||||
| -rwxr-xr-x | shell/hush_test/hush-quoting/dollar_repl_bash2.tests | 8 |
14 files changed, 85 insertions, 29 deletions
diff --git a/shell/ash.c b/shell/ash.c index 817b5635f..9ef8f7742 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -7884,6 +7884,11 @@ subevalvar(char *start, char *str, int strloc, | |||
| 7884 | repl = NULL; | 7884 | repl = NULL; |
| 7885 | break; | 7885 | break; |
| 7886 | } | 7886 | } |
| 7887 | /* Skip over quoted 'str'. Example: ${var/'/'} - second / is not a separator */ | ||
| 7888 | if ((unsigned char)*repl == CTLQUOTEMARK) { | ||
| 7889 | while ((unsigned char)*++repl != CTLQUOTEMARK) | ||
| 7890 | continue; | ||
| 7891 | } | ||
| 7887 | if (*repl == '/') { | 7892 | if (*repl == '/') { |
| 7888 | *repl = '\0'; | 7893 | *repl = '\0'; |
| 7889 | break; | 7894 | break; |
diff --git a/shell/ash_test/ash-parsing/nodone1.right b/shell/ash_test/ash-parsing/nodone1.right new file mode 100644 index 000000000..0150ccad5 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone1.right | |||
| @@ -0,0 +1 @@ | |||
| ./nodone1.tests: line 2: syntax error: unexpected end of file (expecting "done") | |||
diff --git a/shell/ash_test/ash-parsing/nodone1.tests b/shell/ash_test/ash-parsing/nodone1.tests new file mode 100755 index 000000000..de286c5a2 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone1.tests | |||
| @@ -0,0 +1 @@ | |||
| for i; do : | |||
diff --git a/shell/ash_test/ash-parsing/nodone2.right b/shell/ash_test/ash-parsing/nodone2.right new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone2.right | |||
| @@ -0,0 +1 @@ | |||
| 1 | |||
diff --git a/shell/ash_test/ash-parsing/nodone2.tests b/shell/ash_test/ash-parsing/nodone2.tests new file mode 100755 index 000000000..69537b3b1 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone2.tests | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | for i in 1; do echo $i | ||
| 2 | # the next line has no EOL. It still must count as "done" keyword: | ||
| 3 | done \ No newline at end of file | ||
diff --git a/shell/ash_test/ash-quoting/dollar_repl_bash2.right b/shell/ash_test/ash-quoting/dollar_repl_bash2.right new file mode 100644 index 000000000..e3fcd5807 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_bash2.right | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | axxb | ||
| 2 | axxb | ||
| 3 | axxb | ||
| 4 | axxb | ||
diff --git a/shell/ash_test/ash-quoting/dollar_repl_bash2.tests b/shell/ash_test/ash-quoting/dollar_repl_bash2.tests new file mode 100755 index 000000000..45c7a10e2 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_bash2.tests | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | v="x/x" | ||
| 2 | # The second / is quoted, should not be treated as separator | ||
| 3 | echo a${v/'/'}b | ||
| 4 | # The second / is escaped, should not be treated as separator | ||
| 5 | echo a${v/\/}b | ||
| 6 | |||
| 7 | echo "a${v/'/'}b" | ||
| 8 | echo "a${v/\/}b" | ||
diff --git a/shell/hush.c b/shell/hush.c index ca01e2b5b..3e6a13b32 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -5497,6 +5497,15 @@ static struct pipe *parse_stream(char **pstring, | |||
| 5497 | } | 5497 | } |
| 5498 | o_free_and_set_NULL(&ctx.word); | 5498 | o_free_and_set_NULL(&ctx.word); |
| 5499 | done_pipe(&ctx, PIPE_SEQ); | 5499 | done_pipe(&ctx, PIPE_SEQ); |
| 5500 | |||
| 5501 | /* Do we sit inside of any if's, loops or case's? */ | ||
| 5502 | if (HAS_KEYWORDS | ||
| 5503 | IF_HAS_KEYWORDS(&& (ctx.ctx_res_w != RES_NONE || ctx.old_flag != 0)) | ||
| 5504 | ) { | ||
| 5505 | syntax_error_unterm_str("compound statement"); | ||
| 5506 | goto parse_error_exitcode1; | ||
| 5507 | } | ||
| 5508 | |||
| 5500 | pi = ctx.list_head; | 5509 | pi = ctx.list_head; |
| 5501 | /* If we got nothing... */ | 5510 | /* If we got nothing... */ |
| 5502 | /* (this makes bare "&" cmd a no-op. | 5511 | /* (this makes bare "&" cmd a no-op. |
| @@ -5519,7 +5528,7 @@ static struct pipe *parse_stream(char **pstring, | |||
| 5519 | // *heredoc_cnt_ptr = heredoc_cnt; | 5528 | // *heredoc_cnt_ptr = heredoc_cnt; |
| 5520 | debug_leave(); | 5529 | debug_leave(); |
| 5521 | debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt); | 5530 | debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt); |
| 5522 | debug_printf_parse("parse_stream return %p\n", pi); | 5531 | debug_printf_parse("parse_stream return %p: EOF\n", pi); |
| 5523 | return pi; | 5532 | return pi; |
| 5524 | } | 5533 | } |
| 5525 | 5534 | ||
| @@ -9250,6 +9259,37 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) | |||
| 9250 | * backgrounded: cmd & { list } & | 9259 | * backgrounded: cmd & { list } & |
| 9251 | * subshell: ( list ) [&] | 9260 | * subshell: ( list ) [&] |
| 9252 | */ | 9261 | */ |
| 9262 | static void set_G_ifs(void) | ||
| 9263 | { | ||
| 9264 | /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*" | ||
| 9265 | * Result should be 3 lines: q w e, qwe, q w e | ||
| 9266 | */ | ||
| 9267 | if (G.ifs_whitespace != G.ifs) | ||
| 9268 | free(G.ifs_whitespace); | ||
| 9269 | G.ifs = get_local_var_value("IFS"); | ||
| 9270 | if (G.ifs) { | ||
| 9271 | char *p; | ||
| 9272 | G.ifs_whitespace = (char*)G.ifs; | ||
| 9273 | p = skip_whitespace(G.ifs); | ||
| 9274 | if (*p) { | ||
| 9275 | /* Not all $IFS is whitespace */ | ||
| 9276 | char *d; | ||
| 9277 | int len = p - G.ifs; | ||
| 9278 | p = skip_non_whitespace(p); | ||
| 9279 | G.ifs_whitespace = xmalloc(len + strlen(p) + 1); /* can overestimate */ | ||
| 9280 | d = mempcpy(G.ifs_whitespace, G.ifs, len); | ||
| 9281 | while (*p) { | ||
| 9282 | if (isspace(*p)) | ||
| 9283 | *d++ = *p; | ||
| 9284 | p++; | ||
| 9285 | } | ||
| 9286 | *d = '\0'; | ||
| 9287 | } | ||
| 9288 | } else { | ||
| 9289 | G.ifs = defifs; | ||
| 9290 | G.ifs_whitespace = (char*)G.ifs; | ||
| 9291 | } | ||
| 9292 | } | ||
| 9253 | #if !ENABLE_HUSH_MODE_X | 9293 | #if !ENABLE_HUSH_MODE_X |
| 9254 | #define redirect_and_varexp_helper(command, sqp, argv_expanded) \ | 9294 | #define redirect_and_varexp_helper(command, sqp, argv_expanded) \ |
| 9255 | redirect_and_varexp_helper(command, sqp) | 9295 | redirect_and_varexp_helper(command, sqp) |
| @@ -9286,34 +9326,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
| 9286 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); | 9326 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); |
| 9287 | debug_enter(); | 9327 | debug_enter(); |
| 9288 | 9328 | ||
| 9289 | /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*" | 9329 | set_G_ifs(); |
| 9290 | * Result should be 3 lines: q w e, qwe, q w e | ||
| 9291 | */ | ||
| 9292 | if (G.ifs_whitespace != G.ifs) | ||
| 9293 | free(G.ifs_whitespace); | ||
| 9294 | G.ifs = get_local_var_value("IFS"); | ||
| 9295 | if (G.ifs) { | ||
| 9296 | char *p; | ||
| 9297 | G.ifs_whitespace = (char*)G.ifs; | ||
| 9298 | p = skip_whitespace(G.ifs); | ||
| 9299 | if (*p) { | ||
| 9300 | /* Not all $IFS is whitespace */ | ||
| 9301 | char *d; | ||
| 9302 | int len = p - G.ifs; | ||
| 9303 | p = skip_non_whitespace(p); | ||
| 9304 | G.ifs_whitespace = xmalloc(len + strlen(p) + 1); /* can overestimate */ | ||
| 9305 | d = mempcpy(G.ifs_whitespace, G.ifs, len); | ||
| 9306 | while (*p) { | ||
| 9307 | if (isspace(*p)) | ||
| 9308 | *d++ = *p; | ||
| 9309 | p++; | ||
| 9310 | } | ||
| 9311 | *d = '\0'; | ||
| 9312 | } | ||
| 9313 | } else { | ||
| 9314 | G.ifs = defifs; | ||
| 9315 | G.ifs_whitespace = (char*)G.ifs; | ||
| 9316 | } | ||
| 9317 | 9330 | ||
| 9318 | IF_HUSH_JOB(pi->pgrp = -1;) | 9331 | IF_HUSH_JOB(pi->pgrp = -1;) |
| 9319 | pi->stopped_cmds = 0; | 9332 | pi->stopped_cmds = 0; |
| @@ -9758,6 +9771,8 @@ static int run_list(struct pipe *pi) | |||
| 9758 | debug_printf_exec("run_list lvl %d start\n", G.run_list_level); | 9771 | debug_printf_exec("run_list lvl %d start\n", G.run_list_level); |
| 9759 | debug_enter(); | 9772 | debug_enter(); |
| 9760 | 9773 | ||
| 9774 | set_G_ifs(); | ||
| 9775 | |||
| 9761 | #if ENABLE_HUSH_LOOPS | 9776 | #if ENABLE_HUSH_LOOPS |
| 9762 | /* Check syntax for "for" */ | 9777 | /* Check syntax for "for" */ |
| 9763 | { | 9778 | { |
diff --git a/shell/hush_test/hush-parsing/nodone1.right b/shell/hush_test/hush-parsing/nodone1.right new file mode 100644 index 000000000..3dc1bcfbe --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone1.right | |||
| @@ -0,0 +1 @@ | |||
| hush: syntax error: unterminated compound statement | |||
diff --git a/shell/hush_test/hush-parsing/nodone1.tests b/shell/hush_test/hush-parsing/nodone1.tests new file mode 100755 index 000000000..de286c5a2 --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone1.tests | |||
| @@ -0,0 +1 @@ | |||
| for i; do : | |||
diff --git a/shell/hush_test/hush-parsing/nodone2.right b/shell/hush_test/hush-parsing/nodone2.right new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone2.right | |||
| @@ -0,0 +1 @@ | |||
| 1 | |||
diff --git a/shell/hush_test/hush-parsing/nodone2.tests b/shell/hush_test/hush-parsing/nodone2.tests new file mode 100755 index 000000000..69537b3b1 --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone2.tests | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | for i in 1; do echo $i | ||
| 2 | # the next line has no EOL. It still must count as "done" keyword: | ||
| 3 | done \ No newline at end of file | ||
diff --git a/shell/hush_test/hush-quoting/dollar_repl_bash2.right b/shell/hush_test/hush-quoting/dollar_repl_bash2.right new file mode 100644 index 000000000..e3fcd5807 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_repl_bash2.right | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | axxb | ||
| 2 | axxb | ||
| 3 | axxb | ||
| 4 | axxb | ||
diff --git a/shell/hush_test/hush-quoting/dollar_repl_bash2.tests b/shell/hush_test/hush-quoting/dollar_repl_bash2.tests new file mode 100755 index 000000000..45c7a10e2 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_repl_bash2.tests | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | v="x/x" | ||
| 2 | # The second / is quoted, should not be treated as separator | ||
| 3 | echo a${v/'/'}b | ||
| 4 | # The second / is escaped, should not be treated as separator | ||
| 5 | echo a${v/\/}b | ||
| 6 | |||
| 7 | echo "a${v/'/'}b" | ||
| 8 | echo "a${v/\/}b" | ||
