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:
parent
d91afa33fd
commit
fcf37c3183
39
shell/hush.c
39
shell/hush.c
@ -446,6 +446,7 @@ struct globals {
|
||||
int global_argc;
|
||||
#if ENABLE_HUSH_LOOPS
|
||||
unsigned depth_break_continue;
|
||||
unsigned depth_of_loop;
|
||||
#endif
|
||||
pid_t last_bg_pid;
|
||||
const char *ifs;
|
||||
@ -496,6 +497,7 @@ enum { run_list_level = 0 };
|
||||
#define ifs (G.ifs )
|
||||
#define flag_break_continue (G.flag_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 cwd (G.cwd )
|
||||
#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) {
|
||||
/* start of a loop: remember where loop starts */
|
||||
loop_top = pi;
|
||||
depth_of_loop++;
|
||||
}
|
||||
#endif
|
||||
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)
|
||||
flag_skip = 0;
|
||||
/* it is "<false> && CMD" or "<true> || CMD"
|
||||
* and we should not execute CMD */
|
||||
continue;
|
||||
}
|
||||
flag_skip = 1;
|
||||
@ -2277,15 +2280,13 @@ static int run_list(struct pipe *pi)
|
||||
depth_break_continue--;
|
||||
if (depth_break_continue == 0)
|
||||
flag_break_continue = 0;
|
||||
if (depth_break_continue != 0 || fbc == BC_BREAK)
|
||||
goto check_jobs_and_break;
|
||||
/* "continue": simulate end of loop */
|
||||
rword = RES_DONE;
|
||||
continue;
|
||||
}
|
||||
flag_break_continue = 0;
|
||||
bb_error_msg("break/continue: only meaningful in a loop");
|
||||
/* bash compat: exit code is still 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)
|
||||
goto check_jobs_and_break;
|
||||
/* "continue": simulate end of loop */
|
||||
rword = RES_DONE;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
} else if (pi->followup == PIPE_BG) {
|
||||
@ -2358,6 +2359,8 @@ static int run_list(struct pipe *pi)
|
||||
#endif
|
||||
debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
|
||||
#if ENABLE_HUSH_LOOPS
|
||||
if (loop_top)
|
||||
depth_of_loop--;
|
||||
free(for_list);
|
||||
#endif
|
||||
#if ENABLE_HUSH_CASE
|
||||
@ -4554,6 +4557,10 @@ static int builtin_unset(char **argv)
|
||||
#if ENABLE_HUSH_LOOPS
|
||||
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 */
|
||||
depth_break_continue = 1;
|
||||
if (argv[1]) {
|
||||
@ -4564,12 +4571,18 @@ static int builtin_break(char **argv)
|
||||
depth_break_continue = UINT_MAX;
|
||||
}
|
||||
}
|
||||
if (depth_of_loop > depth_break_continue)
|
||||
depth_break_continue = depth_of_loop;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int builtin_continue(char **argv)
|
||||
{
|
||||
flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */
|
||||
return builtin_break(argv);
|
||||
if (depth_of_loop) {
|
||||
flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */
|
||||
return builtin_break(argv);
|
||||
}
|
||||
bb_error_msg("%s: only meaningful in a loop", "continue");
|
||||
return EXIT_SUCCESS; /* bash compat */
|
||||
}
|
||||
#endif
|
||||
|
13
shell/hush_test/hush-misc/break5.right
Normal file
13
shell/hush_test/hush-misc/break5.right
Normal file
@ -0,0 +1,13 @@
|
||||
A
|
||||
B
|
||||
0
|
||||
A:a
|
||||
B
|
||||
D
|
||||
A:b
|
||||
B
|
||||
D
|
||||
A:c
|
||||
B
|
||||
D
|
||||
0
|
4
shell/hush_test/hush-misc/break5.tests
Executable file
4
shell/hush_test/hush-misc/break5.tests
Executable 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 $?
|
Loading…
Reference in New Issue
Block a user