From 2654cb43f63349cff06b3dd26932dd76f53aed4c Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sat, 26 Sep 2015 01:59:48 +0000 Subject: 36651: WARN_CREATE_GLOBAL += math expressions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this, '() { (( x=42 )) }' and '() { for (( i=0; … )) }' wouldn't warn about $x and $i, respectively, being created global. --- Src/exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/Src/exec.c b/Src/exec.c index 109a04a26..da808d6f1 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -176,7 +176,8 @@ mod_export int sfcontext; /**/ struct execstack *exstack; -/* Stack with names of functions currently active. */ +/* Stack with names of function calls, 'source' calls, and 'eval' calls + * currently active. */ /**/ mod_export Funcstack funcstack; -- cgit v1.2.3 From 2bf4f667fb41a8aba139e3ef93b1ebcd9f3e016d Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 30 Sep 2015 20:01:13 -0700 Subject: 36707: distinguish ERR_RETURN value of retflag so that execif() can ignore it in the test sublist --- ChangeLog | 3 +++ Src/exec.c | 2 +- Src/loop.c | 8 ++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 018585611..3f54075f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ 2015-09-30 Barton E. Schaefer + * 36707: Src/exec.c, Src/loop.c: distinguish ERR_RETURN value + of retflag so that execif() can ignore it in the test sublist + * cf. 36690: Doc/Zsh/builtins.yo: remove sentence fragment 2015-09-30 Daniel Shahaf diff --git a/Src/exec.c b/Src/exec.c index da808d6f1..154bbb8db 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1408,7 +1408,7 @@ sublist_done: exit(lastval); } if (errreturn) { - retflag = 1; + retflag = 2; breaks = loops; } } diff --git a/Src/loop.c b/Src/loop.c index 4def9b652..7d1528efe 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -552,8 +552,12 @@ execif(Estate state, int do_exec) run = 1; break; } - if (retflag) - break; + if (retflag) { + if (retflag == 2) + retflag = 0; /* Never ERR_RETURN here */ + else + break; + } s = 1; state->pc = next; } -- cgit v1.2.3 From b581c3fece76c87ed86ae9fc704d0fcf208a79d3 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 3 Oct 2015 19:40:14 -0700 Subject: 36766: fix incorrect reset of noerrexit during "if" conditions --- ChangeLog | 5 +++++ Src/exec.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index e45273e68..a5a235389 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-03 Barton E. Schaefer + + * 36766: Src/exec.c: fix incorrect reset of noerrexit during + "if" conditions + 2015-10-03 Peter Stephenson * 36760: Src/pattern.c: ensure we don't do anything untoward diff --git a/Src/exec.c b/Src/exec.c index 154bbb8db..235faf3ba 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1364,7 +1364,8 @@ sublist_done: * we hit execcmd on the way down. We're now * on the way back up, so don't restore it. */ - noerrexit = (oldnoerrexit == 2) ? 0 : oldnoerrexit; + if (oldnoerrexit != 2) + noerrexit = oldnoerrexit; if (sigtrapped[SIGDEBUG] && !isset(DEBUGBEFORECMD) && !donedebug) { /* -- cgit v1.2.3 From cb26e11c70f95c72e300e1f4f16b33e4e5f54d21 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 3 Oct 2015 22:11:09 -0700 Subject: unposted: back out 36707, add test case for 36766 --- ChangeLog | 4 ++++ Src/exec.c | 2 +- Src/loop.c | 8 ++------ Test/C03traps.ztst | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 7 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index a5a235389..aa2253522 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2015-10-03 Barton E. Schaefer + * unposted (cf. 36696): Test/C03traps.ztst: test case for 36766 + + * unposted: Src/exec.c, Src/loop.c: back out 36707, fixed by 36766 + * 36766: Src/exec.c: fix incorrect reset of noerrexit during "if" conditions diff --git a/Src/exec.c b/Src/exec.c index 235faf3ba..bcc8065a2 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1409,7 +1409,7 @@ sublist_done: exit(lastval); } if (errreturn) { - retflag = 2; + retflag = 1; breaks = loops; } } diff --git a/Src/loop.c b/Src/loop.c index 7d1528efe..4def9b652 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -552,12 +552,8 @@ execif(Estate state, int do_exec) run = 1; break; } - if (retflag) { - if (retflag == 2) - retflag = 0; /* Never ERR_RETURN here */ - else - break; - } + if (retflag) + break; s = 1; state->pc = next; } diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index d179dc46d..4b2843a47 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -450,6 +450,20 @@ fn 1:ERRRETURN in "else" branch (regression test) + $ZTST_testdir/../Src/zsh -f =(<<<" + if false; then + : + else + if [[ -n '' ]]; then + a=2 + fi + print Yes + fi + ") +0:ERRRETURN when false "if" is the first statement in an "else" (regression) +>Yes +F:Must be tested with a top-level script rather than source or function + %clean rm -f TRAPEXIT -- cgit v1.2.3 From 827d36077641ca87d1796b9c5cb05e7c44b01919 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 14 Oct 2015 21:46:26 -0700 Subject: 36853: replace pushheap/popheap by NEWHEAPS/OLDHEAPS in doshfunc() to optimize memory management Includes re-indentation that was not done in the posted patch. --- ChangeLog | 5 + Src/exec.c | 402 ++++++++++++++++++++++++++++++------------------------------- 2 files changed, 206 insertions(+), 201 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 2e31d243b..f0c88c979 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-14 Barton E. Schaefer + + * 36853: Src/exec.c: replace pushheap/popheap by NEWHEAPS/OLDHEAPS + in doshfunc() to optimize memory management + 2015-10-14 Peter Stephenson * 36856: Doc/Zsh/contrib.yo, Functions/Chpwd/cdr: add -p and -P diff --git a/Src/exec.c b/Src/exec.c index bcc8065a2..f0d1d2f70 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -5067,230 +5067,230 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) #ifdef MAX_FUNCTION_DEPTH static int funcdepth; #endif + Heap funcheap; queue_signals(); /* Lots of memory and global state changes coming */ - pushheap(); + NEWHEAPS(funcheap) { + oargv0 = NULL; + obreaks = breaks; + ocontflag = contflag; + oloops = loops; + if (trap_state == TRAP_STATE_PRIMED) + trap_return--; + oldlastval = lastval; + oldnumpipestats = numpipestats; + if (noreturnval) { + /* + * Easiest to use the heap here since we're bracketed + * immediately by a pushheap/popheap pair. + */ + size_t bytes = sizeof(int)*numpipestats; + oldpipestats = (int *)zhalloc(bytes); + memcpy(oldpipestats, pipestats, bytes); + } - oargv0 = NULL; - obreaks = breaks; - ocontflag = contflag; - oloops = loops; - if (trap_state == TRAP_STATE_PRIMED) - trap_return--; - oldlastval = lastval; - oldnumpipestats = numpipestats; - if (noreturnval) { - /* - * Easiest to use the heap here since we're bracketed - * immediately by a pushheap/popheap pair. - */ - size_t bytes = sizeof(int)*numpipestats; - oldpipestats = (int *)zhalloc(bytes); - memcpy(oldpipestats, pipestats, bytes); - } + starttrapscope(); + startpatternscope(); + + pptab = pparams; + if (!(flags & PM_UNDEFINED)) + scriptname = dupstring(name); + oldzoptind = zoptind; + oldoptcind = optcind; + if (!isset(POSIXBUILTINS)) { + zoptind = 1; + optcind = 0; + } - starttrapscope(); - startpatternscope(); - - pptab = pparams; - if (!(flags & PM_UNDEFINED)) - scriptname = dupstring(name); - oldzoptind = zoptind; - oldoptcind = optcind; - if (!isset(POSIXBUILTINS)) { - zoptind = 1; - optcind = 0; - } + /* We need to save the current options even if LOCALOPTIONS is * + * not currently set. That's because if it gets set in the * + * function we need to restore the original options on exit. */ + memcpy(saveopts, opts, sizeof(opts)); + saveemulation = emulation; + save_sticky = sticky; - /* We need to save the current options even if LOCALOPTIONS is * - * not currently set. That's because if it gets set in the * - * function we need to restore the original options on exit. */ - memcpy(saveopts, opts, sizeof(opts)); - saveemulation = emulation; - save_sticky = sticky; + if (sticky_emulation_differs(shfunc->sticky)) { + /* + * Function is marked for sticky emulation. + * Enable it now. + * + * We deliberately do not do this if the sticky emulation + * in effect is the same as that requested. This enables + * option setting naturally within emulation environments. + * Note that a difference in EMULATE_FULLY (emulate with + * or without -R) counts as a different environment. + * + * This propagates the sticky emulation to subfunctions. + */ + sticky = sticky_emulation_dup(shfunc->sticky, 1); + emulation = sticky->emulation; + restore_sticky = 1; + installemulation(emulation, opts); + if (sticky->n_on_opts) { + OptIndex *onptr; + for (onptr = sticky->on_opts; + onptr < sticky->on_opts + sticky->n_on_opts; + onptr++) + opts[*onptr] = 1; + } + if (sticky->n_off_opts) { + OptIndex *offptr; + for (offptr = sticky->off_opts; + offptr < sticky->off_opts + sticky->n_off_opts; + offptr++) + opts[*offptr] = 0; + } + /* All emulations start with pattern disables clear */ + clearpatterndisables(); + } else + restore_sticky = 0; - if (sticky_emulation_differs(shfunc->sticky)) { + if (flags & (PM_TAGGED|PM_TAGGED_LOCAL)) + opts[XTRACE] = 1; + else if (oflags & PM_TAGGED_LOCAL) + opts[XTRACE] = 0; + ooflags = oflags; /* - * Function is marked for sticky emulation. - * Enable it now. - * - * We deliberately do not do this if the sticky emulation - * in effect is the same as that requested. This enables - * option setting naturally within emulation environments. - * Note that a difference in EMULATE_FULLY (emulate with - * or without -R) counts as a different environment. - * - * This propagates the sticky emulation to subfunctions. + * oflags is static, because we compare it on the next recursive + * call. Hence also we maintain ooflags for restoring the previous + * value of oflags after the call. */ - sticky = sticky_emulation_dup(shfunc->sticky, 1); - emulation = sticky->emulation; - restore_sticky = 1; - installemulation(emulation, opts); - if (sticky->n_on_opts) { - OptIndex *onptr; - for (onptr = sticky->on_opts; - onptr < sticky->on_opts + sticky->n_on_opts; - onptr++) - opts[*onptr] = 1; - } - if (sticky->n_off_opts) { - OptIndex *offptr; - for (offptr = sticky->off_opts; - offptr < sticky->off_opts + sticky->n_off_opts; - offptr++) - opts[*offptr] = 0; - } - /* All emulations start with pattern disables clear */ - clearpatterndisables(); - } else - restore_sticky = 0; - - if (flags & (PM_TAGGED|PM_TAGGED_LOCAL)) - opts[XTRACE] = 1; - else if (oflags & PM_TAGGED_LOCAL) - opts[XTRACE] = 0; - ooflags = oflags; - /* - * oflags is static, because we compare it on the next recursive - * call. Hence also we maintain ooflags for restoring the previous - * value of oflags after the call. - */ - oflags = flags; - opts[PRINTEXITVALUE] = 0; - if (doshargs) { - LinkNode node; - - node = firstnode(doshargs); - pparams = x = (char **) zshcalloc(((sizeof *x) * - (1 + countlinknodes(doshargs)))); - if (isset(FUNCTIONARGZERO)) { - oargv0 = argzero; - argzero = ztrdup(getdata(node)); - } - /* first node contains name regardless of option */ - node = node->next; - for (; node; node = node->next, x++) - *x = ztrdup(getdata(node)); - } else { - pparams = (char **) zshcalloc(sizeof *pparams); - if (isset(FUNCTIONARGZERO)) { - oargv0 = argzero; - argzero = ztrdup(argzero); + oflags = flags; + opts[PRINTEXITVALUE] = 0; + if (doshargs) { + LinkNode node; + + node = firstnode(doshargs); + pparams = x = (char **) zshcalloc(((sizeof *x) * + (1 + countlinknodes(doshargs)))); + if (isset(FUNCTIONARGZERO)) { + oargv0 = argzero; + argzero = ztrdup(getdata(node)); + } + /* first node contains name regardless of option */ + node = node->next; + for (; node; node = node->next, x++) + *x = ztrdup(getdata(node)); + } else { + pparams = (char **) zshcalloc(sizeof *pparams); + if (isset(FUNCTIONARGZERO)) { + oargv0 = argzero; + argzero = ztrdup(argzero); + } } - } #ifdef MAX_FUNCTION_DEPTH - if(++funcdepth > MAX_FUNCTION_DEPTH) - { - zerr("maximum nested function level reached"); - goto undoshfunc; - } + if(++funcdepth > MAX_FUNCTION_DEPTH) + { + zerr("maximum nested function level reached"); + goto undoshfunc; + } #endif - fstack.name = dupstring(name); - /* - * The caller is whatever is immediately before on the stack, - * unless we're at the top, in which case it's the script - * or interactive shell name. - */ - fstack.caller = funcstack ? funcstack->name : - dupstring(oargv0 ? oargv0 : argzero); - fstack.lineno = lineno; - fstack.prev = funcstack; - fstack.tp = FS_FUNC; - funcstack = &fstack; - - fstack.flineno = shfunc->lineno; - fstack.filename = dupstring(shfunc->filename); - - prog = shfunc->funcdef; - if (prog->flags & EF_RUN) { - Shfunc shf; + fstack.name = dupstring(name); + /* + * The caller is whatever is immediately before on the stack, + * unless we're at the top, in which case it's the script + * or interactive shell name. + */ + fstack.caller = funcstack ? funcstack->name : + dupstring(oargv0 ? oargv0 : argzero); + fstack.lineno = lineno; + fstack.prev = funcstack; + fstack.tp = FS_FUNC; + funcstack = &fstack; - prog->flags &= ~EF_RUN; + fstack.flineno = shfunc->lineno; + fstack.filename = dupstring(shfunc->filename); - runshfunc(prog, NULL, fstack.name); + prog = shfunc->funcdef; + if (prog->flags & EF_RUN) { + Shfunc shf; - if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, - (name = fname)))) { - zwarn("%s: function not defined by file", name); - if (noreturnval) - errflag |= ERRFLAG_ERROR; - else - lastval = 1; - goto doneshfunc; + prog->flags &= ~EF_RUN; + + runshfunc(prog, NULL, fstack.name); + + if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, + (name = fname)))) { + zwarn("%s: function not defined by file", name); + if (noreturnval) + errflag |= ERRFLAG_ERROR; + else + lastval = 1; + goto doneshfunc; + } + prog = shf->funcdef; } - prog = shf->funcdef; - } - runshfunc(prog, wrappers, fstack.name); - doneshfunc: - funcstack = fstack.prev; + runshfunc(prog, wrappers, fstack.name); + doneshfunc: + funcstack = fstack.prev; #ifdef MAX_FUNCTION_DEPTH - undoshfunc: - --funcdepth; + undoshfunc: + --funcdepth; #endif - if (retflag) { - retflag = 0; - breaks = obreaks; - } - freearray(pparams); - if (oargv0) { - zsfree(argzero); - argzero = oargv0; - } - pparams = pptab; - if (!isset(POSIXBUILTINS)) { - zoptind = oldzoptind; - optcind = oldoptcind; - } - scriptname = oldscriptname; - oflags = ooflags; + if (retflag) { + retflag = 0; + breaks = obreaks; + } + freearray(pparams); + if (oargv0) { + zsfree(argzero); + argzero = oargv0; + } + pparams = pptab; + if (!isset(POSIXBUILTINS)) { + zoptind = oldzoptind; + optcind = oldoptcind; + } + scriptname = oldscriptname; + oflags = ooflags; - endpatternscope(); /* before restoring old LOCALPATTERNS */ + endpatternscope(); /* before restoring old LOCALPATTERNS */ - if (restore_sticky) { - /* - * If we switched to an emulation environment just for - * this function, we interpret the option and emulation - * switch as being a firewall between environments. - */ - memcpy(opts, saveopts, sizeof(opts)); - emulation = saveemulation; - sticky = save_sticky; - } else if (isset(LOCALOPTIONS)) { - /* restore all shell options except PRIVILEGED and RESTRICTED */ - saveopts[PRIVILEGED] = opts[PRIVILEGED]; - saveopts[RESTRICTED] = opts[RESTRICTED]; - memcpy(opts, saveopts, sizeof(opts)); - emulation = saveemulation; - } else { - /* just restore a couple. */ - opts[XTRACE] = saveopts[XTRACE]; - opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE]; - opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS]; - opts[LOCALLOOPS] = saveopts[LOCALLOOPS]; - } + if (restore_sticky) { + /* + * If we switched to an emulation environment just for + * this function, we interpret the option and emulation + * switch as being a firewall between environments. + */ + memcpy(opts, saveopts, sizeof(opts)); + emulation = saveemulation; + sticky = save_sticky; + } else if (isset(LOCALOPTIONS)) { + /* restore all shell options except PRIVILEGED and RESTRICTED */ + saveopts[PRIVILEGED] = opts[PRIVILEGED]; + saveopts[RESTRICTED] = opts[RESTRICTED]; + memcpy(opts, saveopts, sizeof(opts)); + emulation = saveemulation; + } else { + /* just restore a couple. */ + opts[XTRACE] = saveopts[XTRACE]; + opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE]; + opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS]; + opts[LOCALLOOPS] = saveopts[LOCALLOOPS]; + } - if (opts[LOCALLOOPS]) { - if (contflag) - zwarn("`continue' active at end of function scope"); - if (breaks) - zwarn("`break' active at end of function scope"); - breaks = obreaks; - contflag = ocontflag; - loops = oloops; - } + if (opts[LOCALLOOPS]) { + if (contflag) + zwarn("`continue' active at end of function scope"); + if (breaks) + zwarn("`break' active at end of function scope"); + breaks = obreaks; + contflag = ocontflag; + loops = oloops; + } - endtrapscope(); + endtrapscope(); - if (trap_state == TRAP_STATE_PRIMED) - trap_return++; - ret = lastval; - if (noreturnval) { - lastval = oldlastval; - numpipestats = oldnumpipestats; - memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats); - } - popheap(); + if (trap_state == TRAP_STATE_PRIMED) + trap_return++; + ret = lastval; + if (noreturnval) { + lastval = oldlastval; + numpipestats = oldnumpipestats; + memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats); + } + } OLDHEAPS; unqueue_signals(); -- cgit v1.2.3 From 830d54e629e8e12eb5a219a65a013876662e7b3e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 11 Nov 2015 18:04:20 +0000 Subject: 37092: make nested ${(P)name} properly refer to parameter on return --- ChangeLog | 5 +++ Doc/Zsh/expn.yo | 11 ++++- Src/Zle/compctl.c | 4 +- Src/Zle/zle_tricky.c | 2 +- Src/cond.c | 2 +- Src/exec.c | 16 ++++---- Src/glob.c | 2 +- Src/subst.c | 114 +++++++++++++++++++++++++++++++-------------------- Src/zsh.h | 51 +++++++++++++++++------ 9 files changed, 138 insertions(+), 69 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 5f6c59c0a..e9bef7d68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2015-11-11 Peter Stephenson + * 37092: Doc/Zsh/expn.yo, Src/Zle/compctl.c, + Src/Zle/zle_tricky.c, Src/cond.c, Src/exec.c, Src/glob.c, + Src/subst.c, Src/zsh.h: make a ${(P)name} subexpression properly + refer to a parameter name. + * 37091: Src/Zle/zle_utils.c: clear lastline and lastlinesz when freeing. diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 20e0c8d35..4c373d1f2 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -1033,7 +1033,16 @@ var(name) used in this fashion. If used with a nested parameter or command substitution, the result of that will be taken as a parameter name in the same way. For example, if you have `tt(foo=bar)' and `tt(bar=baz)', the strings tt(${(P)foo}), -tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to `tt(baz)'. +tt(${(P)${foo}}), and tt(${(P)$(echo bar)}) will be expanded to +`tt(baz)'. + +Likewise, if the reference is itself nested, the expression with the +flag is treated as if it were directly replaced by the parameter name. +It is an error if this nested substitution produces an array with more +than one word. For example, if `tt(name=assoc)' where the parameter +tt(assoc) is an associative array, then +`tt(${${(P)name}[elt]})' refers to the element of the associative +subscripted `tt(elt)'. ) item(tt(q))( Quote characters that are special to the shell in the resulting words with diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index bac533e7e..8381867d0 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2116,7 +2116,7 @@ getreal(char *str) noerrs = 1; addlinknode(l, dupstring(str)); - prefork(l, 0); + prefork(l, 0, NULL); noerrs = ne; if (!errflag && nonempty(l) && ((char *) peekfirst(l)) && ((char *) peekfirst(l))[0]) @@ -3728,7 +3728,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) errflag &= ~ERRFLAG_ERROR; zcontext_restore(); /* Fine, now do full expansion. */ - prefork(foo, 0); + prefork(foo, 0, NULL); if (!errflag) { globlist(foo, 0); if (!errflag) diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index e26f66379..4e6854928 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2223,7 +2223,7 @@ doexpansion(char *s, int lst, int olst, int explincmd) else if (*ts == '\'') *ts = Snull; addlinknode(vl, ss); - prefork(vl, 0); + prefork(vl, 0, NULL); if (errflag) goto end; if (lst == COMP_LIST_EXPAND || lst == COMP_EXPAND) { diff --git a/Src/cond.c b/Src/cond.c index df9065660..c5ab65eea 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -43,7 +43,7 @@ static void cond_subst(char **strp, int glob_ok) checkglobqual(*strp, strlen(*strp), 1, NULL)) { LinkList args = newlinklist(); addlinknode(args, *strp); - prefork(args, 0); + prefork(args, 0, NULL); while (!errflag && args && nonempty(args) && has_token((char *)peekfirst(args))) zglob(args, firstnode(args), 0); diff --git a/Src/exec.c b/Src/exec.c index f0d1d2f70..c0ee527b7 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2290,7 +2290,7 @@ addvars(Estate state, Wordcode pc, int addflags) if (vl && htok) { prefork(vl, (isstr ? (PREFORK_SINGLE|PREFORK_ASSIGN) : - PREFORK_ASSIGN)); + PREFORK_ASSIGN), NULL); if (errflag) { state->pc = opc; return; @@ -2416,7 +2416,7 @@ void execsubst(LinkList strs) { if (strs) { - prefork(strs, esprefork); + prefork(strs, esprefork, NULL); if (esglob && !errflag) { LinkList ostrs = strs; globlist(strs, 0); @@ -2721,7 +2721,7 @@ execcmd(Estate state, int input, int output, int how, int last1) /* Do prefork substitutions */ esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0; if (args && htok) - prefork(args, esprefork); + prefork(args, esprefork, NULL); if (type == WC_SIMPLE || type == WC_TYPESET) { int unglobbed = 0; @@ -3558,7 +3558,7 @@ execcmd(Estate state, int input, int output, int how, int last1) */ /* Unused dummy value for name */ (void)ecgetstr(state, EC_DUPTOK, &htok); - prefork(&svl, PREFORK_TYPESET); + prefork(&svl, PREFORK_TYPESET, NULL); if (errflag) { state->pc = opc; break; @@ -3584,7 +3584,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } continue; } - prefork(&svl, PREFORK_SINGLE); + prefork(&svl, PREFORK_SINGLE, NULL); name = empty(&svl) ? "" : (char *)getdata(firstnode(&svl)); } @@ -3600,7 +3600,9 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { if (htok) { init_list1(svl, val); - prefork(&svl, PREFORK_SINGLE|PREFORK_ASSIGN); + prefork(&svl, + PREFORK_SINGLE|PREFORK_ASSIGN, + NULL); if (errflag) { state->pc = opc; break; @@ -3622,7 +3624,7 @@ execcmd(Estate state, int input, int output, int how, int last1) EC_DUPTOK, &htok); if (asg->value.array) { - prefork(asg->value.array, PREFORK_ASSIGN); + prefork(asg->value.array, PREFORK_ASSIGN, NULL); if (errflag) { state->pc = opc; break; diff --git a/Src/glob.c b/Src/glob.c index 51ffeb5d5..94b3f620d 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2093,7 +2093,7 @@ xpandredir(struct redir *fn, LinkList redirtab) /* Stick the name in a list... */ init_list1(fake, fn->name); /* ...which undergoes all the usual shell expansions */ - prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE); + prefork(&fake, isset(MULTIOS) ? 0 : PREFORK_SINGLE, NULL); /* Globbing is only done for multios. */ if (!errflag && isset(MULTIOS)) globlist(&fake, 0); diff --git a/Src/subst.c b/Src/subst.c index febdc9bea..f3a4ad44d 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -44,15 +44,23 @@ char nulstring[] = {Nularg, '\0'}; * - Brace expansion * - Tilde and equals substitution * - * PREFORK_* flags are defined in zsh.h + * "flag"s contains PREFORK_* flags, defined in zsh.h. + * + * "ret_flags" is used to return values from nested parameter + * substitions. It may be NULL in which case PREFORK_SUBEXP + * must not appear in flags; any return value from below + * will be discarded. */ /**/ mod_export void -prefork(LinkList list, int flags) +prefork(LinkList list, int flags, int *ret_flags) { LinkNode node, stop = 0; int keep = 0, asssub = (flags & PREFORK_TYPESET) && isset(KSHTYPESET); + int ret_flags_local = 0; + if (!ret_flags) + ret_flags = &ret_flags_local; /* will be discarded */ queue_signals(); for (node = firstnode(list); node; incnode(node)) { @@ -75,10 +83,8 @@ prefork(LinkList list, int flags) setdata(node, cptr); } if (!(node = stringsubst(list, node, - flags & (PREFORK_SINGLE|PREFORK_SPLIT| - PREFORK_SHWORDSPLIT| - PREFORK_NOSHWORDSPLIT), - asssub))) { + flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN), + ret_flags, asssub))) { unqueue_signals(); return; } @@ -149,7 +155,8 @@ stringsubstquote(char *strstart, char **pstrdpos) /**/ static LinkNode -stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub) +stringsubst(LinkList list, LinkNode node, int pf_flags, int *ret_flags, + int asssub) { int qt; char *str3 = (char *)getdata(node); @@ -235,7 +242,8 @@ stringsubst(LinkList list, LinkNode node, int pf_flags, int asssub) pf_flags |= PREFORK_SHWORDSPLIT; node = paramsubst( list, node, &str, qt, - pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT)); + pf_flags & (PREFORK_SINGLE|PREFORK_SHWORDSPLIT| + PREFORK_SUBEXP), ret_flags); if (errflag || !node) return NULL; str3 = (char *)getdata(node); @@ -413,29 +421,13 @@ singsub(char **s) init_list1(foo, *s); - prefork(&foo, PREFORK_SINGLE); + prefork(&foo, PREFORK_SINGLE, NULL); if (errflag) return; *s = (char *) ugetnode(&foo); DPUTS(nonempty(&foo), "BUG: singsub() produced more than one word!"); } -/* - * Bit flags passed back from multsub() to paramsubst(). - */ -enum { - /* - * Set if the string had whitespace at the start - * that should cause word splitting against any preceeding string. - */ - WS_AT_START = 1, - /* - * Set if the string had whitespace at the end - * that should cause word splitting against any following string. - */ - WS_AT_END = 2 -}; - /* Perform substitution on a single word, *s. Unlike with singsub(), the * result can be more than one word. If split is non-zero, the string is * first word-split using IFS, but only for non-quoted "whitespace" (as @@ -448,13 +440,13 @@ enum { * NULL to use IFS). The return value is true iff the expansion resulted * in an empty list. * - * *ws_at_start is set to bits in the enum above as neeed. + * *ms_flags is set to bits in the enum above as neeed. */ /**/ static int multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, - int *ws_sub) + int *ms_flags) { int l; char **r, **p, *x = *s; @@ -470,7 +462,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, l++; if (!iwsep(STOUC(c))) break; - *ws_sub |= WS_AT_START; + *ms_flags |= MULTSUB_WS_AT_START; } } @@ -503,7 +495,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, break; } if (!*x) { - *ws_sub |= WS_AT_END; + *ms_flags |= MULTSUB_WS_AT_END; break; } insertlinknode(&foo, n, (void *)x), incnode(n); @@ -532,7 +524,7 @@ multsub(char **s, int pf_flags, char ***a, int *isarr, char *sep, } } - prefork(&foo, pf_flags); + prefork(&foo, pf_flags, ms_flags); if (errflag) { if (isarr) *isarr = 0; @@ -1517,7 +1509,8 @@ check_colon_subscript(char *str, char **endp) /**/ static LinkNode -paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) +paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, + int *ret_flags) { char *aptr = *str, c, cc; char *s = aptr, *fstr, *idbeg, *idend, *ostr = (char *) getdata(n); @@ -1747,7 +1740,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * whitespace. However, if there's no "x" the whitespace is * simply removed. */ - int ws_sub = 0; + int ms_flags = 0; *s++ = '\0'; /* @@ -2296,8 +2289,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * remove the aspar test and extract a value from an array, if * necessary, when we handle (P) lower down. */ - if (multsub(&val, 0, (aspar ? NULL : &aval), &isarr, NULL, - &ws_sub) && quoted) { + if (multsub(&val, PREFORK_SUBEXP, (aspar ? NULL : &aval), &isarr, NULL, + &ms_flags) && quoted) { /* Empty quoted string --- treat as null string, not elided */ isarr = -1; aval = (char **) hcalloc(sizeof(char *)); @@ -2311,6 +2304,28 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) */ while (inull(*s)) s++; + if (ms_flags & MULTSUB_PARAM_NAME) { + /* + * Downbelow has told us this is a parameter name, e.g. + * ${${(P)name}...}. We're going to behave as if + * we have exactly that name followed by the rest of + * the parameter for subscripting etc. + * + * See below for where we set the flag in the nested + * substitution. + */ + if (isarr) { + if (aval[1]) { + zerr("parameter name reference used with array"); + return NULL; + } + val = aval[0]; + isarr = 0; + } + s = dyncat(val, s); + /* Now behave po-faced as if it was always like that... */ + subexp = aspar = 0; + } v = (Value) NULL; } else if (aspar) { /* @@ -2328,13 +2343,24 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } else vunset = 1; } + if (aspar && (pf_flags & PREFORK_SUBEXP)) { + /* + * This is the inner handling for the case referred to above + * where we have something like ${${(P)name}...}. + * + * Treat this as as a normal value here; all transformations on + * result are in outer instance. + */ + aspar = 0; + *ret_flags |= MULTSUB_PARAM_NAME; + } /* * We need to retrieve a value either if we haven't already * got it from a subexpression, or if the processing so * far has just yielded us a parameter name to be processed * with (P). */ - if (!subexp || aspar) { + else if (!subexp || aspar) { char *ov = val; /* @@ -2768,7 +2794,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) split_flags = PREFORK_NOSHWORDSPLIT; } multsub(&val, split_flags, (aspar ? NULL : &aval), - &isarr, NULL, &ws_sub); + &isarr, NULL, &ms_flags); copied = 1; spbreak = 0; /* Leave globsubst on if forced */ @@ -2797,14 +2823,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * behavior on caller choice of PREFORK_SHWORDSPLIT. */ multsub(&val, spbreak ? PREFORK_SINGLE : PREFORK_NOSHWORDSPLIT, - NULL, &isarr, NULL, &ws_sub); + NULL, &isarr, NULL, &ms_flags); } else { if (spbreak) split_flags = PREFORK_SPLIT|PREFORK_SHWORDSPLIT; else split_flags = PREFORK_NOSHWORDSPLIT; multsub(&val, split_flags, &aval, &isarr, NULL, - &ws_sub); + &ms_flags); spbreak = 0; } if (arrasg) { @@ -3336,7 +3362,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } if (haserr || errflag) return NULL; - ws_sub = 0; + ms_flags = 0; } /* * This handles taking a length with ${#foo} and variations. @@ -3375,7 +3401,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) sprintf(buf, "%ld", len); val = dupstring(buf); isarr = 0; - ws_sub = 0; + ms_flags = 0; } /* At this point we make sure that our arrayness has affected the * arrayness of the linked list. Then, we can turn our value into @@ -3405,7 +3431,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) if (isarr) { val = sepjoin(aval, sep, 1); isarr = 0; - ws_sub = 0; + ms_flags = 0; } if (!ssub && (spbreak || spsep)) { aval = sepsplit(val, spsep, 0, 1); @@ -3690,12 +3716,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * If a multsub result had whitespace at the start and we're * splitting and there's a previous string, now's the time to do so. */ - if ((ws_sub & WS_AT_START) && aptr > ostr) { + if ((ms_flags & MULTSUB_WS_AT_START) && aptr > ostr) { insertlinknode(l, n, dupstrpfx(ostr, aptr - ostr)), incnode(n); ostr = aptr; } /* Likewise at the end */ - if ((ws_sub & WS_AT_END) && *fstr) { + if ((ms_flags & MULTSUB_WS_AT_END) && *fstr) { insertlinknode(l, n, dupstring(fstr)); /* appended, no incnode */ *fstr = '\0'; } @@ -3777,7 +3803,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) *--fstr = Marker; init_list1(tl, fstr); - if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, 0)) + if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, ret_flags, 0)) return NULL; *str = aptr; tn = firstnode(&tl); diff --git a/Src/zsh.h b/Src/zsh.h index a6f039741..d3bfcefcc 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1866,18 +1866,45 @@ enum { }; /* Flags as the second argument to prefork */ -/* argument handled like typeset foo=bar */ -#define PREFORK_TYPESET 0x01 -/* argument handled like the RHS of foo=bar */ -#define PREFORK_ASSIGN 0x02 -/* single word substitution */ -#define PREFORK_SINGLE 0x04 -/* explicitly split nested substitution */ -#define PREFORK_SPLIT 0x08 -/* SHWORDSPLIT in parameter expn */ -#define PREFORK_SHWORDSPLIT 0x10 -/* SHWORDSPLIT forced off in nested subst */ -#define PREFORK_NOSHWORDSPLIT 0x20 +enum { + /* argument handled like typeset foo=bar */ + PREFORK_TYPESET = 0x01, + /* argument handled like the RHS of foo=bar */ + PREFORK_ASSIGN = 0x02, + /* single word substitution */ + PREFORK_SINGLE = 0x04, + /* explicitly split nested substitution */ + PREFORK_SPLIT = 0x08, + /* SHWORDSPLIT in parameter expn */ + PREFORK_SHWORDSPLIT = 0x10, + /* SHWORDSPLIT forced off in nested subst */ + PREFORK_NOSHWORDSPLIT = 0x20, + /* Prefork is part of a parameter subexpression */ + PREFORK_SUBEXP = 0x40 +}; + +/* + * Bit flags passed back from multsub() to paramsubst(). + * Some flags go from a nested parmsubst() through the enclosing + * stringsubst() and prefork(). + */ +enum { + /* + * Set if the string had whitespace at the start + * that should cause word splitting against any preceeding string. + */ + MULTSUB_WS_AT_START = 1, + /* + * Set if the string had whitespace at the end + * that should cause word splitting against any following string. + */ + MULTSUB_WS_AT_END = 2, + /* + * Set by nested paramsubst() to indicate the return + * value is a parameter name, rather than a value. + */ + MULTSUB_PARAM_NAME = 4 +}; /* * Structure for adding parameters in a module. -- cgit v1.2.3