aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c57
-rw-r--r--shell/hush_test/hush-misc/continue2.right1
-rw-r--r--shell/hush_test/hush-misc/continue2.tests3
-rw-r--r--shell/hush_test/hush-misc/continue3.right2
-rw-r--r--shell/hush_test/hush-misc/continue3.tests3
-rw-r--r--shell/hush_test/hush-misc/until1.right3
-rw-r--r--shell/hush_test/hush-misc/until1.tests11
-rw-r--r--shell/hush_test/hush-misc/while2.right2
-rw-r--r--shell/hush_test/hush-misc/while2.tests2
-rwxr-xr-xshell/hush_test/run-all2
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
5484static int builtin_exit(char **argv) 5502static 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 @@
1e=''
2(while test $e && exit 1; true; do e=1; continue; done)
3echo 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 @@
10
20
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)
2e=''
3while 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 @@
11
21
3Ok: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 @@
1x=1
2until test "$x" = 4; do echo $x; x=4; done
3
4# We had a bug in multi-line form
5x=1
6until test "$x" = 4; do
7 echo $x
8 x=4
9done
10
11echo 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 @@
1Hello
2OK: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 @@
1while echo Hello; false; do echo NOT SHOWN; done
2echo 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"