hush: fix a bug where we were requiring semicolon here: (cmd;)
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 14 Jun 2008 17:13:20 +0000 (17:13 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 14 Jun 2008 17:13:20 +0000 (17:13 -0000)
 also fix a bug where after error prompt is not shown.

function                                             old     new   delta
parse_stream                                        1612    1638     +26
parse_and_run_stream                                 361     375     +14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 40/0)               Total: 40 bytes

shell/hush.c
shell/hush_test/hush-bugs/while_in_subshell.right [deleted file]
shell/hush_test/hush-bugs/while_in_subshell.tests [deleted file]
shell/hush_test/hush-misc/colon.tests
shell/hush_test/hush-misc/while_in_subshell.right [new file with mode: 0644]
shell/hush_test/hush-misc/while_in_subshell.tests [new file with mode: 0755]

index a84bb92dc98e61f01beb14d878d7da80c345457e..f4c170117617757874638e8ec8bb275f7bf40105 100644 (file)
@@ -3437,11 +3437,11 @@ static int parse_group(o_string *dest, struct p_context *ctx,
                child->subshell = 1;
        }
        rcode = parse_stream(dest, &sub, input, endch);
-//vda: err chk?
-       done_word(dest, &sub); /* finish off the final word in the subcontext */
-       done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
-       child->group = sub.list_head;
-
+       if (rcode == 0) {
+               done_word(dest, &sub); /* finish off the final word in the subcontext */
+               done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */
+               child->group = sub.list_head;
+       }
        debug_printf_parse("parse_group return %d\n", rcode);
        return rcode;
        /* child remains "open", available for possible redirects */
@@ -3700,11 +3700,19 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                                done_pipe(ctx, PIPE_SEQ);
                        }
                }
-               if ((end_trigger && strchr(end_trigger, ch))
-                && !dest->o_quote && ctx->res_w == RES_NONE
-               ) {
-                       debug_printf_parse("parse_stream return 0: end_trigger char found\n");
-                       return 0;
+               if (end_trigger) {
+                       if (!dest->o_quote && strchr(end_trigger, ch)) {
+                               /* Special case: (...word) makes last word terminate,
+                                * as if ';' is seen */
+                               if (ch == ')') {
+                                       done_word(dest, ctx);
+                                       done_pipe(ctx, PIPE_SEQ);
+                               }
+                               if (ctx->res_w == RES_NONE) {
+                                       debug_printf_parse("parse_stream return 0: end_trigger char found\n");
+                                       return 0;
+                               }
+                       }
                }
                if (m == CHAR_IFS)
                        continue;
@@ -3757,15 +3765,15 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                        dest->nonnull = 1;
                        while (1) {
                                ch = i_getch(input);
-                               if (ch == EOF || ch == '\'')
+                               if (ch == EOF) {
+                                       syntax("unterminated '");
+                                       debug_printf_parse("parse_stream return 1: unterminated '\n");
+                                       return 1;
+                               }
+                               if (ch == '\'')
                                        break;
                                o_addqchr(dest, ch);
                        }
-                       if (ch == EOF) {
-                               syntax("unterminated '");
-                               debug_printf_parse("parse_stream return 1: unterminated '\n");
-                               return 1;
-                       }
                        break;
                case '"':
                        dest->nonnull = 1;
@@ -3861,7 +3869,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                        if (ENABLE_HUSH_DEBUG)
                                bb_error_msg_and_die("BUG: unexpected %c\n", ch);
                }
-       }
+       } /* while (1) */
        /* Complain if quote?  No, maybe we just finished a command substitution
         * that was quoted.  Example:
         * $ echo "`cat foo` plus more"
@@ -3913,8 +3921,9 @@ static int parse_and_run_stream(struct in_str *inp, int parse_flag)
        struct p_context ctx;
        o_string temp = NULL_O_STRING;
        int rcode;
+
        do {
-// It always has PARSEFLAG_SEMICOLON, can we remove all checks for this bit?
+// parse_type always has PARSEFLAG_SEMICOLON, can we remove all checks for this bit?
 // After that, the whole parse_type fiels is not needed.
                ctx.parse_type = parse_flag;
                initialize_context(&ctx);
@@ -3938,17 +3947,21 @@ static int parse_and_run_stream(struct in_str *inp, int parse_flag)
                        debug_printf_exec("parse_stream_outer: run_and_free_list\n");
                        run_and_free_list(ctx.list_head);
                } else {
+                       /* We arrive here also if rcode == 1 (error in parse_stream) */
                        if (ctx.old_flag != 0) {
                                free(ctx.stack);
                                o_reset(&temp);
                        }
                        temp.nonnull = 0;
                        temp.o_quote = 0;
-                       inp->p = NULL;
                        free_pipe_list(ctx.list_head, /* indent: */ 0);
+                       /* Discard all unprocessed line input, force prompt on */
+                       inp->p = NULL;
+                       inp->promptme = 1;
                }
                o_free(&temp);
-       } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
+               /* loop on syntax errors, return on EOF: */
+       } while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP));
        return 0;
 }
 
diff --git a/shell/hush_test/hush-bugs/while_in_subshell.right b/shell/hush_test/hush-bugs/while_in_subshell.right
deleted file mode 100644 (file)
index 290d39b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-OK: 0
diff --git a/shell/hush_test/hush-bugs/while_in_subshell.tests b/shell/hush_test/hush-bugs/while_in_subshell.tests
deleted file mode 100755 (executable)
index def8e09..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-(while true; do exit; done)
-echo OK: $?
index ea3b4d5f3939e4a95667bb9666e898f54204e0ba..cb8ab53060a125a8591f0528659d2b6bf198a3e8 100755 (executable)
@@ -1,6 +1,5 @@
 false
 :
 echo $?
-# Extra ; after done is due to a bug
-(while :; do exit; done;)
+(while :; do exit; done)
 echo OK: $?
diff --git a/shell/hush_test/hush-misc/while_in_subshell.right b/shell/hush_test/hush-misc/while_in_subshell.right
new file mode 100644 (file)
index 0000000..290d39b
--- /dev/null
@@ -0,0 +1 @@
+OK: 0
diff --git a/shell/hush_test/hush-misc/while_in_subshell.tests b/shell/hush_test/hush-misc/while_in_subshell.tests
new file mode 100755 (executable)
index 0000000..def8e09
--- /dev/null
@@ -0,0 +1,2 @@
+(while true; do exit; done)
+echo OK: $?