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 | |
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 | ||||
-rw-r--r-- | src/exec.c | 21 | ||||
-rw-r--r-- | src/exec.h | 2 | ||||
-rw-r--r-- | src/parser.c | 3 | ||||
-rw-r--r-- | src/parser.h | 1 |
5 files changed, 97 insertions, 75 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 */ diff --git a/src/exec.c b/src/exec.c index 6c0a64f..9d0215a 100644 --- a/src/exec.c +++ b/src/exec.c @@ -357,11 +357,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) } updatetbl = (path == pathval()); - if (!updatetbl) { + if (!updatetbl) act |= DO_ALTPATH; - if (strstr(path, "%builtin") != NULL) - act |= DO_ALTBLTIN; - } /* If name is in the table, check answer will be ok */ if ((cmdp = cmdlookup(name, 0)) != NULL) { @@ -373,17 +370,20 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) abort(); #endif case CMDNORMAL: - bit = DO_ALTPATH; + bit = DO_ALTPATH | DO_REGBLTIN; break; case CMDFUNCTION: bit = DO_NOFUNC; break; case CMDBUILTIN: bit = cmdp->param.cmd->flags & BUILTIN_REGULAR ? - 0 : DO_ALTBLTIN; + 0 : DO_REGBLTIN; break; } if (act & bit) { + if (act & bit & DO_REGBLTIN) + goto fail; + updatetbl = 0; cmdp = NULL; } else if (cmdp->rehash == 0) @@ -393,11 +393,13 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) /* If %builtin not in path, check for builtin next */ bcmd = find_builtin(name); - if (bcmd && (bcmd->flags & BUILTIN_REGULAR || ( - act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0 - ))) + if (bcmd && ((bcmd->flags & BUILTIN_REGULAR) | (act & DO_ALTPATH) | + (builtinloc <= 0))) goto builtin_success; + if (act & DO_REGBLTIN) + goto fail; + /* We have to search path. */ prev = -1; /* where to start */ if (cmdp && cmdp->rehash) { /* doing a rehash */ @@ -489,6 +491,7 @@ loop: delete_cmd_entry(); if (act & DO_ERR) sh_warnx("%s: %s", name, errmsg(e, E_EXEC)); +fail: entry->cmdtype = CMDUNKNOWN; return; diff --git a/src/exec.h b/src/exec.h index f394f3f..2b31825 100644 --- a/src/exec.h +++ b/src/exec.h @@ -56,7 +56,7 @@ struct cmdentry { #define DO_ABS 0x02 /* checks absolute paths */ #define DO_NOFUNC 0x04 /* don't return shell functions, for command */ #define DO_ALTPATH 0x08 /* using alternate path */ -#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ +#define DO_REGBLTIN 0x10 /* regular built-ins and functions only */ extern const char *pathopt; /* set by padvance */ diff --git a/src/parser.c b/src/parser.c index 3de977c..c4e6378 100644 --- a/src/parser.c +++ b/src/parser.c @@ -125,8 +125,7 @@ STATIC void synerror(const char *) __attribute__((__noreturn__)); STATIC void setprompt(int); -static inline int -isassignment(const char *p) +int isassignment(const char *p) { const char *q = endofname(p); if (p == q) diff --git a/src/parser.h b/src/parser.h index 2875cce..524ac1c 100644 --- a/src/parser.h +++ b/src/parser.h @@ -82,6 +82,7 @@ extern int whichprompt; /* 1 == PS1, 2 == PS2 */ extern int checkkwd; +int isassignment(const char *p); union node *parsecmd(int); void fixredir(union node *, const char *, int); const char *getprompt(void *); |