diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2018-05-19 02:39:52 +0800 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-05-28 17:12:23 +0800 |
commit | cbb71a836874d176809a34e22f6b6e4e3ba8c85b (patch) | |
tree | 7bfba4c4202e600b13d660d74b6d93cb914a7733 /src/eval.c | |
parent | exec: Never rehash regular built-ins (diff) | |
download | dash-cbb71a836874d176809a34e22f6b6e4e3ba8c85b.tar.gz dash-cbb71a836874d176809a34e22f6b6e4e3ba8c85b.zip |
eval: Add assignment built-in support again
This patch adds assignment built-in support that used to exist in dash prior to 0.3.8-15. This is because it will soon be part of POSIX, and the semantics are now much better defined. Recognition is done at execution time, so even "command -- export" or "var=export; command $var" should work. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to '')
-rw-r--r-- | src/eval.c | 145 |
1 files changed, 82 insertions, 63 deletions
diff --git a/src/eval.c b/src/eval.c index 1b803db..bdc3893 100644 --- a/src/eval.c +++ b/src/eval.c @@ -100,8 +100,9 @@ STATIC int bltincmd(int, char **); STATIC const struct builtincmd bltin = { - name: nullstr, - builtin: bltincmd + .name = nullstr, + .builtin = bltincmd, + .flags = BUILTIN_REGULAR, }; @@ -648,22 +649,42 @@ out: result->fd, result->buf, result->nleft, result->jp)); } -static char ** -parse_command_args(char **argv, const char **path) +static struct strlist *fill_arglist(struct arglist *arglist, + union node **argpp) { + struct strlist **lastp = arglist->lastp; + union node *argp; + + while ((argp = *argpp)) { + expandarg(argp, arglist, EXP_FULL | EXP_TILDE); + *argpp = argp->narg.next; + if (*lastp) + break; + } + + return *lastp; +} + +static int parse_command_args(struct arglist *arglist, union node **argpp, + const char **path) +{ + struct strlist *sp = arglist->list; char *cp, c; for (;;) { - cp = *++argv; - if (!cp) + sp = unlikely(sp->next) ? sp->next : + fill_arglist(arglist, argpp); + if (!sp) return 0; + cp = sp->text; if (*cp++ != '-') break; if (!(c = *cp++)) break; if (c == '-' && !*cp) { - if (!*++argv) + if (likely(!sp->next) && !fill_arglist(arglist, argpp)) return 0; + sp = sp->next; break; } do { @@ -677,10 +698,10 @@ parse_command_args(char **argv, const char **path) } } while ((c = *cp++)); } - return argv; -} - + arglist->list = sp; + return DO_NOFUNC; +} /* * Execute a simple command. @@ -702,6 +723,7 @@ evalcommand(union node *cmd, int flags) struct arglist varlist; char **argv; int argc; + struct strlist *osp; struct strlist *sp; #ifdef notyet int pip[2]; @@ -711,6 +733,7 @@ evalcommand(union node *cmd, int flags) char *lastarg; const char *path; int spclbltin; + int cmd_flag; int execcmd; int status; char **nargv; @@ -733,13 +756,47 @@ evalcommand(union node *cmd, int flags) arglist.lastp = &arglist.list; *arglist.lastp = NULL; + cmd_flag = 0; + execcmd = 0; + spclbltin = -1; + path = NULL; + argc = 0; - for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { - struct strlist **spp; + argp = cmd->ncmd.args; + if ((osp = fill_arglist(&arglist, &argp))) { + int pseudovarflag = 0; - spp = arglist.lastp; - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - for (sp = *spp; sp; sp = sp->next) + for (;;) { + find_command(arglist.list->text, &cmdentry, + cmd_flag | DO_REGBLTIN, pathval()); + + /* implement bltin and command here */ + if (cmdentry.cmdtype != CMDBUILTIN) + break; + + pseudovarflag = cmdentry.u.cmd->flags & BUILTIN_ASSIGN; + if (likely(spclbltin < 0)) { + spclbltin = + cmdentry.u.cmd->flags & + BUILTIN_SPECIAL + ; + } + execcmd = cmdentry.u.cmd == EXECCMD; + if (likely(cmdentry.u.cmd != COMMANDCMD)) + break; + + cmd_flag = parse_command_args(&arglist, &argp, &path); + if (!cmd_flag) + break; + } + + for (; argp; argp = argp->narg.next) + expandarg(argp, &arglist, + pseudovarflag && + isassignment(argp->narg.text) ? + EXP_VARTILDE : EXP_FULL | EXP_TILDE); + + for (sp = arglist.list; sp; sp = sp->next) argc++; } @@ -761,23 +818,13 @@ evalcommand(union node *cmd, int flags) redir_stop = pushredir(cmd->ncmd.redirect); status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); - path = vpath.text; for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { struct strlist **spp; - char *p; spp = varlist.lastp; expandarg(argp, &varlist, EXP_VARTILDE); mklocal((*spp)->text); - - /* - * Modify the command lookup path, if a PATH= assignment - * is present - */ - p = (*spp)->text; - if (varequal(p, path)) - path = p; } /* Print the command if xflag is set. */ @@ -789,53 +836,24 @@ evalcommand(union node *cmd, int flags) outstr(expandstr(ps4val()), out); sep = 0; sep = eprintlist(out, varlist.list, sep); - eprintlist(out, arglist.list, sep); + eprintlist(out, osp, sep); outcslow('\n', out); #ifdef FLUSHERR flushout(out); #endif } - execcmd = 0; - spclbltin = -1; - /* Now locate the command. */ - if (argc) { - const char *oldpath; - int cmd_flag = DO_ERR; - - path += 5; - oldpath = path; - for (;;) { - find_command(argv[0], &cmdentry, cmd_flag, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { - status = 127; + if (cmdentry.cmdtype != CMDBUILTIN || + !(cmdentry.u.cmd->flags & BUILTIN_REGULAR)) { + find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, + unlikely(path) ? path : pathval()); + if (cmdentry.cmdtype == CMDUNKNOWN) { + status = 127; #ifdef FLUSHERR - flushout(&errout); + flushout(&errout); #endif - goto bail; - } - - /* implement bltin and command here */ - if (cmdentry.cmdtype != CMDBUILTIN) - break; - if (spclbltin < 0) - spclbltin = - cmdentry.u.cmd->flags & - BUILTIN_SPECIAL - ; - if (cmdentry.u.cmd == EXECCMD) - execcmd++; - if (cmdentry.u.cmd != COMMANDCMD) - break; - - path = oldpath; - nargv = parse_command_args(argv, &path); - if (!nargv) - break; - argc -= nargv - argv; - argv = nargv; - cmd_flag |= DO_NOFUNC; + goto bail; } } @@ -864,6 +882,7 @@ bail: FORCEINTON; } listsetvar(varlist.list, VEXPORT|VSTACK); + path = unlikely(path) ? path : pathval(); shellexec(argv, path, cmdentry.u.index); /* NOTREACHED */ |