hush: preparatory patch for removing extra empty pipes generation
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 5 May 2007 15:10:52 +0000 (15:10 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 5 May 2007 15:10:52 +0000 (15:10 -0000)
in parse stage. No real code change here.

shell/hush.c

index 78531e8..eb6f37f 100644 (file)
@@ -125,10 +125,10 @@ static const char *indenter(int i)
 #define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
 #endif
 
-#define SPECIAL_VAR_SYMBOL 03
-#define FLAG_EXIT_FROM_LOOP 1
+#define SPECIAL_VAR_SYMBOL   3
+#define FLAG_EXIT_FROM_LOOP  1
 #define FLAG_PARSE_SEMICOLON (1 << 1)          /* symbol ';' is special for parser */
-#define FLAG_REPARSING      (1 << 2)           /* >=2nd pass */
+#define FLAG_REPARSING      (1 << 2)           /* >= 2nd pass */
 
 typedef enum {
        REDIRECT_INPUT     = 1,
@@ -199,10 +199,10 @@ struct p_context {
        struct pipe *list_head;
        struct pipe *pipe;
        struct redir_struct *pending_redirect;
-       reserved_style w;
-       int old_flag;               /* for figuring out valid reserved words */
+       reserved_style res_w;
+       int old_flag;           /* for figuring out valid reserved words */
        struct p_context *stack;
-       int type;           /* define type of parser : ";$" common or special symbol */
+       int parse_type;         /* define type of parser : ";$" common or special symbol */
        /* How about quoting status? */
 };
 
@@ -410,8 +410,8 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
 static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
 static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
 /*   setup: */
-static int parse_stream_outer(struct in_str *inp, int flag);
-static int parse_string_outer(const char *s, int flag);
+static int parse_stream_outer(struct in_str *inp, int parse_flag);
+static int parse_string_outer(const char *s, int parse_flag);
 static int parse_file_outer(FILE *f);
 /*   job management: */
 static int checkjobs(struct pipe* fg_pipe);
@@ -1854,23 +1854,24 @@ static void debug_print_tree(struct pipe *pi, int lvl)
        };
 
        int pin, prn;
-       char **argv;
        pin = 0;
        while (pi) {
                fprintf(stderr, "%*spipe %d r_mode=%s followup=%d %s\n", lvl*2, "",
                                pin, RES[pi->r_mode], pi->followup, PIPE[pi->followup]);
                prn = 0;
                while (prn < pi->num_progs) {
+                       struct child_prog *child = &pi->progs[prn];
+                       char **argv = child->argv;
+
                        fprintf(stderr, "%*s prog %d", lvl*2, "", prn);
-                       if (pi->progs[prn].group) {
+                       if (child->group) {
                                fprintf(stderr, " group %s: (argv=%p)\n",
-                                               (pi->subshell ? "()" : "{}"),
-                                               pi->progs[prn].argv);
-                               debug_print_tree(pi->progs[prn].group, lvl+1);
+                                               (child->subshell ? "()" : "{}"),
+                                               argv);
+                               debug_print_tree(child->group, lvl+1);
                                prn++;
                                continue;
                        }
-                       argv = pi->progs[prn].argv;
                        if (argv) while (*argv) {
                                fprintf(stderr, " '%s'", *argv);
                                argv++;
@@ -1901,7 +1902,7 @@ static int run_list_real(struct pipe *pi)
        int flag_rep = 0;
        int save_num_progs;
        int flag_skip = 1;
-       int rcode = 0; /* probaly for gcc only */
+       int rcode = 0; /* probably for gcc only */
        int flag_restore = 0;
        int if_code = 0, next_if_code = 0;  /* need double-buffer to handle elif */
        reserved_style rmode, skip_more_in_this_rmode = RES_XXXX;
@@ -1968,17 +1969,15 @@ static int run_list_real(struct pipe *pi)
        }
 #endif
 
-       for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
-               if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL
-                || pi->r_mode == RES_FOR
-               ) {
+       for (; pi; pi = flag_restore ? rpipe : pi->next) {
+               rmode = pi->r_mode;
+               if (rmode == RES_WHILE || rmode == RES_UNTIL || rmode == RES_FOR) {
                        flag_restore = 0;
                        if (!rpipe) {
                                flag_rep = 0;
                                rpipe = pi;
                        }
                }
-               rmode = pi->r_mode;
                debug_printf_exec(": rmode=%d if_code=%d next_if_code=%d skip_more=%d\n",
                                rmode, if_code, next_if_code, skip_more_in_this_rmode);
                if (rmode == skip_more_in_this_rmode && flag_skip) {
@@ -2535,7 +2534,7 @@ static void initialize_context(struct p_context *ctx)
        ctx->child = NULL;
        ctx->list_head = new_pipe();
        ctx->pipe = ctx->list_head;
-       ctx->w = RES_NONE;
+       ctx->res_w = RES_NONE;
        ctx->stack = NULL;
        ctx->old_flag = 0;
        done_command(ctx);   /* creates the memory for working child */
@@ -2574,29 +2573,29 @@ static int reserved_word(o_string *dest, struct p_context *ctx)
        enum { NRES = sizeof(reserved_list)/sizeof(reserved_list[0]) };
        const struct reserved_combo *r;
 
-       for (r = reserved_list; r < reserved_list+NRES; r++) {
+       for (r = reserved_list; r < reserved_list + NRES; r++) {
                if (strcmp(dest->data, r->literal) == 0) {
                        debug_printf("found reserved word %s, code %d\n", r->literal, r->code);
                        if (r->flag & FLAG_START) {
                                struct p_context *new = xmalloc(sizeof(struct p_context));
                                debug_printf("push stack\n");
-                               if (ctx->w == RES_IN || ctx->w == RES_FOR) {
+                               if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) {
                                        syntax();
                                        free(new);
-                                       ctx->w = RES_SNTX;
+                                       ctx->res_w = RES_SNTX;
                                        b_reset(dest);
                                        return 1;
                                }
                                *new = *ctx;   /* physical copy */
                                initialize_context(ctx);
                                ctx->stack = new;
-                       } else if (ctx->w == RES_NONE || !(ctx->old_flag & (1 << r->code))) {
+                       } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->code))) {
                                syntax();
-                               ctx->w = RES_SNTX;
+                               ctx->res_w = RES_SNTX;
                                b_reset(dest);
                                return 1;
                        }
-                       ctx->w = r->code;
+                       ctx->res_w = r->code;
                        ctx->old_flag = r->flag;
                        if (ctx->old_flag & FLAG_END) {
                                struct p_context *old;
@@ -2623,7 +2622,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
        glob_t *glob_target;
        int gr, flags = 0;
 
-       debug_printf_parse("done_word: '%s' %p\n", dest->data, child);
+       debug_printf_parse("done_word entered: '%s' %p\n", dest->data, child);
        if (dest->length == 0 && !dest->nonnull) {
                debug_printf_parse("done_word return 0: true null, ignored\n");
                return 0;
@@ -2636,15 +2635,16 @@ static int done_word(o_string *dest, struct p_context *ctx)
                        debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n");
                        return 1;
                }
-               if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
-                       debug_printf_parse(": checking %s for reserved-ness\n", dest->data);
+               if (!child->argv && (ctx->parse_type & FLAG_PARSE_SEMICOLON)) {
+                       debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data);
                        if (reserved_word(dest, ctx)) {
-                               debug_printf_parse("done_word return %d\n", (ctx->w == RES_SNTX));
-                               return (ctx->w == RES_SNTX);
+                               debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX));
+                               return (ctx->res_w == RES_SNTX);
                        }
                }
                glob_target = &child->glob_result;
-               if (child->argv) flags |= GLOB_APPEND;
+               if (child->argv)
+                       flags |= GLOB_APPEND;
        }
        gr = xglob(dest, flags, glob_target);
        if (gr != 0) {
@@ -2663,7 +2663,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
        } else {
                child->argv = glob_target->gl_pathv;
        }
-       if (ctx->w == RES_FOR) {
+       if (ctx->res_w == RES_FOR) {
                done_word(dest, ctx);
                done_pipe(ctx, PIPE_SEQ);
        }
@@ -2676,56 +2676,63 @@ static int done_word(o_string *dest, struct p_context *ctx)
 static int done_command(struct p_context *ctx)
 {
        /* The child is really already in the pipe structure, so
-        * advance the pipe counter and make a new, null child.
-        * Only real trickiness here is that the uncommitted
-        * child structure, to which ctx->child points, is not
-        * counted in pi->num_progs. */
+        * advance the pipe counter and make a new, null child. */
        struct pipe *pi = ctx->pipe;
-       struct child_prog *prog = ctx->child;
+       struct child_prog *child = ctx->child;
 
-       if (prog && prog->group == NULL
-        && prog->argv == NULL
-        && prog->redirects == NULL
-       ) {
-               debug_printf("done_command: skipping null command\n");
-               return 0;
-       }
-       if (prog) {
+       if (child) {
+               if (child->group == NULL
+                && child->argv == NULL
+                && child->redirects == NULL
+               ) {
+                       debug_printf_parse("done_command: skipping null command\n");
+                       return 0;
+               }
                pi->num_progs++;
-               debug_printf("done_command: num_progs incremented to %d\n", pi->num_progs);
+               debug_printf_parse("done_command: ++num_progs=%d\n", pi->num_progs);
        } else {
-               debug_printf("done_command: initializing\n");
+               debug_printf_parse("done_command: initializing, num_progs=%d\n", pi->num_progs);
        }
-       pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
-
-       prog = pi->progs + pi->num_progs;
-       memset(prog, 0, sizeof(*prog));
-       /*prog->redirects = NULL;*/
-       /*prog->argv = NULL; */
-       /*prog->is_stopped = 0;*/
-       /*prog->group = NULL;*/
-       /*prog->glob_result.gl_pathv = NULL;*/
-       prog->family = pi;
-       /*prog->sp = 0;*/
-       ctx->child = prog;
-       prog->type = ctx->type;
 
+       /* Only real trickiness here is that the uncommitted
+        * child structure is not counted in pi->num_progs. */
+       pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
+       child = &pi->progs[pi->num_progs];
+
+       memset(child, 0, sizeof(*child));
+       /*child->redirects = NULL;*/
+       /*child->argv = NULL;*/
+       /*child->is_stopped = 0;*/
+       /*child->group = NULL;*/
+       /*child->glob_result.gl_pathv = NULL;*/
+       child->family = pi;
+       /*child->sp = 0;*/
+       child->type = ctx->parse_type;
+
+       ctx->child = child;
        /* but ctx->pipe and ctx->list_head remain unchanged */
+
        return 0;
 }
 
 static int done_pipe(struct p_context *ctx, pipe_style type)
 {
        struct pipe *new_p;
+
+       debug_printf_parse("done_pipe entered, followup %d\n", type);
        done_command(ctx);  /* implicit closure of previous command */
-       debug_printf_parse("done_pipe, type %d\n", type);
        ctx->pipe->followup = type;
-       ctx->pipe->r_mode = ctx->w;
+       ctx->pipe->r_mode = ctx->res_w;
        new_p = new_pipe();
        ctx->pipe->next = new_p;
        ctx->pipe = new_p;
        ctx->child = NULL;
+// TODO: even just <enter> on command line basically generates
+// tree of three NOPs (!).
+// Can we detect that previous done_command have seen "skipping null command"
+// condition and NOT create new pipe here?
        done_command(ctx);  /* set up new pipe to accept commands */
+       debug_printf_parse("done_pipe return 0\n");
        return 0;
 }
 
@@ -3055,7 +3062,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                }
                if (m == MAP_IFS_IF_UNQUOTED) {
                        if (done_word(dest, ctx)) {
-                               debug_printf_parse("parse_stream return 1\n");
+                               debug_printf_parse("parse_stream return 1: done_word!=0\n");
                                return 1;
                        }
                        /* If we aren't performing a substitution, treat
@@ -3066,9 +3073,9 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                        }
                }
                if ((end_trigger && strchr(end_trigger, ch))
-                && !dest->quote && ctx->w == RES_NONE
+                && !dest->quote && ctx->res_w == RES_NONE
                ) {
-                       debug_printf_parse("parse_stream return 0\n");
+                       debug_printf_parse("parse_stream return 0: end_trigger char found\n");
                        return 0;
                }
                if (m == MAP_IFS_IF_UNQUOTED)
@@ -3089,7 +3096,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                case '\\':
                        if (next == EOF) {
                                syntax();
-                               debug_printf_parse("parse_stream return 1\n");
+                               debug_printf_parse("parse_stream return 1: \\<eof>\n");
                                return 1;
                        }
                        b_addqchr(dest, '\\', dest->quote);
@@ -3111,7 +3118,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                        }
                        if (ch == EOF) {
                                syntax();
-                               debug_printf_parse("parse_stream return 1\n");
+                               debug_printf_parse("parse_stream return 1: unterminated '\n");
                                return 1;
                        }
                        break;
@@ -3204,7 +3211,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
         * that is, we were really supposed to get end_trigger, and never got
         * one before the EOF.  Can't use the standard "syntax error" return code,
         * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
-       debug_printf_parse("parse_stream return -%d\n", end_trigger != NULL);
+       debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
        if (end_trigger)
                return -1;
        return 0;
@@ -3220,7 +3227,8 @@ static void update_ifs_map(void)
 {
        /* char *ifs and char map[256] are both globals. */
        ifs = getenv("IFS");
-       if (ifs == NULL) ifs = " \t\n";
+       if (ifs == NULL)
+               ifs = " \t\n";
        /* Precompute a list of 'flow through' behavior so it can be treated
         * quickly up front.  Computation is necessary because of IFS.
         * Special case handling of IFS == " \t\n" is not implemented.
@@ -3235,24 +3243,26 @@ static void update_ifs_map(void)
 
 /* most recursion does not come through here, the exception is
  * from builtin_source() */
-static int parse_stream_outer(struct in_str *inp, int flag)
+static int parse_stream_outer(struct in_str *inp, int parse_flag)
 {
 // FIXME: '{ true | exit 3; echo $? }' is parsed as a whole,
 // as a result $? is replaced by 0, not 3!
-// Need to stop & execute stuff at ';', not parse till EOL!
 
        struct p_context ctx;
        o_string temp = NULL_O_STRING;
        int rcode;
        do {
-               ctx.type = flag;
+               ctx.parse_type = parse_flag;
                initialize_context(&ctx);
                update_ifs_map();
-               if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING))
+               if (!(parse_flag & FLAG_PARSE_SEMICOLON) || (parse_flag & FLAG_REPARSING))
                        mapset(";$&|", MAP_ORDINARY);
 #if ENABLE_HUSH_INTERACTIVE
                inp->promptmode = 1;
 #endif
+               /* We will stop & execute after each ';' or '\n'.
+                * Example: "sleep 9999; echo TEST" + ctrl-C:
+                * TEST should be printed */
                rcode = parse_stream(&temp, &ctx, inp, ";\n");
                if (rcode != 1 && ctx.old_flag != 0) {
                        syntax();
@@ -3274,15 +3284,15 @@ static int parse_stream_outer(struct in_str *inp, int flag)
                        free_pipe_list(ctx.list_head, 0);
                }
                b_free(&temp);
-       } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
+       } while (rcode != -1 && !(parse_flag & FLAG_EXIT_FROM_LOOP));   /* loop on syntax errors, return on EOF */
        return 0;
 }
 
-static int parse_string_outer(const char *s, int flag)
+static int parse_string_outer(const char *s, int parse_flag)
 {
        struct in_str input;
        setup_string_in_str(&input, s);
-       return parse_stream_outer(&input, flag);
+       return parse_stream_outer(&input, parse_flag);
 }
 
 static int parse_file_outer(FILE *f)
@@ -3303,7 +3313,7 @@ static void setup_job_control(void)
        pid_t shell_pgrp;
 
        saved_task_pgrp = shell_pgrp = getpgrp();
-       debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp);
+       debug_printf_jobs("saved_task_pgrp=%d\n", saved_task_pgrp);
        fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
 
        /* If we were ran as 'hush &',
@@ -3319,7 +3329,7 @@ static void setup_job_control(void)
        set_misc_sighandler(SIG_IGN);
 //huh? signal(SIGCHLD, SIG_IGN);
 
-       /* We _must_ restore tty pgrp fatal signals */
+       /* We _must_ restore tty pgrp on fatal signals */
        set_fatal_sighandler(sigexit);
 
        /* Put ourselves in our own process group.  */