This patch replaces listsetvar with mklocal/setvareq.  As we now
determine special built-in status prior to variable assignment, we
no longer have to do a second pass listsetvar.  Instead we will
call setvareq directly instead of mklocal when necessary.

In order to do this mklocal can now take a flag in order to mark
a variable for export.

Signed-off-by: Herbert Xu <herb...@gondor.apana.org.au>
---

 src/eval.c |   36 +++++++++++++++++++++++-------------
 src/var.c  |   32 +++++---------------------------
 src/var.h  |    3 +--
 3 files changed, 29 insertions(+), 42 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index 122613b..ff8a869 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -737,6 +737,8 @@ evalcommand(union node *cmd, int flags)
        int execcmd;
        int status;
        char **nargv;
+       int vflags;
+       int vlocal;
 
        errlinno = lineno = cmd->ncmd.linno;
        if (funcline)
@@ -745,7 +747,6 @@ evalcommand(union node *cmd, int flags)
        /* First expand the arguments. */
        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
        setstackmark(&smark);
-       localvar_stop = pushlocalvars();
        file_stop = parsefile;
        back_exitstatus = 0;
 
@@ -759,6 +760,8 @@ evalcommand(union node *cmd, int flags)
        cmd_flag = 0;
        execcmd = 0;
        spclbltin = -1;
+       vflags = 0;
+       vlocal = 0;
        path = NULL;
 
        argc = 0;
@@ -770,6 +773,8 @@ evalcommand(union node *cmd, int flags)
                        find_command(arglist.list->text, &cmdentry,
                                     cmd_flag | DO_REGBLTIN, pathval());
 
+                       vlocal++;
+
                        /* implement bltin and command here */
                        if (cmdentry.cmdtype != CMDBUILTIN)
                                break;
@@ -780,6 +785,7 @@ evalcommand(union node *cmd, int flags)
                                        cmdentry.u.cmd->flags &
                                        BUILTIN_SPECIAL
                                ;
+                               vlocal = spclbltin ^ BUILTIN_SPECIAL;
                        }
                        execcmd = cmdentry.u.cmd == EXECCMD;
                        if (likely(cmdentry.u.cmd != COMMANDCMD))
@@ -798,6 +804,9 @@ evalcommand(union node *cmd, int flags)
 
                for (sp = arglist.list; sp; sp = sp->next)
                        argc++;
+
+               if (execcmd && argc > 1)
+                       vflags = VEXPORT;
        }
 
        /* Reserve one extra spot at the front for shellexec. */
@@ -818,7 +827,8 @@ evalcommand(union node *cmd, int flags)
        redir_stop = pushredir(cmd->ncmd.redirect);
        status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
 
-       if (status) {
+       if (unlikely(status)) {
+               vlocal = 0;
 bail:
                exitstatus = status;
 
@@ -829,13 +839,19 @@ bail:
                goto out;
        }
 
+       if (likely(vlocal))
+               localvar_stop = pushlocalvars();
+
        for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
                struct strlist **spp;
 
                spp = varlist.lastp;
                expandarg(argp, &varlist, EXP_VARTILDE);
 
-               mklocal((*spp)->text);
+               if (vlocal)
+                       mklocal((*spp)->text, VEXPORT);
+               else
+                       setvareq((*spp)->text, vflags);
        }
 
        /* Print the command if xflag is set. */
@@ -857,8 +873,8 @@ bail:
        /* Now locate the command. */
        if (cmdentry.cmdtype != CMDBUILTIN ||
            !(cmdentry.u.cmd->flags & BUILTIN_REGULAR)) {
-               find_command(argv[0], &cmdentry, cmd_flag | DO_ERR,
-                            unlikely(path) ? path : pathval());
+               path = unlikely(path) ? path : pathval();
+               find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path);
        }
 
        jp = NULL;
@@ -881,17 +897,10 @@ bail:
                                break;
                        FORCEINTON;
                }
-               listsetvar(varlist.list, VEXPORT|VSTACK);
-               path = unlikely(path) ? path : pathval();
                shellexec(argv, path, cmdentry.u.index);
                /* NOTREACHED */
 
        case CMDBUILTIN:
-               if (spclbltin > 0 || argc == 0) {
-                       poplocalvars(1);
-                       if (execcmd && argc > 1)
-                               listsetvar(varlist.list, VEXPORT);
-               }
                if (evalbltin(cmdentry.u.cmd, argc, argv, flags) &&
                    !(exception == EXERROR && spclbltin <= 0)) {
 raise:
@@ -913,7 +922,8 @@ out:
                popredir(execcmd);
        unwindredir(redir_stop);
        unwindfiles(file_stop);
-       unwindlocalvars(localvar_stop);
+       if (likely(vlocal))
+               unwindlocalvars(localvar_stop);
        if (lastarg)
                /* dsl: I think this is intended to be used to support
                 * '_' in 'vi' command mode during line editing...
diff --git a/src/var.c b/src/var.c
index 604ab1f..40743e5 100644
--- a/src/var.c
+++ b/src/var.c
@@ -302,28 +302,6 @@ out:
        return vp;
 }
 
-
-
-/*
- * Process a linked list of variable assignments.
- */
-
-void
-listsetvar(struct strlist *list, int flags)
-{
-       struct strlist *lp;
-
-       lp = list;
-       if (!lp)
-               return;
-       INTOFF;
-       do {
-               setvareq(lp->text, flags);
-       } while ((lp = lp->next));
-       INTON;
-}
-
-
 /*
  * Find the value of a variable.  Returns NULL if not set.
  */
@@ -468,7 +446,7 @@ localcmd(int argc, char **argv)
 
        argv = argptr;
        while ((name = *argv++) != NULL) {
-               mklocal(name);
+               mklocal(name, 0);
        }
        return 0;
 }
@@ -481,7 +459,7 @@ localcmd(int argc, char **argv)
  * "-" as a special case.
  */
 
-void mklocal(char *name)
+void mklocal(char *name, int flags)
 {
        struct localvar *lvp;
        struct var **vpp;
@@ -502,16 +480,16 @@ void mklocal(char *name)
                eq = strchr(name, '=');
                if (vp == NULL) {
                        if (eq)
-                               vp = setvareq(name, VSTRFIXED);
+                               vp = setvareq(name, VSTRFIXED | flags);
                        else
-                               vp = setvar(name, NULL, VSTRFIXED);
+                               vp = setvar(name, NULL, VSTRFIXED | flags);
                        lvp->flags = VUNSET;
                } else {
                        lvp->text = vp->text;
                        lvp->flags = vp->flags;
                        vp->flags |= VSTRFIXED|VTEXTFIXED;
                        if (eq)
-                               setvareq(name, 0);
+                               setvareq(name, flags);
                }
        }
        lvp->vp = vp;
diff --git a/src/var.h b/src/var.h
index 55fed1b..b2054f7 100644
--- a/src/var.h
+++ b/src/var.h
@@ -139,7 +139,6 @@ struct var *setvar(const char *name, const char *val, int 
flags);
 intmax_t setvarint(const char *, intmax_t, int);
 struct var *setvareq(char *s, int flags);
 struct strlist;
-void listsetvar(struct strlist *, int);
 char *lookupvar(const char *);
 intmax_t lookupvarint(const char *);
 char **listvars(int, int, char ***);
@@ -147,7 +146,7 @@ char **listvars(int, int, char ***);
 int showvars(const char *, int, int);
 int exportcmd(int, char **);
 int localcmd(int, char **);
-void mklocal(char *);
+void mklocal(char *name, int flags);
 struct localvar_list *pushlocalvars(void);
 void poplocalvars(int);
 void unwindlocalvars(struct localvar_list *stop);
--
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