| @@ -2994,7 +2994,7 @@ static void debug_print_tree(struct pipe *pi, int lvl) |
| struct command *command = &pi->cmds[prn]; |
| char **argv = command->argv; |
| |
| - | fprintf(stderr, "%*s prog %d assignment_cnt:%d", |
| + | fprintf(stderr, "%*s cmd %d assignment_cnt:%d", |
| lvl*2, "", prn, |
| command->assignment_cnt); |
| if (command->group) { |
| @@ -3038,8 +3038,8 @@ static int run_list(struct pipe *pi) |
| #else |
| enum { cond_code = 0 }; |
| #endif |
| - | /*enum reserved_style*/ smallint rword; |
| - | /*enum reserved_style*/ smallint last_rword; |
| + | smallint rword; /* enum reserved_style */ |
| + | smallint last_rword; /* ditto */ |
| |
| debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); |
| |
| @@ -3307,8 +3307,7 @@ static int run_list(struct pipe *pi) |
| if (G.run_list_level == 1) |
| insert_bg_job(pi); |
| #endif |
| - | rcode = EXIT_SUCCESS; |
| - | G.last_return_code = EXIT_SUCCESS; |
| + | G.last_return_code = rcode = EXIT_SUCCESS; |
| debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); |
| } else { |
| #if ENABLE_HUSH_JOB |
| @@ -3334,17 +3333,23 @@ static int run_list(struct pipe *pi) |
| cond_code = rcode; |
| #endif |
| #if ENABLE_HUSH_LOOPS |
| - | if (rword == RES_WHILE) { |
| - | if (rcode) { |
| - | rcode = 0; /* "while false; do...done" - exitcode 0 */ |
| - | goto check_jobs_and_break; |
| + | /* Beware of "while false; true; do ..."! */ |
| + | if (pi->next && pi->next->res_word == RES_DO) { |
| + | if (rword == RES_WHILE) { |
| + | if (rcode) { |
| + | /* "while false; do...done" - exitcode 0 */ |
| + | G.last_return_code = rcode = EXIT_SUCCESS; |
| + | debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n"); |
| + | goto check_jobs_and_break; |
| + | } |
| } |
| - | } |
| - | if (rword == RES_UNTIL) { |
| - | if (!rcode) { |
| + | if (rword == RES_UNTIL) { |
| + | if (!rcode) { |
| + | debug_printf_exec(": until expr is true: breaking\n"); |
| check_jobs_and_break: |
| - | checkjobs(NULL); |
| - | break; |
| + | checkjobs(NULL); |
| + | break; |
| + | } |
| } |
| } |
| #endif |
| @@ -3498,10 +3503,12 @@ static int done_command(struct parse_context *ctx) |
| && command->redirects == NULL |
| ) { |
| debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); |
| + | memset(command, 0, sizeof(*command)); /* paranoia */ |
| return pi->num_cmds; |
| } |
| pi->num_cmds++; |
| debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); |
| + | //debug_print_tree(ctx->list_head, 20); |
| } else { |
| debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); |
| } |
| @@ -3526,16 +3533,26 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) |
| /* Close previous command */ |
| not_null = done_command(ctx); |
| ctx->pipe->followup = type; |
| - | IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;) |
| - | IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;) |
| - | IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;) |
| + | #if HAS_KEYWORDS |
| + | ctx->pipe->pi_inverted = ctx->ctx_inverted; |
| + | ctx->ctx_inverted = 0; |
| + | ctx->pipe->res_word = ctx->ctx_res_w; |
| + | #endif |
| |
| /* Without this check, even just <enter> on command line generates |
| * tree of three NOPs (!). Which is harmless but annoying. |
| * IOW: it is safe to do it unconditionally. |
| * RES_NONE case is for "for a in; do ..." (empty IN set) |
| - | * to work, possibly other cases too. */ |
| - | if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) { |
| + | * and other cases to work. */ |
| + | if (not_null |
| + | #if HAS_KEYWORDS |
| + | || ctx->ctx_res_w == RES_FI |
| + | || ctx->ctx_res_w == RES_DONE |
| + | || ctx->ctx_res_w == RES_FOR |
| + | || ctx->ctx_res_w == RES_IN |
| + | || ctx->ctx_res_w == RES_ESAC |
| + | #endif |
| + | ) { |
| struct pipe *new_p; |
| debug_printf_parse("done_pipe: adding new pipe: " |
| "not_null:%d ctx->ctx_res_w:%d\n", |
| @@ -3564,6 +3581,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) |
| * ctx->command = &ctx->pipe->cmds[0]; |
| */ |
| done_command(ctx); |
| + | //debug_print_tree(ctx->list_head, 10); |
| } |
| debug_printf_parse("done_pipe return\n"); |
| } |
| @@ -5483,6 +5501,7 @@ static int builtin_exec(char **argv) |
| |
| static int builtin_exit(char **argv) |
| { |
| + | debug_printf_exec("%s()\n", __func__); |
| // TODO: bash does it ONLY on top-level sh exit (+interacive only?) |
| //puts("exit"); /* bash does it */ |
| // TODO: warn if we have background jobs: "There are stopped jobs" |