diff options
Diffstat (limited to 'toys')
-rw-r--r-- | toys/pending/sh.c | 79 |
1 files changed, 29 insertions, 50 deletions
diff --git a/toys/pending/sh.c b/toys/pending/sh.c index 7aa3189f..e77ebe6f 100644 --- a/toys/pending/sh.c +++ b/toys/pending/sh.c @@ -211,7 +211,7 @@ static int sh_run(char *new); // Pipeline segments struct sh_pipeline { - struct sh_pipeline *next, *prev; + struct sh_pipeline *next, *prev, *end; int count, here, type; struct sh_arg arg[1]; }; @@ -383,7 +383,7 @@ static struct sh_vars *setvar(char *s) error_msg("%.*s: read only", len, s); free(s); - return var; + return 0; } else if (flags&VAR_MAGIC) { if (*s == 'S') TT.SECONDS = millitime() - 1000*do_math(s+len-1); else if (*s == 'R') srandom(do_math(s+len-1)); @@ -1444,7 +1444,7 @@ notfd: // Do we save displaced "to" in env variable instead of undo list? if (cv) { --*pp->urd; - setvar(cv); + if (!setvar(cv)) bad++; cv = 0; } if ((saveclose&1) && save_redirect(&pp->urd, -1, from)) bad++; @@ -1611,23 +1611,6 @@ static void free_pipeline(void *pipeline) free(pl); } -// Return end of current block, or NULL if we weren't in block and fell off end. -static struct sh_pipeline *block_end(struct sh_pipeline *pl) -{ - int i = 0; - -// TODO: should this be inlined into type 1 processing to set blk->end and -// then everything else use that? - - while (pl) { - if (pl->type == 1 || pl->type == 'f') i++; - else if (pl->type == 3) if (--i<1) break; - pl = pl->next; - } - - return pl; -} - static void free_function(struct sh_function *sp) { llist_traverse(sp->pipeline, free_pipeline); @@ -1640,7 +1623,7 @@ static struct sh_pipeline *add_function(char *name, struct sh_pipeline *pl) { dprintf(2, "stub add_function"); - return block_end(pl->next); + return pl->end; } // Add a line of shell script to a shell function. Returns 0 if finished, @@ -1735,6 +1718,7 @@ if (BUGBUG>1) dprintf(255, "[%.*s:%s] ", end ? (int)(end-start) : 0, start, ex ? // Is this a new pipeline segment? if (!pl) { pl = xzalloc(sizeof(struct sh_pipeline)); + pl->end = pl; arg = pl->arg; dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl); } @@ -1890,12 +1874,23 @@ if (BUGBUG>1) dprintf(255, "[%.*s:%s] ", end ? (int)(end-start) : 0, start, ex ? // If we got here we expect a specific word to end this block: is this it? else if (!strcmp(s, ex)) { - // can't "if | then" or "while && do", only ; & or newline works if (last && strcmp(last, "&")) goto flush; + // consume word, record block end location in earlier !0 type blocks free(dlist_lpop(&sp->expect)); - pl->type = anystr(s, tails) ? 3 : 2; + if (3 == (pl->type = anystr(s, tails) ? 3 : 2)) { + struct sh_pipeline *pl2 = pl; + + i = 0; + for (i = 0; (pl2 = pl2->prev);) { + if (pl2->type == 3) i++; + else if (pl2->type) { + if (!i) pl2->end = pl; + if ((pl2->type == 1 || pl2->type == 'f') && --i<0) break; + } + } + } // if it's a multipart block, what comes next? if (!strcmp(s, "do")) end = "done"; @@ -2018,24 +2013,9 @@ static int pipe_segments(char *ctl, int *pipes, int **urd) return 0; } -// Handle && and || traversal in pipeline segments -static struct sh_pipeline *skip_andor(int rc, struct sh_pipeline *pl) -{ - char *ctl = pl->arg->v[pl->arg->c]; - - // For && and || skip pipeline segment(s) based on return code - while (ctl && ((!strcmp(ctl, "&&") && rc) || (!strcmp(ctl, "||") && !rc))) { - if (!pl->next || pl->next->type == 2 || pl->next->type == 3) break; - pl = pl->type ? block_end(pl) : pl->next; - ctl = pl ? pl->arg->v[pl->arg->c] : 0; - } - - return pl; -} - struct blockstack { struct blockstack *next; - struct sh_pipeline *start, *end; + struct sh_pipeline *start; struct sh_process *pin; // processes piping into this block int run, loop, *urd, pout; struct sh_arg farg; // for/select arg stack @@ -2047,7 +2027,7 @@ struct blockstack { static struct sh_pipeline *pop_block(struct blockstack **blist, int *pout) { struct blockstack *blk = *blist; - struct sh_pipeline *pl = blk->end; + struct sh_pipeline *pl = blk->start->end; // when ending a block, free, cleanup redirects and pop stack. if (*pout != -1) close(*pout); @@ -2064,7 +2044,6 @@ static struct sh_pipeline *pop_block(struct blockstack **blist, int *pout) // vfork/exec external commands. static void run_function(struct sh_pipeline *pl) { - struct sh_pipeline *end; struct blockstack *blk = 0, *new; struct sh_process *pplist = 0; // processes piping into current level int *urd = 0, pipes[2] = {-1, -1}; @@ -2134,7 +2113,9 @@ if (BUGBUG) dprintf(255, "%d runtype=%d %s %s\n", getpid(), pl->type, s, ctl); toys.exitval = wait_pipeline(pplist); llist_traverse(pplist, free_process); pplist = 0; - pl = skip_andor(toys.exitval, pl); + // for && and || skip pipeline segment(s) based on return code + while (ctl && !strcmp(ctl, toys.exitval ? "&&" : "||")) + ctl = (pl = pl->type ? pl->end : pl->next)?pl->arg->v[pl->arg->c]:0; } // Start of flow control block? @@ -2146,22 +2127,19 @@ if (BUGBUG) dprintf(255, "%d runtype=%d %s %s\n", getpid(), pl->type, s, ctl); if (!blk || blk->start != pl) { // If it's a nested block we're not running, skip ahead. - end = block_end(pl->next); if (blk && !blk->run) { - pl = end; - if (pl) pl = pl->next; + pl = pl->end->next; continue; } // If previous piped into this block, save context until block end - if (pipe_segments(end->arg->v[end->arg->c], pipes, &urd)) break; + if (pipe_segments(pl->end->arg->v[pl->end->arg->c], pipes, &urd)) break; // It's a new block we're running, save context and add it to the stack. new = xzalloc(sizeof(*blk)); new->next = blk; blk = new; blk->start = pl; - blk->end = end; blk->run = 1; // save context until block end @@ -2171,7 +2149,7 @@ if (BUGBUG) dprintf(255, "%d runtype=%d %s %s\n", getpid(), pl->type, s, ctl); *pipes = -1; // Perform redirects listed at end of block - pp = expand_redir(end->arg, 1, blk->urd); + pp = expand_redir(pl->end->arg, 1, blk->urd); blk->urd = pp->urd; rc = pp->exit; if (pp->arg.c) { @@ -2235,7 +2213,8 @@ TODO: a | b | c needs subshell for builtins? } dlist_add_nomalloc((void *)&pplist, (void *)pp); - pl = blk->end->prev; + pl = pl->end; + continue; } // gearshift from block start to block body (end of flow control test) @@ -2250,7 +2229,7 @@ TODO: a | b | c needs subshell for builtins? else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval; else if (blk->loop >= blk->farg.c) { blk->run = 0; - pl = block_end(pl); + pl = pl->end; continue; } else if (!strncmp(blk->fvar, "((", 2)) { dprintf(2, "TODO skipped running for((;;)), need math parser\n"); |