hush: fix "false && echo yes || echo no" bug 265

function                                             old     new   delta
run_list                                            1159    1189     +30
This commit is contained in:
Denis Vlasenko 2009-04-06 14:11:13 +00:00
parent 0969a49c08
commit a2b11e3395

View File

@ -271,13 +271,6 @@ static const struct {
{ O_RDWR, 1, "<>" } { O_RDWR, 1, "<>" }
}; };
typedef enum pipe_style {
PIPE_SEQ = 1,
PIPE_AND = 2,
PIPE_OR = 3,
PIPE_BG = 4,
} pipe_style;
typedef enum reserved_style { typedef enum reserved_style {
RES_NONE = 0, RES_NONE = 0,
#if ENABLE_HUSH_IF #if ENABLE_HUSH_IF
@ -395,6 +388,12 @@ struct pipe {
IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */ IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */
IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */ IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */
}; };
typedef enum pipe_style {
PIPE_SEQ = 1,
PIPE_AND = 2,
PIPE_OR = 3,
PIPE_BG = 4,
} pipe_style;
/* This holds pointers to the various results of parsing */ /* This holds pointers to the various results of parsing */
struct parse_context { struct parse_context {
@ -2158,7 +2157,7 @@ static void free_pipe_list(struct pipe *head, int indent)
for (pi = head; pi; pi = next) { for (pi = head; pi; pi = next) {
#if HAS_KEYWORDS #if HAS_KEYWORDS
debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word); debug_printf_clean("%s pipe reserved word %d\n", indenter(indent), pi->res_word);
#endif #endif
free_pipe(pi, indent); free_pipe(pi, indent);
debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup); debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
@ -2182,7 +2181,7 @@ typedef struct nommu_save_t {
pseudo_exec(command, argv_expanded) pseudo_exec(command, argv_expanded)
#endif #endif
/* Called after [v]fork() in run_pipe(), or from builtin_exec(). /* Called after [v]fork() in run_pipe, or from builtin_exec.
* Never returns. * Never returns.
* XXX no exit() here. If you don't exec, use _exit instead. * XXX no exit() here. If you don't exec, use _exit instead.
* The at_exit handlers apparently confuse the calling process, * The at_exit handlers apparently confuse the calling process,
@ -2389,7 +2388,7 @@ static void clean_up_after_re_execute(void)
static int run_list(struct pipe *pi); static int run_list(struct pipe *pi);
/* Called after [v]fork() in run_pipe() /* Called after [v]fork() in run_pipe
*/ */
static void pseudo_exec(nommu_save_t *nommu_save, static void pseudo_exec(nommu_save_t *nommu_save,
struct command *command, struct command *command,
@ -3032,15 +3031,15 @@ static int run_list(struct pipe *pi)
char **for_lcur = NULL; char **for_lcur = NULL;
char **for_list = NULL; char **for_list = NULL;
#endif #endif
smallint flag_skip = 1; smallint last_followup;
smalluint rcode = 0; /* probably just for compiler */ smalluint rcode;
#if ENABLE_HUSH_IF || ENABLE_HUSH_CASE #if ENABLE_HUSH_IF || ENABLE_HUSH_CASE
smalluint cond_code = 0; smalluint cond_code = 0;
#else #else
enum { cond_code = 0, }; enum { cond_code = 0 };
#endif #endif
/*enum reserved_style*/ smallint rword = RES_NONE; /*enum reserved_style*/ smallint rword;
/*enum reserved_style*/ smallint skip_more_for_this_rword = RES_XXXX; /*enum reserved_style*/ smallint last_rword;
debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1);
@ -3119,6 +3118,11 @@ static int run_list(struct pipe *pi)
} }
#endif /* JOB */ #endif /* JOB */
rcode = G.last_return_code;
rword = RES_NONE;
last_rword = RES_XXXX;
last_followup = PIPE_SEQ;
/* Go through list of pipes, (maybe) executing them. */ /* Go through list of pipes, (maybe) executing them. */
for (; pi; pi = USE_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { for (; pi; pi = USE_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
if (G.flag_SIGINT) if (G.flag_SIGINT)
@ -3126,8 +3130,8 @@ static int run_list(struct pipe *pi)
IF_HAS_KEYWORDS(rword = pi->res_word;) IF_HAS_KEYWORDS(rword = pi->res_word;)
IF_HAS_NO_KEYWORDS(rword = RES_NONE;) IF_HAS_NO_KEYWORDS(rword = RES_NONE;)
debug_printf_exec(": rword=%d cond_code=%d skip_more=%d\n", debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
rword, cond_code, skip_more_for_this_rword); rword, cond_code, last_rword);
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
&& loop_top == NULL /* avoid bumping G.depth_of_loop twice */ && loop_top == NULL /* avoid bumping G.depth_of_loop twice */
@ -3137,15 +3141,20 @@ static int run_list(struct pipe *pi)
G.depth_of_loop++; G.depth_of_loop++;
} }
#endif #endif
if (rword == skip_more_for_this_rword && flag_skip) { /* Still in the same "if...", "then..." or "do..." branch? */
if (pi->followup == PIPE_SEQ) if (rword == last_rword) {
flag_skip = 0; if ((rcode == 0 && last_followup == PIPE_OR)
/* it is "<false> && CMD" or "<true> || CMD" || (rcode != 0 && last_followup == PIPE_AND)
* and we should not execute CMD */ ) {
continue; /* It is "<true> || CMD" or "<false> && CMD"
* and we should not execute CMD */
debug_printf_exec("skipped cmd because of || or &&\n");
last_followup = pi->followup;
continue;
}
} }
flag_skip = 1; last_followup = pi->followup;
skip_more_for_this_rword = RES_XXXX; last_rword = rword;
#if ENABLE_HUSH_IF #if ENABLE_HUSH_IF
if (cond_code) { if (cond_code) {
if (rword == RES_THEN) { if (rword == RES_THEN) {
@ -3176,8 +3185,11 @@ static int run_list(struct pipe *pi)
vals = (char**)encoded_dollar_at_argv; vals = (char**)encoded_dollar_at_argv;
if (pi->next->res_word == RES_IN) { if (pi->next->res_word == RES_IN) {
/* if no variable values after "in" we skip "for" */ /* if no variable values after "in" we skip "for" */
if (!pi->next->cmds[0].argv) if (!pi->next->cmds[0].argv) {
G.last_return_code = rcode = EXIT_SUCCESS;
debug_printf_exec(": null FOR: exitcode EXIT_SUCCESS\n");
break; break;
}
vals = pi->next->cmds[0].argv; vals = pi->next->cmds[0].argv;
} /* else: "for var; do..." -> assume "$@" list */ } /* else: "for var; do..." -> assume "$@" list */
/* create list of variable values */ /* create list of variable values */
@ -3197,7 +3209,7 @@ static int run_list(struct pipe *pi)
pi->cmds[0].argv[0] = for_varname; pi->cmds[0].argv[0] = for_varname;
break; break;
} }
/* insert next value from for_lcur */ /* Insert next value from for_lcur */
//TODO: does it need escaping? //TODO: does it need escaping?
pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
pi->cmds[0].assignment_cnt = 1; pi->cmds[0].assignment_cnt = 1;
@ -3251,7 +3263,7 @@ static int run_list(struct pipe *pi)
/* After analyzing all keywords and conditions, we decided /* After analyzing all keywords and conditions, we decided
* to execute this pipe. NB: have to do checkjobs(NULL) * to execute this pipe. NB: have to do checkjobs(NULL)
* after run_pipe() to collect any background children, * after run_pipe to collect any background children,
* even if list execution is to be stopped. */ * even if list execution is to be stopped. */
debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds);
{ {
@ -3261,14 +3273,16 @@ static int run_list(struct pipe *pi)
#endif #endif
rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ rcode = r = run_pipe(pi); /* NB: rcode is a smallint */
if (r != -1) { if (r != -1) {
/* we only ran a builtin: rcode is already known /* We only ran a builtin: rcode is already known
* and we don't need to wait for anything. */ * and we don't need to wait for anything. */
G.last_return_code = rcode;
debug_printf_exec(": builtin exitcode %d\n", rcode);
check_and_run_traps(0); check_and_run_traps(0);
#if ENABLE_HUSH_LOOPS #if ENABLE_HUSH_LOOPS
/* was it "break" or "continue"? */ /* Was it "break" or "continue"? */
if (G.flag_break_continue) { if (G.flag_break_continue) {
smallint fbc = G.flag_break_continue; smallint fbc = G.flag_break_continue;
/* we might fall into outer *loop*, /* We might fall into outer *loop*,
* don't want to break it too */ * don't want to break it too */
if (loop_top) { if (loop_top) {
G.depth_break_continue--; G.depth_break_continue--;
@ -3284,7 +3298,7 @@ static int run_list(struct pipe *pi)
} }
#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? */
/* even bash 3.2 doesn't do that well with nested bg: /* even bash 3.2 doesn't do that well with nested bg:
* try "{ { sleep 10; echo DEEP; } & echo HERE; } &". * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
* I'm NOT treating inner &'s as jobs */ * I'm NOT treating inner &'s as jobs */
@ -3293,25 +3307,26 @@ static int run_list(struct pipe *pi)
if (G.run_list_level == 1) if (G.run_list_level == 1)
insert_bg_job(pi); insert_bg_job(pi);
#endif #endif
rcode = 0; /* EXIT_SUCCESS */ rcode = EXIT_SUCCESS;
G.last_return_code = EXIT_SUCCESS;
debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
} else { } else {
#if ENABLE_HUSH_JOB #if ENABLE_HUSH_JOB
if (G.run_list_level == 1 && G_interactive_fd) { if (G.run_list_level == 1 && G_interactive_fd) {
/* waits for completion, then fg's main shell */ /* Waits for completion, then fg's main shell */
rcode = checkjobs_and_fg_shell(pi); rcode = checkjobs_and_fg_shell(pi);
debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode);
check_and_run_traps(0); check_and_run_traps(0);
debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode);
} else } else
#endif #endif
{ /* this one just waits for completion */ { /* This one just waits for completion */
rcode = checkjobs(pi); rcode = checkjobs(pi);
debug_printf_exec(": checkjobs exitcode %d\n", rcode);
check_and_run_traps(0); check_and_run_traps(0);
debug_printf_exec(": checkjobs returned %d\n", rcode);
} }
G.last_return_code = rcode;
} }
} }
debug_printf_exec(": setting last_return_code=%d\n", rcode);
G.last_return_code = rcode;
/* Analyze how result affects subsequent commands */ /* Analyze how result affects subsequent commands */
#if ENABLE_HUSH_IF #if ENABLE_HUSH_IF
@ -3333,11 +3348,6 @@ static int run_list(struct pipe *pi)
} }
} }
#endif #endif
if ((rcode == 0 && pi->followup == PIPE_OR)
|| (rcode != 0 && pi->followup == PIPE_AND)
) {
skip_more_for_this_rword = rword;
}
check_jobs_and_continue: check_jobs_and_continue:
checkjobs(NULL); checkjobs(NULL);
@ -3375,7 +3385,7 @@ static int run_and_free_list(struct pipe *pi)
int rcode = 0; int rcode = 0;
debug_printf_exec("run_and_free_list entered\n"); debug_printf_exec("run_and_free_list entered\n");
if (!G.fake_mode) { if (!G.fake_mode) {
debug_printf_exec(": run_list with %d members\n", pi->num_cmds); debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds);
rcode = run_list(pi); rcode = run_list(pi);
} }
/* free_pipe_list has the side effect of clearing memory. /* free_pipe_list has the side effect of clearing memory.