summaryrefslogtreecommitdiff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c187
1 files changed, 166 insertions, 21 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 5ad957f98..d0fadd69a 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
};
@@ -1005,6 +1006,8 @@ entersubsh(int flags)
signal_default(SIGTERM);
if (!(sigtrapped[SIGINT] & ZSIG_IGNORED))
signal_default(SIGINT);
+ if (!(sigtrapped[SIGPIPE]))
+ signal_default(SIGPIPE);
}
if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED))
signal_default(SIGQUIT);
@@ -1116,8 +1119,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;
@@ -2783,6 +2789,58 @@ execcmd(Estate state, int input, int output, int how, int last1)
errflag = 1;
}
+ 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 || type == WC_AUTOFN) {
+ Shfunc shf;
+ if (is_shfunc)
+ shf = (Shfunc)hn;
+ else {
+ shf = loadautofn(state->prog->shf, 1, 0);
+ if (shf)
+ state->prog->shf = shf;
+ else {
+ /*
+ * This doesn't set errflag, so just return now.
+ */
+ lastval = 1;
+ if (oautocont >= 0)
+ opts[AUTOCONTINUE] = oautocont;
+ return;
+ }
+ }
+ /*
+ * 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 (errflag) {
lastval = 1;
if (oautocont >= 0)
@@ -3050,7 +3108,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
break;
case REDIR_CLOSE:
if (fn->varid) {
- char *s = fn->varid;
+ char *s = fn->varid, *t;
struct value vbuf;
Value v;
int bad = 0;
@@ -3060,13 +3118,25 @@ execcmd(Estate state, int input, int output, int how, int last1)
} else if (v->pm->node.flags & PM_READONLY) {
bad = 2;
} else {
- fn->fd1 = (int)getintvalue(v);
+ s = getstrvalue(v);
if (errflag)
bad = 1;
- else if (fn->fd1 <= max_zsh_fd) {
- if (fn->fd1 >= 10 &&
- fdtable[fn->fd1] == FDT_INTERNAL)
- bad = 3;
+ else {
+ fn->fd1 = zstrtol(s, &t, 0);
+ if (s == t)
+ bad = 1;
+ else if (*t) {
+ /* Check for base#number format */
+ if (*t == '#' && *s != '0')
+ fn->fd1 = zstrtol(s = t+1, &t, fn->fd1);
+ if (s == t || *t)
+ bad = 1;
+ }
+ if (!bad && fn->fd1 <= max_zsh_fd) {
+ if (fn->fd1 >= 10 &&
+ fdtable[fn->fd1] == FDT_INTERNAL)
+ bad = 3;
+ }
}
}
if (bad) {
@@ -3131,7 +3201,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
fil = movefd(dup(fd));
}
if (fil == -1) {
- char fdstr[4];
+ char fdstr[DIGBUFSIZE];
closemnodes(mfds);
fixfds(save);
@@ -3226,10 +3296,44 @@ 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);
+ if (type == WC_AUTOFN) {
+ /*
+ * We pre-loaded this to get any redirs.
+ * So we execuate a simplified function here.
+ */
+ lastval = execautofn_basic(state, do_exec);
+ } else
+ lastval = (execfuncs[type - WC_CURSH])(state, do_exec);
} else if (is_builtin || is_shfunc) {
LinkList restorelist = 0, removelist = 0;
/* builtin or shell function */
@@ -3569,8 +3673,11 @@ closem(int how)
for (i = 10; i <= max_zsh_fd; i++)
if (fdtable[i] != FDT_UNUSED &&
- (how == FDT_UNUSED || fdtable[i] == how))
+ (how == FDT_UNUSED || fdtable[i] == how)) {
+ if (i == SHTTY)
+ SHTTY = -1;
zclose(i);
+ }
}
/* convert here document into a here string */
@@ -4220,11 +4327,12 @@ 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;
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;
@@ -4249,6 +4357,8 @@ execfuncdef(Estate state, UNUSED(int do_exec))
}
}
+ DPUTS(!names && redir_prog,
+ "Passing redirection to anon function definition.");
while (!names || (s = (char *) ugetnode(names))) {
if (!names) {
prog = (Eprog) zhalloc(sizeof(*prog));
@@ -4290,6 +4400,15 @@ execfuncdef(Estate state, UNUSED(int do_exec))
shf->node.flags = 0;
shf->filename = ztrdup(scriptfilename);
shf->lineno = lineno;
+ /*
+ * 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) {
@@ -4320,6 +4439,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;
@@ -4343,6 +4464,10 @@ execfuncdef(Estate state, UNUSED(int do_exec))
shfunctab->addnode(shfunctab, ztrdup(s), shf);
}
}
+ if (!nfunc && redir_prog) {
+ /* For completeness, shouldn't happen */
+ freeeprog(redir_prog);
+ }
state->pc = end;
return ret;
}
@@ -4439,21 +4564,28 @@ execshfunc(Shfunc shf, LinkList args)
deletefilelist(last_file_list, 0);
}
-/* Function to execute the special type of command that represents an *
- * autoloaded shell function. The command structure tells us which *
- * function it is. This function is actually called as part of the *
- * execution of the autoloaded function itself, so when the function *
- * has been autoloaded, its list is just run with no frills. */
+/*
+ * Function to execute the special type of command that represents an
+ * autoloaded shell function. The command structure tells us which
+ * function it is. This function is actually called as part of the
+ * execution of the autoloaded function itself, so when the function
+ * has been autoloaded, its list is just run with no frills.
+ *
+ * There are two cases because if we are doing all-singing, all-dancing
+ * non-simple code we load the shell function early in execcmd() (the
+ * action also present in the non-basic version) to check if
+ * there are redirections that need to be handled at that point.
+ * Then we call execautofn_basic() to do the rest.
+ */
/**/
static int
-execautofn(Estate state, UNUSED(int do_exec))
+execautofn_basic(Estate state, UNUSED(int do_exec))
{
Shfunc shf;
char *oldscriptname, *oldscriptfilename;
- if (!(shf = loadautofn(state->prog->shf, 1, 0)))
- return 1;
+ shf = state->prog->shf;
/*
* Probably we didn't know the filename where this function was
@@ -4473,6 +4605,19 @@ execautofn(Estate state, UNUSED(int do_exec))
}
/**/
+static int
+execautofn(Estate state, UNUSED(int do_exec))
+{
+ Shfunc shf;
+
+ if (!(shf = loadautofn(state->prog->shf, 1, 0)))
+ return 1;
+
+ state->prog->shf = shf;
+ return execautofn_basic(state, 0);
+}
+
+/**/
Shfunc
loadautofn(Shfunc shf, int fksh, int autol)
{