diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-29 11:37:15 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-29 11:37:15 +0000 |
commit | fcf37c31838fbdd4f8cfe24c1c8ef957838a6de4 (patch) | |
tree | 9834030682794e8d7a3ced1aa2c57870951f1b3f | |
parent | d91afa33fd6874aeed458a84ceeb2b51af84505d (diff) | |
download | busybox-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.c | 39 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/break5.right | 13 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/break5.tests | 4 |
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 |
4555 | static int builtin_break(char **argv) | 4558 | static 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 | ||
4570 | static int builtin_continue(char **argv) | 4579 | static 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 @@ | |||
1 | A | ||
2 | B | ||
3 | 0 | ||
4 | A:a | ||
5 | B | ||
6 | D | ||
7 | A:b | ||
8 | B | ||
9 | D | ||
10 | A:c | ||
11 | B | ||
12 | D | ||
13 | 0 | ||
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 @@ | |||
1 | while true; do echo A; { echo B; break; echo C; }; echo D; done | ||
2 | echo $? | ||
3 | for v in a b c; do echo A:$v; (echo B; break; echo C); echo D; done | ||
4 | echo $? | ||