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
This commit is contained in:
Denis Vlasenko 2008-07-29 11:37:15 +00:00
parent d91afa33fd
commit fcf37c3183
3 changed files with 43 additions and 13 deletions

View File

@ -446,6 +446,7 @@ struct globals {
int global_argc; int global_argc;
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
unsigned depth_break_continue; unsigned depth_break_continue;
unsigned depth_of_loop;
#endif #endif
pid_t last_bg_pid; pid_t last_bg_pid;
const char *ifs; const char *ifs;
@ -496,6 +497,7 @@ enum { run_list_level = 0 };
#define ifs (G.ifs ) #define ifs (G.ifs )
#define flag_break_continue (G.flag_break_continue ) #define flag_break_continue (G.flag_break_continue )
#define depth_break_continue (G.depth_break_continue) #define depth_break_continue (G.depth_break_continue)
#define depth_of_loop (G.depth_of_loop )
#define fake_mode (G.fake_mode ) #define fake_mode (G.fake_mode )
#define cwd (G.cwd ) #define cwd (G.cwd )
#define last_bg_pid (G.last_bg_pid ) #define last_bg_pid (G.last_bg_pid )
@ -2153,13 +2155,14 @@ static int run_list(struct pipe *pi)
if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) { if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
/* start of a loop: remember where loop starts */ /* start of a loop: remember where loop starts */
loop_top = pi; loop_top = pi;
depth_of_loop++;
} }
#endif #endif
if (rword == skip_more_for_this_rword && flag_skip) { if (rword == skip_more_for_this_rword && flag_skip) {
/* it is "<false> && CMD" or "<true> || CMD"
* and we should not execute CMD */
if (pi->followup == PIPE_SEQ) if (pi->followup == PIPE_SEQ)
flag_skip = 0; flag_skip = 0;
/* it is "<false> && CMD" or "<true> || CMD"
* and we should not execute CMD */
continue; continue;
} }
flag_skip = 1; flag_skip = 1;
@ -2277,16 +2280,14 @@ static int run_list(struct pipe *pi)
depth_break_continue--; depth_break_continue--;
if (depth_break_continue == 0) if (depth_break_continue == 0)
flag_break_continue = 0; flag_break_continue = 0;
/* else: e.g. "continue 2" should *break* once, *then* continue */
} /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */
if (depth_break_continue != 0 || fbc == BC_BREAK) if (depth_break_continue != 0 || fbc == BC_BREAK)
goto check_jobs_and_break; goto check_jobs_and_break;
/* "continue": simulate end of loop */ /* "continue": simulate end of loop */
rword = RES_DONE; rword = RES_DONE;
continue; continue;
} }
flag_break_continue = 0;
bb_error_msg("break/continue: only meaningful in a loop");
/* bash compat: exit code is still 0 */
}
#endif #endif
} else if (pi->followup == PIPE_BG) { } else if (pi->followup == PIPE_BG) {
/* what does bash do with attempts to background builtins? */ /* what does bash do with attempts to background builtins? */
@ -2358,6 +2359,8 @@ static int run_list(struct pipe *pi)
#endif #endif
debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode); debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
if (loop_top)
depth_of_loop--;
free(for_list); free(for_list);
#endif #endif
#if ENABLE_HUSH_CASE #if ENABLE_HUSH_CASE
@ -4554,6 +4557,10 @@ static int builtin_unset(char **argv)
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
static int builtin_break(char **argv) static int builtin_break(char **argv)
{ {
if (depth_of_loop == 0) {
bb_error_msg("%s: only meaningful in a loop", "break");
return EXIT_SUCCESS; /* bash compat */
}
flag_break_continue++; /* BC_BREAK = 1 */ flag_break_continue++; /* BC_BREAK = 1 */
depth_break_continue = 1; depth_break_continue = 1;
if (argv[1]) { if (argv[1]) {
@ -4564,12 +4571,18 @@ static int builtin_break(char **argv)
depth_break_continue = UINT_MAX; depth_break_continue = UINT_MAX;
} }
} }
if (depth_of_loop > depth_break_continue)
depth_break_continue = depth_of_loop;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int builtin_continue(char **argv) static int builtin_continue(char **argv)
{ {
if (depth_of_loop) {
flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */ flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */
return builtin_break(argv); return builtin_break(argv);
}
bb_error_msg("%s: only meaningful in a loop", "continue");
return EXIT_SUCCESS; /* bash compat */
} }
#endif #endif

View File

@ -0,0 +1,13 @@
A
B
0
A:a
B
D
A:b
B
D
A:c
B
D
0

View File

@ -0,0 +1,4 @@
while true; do echo A; { echo B; break; echo C; }; echo D; done
echo $?
for v in a b c; do echo A:$v; (echo B; break; echo C); echo D; done
echo $?