diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/eval.c | 7 | ||||
-rw-r--r-- | src/var.c | 50 | ||||
-rw-r--r-- | src/var.h | 1 |
3 files changed, 47 insertions, 11 deletions
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 *); |