From cf6b0f5663e798c8d4303697115230ac4469baca Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 29 Sep 2014 21:02:59 +0100 Subject: 33285: apply function definition redirections at execution --- Src/exec.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 4 deletions(-) (limited to 'Src/exec.c') diff --git a/Src/exec.c b/Src/exec.c index fb2739acc..1c2a9044c 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -198,7 +198,8 @@ static char *blank_env[] = { NULL }; /* Execution functions. */ static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = { - execcursh, exectime, execfuncdef, execfor, execselect, + execcursh, exectime, NULL /* execfuncdef handled specially */, + execfor, execselect, execwhile, execrepeat, execcase, execif, execcond, execarith, execautofn, exectry }; @@ -1116,8 +1117,11 @@ execsimple(Estate state) fflush(xtrerr); } lv = (errflag ? errflag : cmdoutval); - } else + } else if (code == WC_FUNCDEF) { + lv = execfuncdef(state, NULL); + } else { lv = (execfuncs[code - WC_CURSH])(state, 0); + } thisjob = otj; @@ -2790,6 +2794,42 @@ execcmd(Estate state, int input, int output, int how, int last1) return; } + if (type == WC_FUNCDEF) { + /* + * The first word of a function definition is a list of + * names. If this is empty, we're doing an anonymous function: + * in that case redirections are handled normally. + * If not, it's a function definition: then we don't do + * redirections here but pass in the list of redirections to + * be stored for recall with the function. + */ + if (*state->pc != 0) { + /* Nonymous, don't do redirections here */ + redir = NULL; + } + } else if (is_shfunc) { + Shfunc shf = (Shfunc)hn; + /* + * A function definition may have a list of additional + * redirections to apply, so retrieve it. + */ + if (shf->redir) { + struct estate s; + LinkList redir2; + + s.prog = shf->redir; + s.pc = shf->redir->prog; + s.strs = shf->redir->strs; + redir2 = ecgetredirs(&s); + if (!redir) + redir = redir2; + else { + while (nonempty(redir2)) + addlinknode(redir, ugetnode(redir2)); + } + } + } + if (type == WC_SIMPLE && !nullexec) { char *s; char trycd = (isset(AUTOCD) && isset(SHINSTDIN) && @@ -3238,7 +3278,33 @@ execcmd(Estate state, int input, int output, int how, int last1) flags |= ESUB_REVERTPGRP; entersubsh(flags); } - if (type >= WC_CURSH) { + if (type == WC_FUNCDEF) { + Eprog redir_prog; + if (!redir && wc_code(*beg) == WC_REDIR) { + /* + * We're not using a redirection from the currently + * parsed environment, which is what we'd do for an + * anonymous function, but there are redirections we + * should store with the new function. + */ + struct estate s; + + s.prog = state->prog; + s.pc = beg; + s.strs = state->prog->strs; + + /* + * The copy uses the wordcode parsing area, so save and + * restore state. + */ + lexsave(); + redir_prog = eccopyredirs(&s); + lexrestore(); + } else + redir_prog = NULL; + + lastval = execfuncdef(state, redir_prog); + } else if (type >= WC_CURSH) { if (last1 == 1) do_exec = 1; lastval = (execfuncs[type - WC_CURSH])(state, do_exec); @@ -4235,7 +4301,7 @@ exectime(Estate state, UNUSED(int do_exec)) /**/ static int -execfuncdef(Estate state, UNUSED(int do_exec)) +execfuncdef(Estate state, Eprog redir_prog) { Shfunc shf; char *s = NULL; @@ -4305,6 +4371,7 @@ execfuncdef(Estate state, UNUSED(int do_exec)) shf->node.flags = 0; shf->filename = ztrdup(scriptfilename); shf->lineno = lineno; + shf->redir = redir_prog; shfunc_set_sticky(shf); if (!names) { @@ -4335,6 +4402,8 @@ execfuncdef(Estate state, UNUSED(int do_exec)) ret = lastval; freeeprog(shf->funcdef); + if (shf->redir) /* shouldn't be */ + freeeprog(shf->redir); zsfree(shf->filename); zfree(shf, sizeof(*shf)); break; -- cgit 1.4.1 From 8cb67e721b3f02779bf4cf0d6a368f67c49c11f8 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 29 Sep 2014 21:31:37 +0100 Subject: 33286: handle redirections for multiply named functions --- ChangeLog | 3 +++ Src/exec.c | 17 ++++++++++++++++- Test/A04redirect.ztst | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 7fa84fb86..b8bbbdea8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2014-09-29 Peter Stephenson + * 33286: Src/exec.c, Test/A04redirect.ztst: handle redirections + for multiple named functions. + * 33285: NEWS, Src/exec.c, Src/hashtable.c, Src/parse.c, Src/signals.c, Src/zsh.h, Test/A04redirect.ztst: redirections in function definitions are applied at execution not definition. diff --git a/Src/exec.c b/Src/exec.c index 1c2a9044c..cedadc86a 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4306,6 +4306,7 @@ execfuncdef(Estate state, Eprog redir_prog) Shfunc shf; char *s = NULL; int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0, ret = 0; + int nfunc = 0; Wordcode beg = state->pc, end; Eprog prog; Patprog *pp; @@ -4330,6 +4331,8 @@ execfuncdef(Estate state, Eprog redir_prog) } } + DPUTS(!names && redir_prog, + "Passing redirection to anon function definition."); while (!names || (s = (char *) ugetnode(names))) { if (!names) { prog = (Eprog) zhalloc(sizeof(*prog)); @@ -4371,7 +4374,15 @@ execfuncdef(Estate state, Eprog redir_prog) shf->node.flags = 0; shf->filename = ztrdup(scriptfilename); shf->lineno = lineno; - shf->redir = redir_prog; + /* + * redir_prog is permanently allocated --- but if + * this function has multiple names we need an additional + * one. + */ + if (nfunc++ && redir_prog) + shf->redir = dupeprog(redir_prog, 0); + else + shf->redir = redir_prog; shfunc_set_sticky(shf); if (!names) { @@ -4427,6 +4438,10 @@ execfuncdef(Estate state, Eprog redir_prog) shfunctab->addnode(shfunctab, ztrdup(s), shf); } } + if (!nfunc && redir_prog) { + /* For completeness, shouldn't happen */ + freeeprog(redir_prog); + } state->pc = end; return ret; } diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst index 436ae59cd..6c38a3194 100644 --- a/Test/A04redirect.ztst +++ b/Test/A04redirect.ztst @@ -491,3 +491,19 @@ > print I want to tell you about $var > print Also, this might be an error >&2 >} < input2 > output2 2>&1 + + 1func 2func 3func() { print Ich heisse $0 } >output3 + for i in 1 2 3; do + f=${i}func + print Running $f + $f + cat output3 + unfunction $f + done +0:multiply named functions with redirection +>Running 1func +>Ich heisse 1func +>Running 2func +>Ich heisse 2func +>Running 3func +>Ich heisse 3func -- cgit 1.4.1