[VAR] Add localvars nesting

This patch adds localvars nesting infrastructure so we can reuse
the localvars mechanism for command evaluation.

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

 ChangeLog  |    4 ++++
 src/eval.c |    7 ++-----
 src/var.c  |   50 ++++++++++++++++++++++++++++++++++++++++++++------
 src/var.h  |    1 +
 4 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ee78154..7285a23 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-05-24  Herbert Xu <herb...@gondor.apana.org.au>
+
+       * Add localvars nesting.
+
 2010-05-03  Gerrit Pape <p...@smarden.org>
 
        * Fix command -- crash.
diff --git a/src/eval.c b/src/eval.c
index 62d9d5d..8d2767c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -928,20 +928,17 @@ STATIC int
 evalfun(struct funcnode *func, int argc, char **argv, int flags)
 {
        volatile struct shparam saveparam;
-       struct localvar *volatile savelocalvars;
        struct jmploc *volatile savehandler;
        struct jmploc jmploc;
        int e;
 
        saveparam = shellparam;
-       savelocalvars = localvars;
        if ((e = setjmp(jmploc.loc))) {
                goto funcdone;
        }
        INTOFF;
        savehandler = handler;
        handler = &jmploc;
-       localvars = NULL;
        shellparam.malloc = 0;
        func->count++;
        funcnest++;
@@ -950,13 +947,13 @@ evalfun(struct funcnode *func, int argc, char **argv, int 
flags)
        shellparam.p = argv + 1;
        shellparam.optind = 1;
        shellparam.optoff = -1;
+       pushlocalvars();
        evaltree(&func->n, flags & EV_TESTED);
+       poplocalvars();
 funcdone:
        INTOFF;
        funcnest--;
        freefunc(func);
-       poplocalvars();
-       localvars = savelocalvars;
        freeparam(&shellparam);
        shellparam = saveparam;
        handler = savehandler;
diff --git a/src/var.c b/src/var.c
index 2737fb1..de1a5f5 100644
--- a/src/var.c
+++ b/src/var.c
@@ -64,7 +64,12 @@
 #define VTABSIZE 39
 
 
-struct localvar *localvars;
+struct localvar_list {
+       struct localvar_list *next;
+       struct localvar *lv;
+};
+
+MKINIT struct localvar_list *localvar_stack;
 
 const char defpathvar[] =
        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
@@ -139,6 +144,11 @@ INIT {
                        p = 0;
        setpwd(p, 0);
 }
+
+RESET {
+       while (localvar_stack)
+               poplocalvars();
+}
 #endif
 
 
@@ -446,6 +456,9 @@ localcmd(int argc, char **argv)
 {
        char *name;
 
+       if (!localvar_stack)
+               sh_error("not in a function");
+
        argv = argptr;
        while ((name = *argv++) != NULL) {
                mklocal(name);
@@ -497,8 +510,8 @@ mklocal(char *name)
                }
        }
        lvp->vp = vp;
-       lvp->next = localvars;
-       localvars = lvp;
+       lvp->next = localvar_stack->lv;
+       localvar_stack->lv = lvp;
        INTON;
 }
 
@@ -511,11 +524,19 @@ mklocal(char *name)
 void
 poplocalvars(void)
 {
-       struct localvar *lvp;
+       struct localvar_list *ll;
+       struct localvar *lvp, *next;
        struct var *vp;
 
-       while ((lvp = localvars) != NULL) {
-               localvars = lvp->next;
+       INTOFF;
+       ll = localvar_stack;
+       localvar_stack = ll->next;
+
+       next = ll->lv;
+       ckfree(ll);
+
+       while ((lvp = next) != NULL) {
+               next = lvp->next;
                vp = lvp->vp;
                TRACE(("poplocalvar %s", vp ? vp->text : "-"));
                if (vp == NULL) {       /* $- saved */
@@ -534,6 +555,23 @@ poplocalvars(void)
                }
                ckfree(lvp);
        }
+       INTON;
+}
+
+
+/*
+ * Create a new localvar environment.
+ */
+void pushlocalvars(void)
+{
+       struct localvar_list *ll;
+
+       INTOFF;
+       ll = ckmalloc(sizeof(*ll));
+       ll->lv = NULL;
+       ll->next = localvar_stack;
+       localvar_stack = ll;
+       INTON;
 }
 
 
diff --git a/src/var.h b/src/var.h
index e4e2cff..32b0dde 100644
--- a/src/var.h
+++ b/src/var.h
@@ -139,6 +139,7 @@ char **listvars(int, int, char ***);
 int showvars(const char *, int, int);
 int exportcmd(int, char **);
 int localcmd(int, char **);
+void pushlocalvars(void);
 void poplocalvars(void);
 int unsetcmd(int, char **);
 int unsetvar(const char *);
--
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