hush: fix "for a in; do echo 'I should never run'; done" bug
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 17 Jun 2008 12:09:21 +0000 (12:09 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 17 Jun 2008 12:09:21 +0000 (12:09 -0000)
shell/hush.c
shell/hush_test/hush-bugs/empty_for.right [deleted file]
shell/hush_test/hush-bugs/empty_for.tests [deleted file]
shell/hush_test/hush-misc/empty_for.right [new file with mode: 0644]
shell/hush_test/hush-misc/empty_for.tests [new file with mode: 0755]

index ae12ebec49c73622a5627fda4ea0231812d2fce0..45448c5f30e7cf1ebad464dfbae16de406ea971e 100644 (file)
@@ -2004,7 +2004,7 @@ static int run_list(struct pipe *pi)
                 || (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN)
                ) {
                        /* TODO: what is tested in the first condition? */
-                       syntax("malformed for"); /* 2nd condition: not followed by IN */
+                       syntax("malformed for"); /* 2nd condition: FOR not followed by IN */
                        debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
                        return 1;
                }
@@ -2898,7 +2898,8 @@ static int done_word(o_string *word, struct p_context *ctx)
                ctx->pending_redirect = NULL;
        }
 #if ENABLE_HUSH_LOOPS
-       if (ctx->res_w == RES_FOR) { /* comment? */
+       /* comment? is it forcing "for" to have just one word (variable name)? */
+       if (ctx->res_w == RES_FOR) {
 //TESTING
 //looks like (word->length == 0 && !word->nonnull) is true here, always
 //(due to o_reset). done_word would return at once. Why then?
@@ -2910,8 +2911,8 @@ static int done_word(o_string *word, struct p_context *ctx)
        return 0;
 }
 
-/* The only possible error here is out of memory, in which case
- * xmalloc exits. */
+/* Command (member of a pipe) is complete. The only possible error here
+ * is out of memory, in which case xmalloc exits. */
 static int done_command(struct p_context *ctx)
 {
        /* The child is really already in the pipe structure, so
@@ -2949,7 +2950,6 @@ static int done_command(struct p_context *ctx)
 
 static void done_pipe(struct p_context *ctx, pipe_style type)
 {
-       struct pipe *new_p;
        int not_null;
 
        debug_printf_parse("done_pipe entered, followup %d\n", type);
@@ -2960,9 +2960,11 @@ static void done_pipe(struct p_context *ctx, pipe_style type)
        ctx->ctx_inverted = 0;
        /* 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. */
-       if (not_null) {
-               new_p = new_pipe();
+        * IOW: it is safe to do it unconditionally.
+        * RES_IN case is for "for a in; do ..." (empty IN set)
+        * to work. */
+       if (not_null || ctx->pipe->res_word == RES_IN) {
+               struct pipe *new_p = new_pipe();
                ctx->pipe->next = new_p;
                ctx->pipe = new_p;
                ctx->child = NULL; /* needed! */
diff --git a/shell/hush_test/hush-bugs/empty_for.right b/shell/hush_test/hush-bugs/empty_for.right
deleted file mode 100644 (file)
index 290d39b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-OK: 0
diff --git a/shell/hush_test/hush-bugs/empty_for.tests b/shell/hush_test/hush-bugs/empty_for.tests
deleted file mode 100755 (executable)
index 0cb52e8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-false
-for a in; do echo "HELLO"; done
-echo OK: $?
diff --git a/shell/hush_test/hush-misc/empty_for.right b/shell/hush_test/hush-misc/empty_for.right
new file mode 100644 (file)
index 0000000..290d39b
--- /dev/null
@@ -0,0 +1 @@
+OK: 0
diff --git a/shell/hush_test/hush-misc/empty_for.tests b/shell/hush_test/hush-misc/empty_for.tests
new file mode 100755 (executable)
index 0000000..0cb52e8
--- /dev/null
@@ -0,0 +1,3 @@
+false
+for a in; do echo "HELLO"; done
+echo OK: $?