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