diff options
-rw-r--r-- | shell/hush.c | 57 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/continue2.right | 1 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/continue2.tests | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/continue3.right | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/continue3.tests | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/until1.right | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/until1.tests | 11 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/while2.right | 2 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/while2.tests | 2 | ||||
-rwxr-xr-x | shell/hush_test/run-all | 2 |
10 files changed, 66 insertions, 20 deletions
diff --git a/shell/hush.c b/shell/hush.c index 227e73507..c74d10c1b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2994,7 +2994,7 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
2994 | struct command *command = &pi->cmds[prn]; | 2994 | struct command *command = &pi->cmds[prn]; |
2995 | char **argv = command->argv; | 2995 | char **argv = command->argv; |
2996 | 2996 | ||
2997 | fprintf(stderr, "%*s prog %d assignment_cnt:%d", | 2997 | fprintf(stderr, "%*s cmd %d assignment_cnt:%d", |
2998 | lvl*2, "", prn, | 2998 | lvl*2, "", prn, |
2999 | command->assignment_cnt); | 2999 | command->assignment_cnt); |
3000 | if (command->group) { | 3000 | if (command->group) { |
@@ -3038,8 +3038,8 @@ static int run_list(struct pipe *pi) | |||
3038 | #else | 3038 | #else |
3039 | enum { cond_code = 0 }; | 3039 | enum { cond_code = 0 }; |
3040 | #endif | 3040 | #endif |
3041 | /*enum reserved_style*/ smallint rword; | 3041 | smallint rword; /* enum reserved_style */ |
3042 | /*enum reserved_style*/ smallint last_rword; | 3042 | smallint last_rword; /* ditto */ |
3043 | 3043 | ||
3044 | debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); | 3044 | debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1); |
3045 | 3045 | ||
@@ -3307,8 +3307,7 @@ static int run_list(struct pipe *pi) | |||
3307 | if (G.run_list_level == 1) | 3307 | if (G.run_list_level == 1) |
3308 | insert_bg_job(pi); | 3308 | insert_bg_job(pi); |
3309 | #endif | 3309 | #endif |
3310 | rcode = EXIT_SUCCESS; | 3310 | G.last_return_code = rcode = EXIT_SUCCESS; |
3311 | G.last_return_code = EXIT_SUCCESS; | ||
3312 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); | 3311 | debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); |
3313 | } else { | 3312 | } else { |
3314 | #if ENABLE_HUSH_JOB | 3313 | #if ENABLE_HUSH_JOB |
@@ -3334,17 +3333,23 @@ static int run_list(struct pipe *pi) | |||
3334 | cond_code = rcode; | 3333 | cond_code = rcode; |
3335 | #endif | 3334 | #endif |
3336 | #if ENABLE_HUSH_LOOPS | 3335 | #if ENABLE_HUSH_LOOPS |
3337 | if (rword == RES_WHILE) { | 3336 | /* Beware of "while false; true; do ..."! */ |
3338 | if (rcode) { | 3337 | if (pi->next && pi->next->res_word == RES_DO) { |
3339 | rcode = 0; /* "while false; do...done" - exitcode 0 */ | 3338 | if (rword == RES_WHILE) { |
3340 | goto check_jobs_and_break; | 3339 | if (rcode) { |
3340 | /* "while false; do...done" - exitcode 0 */ | ||
3341 | G.last_return_code = rcode = EXIT_SUCCESS; | ||
3342 | debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n"); | ||
3343 | goto check_jobs_and_break; | ||
3344 | } | ||
3341 | } | 3345 | } |
3342 | } | 3346 | if (rword == RES_UNTIL) { |
3343 | if (rword == RES_UNTIL) { | 3347 | if (!rcode) { |
3344 | if (!rcode) { | 3348 | debug_printf_exec(": until expr is true: breaking\n"); |
3345 | check_jobs_and_break: | 3349 | check_jobs_and_break: |
3346 | checkjobs(NULL); | 3350 | checkjobs(NULL); |
3347 | break; | 3351 | break; |
3352 | } | ||
3348 | } | 3353 | } |
3349 | } | 3354 | } |
3350 | #endif | 3355 | #endif |
@@ -3498,10 +3503,12 @@ static int done_command(struct parse_context *ctx) | |||
3498 | && command->redirects == NULL | 3503 | && command->redirects == NULL |
3499 | ) { | 3504 | ) { |
3500 | debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); | 3505 | debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); |
3506 | memset(command, 0, sizeof(*command)); /* paranoia */ | ||
3501 | return pi->num_cmds; | 3507 | return pi->num_cmds; |
3502 | } | 3508 | } |
3503 | pi->num_cmds++; | 3509 | pi->num_cmds++; |
3504 | debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); | 3510 | debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); |
3511 | //debug_print_tree(ctx->list_head, 20); | ||
3505 | } else { | 3512 | } else { |
3506 | debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); | 3513 | debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); |
3507 | } | 3514 | } |
@@ -3526,16 +3533,26 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
3526 | /* Close previous command */ | 3533 | /* Close previous command */ |
3527 | not_null = done_command(ctx); | 3534 | not_null = done_command(ctx); |
3528 | ctx->pipe->followup = type; | 3535 | ctx->pipe->followup = type; |
3529 | IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;) | 3536 | #if HAS_KEYWORDS |
3530 | IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;) | 3537 | ctx->pipe->pi_inverted = ctx->ctx_inverted; |
3531 | IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;) | 3538 | ctx->ctx_inverted = 0; |
3539 | ctx->pipe->res_word = ctx->ctx_res_w; | ||
3540 | #endif | ||
3532 | 3541 | ||
3533 | /* Without this check, even just <enter> on command line generates | 3542 | /* Without this check, even just <enter> on command line generates |
3534 | * tree of three NOPs (!). Which is harmless but annoying. | 3543 | * tree of three NOPs (!). Which is harmless but annoying. |
3535 | * IOW: it is safe to do it unconditionally. | 3544 | * IOW: it is safe to do it unconditionally. |
3536 | * RES_NONE case is for "for a in; do ..." (empty IN set) | 3545 | * RES_NONE case is for "for a in; do ..." (empty IN set) |
3537 | * to work, possibly other cases too. */ | 3546 | * and other cases to work. */ |
3538 | if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) { | 3547 | if (not_null |
3548 | #if HAS_KEYWORDS | ||
3549 | || ctx->ctx_res_w == RES_FI | ||
3550 | || ctx->ctx_res_w == RES_DONE | ||
3551 | || ctx->ctx_res_w == RES_FOR | ||
3552 | || ctx->ctx_res_w == RES_IN | ||
3553 | || ctx->ctx_res_w == RES_ESAC | ||
3554 | #endif | ||
3555 | ) { | ||
3539 | struct pipe *new_p; | 3556 | struct pipe *new_p; |
3540 | debug_printf_parse("done_pipe: adding new pipe: " | 3557 | debug_printf_parse("done_pipe: adding new pipe: " |
3541 | "not_null:%d ctx->ctx_res_w:%d\n", | 3558 | "not_null:%d ctx->ctx_res_w:%d\n", |
@@ -3564,6 +3581,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
3564 | * ctx->command = &ctx->pipe->cmds[0]; | 3581 | * ctx->command = &ctx->pipe->cmds[0]; |
3565 | */ | 3582 | */ |
3566 | done_command(ctx); | 3583 | done_command(ctx); |
3584 | //debug_print_tree(ctx->list_head, 10); | ||
3567 | } | 3585 | } |
3568 | debug_printf_parse("done_pipe return\n"); | 3586 | debug_printf_parse("done_pipe return\n"); |
3569 | } | 3587 | } |
@@ -5483,6 +5501,7 @@ static int builtin_exec(char **argv) | |||
5483 | 5501 | ||
5484 | static int builtin_exit(char **argv) | 5502 | static int builtin_exit(char **argv) |
5485 | { | 5503 | { |
5504 | debug_printf_exec("%s()\n", __func__); | ||
5486 | // TODO: bash does it ONLY on top-level sh exit (+interacive only?) | 5505 | // TODO: bash does it ONLY on top-level sh exit (+interacive only?) |
5487 | //puts("exit"); /* bash does it */ | 5506 | //puts("exit"); /* bash does it */ |
5488 | // TODO: warn if we have background jobs: "There are stopped jobs" | 5507 | // TODO: warn if we have background jobs: "There are stopped jobs" |
diff --git a/shell/hush_test/hush-misc/continue2.right b/shell/hush_test/hush-misc/continue2.right new file mode 100644 index 000000000..49d3ebd3a --- /dev/null +++ b/shell/hush_test/hush-misc/continue2.right | |||
@@ -0,0 +1 @@ | |||
Ok:1 | |||
diff --git a/shell/hush_test/hush-misc/continue2.tests b/shell/hush_test/hush-misc/continue2.tests new file mode 100644 index 000000000..c2df07195 --- /dev/null +++ b/shell/hush_test/hush-misc/continue2.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | e='' | ||
2 | (while test $e && exit 1; true; do e=1; continue; done) | ||
3 | echo Ok:$? | ||
diff --git a/shell/hush_test/hush-misc/continue3.right b/shell/hush_test/hush-misc/continue3.right new file mode 100644 index 000000000..aa47d0d46 --- /dev/null +++ b/shell/hush_test/hush-misc/continue3.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 0 | ||
2 | 0 | ||
diff --git a/shell/hush_test/hush-misc/continue3.tests b/shell/hush_test/hush-misc/continue3.tests new file mode 100644 index 000000000..0aff867cd --- /dev/null +++ b/shell/hush_test/hush-misc/continue3.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | # Test that "continue" does affect exitcode (sets to 0) | ||
2 | e='' | ||
3 | while echo $?; test $e && exit; true; do e=1; false; continue; done | ||
diff --git a/shell/hush_test/hush-misc/until1.right b/shell/hush_test/hush-misc/until1.right new file mode 100644 index 000000000..be2daad95 --- /dev/null +++ b/shell/hush_test/hush-misc/until1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | 1 | ||
2 | 1 | ||
3 | Ok:0 | ||
diff --git a/shell/hush_test/hush-misc/until1.tests b/shell/hush_test/hush-misc/until1.tests new file mode 100644 index 000000000..10ab28381 --- /dev/null +++ b/shell/hush_test/hush-misc/until1.tests | |||
@@ -0,0 +1,11 @@ | |||
1 | x=1 | ||
2 | until test "$x" = 4; do echo $x; x=4; done | ||
3 | |||
4 | # We had a bug in multi-line form | ||
5 | x=1 | ||
6 | until test "$x" = 4; do | ||
7 | echo $x | ||
8 | x=4 | ||
9 | done | ||
10 | |||
11 | echo Ok:$? | ||
diff --git a/shell/hush_test/hush-misc/while2.right b/shell/hush_test/hush-misc/while2.right new file mode 100644 index 000000000..07207cc84 --- /dev/null +++ b/shell/hush_test/hush-misc/while2.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Hello | ||
2 | OK:0 | ||
diff --git a/shell/hush_test/hush-misc/while2.tests b/shell/hush_test/hush-misc/while2.tests new file mode 100644 index 000000000..2247adc74 --- /dev/null +++ b/shell/hush_test/hush-misc/while2.tests | |||
@@ -0,0 +1,2 @@ | |||
1 | while echo Hello; false; do echo NOT SHOWN; done | ||
2 | echo OK:$? | ||
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 3fe3ba51d..c7989a172 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all | |||
@@ -46,7 +46,7 @@ do_test() | |||
46 | test -x "$x" || continue | 46 | test -x "$x" || continue |
47 | name="${x%%.tests}" | 47 | name="${x%%.tests}" |
48 | test -f "$name.right" || continue | 48 | test -f "$name.right" || continue |
49 | # echo Running test: "$name.right" | 49 | # echo Running test: "$x" |
50 | { | 50 | { |
51 | "$THIS_SH" "./$x" >"$name.xx" 2>&1 | 51 | "$THIS_SH" "./$x" >"$name.xx" 2>&1 |
52 | diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" | 52 | diff -u "$name.xx" "$name.right" >"../$1-$x.fail" && rm -f "$name.xx" "../$1-$x.fail" |