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 <herb...@gondor.apana.org.au>
---

 src/eval.c   |  145 +++++++++++++++++++++++++++++++++--------------------------
 src/exec.c   |   21 ++++----
 src/exec.h   |    2 
 src/parser.c |    3 -
 src/parser.h |    1 
 5 files changed, 97 insertions(+), 75 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index 1b803db..22fe2d7 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 *);
--
To unsubscribe from this list: send the line "unsubscribe dash" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to