aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2018-05-19 02:39:52 +0800
committerBen Hutchings <ben@decadent.org.uk>2020-03-28 21:42:55 +0000
commit166a88f4568067378ddce23b91be7b4ec9a9dfb4 (patch)
treef5a7f8d4ab9745a27b5db60c1621ec2d1dc95135
parente8b1ed5d253922aeb880518f27312b112e360f09 (diff)
downloadklibc-166a88f4568067378ddce23b91be7b4ec9a9dfb4.tar.gz
[klibc] dash: eval: Add assignment built-in support again
[ dash commit cbb71a836874d176809a34e22f6b6e4e3ba8c85b ] 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> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--usr/dash/eval.c145
-rw-r--r--usr/dash/exec.c21
-rw-r--r--usr/dash/exec.h2
-rw-r--r--usr/dash/parser.c3
-rw-r--r--usr/dash/parser.h1
5 files changed, 97 insertions, 75 deletions
diff --git a/usr/dash/eval.c b/usr/dash/eval.c
index ff27ba9c85288..9e88fef28ac8b 100644
--- a/usr/dash/eval.c
+++ b/usr/dash/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/usr/dash/exec.c b/usr/dash/exec.c
index 6c0a64f6460fa..9d0215a6533f3 100644
--- a/usr/dash/exec.c
+++ b/usr/dash/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/usr/dash/exec.h b/usr/dash/exec.h
index f394f3f735781..2b31825775b30 100644
--- a/usr/dash/exec.h
+++ b/usr/dash/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/usr/dash/parser.c b/usr/dash/parser.c
index 3de977c1eff1d..c4e63781e5e39 100644
--- a/usr/dash/parser.c
+++ b/usr/dash/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/usr/dash/parser.h b/usr/dash/parser.h
index 2875cce6d4241..524ac1c7d579b 100644
--- a/usr/dash/parser.h
+++ b/usr/dash/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 *);