about summary refs log tree commit diff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c396
1 files changed, 223 insertions, 173 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 952dfbb78..5cfe3e3ef 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -139,8 +139,7 @@ parse_string(char *s)
 
     lexsave();
     inpush(s, 0, NULL);
-    strinbeg();
-    stophist = 2;
+    strinbeg(0);
     l = parse_list();
     strinend();
     inpop();
@@ -298,12 +297,12 @@ static char list_pipe_text[JOBTEXTSIZE];
 
 /**/
 static int
-execcursh(Cmd cmd)
+execcursh(Cmd cmd, LinkList args, int flags)
 {
     if (!list_pipe)
 	deletejob(jobtab + thisjob);
-    execlist(cmd->u.list, 1, cmd->flags & CFLAG_EXEC);
-    cmd->u.list = NULL;
+    execlist(cmd->u.list, 1, flags & CFLAG_EXEC);
+
     return lastval;
 }
 
@@ -718,7 +717,6 @@ execlist(List list, int dont_change_job, int exiting)
 	/* Reset donetrap:  this ensures that a trap is only *
 	 * called once for each sublist that fails.          */
 	donetrap = 0;
-	simplifyright(list);
 	slist = list->left;
 
 	/* Loop through code followed by &&, ||, or end of sublist. */
@@ -1009,11 +1007,13 @@ execpline2(Pline pline, int how, int input, int output, int last1)
     lineno = pline->left->lineno;
 
     if (pline_level == 1)
-	strcpy(list_pipe_text, getjobtext((void *) pline->left));
-    if (pline->type == END) {
+	if (!sfcontext)
+	    strcpy(list_pipe_text, getjobtext((void *) pline->left));
+	else
+	    list_pipe_text[0] = '\0';
+    if (pline->type == END)
 	execcmd(pline->left, input, output, how, last1 ? 1 : 2);
-	pline->left = NULL;
-    } else {
+    else {
 	int old_list_pipe = list_pipe;
 
 	mpipe(pipes);
@@ -1046,11 +1046,10 @@ execpline2(Pline pline, int how, int input, int output, int last1)
 		_exit(lastval);
 	    }
 	} else {
-	/* otherwise just do the pipeline normally. */
+	    /* otherwise just do the pipeline normally. */
 	    subsh_close = pipes[0];
 	    execcmd(pline->left, input, pipes[1], how, 0);
 	}
-	pline->left = NULL;
 	zclose(pipes[1]);
 	if (pline->right) {
 	    /* if another execpline() is invoked because the command is *
@@ -1102,13 +1101,17 @@ makecline(LinkList list)
 void
 untokenize(char *s)
 {
-    for (; *s; s++)
-	if (itok(*s)) {
-	    if (*s == Nularg)
-		chuck(s--);
-	    else
-		*s = ztokens[*s - Pound];
-	}
+    if (*s) {
+	char *p = s, c;
+
+	while ((c = *s++))
+	    if (itok(c)) {
+		if (c != Nularg)
+		    *p++ = ztokens[c - Pound];
+	    } else
+		*p++ = c;
+	*p = '\0';
+    }
 }
 
 /* Open a file for writing redicection */
@@ -1152,34 +1155,34 @@ clobber_open(struct redir *f)
 static void
 closemn(struct multio **mfds, int fd)
 {
-    struct multio *mn = mfds[fd];
-    char buf[TCBUFSIZE];
-    int len, i;
+    if (fd >= 0 && mfds[fd] && mfds[fd]->ct >= 2) {
+	struct multio *mn = mfds[fd];
+	char buf[TCBUFSIZE];
+	int len, i;
 
-    if (fd < 0 || !mfds[fd] || mfds[fd]->ct < 2)
-	return;
-    if (zfork()) {
-	for (i = 0; i < mn->ct; i++)
-	    zclose(mn->fds[i]);
-	zclose(mn->pipe);
-	mn->ct = 1;
-	mn->fds[0] = fd;
-	return;
-    }
-    /* pid == 0 */
-    closeallelse(mn);
-    if (mn->rflag) {
-	/* tee process */
-	while ((len = read(mn->pipe, buf, TCBUFSIZE)) > 0)
+	if (zfork()) {
 	    for (i = 0; i < mn->ct; i++)
-		write(mn->fds[i], buf, len);
-    } else {
-	/* cat process */
-	for (i = 0; i < mn->ct; i++)
-	    while ((len = read(mn->fds[i], buf, TCBUFSIZE)) > 0)
-		write(mn->pipe, buf, len);
+		zclose(mn->fds[i]);
+	    zclose(mn->pipe);
+	    mn->ct = 1;
+	    mn->fds[0] = fd;
+	    return;
+	}
+	/* pid == 0 */
+	closeallelse(mn);
+	if (mn->rflag) {
+	    /* tee process */
+	    while ((len = read(mn->pipe, buf, TCBUFSIZE)) > 0)
+		for (i = 0; i < mn->ct; i++)
+		    write(mn->fds[i], buf, len);
+	} else {
+	    /* cat process */
+	    for (i = 0; i < mn->ct; i++)
+		while ((len = read(mn->fds[i], buf, TCBUFSIZE)) > 0)
+		    write(mn->pipe, buf, len);
+	}
+	_exit(0);
     }
-    _exit(0);
 }
 
 /* close all the mnodes (failure) */
@@ -1273,9 +1276,10 @@ static void
 addvars(LinkList l, int export)
 {
     Varasg v;
+    LinkNode n;
     LinkList vl;
     int xtr;
-    char **arr, **ptr;
+    char **arr, **ptr, *name;
 
     xtr = isset(XTRACE);
     if (xtr && nonempty(l)) {
@@ -1283,26 +1287,30 @@ addvars(LinkList l, int export)
 	doneps4 = 1;
     }
 
-    while (nonempty(l)) {
-	v = (Varasg) ugetnode(l);
-	singsub(&v->name);
+    for (n = firstnode(l); n; incnode(n)) {
+	v = (Varasg) getdata(n);
+	name = dupstring(v->name);
+	singsub(&name);
 	if (errflag)
 	    return;
-	untokenize(v->name);
+	untokenize(name);
 	if (xtr)
-	    fprintf(stderr, "%s=", v->name);
+	    fprintf(stderr, "%s=", name);
 	if (v->type == PM_SCALAR) {
 	    vl = newlinklist();
-	    addlinknode(vl, v->str);
+	    addlinknode(vl, dupstring(v->str));
 	} else
-	    vl = v->arr;
-	prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) : PF_ASSIGN);
-	if (errflag)
-	    return;
-	if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
-	    globlist(vl);
-	if (errflag)
-	    return;
+	    vl = listdup(v->arr);
+	if (vl) {
+	    prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) :
+		                               PF_ASSIGN);
+	    if (errflag)
+		return;
+	    if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
+		globlist(vl);
+	    if (errflag)
+		return;
+	}
 	if (v->type == PM_SCALAR && (empty(vl) || !nextnode(firstnode(vl)))) {
 	    Param pm;
 	    char *val;
@@ -1319,7 +1327,7 @@ addvars(LinkList l, int export)
 	    if (export) {
 		if (export < 0) {
 		    /* We are going to fork so do not bother freeing this */
-		    pm = (Param) paramtab->removenode(paramtab, v->name);
+		    pm = (Param) paramtab->removenode(paramtab, name);
 		    if (isset(RESTRICTED) && (pm->flags & PM_RESTRICTED)) {
 			zerr("%s: restricted", pm->nam, 0);
 			zsfree(val);
@@ -1328,18 +1336,22 @@ addvars(LinkList l, int export)
 		}
 		allexp = opts[ALLEXPORT];
 		opts[ALLEXPORT] = 1;
-		pm = setsparam(v->name, val);
+		pm = setsparam(name, val);
 		opts[ALLEXPORT] = allexp;
 	    } else
-		pm = setsparam(v->name, val);
+		pm = setsparam(name, val);
 	    if (errflag)
 		return;
 	    continue;
 	}
-	ptr = arr = (char **) zalloc(sizeof(char **) * (countlinknodes(vl) + 1));
+	if (vl) {
+	    ptr = arr = (char **) zalloc(sizeof(char **) *
+					 (countlinknodes(vl) + 1));
 
-	while (nonempty(vl))
-	    *ptr++ = ztrdup((char *) ugetnode(vl));
+	    while (nonempty(vl))
+		*ptr++ = ztrdup((char *) ugetnode(vl));
+	} else
+	    ptr = arr = (char **) zalloc(sizeof(char **));
 
 	*ptr = NULL;
 	if (xtr) {
@@ -1348,7 +1360,7 @@ addvars(LinkList l, int export)
 		fprintf(stderr, "%s ", *ptr);
 	    fprintf(stderr, ") ");
 	}
-	setaparam(v->name, arr);
+	setaparam(name, arr);
 	if (errflag)
 	    return;
     }
@@ -1364,15 +1376,19 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     struct multio *mfds[10];
     char *text;
     int save[10];
-    int fil, dfil, is_cursh, type, i;
+    int fil, dfil, is_cursh, type, flags, i;
     int nullexec = 0, assign = 0, forked = 0;
     int is_shfunc = 0, is_builtin = 0, is_exec = 0;
     /* Various flags to the command. */
     int cflags = 0, checked = 0;
+    LinkList vars, redir;
 
     doneps4 = 0;
-    args = cmd->args;
+    args = listdup(cmd->args);
     type = cmd->type;
+    flags = cmd->flags;
+    redir = dupheaplist(cmd->redir);
+    vars = cmd->vars;
 
     for (i = 0; i < 10; i++) {
 	save[i] = -2;
@@ -1381,7 +1397,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 
     /* If the command begins with `%', then assume it is a *
      * reference to a job in the job table.                */
-    if (type == SIMPLE && nonempty(args) &&
+    if (type == SIMPLE && args && nonempty(args) &&
 	*(char *)peekfirst(args) == '%') {
 	pushnode(args, dupstring((how & Z_DISOWN)
 				 ? "disown" : (how & Z_ASYNC) ? "bg" : "fg"));
@@ -1393,7 +1409,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
      * job currently in the job table.  If it does, then we treat it *
      * as a command to resume this job.                              */
     if (isset(AUTORESUME) && type == SIMPLE && (how & Z_SYNC) &&
-	nonempty(args) && empty(cmd->redir) && !input &&
+	args && nonempty(args) &&
+	(!cmd->redir || empty(cmd->redir)) && !input &&
 	!nextnode(firstnode(args))) {
 	if (unset(NOTIFY))
 	    scanjobs();
@@ -1407,7 +1424,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
      * only works in simple cases.  has_token() is called to make sure   *
      * this really is a simple case.                                     */
     if (type == SIMPLE) {
-	while (nonempty(args)) {
+	while (args && nonempty(args)) {
 	    char *cmdarg = (char *) peekfirst(args);
 	    checked = !has_token(cmdarg);
 	    if (!checked)
@@ -1444,7 +1461,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     }
 
     /* Do prefork substitutions */
-    prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0);
+    if (args)
+	prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0);
 
     if (type == SIMPLE) {
 	int unglobbed = 0;
@@ -1453,7 +1471,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    char *cmdarg;
 
 	    if (!(cflags & BINF_NOGLOB))
-		while (!checked && !errflag && nonempty(args) &&
+		while (!checked && !errflag && args && nonempty(args) &&
 		       has_token((char *) peekfirst(args)))
 		    glob(args, firstnode(args));
 	    else if (!unglobbed) {
@@ -1465,12 +1483,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    /* Current shell should not fork unless the *
 	     * exec occurs at the end of a pipeline.    */
 	    if ((cflags & BINF_EXEC) && last1 == 2)
-		cmd->flags |= CFLAG_EXEC;
+		flags |= CFLAG_EXEC;
 
 	    /* Empty command */
-	    if (empty(args)) {
-		if (nonempty(cmd->redir)) {
-		    if (cmd->flags & CFLAG_EXEC) {
+	    if (!args || empty(args)) {
+		if (redir && nonempty(redir)) {
+		    if (flags & CFLAG_EXEC) {
 			/* Was this "exec < foobar"? */
 			nullexec = 1;
 			break;
@@ -1480,17 +1498,23 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 			errflag = lastval = 1;
 			return;
 		    } else if (readnullcmd && *readnullcmd &&
-			       ((Redir) peekfirst(cmd->redir))->type == READ &&
-			       !nextnode(firstnode(cmd->redir))) {
+			       ((Redir) peekfirst(redir))->type == READ &&
+			       !nextnode(firstnode(redir))) {
+			if (!args)
+			    args = newlinklist();
 			addlinknode(args, dupstring(readnullcmd));
-		    } else
+		    } else {
+			if (!args)
+			    args = newlinklist();
 			addlinknode(args, dupstring(nullcmd));
+		    }
 		} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
 		    lastval = 0;
 		    return;
 		} else {
 		    cmdoutval = 0;
-		    addvars(cmd->vars, 0);
+		    if (vars)
+			addvars(vars, 0);
 		    if (errflag)
 			lastval = errflag;
 		    else
@@ -1502,7 +1526,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		    return;
 		}
 	    } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) &&
-		       (cmd->flags & CFLAG_EXEC)) {
+		       (flags & CFLAG_EXEC)) {
 		zerrnam("exec", "%s: restricted", (char *) getdata(firstnode(args)), 0);
 		lastval = 1;
 		return;
@@ -1548,22 +1572,32 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     }
 
     /* Get the text associated with this command. */
-    if (jobbing || (how & Z_TIMED))
+    if (!sfcontext && (jobbing || (how & Z_TIMED)))
 	text = getjobtext((void *) cmd);
     else
 	text = NULL;
 
     /* Set up special parameter $_ */
-    zsfree(underscore);
-    if (nonempty(args)
-	&& (underscore = ztrdup((char *) getdata(lastnode(args)))))
-	untokenize(underscore); 
-    else
-  	underscore = ztrdup("");
+    if (args && nonempty(args)) {
+	char *u = (char *) getdata(lastnode(args));
+
+	if (u) {
+	    int ul = strlen(u);
+
+	    if (ul >= underscorelen) {
+		zfree(underscore, underscorelen);
+		underscore = (char *) zalloc(underscorelen = ul + 32);
+	    }
+	    strcpy(underscore, u);
+	} else
+	    *underscore = '\0';
+    } else
+	*underscore = '\0';
 
     /* Warn about "rm *" */
     if (type == SIMPLE && interact && unset(RMSTARSILENT)
-	&& isset(SHINSTDIN) && nonempty(args) && nextnode(firstnode(args))
+	&& isset(SHINSTDIN) && args && nonempty(args)
+	&& nextnode(firstnode(args))
 	&& !strcmp(peekfirst(args), "rm")) {
 	LinkNode node, next;
 
@@ -1596,11 +1630,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
     if (type == SIMPLE && !nullexec) {
 	char *s;
 	char trycd = (isset(AUTOCD) && isset(SHINSTDIN)
-		      && empty(cmd->redir) && !empty(args)
+		      && (!redir || empty(redir)) && args && !empty(args)
 		      && !nextnode(firstnode(args))
 		      && *(char *)peekfirst(args));
 
-	DPUTS(empty(args), "BUG: empty(args) in exec.c");
+	DPUTS((!args || empty(args)), "BUG: empty(args) in exec.c");
 	if (!hn) {
 	    /* Resolve external commands */
 	    char *cmdarg = (char *) peekfirst(args);
@@ -1652,7 +1686,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
      * current shell.                                                         *
      **************************************************************************/
 
-    if ((how & Z_ASYNC) || (!(cmd->flags & CFLAG_EXEC) &&
+    if ((how & Z_ASYNC) || (!(flags & CFLAG_EXEC) &&
        (((is_builtin || is_shfunc) && output) ||
        (!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] ||
         sigtrapped[SIGEXIT] || havefiles()))))) {
@@ -1677,10 +1711,13 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 #endif
 	    if (how & Z_ASYNC) {
 		lastpid = (zlong) pid;
-	    } else if (!jobtab[thisjob].stty_in_env && nonempty(cmd->vars)) {
+	    } else if (!jobtab[thisjob].stty_in_env &&
+		       vars && nonempty(vars)) {
 		/* search for STTY=... */
-		while (nonempty(cmd->vars))
-		    if (!strcmp(((Varasg) ugetnode(cmd->vars))->name, "STTY")) {
+		LinkNode n;
+
+		for (n = firstnode(vars); n; incnode(n))
+		    if (!strcmp(((Varasg) getdata(n))->name, "STTY")) {
 			jobtab[thisjob].stty_in_env = 1;
 			break;
 		    }
@@ -1713,7 +1750,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	is_exec = 1;
     }
 
-    if (!(cflags & BINF_NOGLOB))
+    if (args && !(cflags & BINF_NOGLOB))
 	globlist(args);
     if (errflag) {
 	lastval = 1;
@@ -1727,11 +1764,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	addfd(forked, save, mfds, 1, output, 1);
 
     /* Do process substitutions */
-    spawnpipes(cmd->redir);
+    if (redir)
+	spawnpipes(redir);
 
     /* Do io redirections */
-    while (nonempty(cmd->redir)) {
-	fn = (Redir) ugetnode(cmd->redir);
+    while (redir && nonempty(redir)) {
+	fn = (Redir) ugetnode(redir);
 	DPUTS(fn->type == HEREDOC || fn->type == HEREDOCDASH,
 	      "BUG: unexpanded here document");
 	if (fn->type == INPIPE) {
@@ -1749,7 +1787,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    }
 	    addfd(forked, save, mfds, fn->fd1, fn->fd2, 1);
 	} else {
-	    if (fn->type != HERESTR && xpandredir(fn, cmd->redir))
+	    if (fn->type != HERESTR && xpandredir(fn, redir))
 		continue;
 	    if (errflag) {
 		closemnodes(mfds);
@@ -1870,15 +1908,15 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	if (is_exec)
 	    entersubsh(how, type != SUBSH ? 2 : 1, 1);
 	if (type >= CURSH) {
-	    static int (*func[]) _((Cmd)) = {
+	    static int (*func[]) _((Cmd, LinkList, int)) = {
 		execcursh, exectime, execfuncdef, execfor, execwhile,
 		execrepeat, execif, execcase, execselect, execcond,
 		execarith, execautofn
 	    };
 
 	    if (last1 == 1)
-		cmd->flags |= CFLAG_EXEC;
-	    lastval = (func[type - CURSH]) (cmd);
+		flags |= CFLAG_EXEC;
+	    lastval = (func[type - CURSH]) (cmd, args, flags);
 	} else if (is_builtin || is_shfunc) {
 	    LinkList restorelist = 0, removelist = 0;
 	    /* builtin or shell function */
@@ -1889,11 +1927,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 			     !(hn->flags & BINF_PSPECIAL))))
 		save_params(cmd, &restorelist, &removelist);
 
-	    if (cmd->vars) {
+	    if (vars) {
 		/* Export this if the command is a shell function,
 		 * but not if it's a builtin.
 		 */
-		addvars(cmd->vars, is_shfunc);
+		addvars(vars, is_shfunc);
 		if (errflag) {
 		    restore_params(restorelist, removelist);
 		    lastval = 1;
@@ -1904,6 +1942,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 
 	    if (is_shfunc) {
 		/* It's a shell function */
+
 #ifdef PATH_DEV_FD
 		int i;
 
@@ -1914,7 +1953,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		if (subsh_close >= 0)
 		    zclose(subsh_close);
 		subsh_close = -1;
-		execshfunc(cmd, (Shfunc) hn);
+		execshfunc(cmd, (Shfunc) hn, args);
 #ifdef PATH_DEV_FD
 		for (i = 10; i <= max_zsh_fd; i++)
 		    if (fdtable[i] > 1)
@@ -1943,7 +1982,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		    clearerr(stdout);
 	    }
 
-	    if (cmd->flags & CFLAG_EXEC) {
+	    if (flags & CFLAG_EXEC) {
 		if (subsh)
 		    _exit(lastval);
 
@@ -1957,7 +1996,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    restore_params(restorelist, removelist);
 
 	} else {
-	    if (cmd->flags & CFLAG_EXEC) {
+	    if (flags & CFLAG_EXEC) {
 		setiparam("SHLVL", --shlvl);
 		/* If we are exec'ing a command, and we are not *
 		 * in a subshell, then save the history file.   */
@@ -1965,8 +2004,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 		    savehistfile(NULL, 1, HFILE_USE_OPTIONS);
 	    }
 	    if (type == SIMPLE) {
-		if (cmd->vars) {
-		    addvars(cmd->vars, -1);
+		if (vars) {
+		    addvars(vars, -1);
 		    if (errflag)
 			_exit(1);
 		}
@@ -1981,7 +2020,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 #endif
 		execute((Cmdnam) hn, cflags & BINF_DASH);
 	    } else {		/* ( ... ) */
-		DPUTS(cmd->vars && nonempty(cmd->vars),
+		DPUTS(vars && nonempty(vars),
 		      "BUG: assigment before complex command");
 		list_pipe = 0;
 		if (subsh_close >= 0)
@@ -2011,7 +2050,11 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p)
     char *s;
 
     MUSTUSEHEAP("save_params()");
-
+    
+    if (!cmd->vars) {
+	*restore_p = *remove_p = NULL;
+	return;
+    }
     *restore_p = newlinklist();
     *remove_p = newlinklist();
 
@@ -2283,8 +2326,9 @@ getoutput(char *cmd, int qt)
 	return NULL;
     if (list != &dummy_list && !list->right && !list->left->flags &&
 	list->left->type == END && list->left->left->type == END &&
-	(c = list->left->left->left)->type == SIMPLE && empty(c->args) &&
-	empty(c->vars) && nonempty(c->redir) &&
+	(c = list->left->left->left)->type == SIMPLE && 
+	(!c->args || empty(c->args)) &&
+	(!c->vars || empty(c->vars)) && c->redir && nonempty(c->redir) &&
 	!nextnode(firstnode(c->redir)) &&
 	(r = (Redir) getdata(firstnode(c->redir)))->fd1 == 0 &&
 	r->type == READ) {
@@ -2613,7 +2657,7 @@ extern int tracingcond;
 
 /**/
 static int
-execcond(Cmd cmd)
+execcond(Cmd cmd, LinkList args, int flags)
 {
     int stat;
     if (isset(XTRACE)) {
@@ -2633,18 +2677,19 @@ execcond(Cmd cmd)
 
 /**/
 static int
-execarith(Cmd cmd)
+execarith(Cmd cmd, LinkList args, int flags)
 {
     char *e;
     zlong val = 0;
 
     if (isset(XTRACE))
 	fprintf(stderr, "%s((", prompt4 ? prompt4 : "");
-    while ((e = (char *) ugetnode(cmd->args))) {
-	if (isset(XTRACE))
-	    fprintf(stderr, " %s", e);
-	val = matheval(e);
-    }
+    if (args)
+	while ((e = (char *) ugetnode(args))) {
+	    if (isset(XTRACE))
+		fprintf(stderr, " %s", e);
+	    val = matheval(e);
+	}
     if (isset(XTRACE)) {
 	fprintf(stderr, " ))\n");
 	fflush(stderr);
@@ -2657,7 +2702,7 @@ execarith(Cmd cmd)
 
 /**/
 static int
-exectime(Cmd cmd)
+exectime(Cmd cmd, LinkList args, int flags)
 {
     int jb;
 
@@ -2675,30 +2720,33 @@ exectime(Cmd cmd)
 
 /**/
 static int
-execfuncdef(Cmd cmd)
+execfuncdef(Cmd cmd, LinkList args, int flags)
 {
     Shfunc shf;
     char *s;
     int signum;
 
-    PERMALLOC {
-	while ((s = (char *) ugetnode(cmd->args))) {
-	    shf = (Shfunc) zalloc(sizeof *shf);
-	    shf->funcdef = (List) dupstruct(cmd->u.list);
-	    shf->flags = 0;
-
-	    /* is this shell function a signal trap? */
-	    if (!strncmp(s, "TRAP", 4) && (signum = getsignum(s + 4)) != -1) {
-		if (settrap(signum, shf->funcdef)) {
-		    freestruct(shf->funcdef);
-		    zfree(shf, sizeof *shf);
-		    LASTALLOC_RETURN 1;
-		}
-		sigtrapped[signum] |= ZSIG_FUNC;
-	    }
-	    shfunctab->addnode(shfunctab, ztrdup(s), shf);
-	}
-    } LASTALLOC;
+    if (args) {
+	PERMALLOC {
+	    while ((s = (char *) ugetnode(args))) {
+		shf = (Shfunc) zalloc(sizeof *shf);
+		shf->funcdef = (List) dupstruct(cmd->u.list);
+		shf->flags = 0;
+
+		/* is this shell function a signal trap? */
+		if (!strncmp(s, "TRAP", 4) &&
+		    (signum = getsignum(s + 4)) != -1) {
+		    if (settrap(signum, shf->funcdef)) {
+			freestruct(shf->funcdef);
+			zfree(shf, sizeof *shf);
+			LASTALLOC_RETURN 1;
+		    }
+		    sigtrapped[signum] |= ZSIG_FUNC;
+  		}
+		shfunctab->addnode(shfunctab, ztrdup(s), shf);
+  	    }
+	} LASTALLOC;
+    }
     if(isset(HISTNOFUNCTIONS))
 	remhist();
     return 0;
@@ -2708,7 +2756,7 @@ execfuncdef(Cmd cmd)
 
 /**/
 static void
-execshfunc(Cmd cmd, Shfunc shf)
+execshfunc(Cmd cmd, Shfunc shf, LinkList args)
 {
     LinkList last_file_list = NULL;
 
@@ -2726,16 +2774,17 @@ execshfunc(Cmd cmd, Shfunc shf)
     if (isset(XTRACE)) {
 	LinkNode lptr;
 	fprintf(stderr, "%s", prompt4 ? prompt4 : prompt4);
-	for (lptr = firstnode(cmd->args); lptr; incnode(lptr)) {
-	    if (lptr != firstnode(cmd->args))
-		fputc(' ', stderr);
-	    fprintf(stderr, "%s", (char *)getdata(lptr));
-	}
+	if (args)
+	    for (lptr = firstnode(args); lptr; incnode(lptr)) {
+		if (lptr != firstnode(args))
+		    fputc(' ', stderr);
+		fprintf(stderr, "%s", (char *)getdata(lptr));
+	    }
 	fputc('\n', stderr);
 	fflush(stderr);
     }
 
-    doshfunc(shf->nam, shf->funcdef, cmd->args, shf->flags, 0);
+    doshfunc(shf->nam, shf->funcdef, args, shf->flags, 0);
 
     if (!list_pipe)
 	deletefilelist(last_file_list);
@@ -2749,10 +2798,16 @@ execshfunc(Cmd cmd, Shfunc shf)
 
 /**/
 static int
-execautofn(Cmd cmd)
+execautofn(Cmd cmd, LinkList args, int flags)
 {
     Shfunc shf = cmd->u.autofn->shf;
-    List l = getfpfunc(shf->nam);
+    int noalias = noaliases;
+    List l;
+
+    noaliases = (shf->flags & PM_UNALIASED);
+    l = getfpfunc(shf->nam);
+    noaliases = noalias;
+
     if(l == &dummy_list) {
 	zerr("%s: function definition file not found", shf->nam, 0);
 	return 1;
@@ -2773,9 +2828,7 @@ execautofn(Cmd cmd)
 	} LASTALLOC;
 	shf->flags &= ~PM_UNDEFINED;
     }
-    HEAPALLOC {
-	execlist(dupstruct(shf->funcdef), 1, 0);
-    } LASTALLOC;
+    execlist(shf->funcdef, 1, 0);
     return lastval;
 }
 
@@ -2822,7 +2875,8 @@ doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval)
 	    LinkNode node;
 
 	    node = doshargs->first;
-	    pparams = x = (char **) zcalloc(((sizeof *x) * (1 + countlinknodes(doshargs))));
+	    pparams = x = (char **) zcalloc(((sizeof *x) *
+					     (1 + countlinknodes(doshargs))));
 	    if (isset(FUNCTIONARGZERO)) {
 		oargv0 = argzero;
 		argzero = ztrdup((char *) node->dat);
@@ -2901,7 +2955,7 @@ void
 runshfunc(List list, FuncWrap wrap, char *name)
 {
     int cont;
-    char *ou;
+    VARARR(char, ou, underscorelen);
 
     while (wrap) {
 	wrap->module->wrapper++;
@@ -2917,11 +2971,9 @@ runshfunc(List list, FuncWrap wrap, char *name)
 	wrap = wrap->next;
     }
     startparamscope();
-    ou = underscore;
-    underscore = ztrdup(underscore);
-    execlist(dupstruct(list), 1, 0);
-    zsfree(underscore);
-    underscore = ou;
+    strcpy(ou, underscore);
+    execlist(list, 1, 0);
+    strcpy(underscore, ou);
     endparamscope();
 }
 
@@ -2949,20 +3001,18 @@ getfpfunc(char *s)
 	unmetafy(buf, NULL);
 	if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) {
 	    if ((len = lseek(fd, 0, 2)) != -1) {
+		d = (char *) zalloc(len + 1);
 		lseek(fd, 0, 0);
-		d = (char *) zcalloc(len + 1);
 		if (read(fd, d, len) == len) {
 		    close(fd);
+		    d[len] = '\0';
 		    d = metafy(d, len, META_REALLOC);
 		    HEAPALLOC {
 			r = parse_string(d);
 		    } LASTALLOC;
-		    zfree(d, len + 1);
 		    return r;
-		} else {
-		    zfree(d, len + 1);
+		} else
 		    close(fd);
-		}
 	    } else {
 		close(fd);
 	    }
@@ -2995,9 +3045,10 @@ stripkshdef(List l, char *name)
     if(p->right)
 	return l;
     c = p->left;
-    if(c->type != FUNCDEF || c->flags ||
-	nonempty(c->redir) || nonempty(c->vars) ||
-	empty(c->args) || lastnode(c->args) != firstnode(c->args) ||
+    if (c->type != FUNCDEF || c->flags ||
+	(c->redir && nonempty(c->redir)) || (c->vars && nonempty(c->vars)) ||
+	!c->args || empty(c->args) ||
+	lastnode(c->args) != firstnode(c->args) ||
 	strcmp(name, peekfirst(c->args)))
 	return l;
     return c->u.list;
@@ -3076,8 +3127,7 @@ execsave(void)
     es->trapreturn = trapreturn;
     es->noerrs = noerrs;
     es->subsh_close = subsh_close;
-    es->underscore = underscore;
-    underscore = ztrdup(underscore);
+    es->underscore = ztrdup(underscore);
     es->next = exstack;
     exstack = es;
     noerrs = cmdoutpid = 0;
@@ -3105,8 +3155,8 @@ execrestore(void)
     trapreturn = exstack->trapreturn;
     noerrs = exstack->noerrs;
     subsh_close = exstack->subsh_close;
-    zsfree(underscore);
-    underscore = exstack->underscore;
+    strcpy(underscore, exstack->underscore);
+    zsfree(exstack->underscore);
     en = exstack->next;
     free(exstack);
     exstack = en;