aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-29 11:37:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-29 11:37:15 +0000
commitfcf37c31838fbdd4f8cfe24c1c8ef957838a6de4 (patch)
tree9834030682794e8d7a3ced1aa2c57870951f1b3f
parentd91afa33fd6874aeed458a84ceeb2b51af84505d (diff)
downloadbusybox-w32-fcf37c31838fbdd4f8cfe24c1c8ef957838a6de4.tar.gz
busybox-w32-fcf37c31838fbdd4f8cfe24c1c8ef957838a6de4.tar.bz2
busybox-w32-fcf37c31838fbdd4f8cfe24c1c8ef957838a6de4.zip
hush: fix break'ing out of {} and () groups; with testcase
function old new delta builtin_break 93 129 +36 builtin_continue 21 47 +26 run_list 1973 1976 +3
-rw-r--r--shell/hush.c39
-rw-r--r--shell/hush_test/hush-misc/break5.right13
-rwxr-xr-xshell/hush_test/hush-misc/break5.tests4
3 files changed, 43 insertions, 13 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 8ffc6121a..eb70c9d9f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -446,6 +446,7 @@ struct globals {
446 int global_argc; 446 int global_argc;
447#if ENABLE_HUSH_LOOPS 447#if ENABLE_HUSH_LOOPS
448 unsigned depth_break_continue; 448 unsigned depth_break_continue;
449 unsigned depth_of_loop;
449#endif 450#endif
450 pid_t last_bg_pid; 451 pid_t last_bg_pid;
451 const char *ifs; 452 const char *ifs;
@@ -496,6 +497,7 @@ enum { run_list_level = 0 };
496#define ifs (G.ifs ) 497#define ifs (G.ifs )
497#define flag_break_continue (G.flag_break_continue ) 498#define flag_break_continue (G.flag_break_continue )
498#define depth_break_continue (G.depth_break_continue) 499#define depth_break_continue (G.depth_break_continue)
500#define depth_of_loop (G.depth_of_loop )
499#define fake_mode (G.fake_mode ) 501#define fake_mode (G.fake_mode )
500#define cwd (G.cwd ) 502#define cwd (G.cwd )
501#define last_bg_pid (G.last_bg_pid ) 503#define last_bg_pid (G.last_bg_pid )
@@ -2153,13 +2155,14 @@ static int run_list(struct pipe *pi)
2153 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) { 2155 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
2154 /* start of a loop: remember where loop starts */ 2156 /* start of a loop: remember where loop starts */
2155 loop_top = pi; 2157 loop_top = pi;
2158 depth_of_loop++;
2156 } 2159 }
2157#endif 2160#endif
2158 if (rword == skip_more_for_this_rword && flag_skip) { 2161 if (rword == skip_more_for_this_rword && flag_skip) {
2159 /* it is "<false> && CMD" or "<true> || CMD"
2160 * and we should not execute CMD */
2161 if (pi->followup == PIPE_SEQ) 2162 if (pi->followup == PIPE_SEQ)
2162 flag_skip = 0; 2163 flag_skip = 0;
2164 /* it is "<false> && CMD" or "<true> || CMD"
2165 * and we should not execute CMD */
2163 continue; 2166 continue;
2164 } 2167 }
2165 flag_skip = 1; 2168 flag_skip = 1;
@@ -2277,15 +2280,13 @@ static int run_list(struct pipe *pi)
2277 depth_break_continue--; 2280 depth_break_continue--;
2278 if (depth_break_continue == 0) 2281 if (depth_break_continue == 0)
2279 flag_break_continue = 0; 2282 flag_break_continue = 0;
2280 if (depth_break_continue != 0 || fbc == BC_BREAK) 2283 /* else: e.g. "continue 2" should *break* once, *then* continue */
2281 goto check_jobs_and_break; 2284 } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */
2282 /* "continue": simulate end of loop */ 2285 if (depth_break_continue != 0 || fbc == BC_BREAK)
2283 rword = RES_DONE; 2286 goto check_jobs_and_break;
2284 continue; 2287 /* "continue": simulate end of loop */
2285 } 2288 rword = RES_DONE;
2286 flag_break_continue = 0; 2289 continue;
2287 bb_error_msg("break/continue: only meaningful in a loop");
2288 /* bash compat: exit code is still 0 */
2289 } 2290 }
2290#endif 2291#endif
2291 } else if (pi->followup == PIPE_BG) { 2292 } else if (pi->followup == PIPE_BG) {
@@ -2358,6 +2359,8 @@ static int run_list(struct pipe *pi)
2358#endif 2359#endif
2359 debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode); 2360 debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
2360#if ENABLE_HUSH_LOOPS 2361#if ENABLE_HUSH_LOOPS
2362 if (loop_top)
2363 depth_of_loop--;
2361 free(for_list); 2364 free(for_list);
2362#endif 2365#endif
2363#if ENABLE_HUSH_CASE 2366#if ENABLE_HUSH_CASE
@@ -4554,6 +4557,10 @@ static int builtin_unset(char **argv)
4554#if ENABLE_HUSH_LOOPS 4557#if ENABLE_HUSH_LOOPS
4555static int builtin_break(char **argv) 4558static int builtin_break(char **argv)
4556{ 4559{
4560 if (depth_of_loop == 0) {
4561 bb_error_msg("%s: only meaningful in a loop", "break");
4562 return EXIT_SUCCESS; /* bash compat */
4563 }
4557 flag_break_continue++; /* BC_BREAK = 1 */ 4564 flag_break_continue++; /* BC_BREAK = 1 */
4558 depth_break_continue = 1; 4565 depth_break_continue = 1;
4559 if (argv[1]) { 4566 if (argv[1]) {
@@ -4564,12 +4571,18 @@ static int builtin_break(char **argv)
4564 depth_break_continue = UINT_MAX; 4571 depth_break_continue = UINT_MAX;
4565 } 4572 }
4566 } 4573 }
4574 if (depth_of_loop > depth_break_continue)
4575 depth_break_continue = depth_of_loop;
4567 return EXIT_SUCCESS; 4576 return EXIT_SUCCESS;
4568} 4577}
4569 4578
4570static int builtin_continue(char **argv) 4579static int builtin_continue(char **argv)
4571{ 4580{
4572 flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */ 4581 if (depth_of_loop) {
4573 return builtin_break(argv); 4582 flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */
4583 return builtin_break(argv);
4584 }
4585 bb_error_msg("%s: only meaningful in a loop", "continue");
4586 return EXIT_SUCCESS; /* bash compat */
4574} 4587}
4575#endif 4588#endif
diff --git a/shell/hush_test/hush-misc/break5.right b/shell/hush_test/hush-misc/break5.right
new file mode 100644
index 000000000..0b9df2a4f
--- /dev/null
+++ b/shell/hush_test/hush-misc/break5.right
@@ -0,0 +1,13 @@
1A
2B
30
4A:a
5B
6D
7A:b
8B
9D
10A:c
11B
12D
130
diff --git a/shell/hush_test/hush-misc/break5.tests b/shell/hush_test/hush-misc/break5.tests
new file mode 100755
index 000000000..273e040ec
--- /dev/null
+++ b/shell/hush_test/hush-misc/break5.tests
@@ -0,0 +1,4 @@
1while true; do echo A; { echo B; break; echo C; }; echo D; done
2echo $?
3for v in a b c; do echo A:$v; (echo B; break; echo C); echo D; done
4echo $?