summaryrefslogtreecommitdiff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c1882
1 files changed, 1275 insertions, 607 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 1b355d028..0dffaf4e2 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -38,7 +38,7 @@ int noerrexit;
/* suppress error messages */
/**/
-int noerrs;
+mod_export int noerrs;
/* do not save history on exec and exit */
@@ -48,7 +48,7 @@ int nohistsave;
/* error/break flag */
/**/
-int errflag;
+mod_export int errflag;
/* Status of return from a trap */
@@ -63,7 +63,7 @@ int subsh;
/* != 0 if we have a return pending */
/**/
-int retflag;
+mod_export int retflag;
/**/
long lastval2;
@@ -92,17 +92,17 @@ int max_zsh_fd;
/* input fd from the coprocess */
/**/
-int coprocin;
+mod_export int coprocin;
/* output fd from the coprocess */
/**/
-int coprocout;
+mod_export int coprocout;
/* != 0 if the line editor is active */
/**/
-int zleactive;
+mod_export int zleactive;
/* pid of process undergoing 'process substitution' */
@@ -113,45 +113,66 @@ pid_t cmdoutpid;
/**/
int cmdoutval;
-
+
+/* The context in which a shell function is called, see SFC_* in zsh.h. */
+
+/**/
+mod_export int sfcontext;
+
/* Stack to save some variables before executing a signal handler function */
/**/
struct execstack *exstack;
-#define execerr() if (!forked) { lastval = 1; return; } else _exit(1)
+/* Stack with names of functions currently active. */
+
+/**/
+mod_export Funcstack funcstack;
+
+#define execerr() if (!forked) { lastval = 1; goto done; } else _exit(1)
static LinkList args;
static int doneps4;
+/* Execution functions. */
+
+static int (*execfuncs[]) _((Estate, int)) = {
+ execcursh, exectime, execfuncdef, execfor, execselect,
+ execwhile, execrepeat, execcase, execif, execcond,
+ execarith, execautofn
+};
+
/* parse string into a list */
/**/
-List
-parse_string(char *s)
+mod_export Eprog
+parse_string(char *s, int ln)
{
- List l;
+ Eprog p;
+ int oldlineno = lineno;
lexsave();
- inpush(s, 0, NULL);
- strinbeg();
- stophist = 2;
- l = parse_list();
+ inpush(s, (ln ? INP_LINENO : 0), NULL);
+ strinbeg(0);
+ lineno = ln ? 1 : -1;
+ p = parse_list();
+ lineno = oldlineno;
strinend();
inpop();
lexrestore();
- return l;
+ return p;
}
+/**/
#ifdef HAVE_GETRLIMIT
/* the resource limits for the shell and its children */
/**/
-struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS];
+mod_export struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS];
/**/
-int
+mod_export int
zsetlimit(int limnum, char *nam)
{
if (limits[limnum].rlim_max != current_limits[limnum].rlim_max ||
@@ -167,7 +188,7 @@ zsetlimit(int limnum, char *nam)
}
/**/
-int
+mod_export int
setlimits(char *nam)
{
int limnum;
@@ -179,6 +200,7 @@ setlimits(char *nam)
return ret;
}
+/**/
#endif /* HAVE_GETRLIMIT */
/* fork and set limits */
@@ -206,6 +228,78 @@ zfork(void)
return pid;
}
+/*
+ * Allen Edeln gebiet ich Andacht,
+ * Hohen und Niedern von Heimdalls Geschlecht;
+ * Ich will list_pipe's Wirken kuenden
+ * Die aeltesten Sagen, der ich mich entsinne...
+ *
+ * In most shells, if you do something like:
+ *
+ * cat foo | while read a; do grep $a bar; done
+ *
+ * the shell forks and executes the loop in the sub-shell thus created.
+ * In zsh this traditionally executes the loop in the current shell, which
+ * is nice to have if the loop does something to change the shell, like
+ * setting parameters or calling builtins.
+ * Putting the loop in a sub-shell makes live easy, because the shell only
+ * has to put it into the job-structure and then treats it as a normal
+ * process. Suspending and interrupting is no problem then.
+ * Some years ago, zsh either couldn't suspend such things at all, or
+ * it got really messed up when users tried to do it. As a solution, we
+ * implemented the list_pipe-stuff, which has since then become a reason
+ * for many nightmares.
+ * Pipelines like the one above are executed by the functions in this file
+ * which call each other (and sometimes recursively). The one above, for
+ * example would lead to a function call stack roughly like:
+ *
+ * execlist->execpline->execcmd->execwhile->execlist->execpline
+ *
+ * (when waiting for the grep, ignoring execpline2 for now). At this time,
+ * zsh has build two job-table entries for it: one for the cat and one for
+ * the grep. If the user hits ^Z at this point (and jobbing is used), the
+ * shell is notified that the grep was suspended. The list_pipe flag is
+ * used to tell the execpline where it was waiting that it was in a pipeline
+ * with a shell construct at the end (which may also be a shell function or
+ * several other things). When zsh sees the suspended grep, it forks to let
+ * the sub-shell execute the rest of the while loop. The parent shell walks
+ * up in the function call stack to the first execpline. There it has to find
+ * out that it has just forked and then has to add information about the sub-
+ * shell (its pid and the text for it) in the job entry of the cat. The pid
+ * is passed down in the list_pipe_pid variable.
+ * But there is a problem: the suspended grep is a child of the parent shell
+ * and can't be adopted by the sub-shell. So the parent shell also has to
+ * keep the information about this process (more precisely: this pipeline)
+ * by keeping the job table entry it created for it. The fact that there
+ * are two jobs which have to be treated together is remembered by setting
+ * the STAT_SUPERJOB flag in the entry for the cat-job (which now also
+ * contains a process-entry for the whole loop -- the sub-shell) and by
+ * setting STAT_SUBJOB in the job of the grep-job. With that we can keep
+ * sub-jobs from being displayed and we can handle an fg/bg on the super-
+ * job correctly. When the super-job is continued, the shell also wakes up
+ * the sub-job. But then, the grep will exit sometime. Now the parent shell
+ * has to remember not to try to wake it up again (in case of another ^Z).
+ * It also has to wake up the sub-shell (which suspended itself immediately
+ * after creation), so that the rest of the loop is executed by it.
+ * But there is more: when the sub-shell is created, the cat may already
+ * have exited, so we can't put the sub-shell in the process group of it.
+ * In this case, we put the sub-shell in the process group of the parent
+ * shell and in any case, the sub-shell has to put all commands executed
+ * by it into its own process group, because only this way the parent
+ * shell can control them since it only knows the process group of the sub-
+ * shell. Of course, this information is also important when putting a job
+ * in the foreground, where we have to attach its process group to the
+ * controlling tty.
+ * All this is made more difficult because we have to handle return values
+ * correctly. If the grep is signaled, its exit status has to be propagated
+ * back to the parent shell which needs it to set the exit status of the
+ * super-job. And of course, when the grep is signaled (including ^C), the
+ * loop has to be stopped, etc.
+ * The code for all this is distributed over three files (exec.c, jobs.c,
+ * and signals.c) and none of them is a simple one. So, all in all, there
+ * may still be bugs, but considering the complexity (with race conditions,
+ * signal handling, and all that), this should probably be expected.
+ */
/**/
int list_pipe = 0, simple_pline = 0;
@@ -219,12 +313,18 @@ static char list_pipe_text[JOBTEXTSIZE];
/**/
static int
-execcursh(Cmd cmd)
+execcursh(Estate state, int do_exec)
{
- if (!list_pipe)
+ Wordcode end = state->pc + WC_CURSH_SKIP(state->pc[-1]);
+
+ if (!list_pipe && thisjob != list_pipe_job)
deletejob(jobtab + thisjob);
- execlist(cmd->u.list, 1, cmd->flags & CFLAG_EXEC);
- cmd->u.list = NULL;
+ cmdpush(CS_CURSH);
+ execlist(state, 1, do_exec);
+ cmdpop();
+
+ state->pc = end;
+
return lastval;
}
@@ -276,7 +376,9 @@ zexecve(char *pth, char **argv)
if (execvebuf[1] == '!') {
for (t0 = 0; t0 != ct; t0++)
if (execvebuf[t0] == '\n')
- execvebuf[t0] = '\0';
+ break;
+ while (inblank(execvebuf[t0]))
+ execvebuf[t0--] = '\0';
execvebuf[POUNDBANGLIMIT] = '\0';
for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++);
for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
@@ -383,6 +485,7 @@ execute(Cmdnam not_used_yet, int dash)
}
argv = makecline(args);
+ closem(3);
child_unblock();
if ((int) strlen(arg0) >= PATH_MAX) {
zerr("command too long: %s", arg0, 0);
@@ -452,13 +555,17 @@ execute(Cmdnam not_used_yet, int dash)
_exit(1);
}
-#define try(X) { if (iscom(X)) return ztrdup(X); }
+#define RET_IF_COM(X) { if (iscom(X)) return docopy ? dupstring(X) : arg0; }
-/* get the full pathname of an external command */
+/*
+ * Get the full pathname of an external command.
+ * If the second argument is zero, return the first argument if found;
+ * if non-zero, return the path using heap memory. (RET_IF_COM(X), above).
+ */
/**/
-char *
-findcmd(char *arg0)
+mod_export char *
+findcmd(char *arg0, int docopy)
{
char **pp;
char *z, *s, buf[MAXCMDLEN];
@@ -471,7 +578,7 @@ findcmd(char *arg0)
return NULL;
for (s = arg0; *s; s++)
if (*s == '/') {
- try(arg0);
+ RET_IF_COM(arg0);
if (arg0 == s || unset(PATHDIRS)) {
return NULL;
}
@@ -491,13 +598,13 @@ findcmd(char *arg0)
*z++ = '/';
}
strcpy(z, arg0);
- try(buf);
+ RET_IF_COM(buf);
}
strcpy(nn, cn->u.name ? *(cn->u.name) : "");
strcat(nn, "/");
strcat(nn, cn->nam);
}
- try(nn);
+ RET_IF_COM(nn);
}
for (pp = path; *pp; pp++) {
z = buf;
@@ -506,7 +613,7 @@ findcmd(char *arg0)
*z++ = '/';
}
strcpy(z, arg0);
- try(buf);
+ RET_IF_COM(buf);
}
return NULL;
}
@@ -528,9 +635,15 @@ isreallycom(Cmdnam cn)
{
char fullnam[MAXCMDLEN];
- strcpy(fullnam, cn->u.name ? *(cn->u.name) : "");
- strcat(fullnam, "/");
- strcat(fullnam, cn->nam);
+ if (cn->flags & HASHED)
+ strcpy(fullnam, cn->u.cmd);
+ else if (!cn->u.name)
+ return 0;
+ else {
+ strcpy(fullnam, *(cn->u.name));
+ strcat(fullnam, "/");
+ strcat(fullnam, cn->nam);
+ }
return iscom(fullnam);
}
@@ -549,7 +662,7 @@ isrelative(char *s)
}
/**/
-Cmdnam
+mod_export Cmdnam
hashcmd(char *arg0, char **pp)
{
Cmdnam cn;
@@ -588,17 +701,60 @@ hashcmd(char *arg0, char **pp)
/* execute a string */
/**/
-void
+mod_export void
execstring(char *s, int dont_change_job, int exiting)
{
- List list;
+ Eprog prog;
pushheap();
- if ((list = parse_string(s)))
- execlist(list, dont_change_job, exiting);
+ if ((prog = parse_string(s, 0)))
+ execode(prog, dont_change_job, exiting);
popheap();
}
+/**/
+void
+execode(Eprog p, int dont_change_job, int exiting)
+{
+ struct estate s;
+
+ s.prog = p;
+ s.pc = p->prog;
+ s.strs = p->strs;
+
+ execlist(&s, dont_change_job, exiting);
+}
+
+/* Execute a simplified command. This is used to execute things that
+ * will run completely in the shell, so that we can by-pass all that
+ * nasty job-handling and redirection stuff in execpline and execcmd. */
+
+/**/
+static int
+execsimple(Estate state)
+{
+ wordcode code = *state->pc++;
+
+ if (errflag)
+ return (lastval = 1);
+
+ if (code)
+ lineno = code - 1;
+
+ code = wc_code(*state->pc++);
+
+ if (code == WC_ASSIGN) {
+ cmdoutval = 0;
+ addvars(state, state->pc - 1, 0);
+ if (isset(XTRACE)) {
+ fputc('\n', xtrerr);
+ fflush(xtrerr);
+ }
+ return (lastval = (errflag ? errflag : cmdoutval));
+ } else
+ return (lastval = (execfuncs[code - WC_CURSH])(state, 0));
+}
+
/* Main routine for executing a list. *
* exiting means that the (sub)shell we are in is a definite goner *
* after the current list is finished, so we may be able to exec the *
@@ -608,45 +764,78 @@ execstring(char *s, int dont_change_job, int exiting)
/**/
void
-execlist(List list, int dont_change_job, int exiting)
+execlist(Estate state, int dont_change_job, int exiting)
{
- Sublist slist;
static int donetrap;
- int ret, cj;
- int old_pline_level, old_list_pipe;
+ Wordcode next;
+ wordcode code;
+ int ret, cj, csp, ltype;
+ int old_pline_level, old_list_pipe, oldlineno;
+ /*
+ * ERREXIT only forces the shell to exit if the last command in a &&
+ * or || fails. This is the case even if an earlier command is a
+ * shell function or other current shell structure, so we have to set
+ * noerrexit here if the sublist is not of type END.
+ */
+ int oldnoerrexit = noerrexit;
cj = thisjob;
old_pline_level = pline_level;
old_list_pipe = list_pipe;
+ oldlineno = lineno;
if (sourcelevel && unset(SHINSTDIN))
pline_level = list_pipe = 0;
/* Loop over all sets of comands separated by newline, *
* semi-colon or ampersand (`sublists'). */
- while (list && list != &dummy_list && !breaks && !retflag) {
+ code = *state->pc++;
+ while (wc_code(code) == WC_LIST && !breaks && !retflag) {
+ ltype = WC_LIST_TYPE(code);
+ csp = cmdsp;
+
+ if (ltype & Z_SIMPLE) {
+ next = state->pc + WC_LIST_SKIP(code);
+ execsimple(state);
+ state->pc = next;
+ goto sublist_done;
+ }
/* 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. */
- while (slist) {
- switch (slist->type) {
- case END:
+ code = *state->pc++;
+ while (wc_code(code) == WC_SUBLIST) {
+ next = state->pc + WC_SUBLIST_SKIP(code);
+ if (!oldnoerrexit)
+ noerrexit = (WC_SUBLIST_TYPE(code) != WC_SUBLIST_END);
+ switch (WC_SUBLIST_TYPE(code)) {
+ case WC_SUBLIST_END:
/* End of sublist; just execute, ignoring status. */
- execpline(slist, list->type, !list->right && exiting);
+ if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE)
+ execsimple(state);
+ else
+ execpline(state, code, ltype, (ltype & Z_END) && exiting);
+ state->pc = next;
goto sublist_done;
break;
- case ANDNEXT:
+ case WC_SUBLIST_AND:
/* If the return code is non-zero, we skip pipelines until *
* we find a sublist followed by ORNEXT. */
- if ((ret = execpline(slist, Z_SYNC, 0))) {
- while ((slist = slist->right))
- if (slist->type == ORNEXT)
- break;
- if (!slist) {
+ if ((ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
+ execsimple(state) :
+ execpline(state, code, Z_SYNC, 0)))) {
+ state->pc = next;
+ code = *state->pc++;
+ next = state->pc + WC_SUBLIST_SKIP(code);
+ while (wc_code(code) == WC_SUBLIST &&
+ WC_SUBLIST_TYPE(code) == WC_SUBLIST_AND) {
+ state->pc = next;
+ code = *state->pc++;
+ next = state->pc + WC_SUBLIST_SKIP(code);
+ }
+ if (wc_code(code) != WC_SUBLIST) {
/* We've skipped to the end of the list, not executing *
* the final pipeline, so don't perform error handling *
* for this sublist. */
@@ -654,28 +843,43 @@ execlist(List list, int dont_change_job, int exiting)
goto sublist_done;
}
}
+ cmdpush(CS_CMDAND);
break;
- case ORNEXT:
+ case WC_SUBLIST_OR:
/* If the return code is zero, we skip pipelines until *
* we find a sublist followed by ANDNEXT. */
- if (!(ret = execpline(slist, Z_SYNC, 0))) {
- while ((slist = slist->right))
- if (slist->type == ANDNEXT)
- break;
- if (!slist) {
+ if (!(ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
+ execsimple(state) :
+ execpline(state, code, Z_SYNC, 0)))) {
+ state->pc = next;
+ code = *state->pc++;
+ next = state->pc + WC_SUBLIST_SKIP(code);
+ while (wc_code(code) == WC_SUBLIST &&
+ WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) {
+ state->pc = next;
+ code = *state->pc++;
+ next = state->pc + WC_SUBLIST_SKIP(code);
+ }
+ if (wc_code(code) != WC_SUBLIST) {
/* We've skipped to the end of the list, not executing *
* the final pipeline, so don't perform error handling *
* for this sublist. */
donetrap = 1;
goto sublist_done;
- }
+ }
}
+ cmdpush(CS_CMDOR);
break;
}
- slist = slist->right;
+ state->pc = next;
+ code = *state->pc++;
}
+ state->pc--;
sublist_done:
+ cmdsp = csp;
+ noerrexit = oldnoerrexit;
+
if (sigtrapped[SIGDEBUG])
dotrap(SIGDEBUG);
@@ -696,12 +900,13 @@ sublist_done:
exit(lastval);
}
}
-
- list = list->right;
+ if (ltype & Z_END)
+ break;
+ code = *state->pc++;
}
-
pline_level = old_pline_level;
list_pipe = old_list_pipe;
+ lineno = oldlineno;
if (dont_change_job)
thisjob = cj;
}
@@ -718,15 +923,17 @@ sublist_done:
/**/
static int
-execpline(Sublist l, int how, int last1)
+execpline(Estate state, wordcode slcode, int how, int last1)
{
int ipipe[2], opipe[2];
int pj, newjob;
int old_simple_pline = simple_pline;
- static int lastwj;
+ int slflags = WC_SUBLIST_FLAGS(slcode);
+ wordcode code = *state->pc++;
+ static int lastwj, lpforked;
- if (!l->left)
- return lastval = (l->flags & PFLAG_NOT) != 0;
+ if (wc_code(code) != WC_PIPE)
+ return lastval = (slflags & WC_SUBLIST_NOT) != 0;
pj = thisjob;
ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
@@ -735,10 +942,11 @@ execpline(Sublist l, int how, int last1)
/* get free entry in job table and initialize it */
if ((thisjob = newjob = initjob()) == -1)
return 1;
+
if (how & Z_TIMED)
jobtab[thisjob].stat |= STAT_TIMED;
- if (l->flags & PFLAG_COPROC) {
+ if (slflags & WC_SUBLIST_COPROC) {
how = Z_ASYNC;
if (coprocin >= 0) {
zclose(coprocin);
@@ -750,20 +958,26 @@ execpline(Sublist l, int how, int last1)
coprocout = opipe[1];
fdtable[coprocin] = fdtable[coprocout] = 0;
}
+ /* This used to set list_pipe_pid=0 unconditionally, but in things
+ * like `ls|if true; then sleep 20; cat; fi' where the sleep was
+ * stopped, the top-level execpline() didn't get the pid for the
+ * sub-shell because it was overwritten. */
if (!pline_level++) {
list_pipe_job = newjob;
+ list_pipe_pid = 0;
nowait = 0;
+ simple_pline = (WC_PIPE_TYPE(code) == WC_PIPE_END);
}
- list_pipe_pid = lastwj = 0;
- if (pline_level == 1)
- simple_pline = (l->left->type == END);
- execpline2(l->left, how, opipe[0], ipipe[1], last1);
+ lastwj = lpforked = 0;
+ execpline2(state, code, how, opipe[0], ipipe[1], last1);
pline_level--;
if (how & Z_ASYNC) {
lastwj = newjob;
jobtab[thisjob].stat |= STAT_NOSTTY;
- if (l->flags & PFLAG_COPROC)
+ if (slflags & WC_SUBLIST_COPROC) {
zclose(ipipe[1]);
+ zclose(opipe[0]);
+ }
if (how & Z_DISOWN) {
deletejob(jobtab + thisjob);
thisjob = -1;
@@ -775,13 +989,14 @@ execpline(Sublist l, int how, int last1)
} else {
if (newjob != lastwj) {
Job jn = jobtab + newjob;
+ int updated;
if (newjob == list_pipe_job && list_pipe_child)
_exit(0);
lastwj = thisjob = newjob;
- if (list_pipe)
+ if (list_pipe || (pline_level && !(how & Z_TIMED)))
jn->stat |= STAT_NOPRINT;
if (nowait) {
@@ -789,8 +1004,15 @@ execpline(Sublist l, int how, int last1)
struct process *pn, *qn;
curjob = newjob;
+ DPUTS(!list_pipe_pid, "invalid list_pipe_pid");
addproc(list_pipe_pid, list_pipe_text);
+ /* If the super-job contains only the sub-shell, the
+ sub-shell is the group leader. */
+ if (!jn->procs->next || lpforked == 2) {
+ jn->gleader = list_pipe_pid;
+ jn->stat |= STAT_SUBLEADER;
+ }
for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
if (WIFSTOPPED(pn->status))
break;
@@ -801,27 +1023,42 @@ execpline(Sublist l, int how, int last1)
}
jn->stat &= ~(STAT_DONE | STAT_NOPRINT);
- jn->stat |= STAT_STOPPED | STAT_CHANGED;
+ jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED;
printjob(jn, !!isset(LONGLISTJOBS), 1);
}
- else
+ else if (newjob != list_pipe_job)
deletejob(jn);
+ else
+ lastwj = -1;
}
+ errbrk_saved = 0;
for (; !nowait;) {
if (list_pipe_child) {
jn->stat |= STAT_NOPRINT;
makerunning(jn);
}
- if (!(jn->stat & STAT_LOCKED))
+ if (!(jn->stat & STAT_LOCKED)) {
+ updated = !!jobtab[thisjob].procs;
waitjobs();
-
+ child_block();
+ } else
+ updated = 0;
+ if (!updated &&
+ list_pipe_job && jobtab[list_pipe_job].procs &&
+ !(jobtab[list_pipe_job].stat & STAT_STOPPED)) {
+ child_unblock();
+ child_block();
+ }
if (list_pipe_child &&
jn->stat & STAT_DONE &&
lastval2 & 0200)
killpg(mypgrp, lastval2 & ~0200);
- if ((list_pipe || last1) && !list_pipe_child &&
- jn->stat & STAT_STOPPED) {
+ if (!list_pipe_child && !lpforked && !subsh && jobbing &&
+ (list_pipe || last1 || pline_level) &&
+ ((jn->stat & STAT_STOPPED) ||
+ (list_pipe_job && pline_level &&
+ (jobtab[list_pipe_job].stat & STAT_STOPPED)))) {
pid_t pid;
int synch[2];
@@ -841,27 +1078,45 @@ execpline(Sublist l, int how, int last1)
else if (pid) {
char dummy;
+ lpforked =
+ (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1);
list_pipe_pid = pid;
nowait = errflag = 1;
breaks = loops;
close(synch[1]);
read(synch[0], &dummy, 1);
close(synch[0]);
- jobtab[list_pipe_job].other = newjob;
- jobtab[list_pipe_job].stat |= STAT_SUPERJOB;
- jn->stat |= STAT_SUBJOB | STAT_NOPRINT;
- jn->other = pid;
- killpg(jobtab[list_pipe_job].gleader, SIGSTOP);
+ /* If this job has finished, we leave it as a
+ * normal (non-super-) job. */
+ if (!(jn->stat & STAT_DONE)) {
+ jobtab[list_pipe_job].other = newjob;
+ jobtab[list_pipe_job].stat |= STAT_SUPERJOB;
+ jn->stat |= STAT_SUBJOB | STAT_NOPRINT;
+ jn->other = pid;
+ }
+ if ((list_pipe || last1) && jobtab[list_pipe_job].procs)
+ killpg(jobtab[list_pipe_job].gleader, SIGSTOP);
break;
}
else {
close(synch[0]);
entersubsh(Z_ASYNC, 0, 0);
- setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader);
+ if (jobtab[list_pipe_job].procs) {
+ if (setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader)
+ == -1) {
+ setpgrp(0L, mypgrp = getpid());
+ }
+ } else
+ setpgrp(0L, mypgrp = getpid());
close(synch[1]);
kill(getpid(), SIGSTOP);
list_pipe = 0;
list_pipe_child = 1;
+ opts[INTERACTIVE] = 0;
+ if (errbrk_saved) {
+ errflag = prev_errflag;
+ breaks = prev_breaks;
+ }
break;
}
}
@@ -874,16 +1129,18 @@ execpline(Sublist l, int how, int last1)
if (list_pipe && (lastval & 0200) && pj >= 0 &&
(!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) {
+ deletejob(jn);
jn = jobtab + pj;
- jn->stat |= STAT_NOPRINT;
- killjb(jobtab + pj, lastval & ~0200);
+ killjb(jn, lastval & ~0200);
}
- if (list_pipe_child || (list_pipe && (jn->stat & STAT_DONE)))
+ if (list_pipe_child ||
+ ((jn->stat & STAT_DONE) &&
+ (list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB)))))
deletejob(jn);
thisjob = pj;
}
- if (l->flags & PFLAG_NOT)
+ if (slflags & WC_SUBLIST_NOT)
lastval = !lastval;
}
if (!pline_level)
@@ -897,32 +1154,43 @@ static int subsh_close = -1;
/**/
static void
-execpline2(Pline pline, int how, int input, int output, int last1)
+execpline2(Estate state, wordcode pcode,
+ int how, int input, int output, int last1)
{
pid_t pid;
int pipes[2];
- int oldlineno;
if (breaks || retflag)
return;
- oldlineno = lineno;
- lineno = pline->left->lineno;
+ if (WC_PIPE_LINENO(pcode))
+ lineno = WC_PIPE_LINENO(pcode) - 1;
- if (pline_level == 1)
- strcpy(list_pipe_text, getjobtext((void *) pline->left));
- if (pline->type == END) {
- execcmd(pline->left, input, output, how, last1 ? 1 : 2);
- pline->left = NULL;
- } else {
+ if (pline_level == 1) {
+ if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel))
+ strcpy(list_pipe_text,
+ getjobtext(state->prog,
+ state->pc + (WC_PIPE_TYPE(pcode) == WC_PIPE_END ?
+ 0 : 1)));
+ else
+ list_pipe_text[0] = '\0';
+ }
+ if (WC_PIPE_TYPE(pcode) == WC_PIPE_END)
+ execcmd(state, input, output, how, last1 ? 1 : 2);
+ else {
int old_list_pipe = list_pipe;
+ Wordcode next = state->pc + (*state->pc);
+ wordcode code;
+
+ state->pc++;
+ code = *state->pc;
mpipe(pipes);
/* if we are doing "foo | bar" where foo is a current *
* shell command, do foo in a subshell and do the *
* rest of the pipeline in the current shell. */
- if (pline->left->type >= CURSH && (how & Z_SYNC)) {
+ if (wc_code(code) >= WC_CURSH && (how & Z_SYNC)) {
int synch[2];
pipe(synch);
@@ -933,7 +1201,7 @@ execpline2(Pline pline, int how, int input, int output, int last1)
} else if (pid) {
char dummy, *text;
- text = getjobtext((void *) pline->left);
+ text = getjobtext(state->prog, state->pc);
addproc(pid, text);
close(synch[1]);
read(synch[0], &dummy, 1);
@@ -943,28 +1211,27 @@ execpline2(Pline pline, int how, int input, int output, int last1)
close(synch[0]);
entersubsh(how, 2, 0);
close(synch[1]);
- execcmd(pline->left, input, pipes[1], how, 0);
+ execcmd(state, input, pipes[1], how, 0);
_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);
+ execcmd(state, input, pipes[1], how, 0);
}
- pline->left = NULL;
zclose(pipes[1]);
- if (pline->right) {
- /* if another execpline() is invoked because the command is *
- * a list it must know that we're already in a pipeline */
- list_pipe = 1;
- execpline2(pline->right, how, pipes[0], output, last1);
- list_pipe = old_list_pipe;
- zclose(pipes[0]);
- subsh_close = -1;
- }
+ state->pc = next;
+
+ /* if another execpline() is invoked because the command is *
+ * a list it must know that we're already in a pipeline */
+ cmdpush(CS_PIPE);
+ list_pipe = 1;
+ execpline2(state, *state->pc++, how, pipes[0], output, last1);
+ list_pipe = old_list_pipe;
+ cmdpop();
+ zclose(pipes[0]);
+ subsh_close = -1;
}
-
- lineno = oldlineno;
}
/* make the argv array */
@@ -977,20 +1244,21 @@ makecline(LinkList list)
char **argv, **ptr;
/* A bigger argv is necessary for executing scripts */
- ptr =
- argv = 2 + (char **) ncalloc((countlinknodes(list) + 4) * sizeof(char *));
+ ptr = argv = 2 + (char **) hcalloc((countlinknodes(list) + 4) *
+ sizeof(char *));
+
if (isset(XTRACE)) {
if (!doneps4)
- fprintf(stderr, "%s", (prompt4) ? prompt4 : "");
+ printprompt4();
for (node = firstnode(list); node; incnode(node)) {
*ptr++ = (char *)getdata(node);
- zputs(getdata(node), stderr);
+ zputs(getdata(node), xtrerr);
if (nextnode(node))
- fputc(' ', stderr);
+ fputc(' ', xtrerr);
}
- fputc('\n', stderr);
- fflush(stderr);
+ fputc('\n', xtrerr);
+ fflush(xtrerr);
} else {
for (node = firstnode(list); node; incnode(node))
*ptr++ = (char *)getdata(node);
@@ -1000,18 +1268,33 @@ makecline(LinkList list)
}
/**/
-void
+mod_export void
untokenize(char *s)
{
- for (; *s; s++)
- if (itok(*s))
- if (*s == Nularg)
- chuck(s--);
- else
- *s = ztokens[*s - Pound];
+ if (*s) {
+ int c;
+
+ while ((c = *s++))
+ if (itok(c)) {
+ char *p = s - 1;
+
+ if (c != Nularg)
+ *p++ = ztokens[c - Pound];
+
+ while ((c = *s++)) {
+ if (itok(c)) {
+ if (c != Nularg)
+ *p++ = ztokens[c - Pound];
+ } else
+ *p++ = c;
+ }
+ *p = '\0';
+ break;
+ }
+ }
}
-/* Open a file for writing redicection */
+/* Open a file for writing redirection */
/**/
static int
@@ -1052,34 +1335,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) */
@@ -1135,7 +1418,7 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag)
if (!mfds[fd1] || unset(MULTIOS)) {
if(!mfds[fd1]) { /* starting a new multio */
- mfds[fd1] = (struct multio *) alloc(sizeof(struct multio));
+ mfds[fd1] = (struct multio *) zhalloc(sizeof(struct multio));
if (!forked && save[fd1] == -2)
save[fd1] = (fd1 == fd2) ? -1 : movefd(fd1);
}
@@ -1170,40 +1453,48 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag)
/**/
static void
-addvars(LinkList l, int export)
+addvars(Estate state, Wordcode pc, int export)
{
- Varasg v;
LinkList vl;
- int xtr;
- char **arr, **ptr;
+ int xtr, isstr, htok = 0;
+ char **arr, **ptr, *name;
+ Wordcode opc = state->pc;
+ wordcode ac;
+ local_list1(svl);
xtr = isset(XTRACE);
- if (xtr && nonempty(l)) {
- fprintf(stderr, "%s", prompt4 ? prompt4 : "");
+ if (xtr) {
+ printprompt4();
doneps4 = 1;
}
-
- while (nonempty(l)) {
- v = (Varasg) ugetnode(l);
- singsub(&v->name);
- if (errflag)
- return;
- untokenize(v->name);
+ state->pc = pc;
+ while (wc_code(ac = *state->pc++) == WC_ASSIGN) {
+ name = ecgetstr(state, EC_DUPTOK, &htok);
+ if (htok)
+ untokenize(name);
if (xtr)
- fprintf(stderr, "%s=", v->name);
- if (v->type == PM_SCALAR) {
- vl = newlinklist();
- addlinknode(vl, v->str);
+ fprintf(xtrerr, "%s=", name);
+ if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) {
+ init_list1(svl, ecgetstr(state, EC_DUPTOK, &htok));
+ vl = &svl;
} else
- vl = v->arr;
- prefork(vl, v->type == PM_SCALAR ? 7 : 3);
- 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)))) {
+ vl = ecgetlist(state, WC_ASSIGN_NUM(ac), EC_DUPTOK, &htok);
+
+ if (vl && htok) {
+ prefork(vl, (isstr ? (PF_SINGLE|PF_ASSIGN) :
+ PF_ASSIGN));
+ if (errflag) {
+ state->pc = opc;
+ return;
+ }
+ if (isset(GLOBASSIGN) || !isstr)
+ globlist(vl, 0);
+ if (errflag) {
+ state->pc = opc;
+ return;
+ }
+ }
+ if (isstr && (empty(vl) || !nextnode(firstnode(vl)))) {
Param pm;
char *val;
int allexp;
@@ -1215,48 +1506,100 @@ addvars(LinkList l, int export)
val = ztrdup(ugetnode(vl));
}
if (xtr)
- fprintf(stderr, "%s ", val);
- if (export) {
- if (export < 0) {
- /* We are going to fork so do not bother freeing this */
- pm = (Param) paramtab->removenode(paramtab, v->name);
- if (isset(RESTRICTED) && (pm->flags & PM_RESTRICTED)) {
- zerr("%s: restricted", pm->nam, 0);
- zsfree(val);
- return;
- }
+ fprintf(xtrerr, "%s ", val);
+ if (export && !strchr(name, '[')) {
+ if (export < 0 && isset(RESTRICTED) &&
+ (pm = (Param) paramtab->removenode(paramtab, name)) &&
+ (pm->flags & PM_RESTRICTED)) {
+ zerr("%s: restricted", pm->nam, 0);
+ zsfree(val);
+ state->pc = opc;
+ return;
}
allexp = opts[ALLEXPORT];
opts[ALLEXPORT] = 1;
- pm = setsparam(v->name, val);
+ pm = setsparam(name, val);
opts[ALLEXPORT] = allexp;
} else
- pm = setsparam(v->name, val);
- if (errflag)
+ pm = setsparam(name, val);
+ if (errflag) {
+ state->pc = opc;
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) {
- fprintf(stderr, "( ");
+ fprintf(xtrerr, "( ");
for (ptr = arr; *ptr; ptr++)
- fprintf(stderr, "%s ", *ptr);
- fprintf(stderr, ") ");
+ fprintf(xtrerr, "%s ", *ptr);
+ fprintf(xtrerr, ") ");
}
- setaparam(v->name, arr);
- if (errflag)
+ setaparam(name, arr);
+ if (errflag) {
+ state->pc = opc;
return;
+ }
+ }
+ state->pc = opc;
+}
+
+/**/
+void
+setunderscore(char *str)
+{
+ if (str && *str) {
+ int l = strlen(str) + 1, nl = (l + 31) & ~31;
+
+ if (nl > underscorelen || (underscorelen - nl) > 64) {
+ zfree(underscore, underscorelen);
+ underscore = (char *) zalloc(underscorelen = nl);
+ }
+ strcpy(underscore, str);
+ underscoreused = l;
+ } else {
+ if (underscorelen > 128) {
+ zfree(underscore, underscorelen);
+ underscore = (char *) zalloc(underscorelen = 32);
+ }
+ *underscore = '\0';
+ underscoreused = 1;
+ }
+}
+
+/* These describe the type of espansions that need to be done on the words
+ * used in the thing we are about to execute. They are set in execcmd() and
+ * used in execsubst() which might be called from one of the functions
+ * called from execcmd() (like execfor() and so on). */
+
+static int esprefork, esglob = 1;
+
+/**/
+void
+execsubst(LinkList strs)
+{
+ if (strs) {
+ prefork(strs, esprefork);
+ if (esglob) {
+ LinkList ostrs = strs;
+ globlist(strs, 0);
+ strs = ostrs;
+ }
}
}
/**/
static void
-execcmd(Cmd cmd, int input, int output, int how, int last1)
+execcmd(Estate state, int input, int output, int how, int last1)
{
HashNode hn = NULL;
LinkNode node;
@@ -1264,15 +1607,35 @@ 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, do_exec = 0, i, htok = 0;
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 redir;
+ wordcode code;
+ Wordcode beg = state->pc, varspc;
+ FILE *oxtrerr = xtrerr;
doneps4 = 0;
- args = cmd->args;
- type = cmd->type;
+ redir = (wc_code(*state->pc) == WC_REDIR ? ecgetredirs(state) : NULL);
+ if (wc_code(*state->pc) == WC_ASSIGN) {
+ varspc = state->pc;
+ while (wc_code((code = *state->pc)) == WC_ASSIGN)
+ state->pc += (WC_ASSIGN_TYPE(code) == WC_ASSIGN_SCALAR ?
+ 3 : WC_ASSIGN_NUM(code) + 2);
+ } else
+ varspc = NULL;
+
+ code = *state->pc++;
+
+ type = wc_code(code);
+
+ /* It would be nice if we could use EC_DUPTOK instead of EC_DUP here.
+ * But for that we would need to check/change all builtins so that
+ * they don't modify their argument strings. */
+ args = (type == WC_SIMPLE ?
+ ecgetlist(state, WC_SIMPLE_ARGC(code), EC_DUP, &htok) : NULL);
for (i = 0; i < 10; i++) {
save[i] = -2;
@@ -1281,7 +1644,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 == WC_SIMPLE && args && nonempty(args) &&
*(char *)peekfirst(args) == '%') {
pushnode(args, dupstring((how & Z_DISOWN)
? "disown" : (how & Z_ASYNC) ? "bg" : "fg"));
@@ -1292,8 +1655,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
* any redirections, then check if it matches as a prefix of a *
* 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 &&
+ if (isset(AUTORESUME) && type == WC_SIMPLE && (how & Z_SYNC) &&
+ args && nonempty(args) && (!redir || empty(redir)) && !input &&
!nextnode(firstnode(args))) {
if (unset(NOTIFY))
scanjobs();
@@ -1306,8 +1669,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
* command if it contains some tokens (e.g. x=ex; ${x}port), so this *
* only works in simple cases. has_token() is called to make sure *
* this really is a simple case. */
- if (type == SIMPLE) {
- while (nonempty(args)) {
+ if (type == WC_SIMPLE) {
+ while (args && nonempty(args)) {
char *cmdarg = (char *) peekfirst(args);
checked = !has_token(cmdarg);
if (!checked)
@@ -1323,13 +1686,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
}
if (!(hn->flags & BINF_PREFIX)) {
is_builtin = 1;
-#ifdef DYNAMIC
+
/* autoload the builtin if necessary */
if (!((Builtin) hn)->handlerfunc) {
load_module(((Builtin) hn)->optstr);
hn = builtintab->getnode(builtintab, cmdarg);
}
-#endif
assign = (hn->flags & BINF_MAGICEQUALS);
break;
}
@@ -1344,18 +1706,20 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
}
/* Do prefork substitutions */
- prefork(args, assign ? 2 : isset(MAGICEQUALSUBST));
+ esprefork = (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0;
+ if (args && htok)
+ prefork(args, esprefork);
- if (type == SIMPLE) {
+ if (type == WC_SIMPLE) {
int unglobbed = 0;
for (;;) {
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));
+ glob(args, firstnode(args), 0);
else if (!unglobbed) {
for (node = firstnode(args); node; incnode(node))
untokenize((char *) getdata(node));
@@ -1364,46 +1728,59 @@ 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;
+ if ((cflags & BINF_EXEC) && last1)
+ do_exec = 1;
/* Empty command */
- if (empty(args)) {
- if (nonempty(cmd->redir)) {
- if (cmd->flags & CFLAG_EXEC) {
+ if (!args || empty(args)) {
+ if (redir && nonempty(redir)) {
+ if (do_exec) {
/* Was this "exec < foobar"? */
nullexec = 1;
break;
- } else if (!nullcmd || !*nullcmd ||
+ } else if (varspc) {
+ nullexec = 2;
+ break;
+ } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] ||
(cflags & BINF_PREFIX)) {
zerr("redirection with no command", NULL, 0);
errflag = lastval = 1;
return;
+ } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) {
+ if (!args)
+ args = newlinklist();
+ addlinknode(args, dupstring(":"));
} 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 (varspc)
+ addvars(state, varspc, 0);
if (errflag)
lastval = errflag;
else
lastval = cmdoutval;
if (isset(XTRACE)) {
- fputc('\n', stderr);
- fflush(stderr);
+ fputc('\n', xtrerr);
+ fflush(xtrerr);
}
return;
}
- } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) &&
- (cmd->flags & CFLAG_EXEC)) {
- zerrnam("exec", "%s: restricted", (char *) getdata(firstnode(args)), 0);
+ } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
+ zerrnam("exec", "%s: restricted",
+ (char *) getdata(firstnode(args)), 0);
lastval = 1;
return;
}
@@ -1428,11 +1805,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
}
if (!(hn->flags & BINF_PREFIX)) {
is_builtin = 1;
-#ifdef DYNAMIC
+
/* autoload the builtin if necessary */
- if (!((Builtin) hn)->handlerfunc)
+ if (!((Builtin) hn)->handlerfunc) {
load_module(((Builtin) hn)->optstr);
-#endif
+ hn = builtintab->getnode(builtintab, cmdarg);
+ }
break;
}
cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
@@ -1448,23 +1826,20 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
}
/* Get the text associated with this command. */
- if (jobbing || (how & Z_TIMED))
- text = getjobtext((void *) cmd);
+ if ((how & Z_ASYNC) ||
+ (!sfcontext && !sourcelevel && (jobbing || (how & Z_TIMED))))
+ text = getjobtext(state->prog, beg);
else
text = NULL;
/* Set up special parameter $_ */
- zsfree(underscore);
- if (nonempty(args)
- && (underscore = ztrdup((char *) getdata(lastnode(args)))))
- untokenize(underscore);
- else
- underscore = ztrdup("");
+
+ setunderscore((args && nonempty(args)) ? ((char *) getdata(lastnode(args))) : "");
/* Warn about "rm *" */
- if (type == SIMPLE && interact && unset(RMSTARSILENT)
- && isset(SHINSTDIN) && nonempty(args) && nextnode(firstnode(args))
- && !strcmp(peekfirst(args), "rm")) {
+ if (type == WC_SIMPLE && interact && unset(RMSTARSILENT) &&
+ isset(SHINSTDIN) && args && nonempty(args) &&
+ nextnode(firstnode(args)) && !strcmp(peekfirst(args), "rm")) {
LinkNode node, next;
for (node = nextnode(firstnode(args)); node && !errflag; node = next) {
@@ -1493,28 +1868,33 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
return;
}
- if (type == SIMPLE && !nullexec) {
+ if (type == WC_SIMPLE && !nullexec) {
char *s;
- char trycd = (isset(AUTOCD) && isset(SHINSTDIN)
- && empty(cmd->redir) && !empty(args)
- && !nextnode(firstnode(args))
- && *(char *)peekfirst(args));
+ char trycd = (isset(AUTOCD) && isset(SHINSTDIN) &&
+ (!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);
+ char **checkpath = pathchecked;
+ int dohashcmd = isset(HASHCMDS);
hn = cmdnamtab->getnode(cmdnamtab, cmdarg);
if (hn && trycd && !isreallycom((Cmdnam)hn)) {
+ if (!(((Cmdnam)hn)->flags & HASHED)) {
+ checkpath = path;
+ dohashcmd = 1;
+ }
cmdnamtab->removenode(cmdnamtab, cmdarg);
cmdnamtab->freenode(hn);
hn = NULL;
}
- if (!hn && isset(HASHCMDS) && strcmp(cmdarg, "..")) {
+ if (!hn && dohashcmd && strcmp(cmdarg, "..")) {
for (s = cmdarg; *s && *s != '/'; s++);
if (!*s)
- hn = (HashNode) hashcmd(cmdarg, pathchecked);
+ hn = (HashNode) hashcmd(cmdarg, checkpath);
}
}
@@ -1529,7 +1909,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
}
/* This is nonzero if the command is a current shell procedure? */
- is_cursh = (is_builtin || is_shfunc || (type >= CURSH) || nullexec);
+ is_cursh = (is_builtin || is_shfunc || nullexec || type >= WC_CURSH);
/**************************************************************************
* Do we need to fork? We need to fork if: *
@@ -1552,10 +1932,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
* current shell. *
**************************************************************************/
- if ((how & Z_ASYNC) || (!(cmd->flags & CFLAG_EXEC) &&
- (((is_builtin || is_shfunc) && output) ||
- (!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] ||
- sigtrapped[SIGEXIT] || havefiles()))))) {
+ if ((how & Z_ASYNC) ||
+ (!do_exec &&
+ (((is_builtin || is_shfunc) && output) ||
+ (!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] ||
+ sigtrapped[SIGEXIT] || havefiles()))))) {
pid_t pid;
int synch[2];
@@ -1576,21 +1957,27 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
closem(2);
#endif
if (how & Z_ASYNC) {
- lastpid = (long) pid;
- } else if (!jobtab[thisjob].stty_in_env && nonempty(cmd->vars)) {
+ lastpid = (zlong) pid;
+ } else if (!jobtab[thisjob].stty_in_env && varspc) {
/* search for STTY=... */
- while (nonempty(cmd->vars))
- if (!strcmp(((Varasg) ugetnode(cmd->vars))->name, "STTY")) {
+ Wordcode p = varspc;
+ wordcode ac;
+
+ while (wc_code(ac = *p) == WC_ASSIGN) {
+ if (!strcmp(ecrawstr(state->prog, p + 1, NULL), "STTY")) {
jobtab[thisjob].stty_in_env = 1;
break;
}
+ p += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
+ 3 : WC_ASSIGN_NUM(ac) + 2);
+ }
}
addproc(pid, text);
return;
}
/* pid == 0 */
close(synch[0]);
- entersubsh(how, type != SUBSH && !(how & Z_ASYNC) ? 2 : 1, 0);
+ entersubsh(how, (type != WC_SUBSH) && !(how & Z_ASYNC) ? 2 : 1, 0);
close(synch[1]);
forked = 1;
if (sigtrapped[SIGINT] & ZSIG_IGNORED)
@@ -1613,13 +2000,26 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
is_exec = 1;
}
- if (!(cflags & BINF_NOGLOB))
- globlist(args);
+ if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) {
+ LinkList oargs = args;
+ globlist(args, 0);
+ args = oargs;
+ }
if (errflag) {
lastval = 1;
goto err;
}
+ /* Make a copy of stderr for xtrace output before redirecting */
+ fflush(xtrerr);
+ if (isset(XTRACE) && xtrerr == stderr &&
+ (type < WC_SUBSH || type == WC_TIMED)) {
+ if (!(xtrerr = fdopen(movefd(dup(fileno(stderr))), "w")))
+ xtrerr = stderr;
+ else
+ fdtable[fileno(xtrerr)] = 3;
+ }
+
/* Add pipeline input/output to mnodes */
if (input)
addfd(forked, save, mfds, 0, input, 0);
@@ -1627,11 +2027,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) {
@@ -1649,7 +2050,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);
@@ -1691,7 +2092,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
addfd(forked, save, mfds, fn->fd1, fil, 0);
/* If this is 'exec < file', read from stdin, *
* not terminal, unless `file' is a terminal. */
- if (nullexec && fn->fd1 == 0 && isset(SHINSTDIN) && interact)
+ if (nullexec == 1 && fn->fd1 == 0 &&
+ isset(SHINSTDIN) && interact)
init_io();
break;
case CLOSE:
@@ -1702,16 +2104,28 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
break;
case MERGEIN:
case MERGEOUT:
- if(fn->fd2 < 10)
+ if (fn->fd2 < 10)
closemn(mfds, fn->fd2);
- fil = dup(fn->fd2);
+ if (fn->fd2 > 9 &&
+ (fdtable[fn->fd2] ||
+ fn->fd2 == coprocin ||
+ fn->fd2 == coprocout)) {
+ fil = -1;
+ errno = EBADF;
+ } else {
+ int fd = fn->fd2;
+ if(fd == -2)
+ fd = (fn->type == MERGEOUT) ? coprocout : coprocin;
+ fil = dup(fd);
+ }
if (fil == -1) {
char fdstr[4];
closemnodes(mfds);
fixfds(save);
- sprintf(fdstr, "%d", fn->fd2);
- zerr("%s: %e", fdstr, errno);
+ if (fn->fd2 != -2)
+ sprintf(fdstr, "%d", fn->fd2);
+ zerr("%s: %e", fn->fd2 == -2 ? "coprocess" : fdstr, errno);
execerr();
}
addfd(forked, save, mfds, fn->fd1, fil, fn->type == MERGEOUT);
@@ -1748,37 +2162,43 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
/* We are done with redirection. close the mnodes, *
* spawning tee/cat processes as necessary. */
for (i = 0; i < 10; i++)
- closemn(mfds, i);
+ if (mfds[i] && mfds[i]->ct >= 2)
+ closemn(mfds, i);
if (nullexec) {
- for (i = 0; i < 10; i++)
- if (save[i] != -2)
- zclose(save[i]);
+ if (nullexec == 1) {
+ /*
+ * If nullexec is 1 we specifically *don't* restore the original
+ * fd's before returning.
+ */
+ for (i = 0; i < 10; i++)
+ if (save[i] != -2)
+ zclose(save[i]);
+ goto done;
+ }
/*
- * Here we specifically *don't* restore the original fd's
- * before returning.
+ * If nullexec is 2, we have variables to add with the redirections
+ * in place.
*/
- return;
- }
-
- if (isset(EXECOPT) && !errflag) {
+ if (varspc)
+ addvars(state, varspc, 0);
+ lastval = errflag ? errflag : cmdoutval;
+ if (isset(XTRACE)) {
+ fputc('\n', xtrerr);
+ fflush(xtrerr);
+ }
+ } else if (isset(EXECOPT) && !errflag) {
/*
* We delay the entersubsh() to here when we are exec'ing
* the current shell (including a fake exec to run a builtin then
* exit) in case there is an error return.
*/
if (is_exec)
- entersubsh(how, type != SUBSH ? 2 : 1, 1);
- if (type >= CURSH) {
- static int (*func[]) _((Cmd)) = {
- execcursh, exectime, execfuncdef, execfor, execwhile,
- execrepeat, execif, execcase, execselect, execcond,
- execarith, execautofn
- };
-
+ entersubsh(how, (type != WC_SUBSH) ? 2 : 1, 1);
+ if (type >= WC_CURSH) {
if (last1 == 1)
- cmd->flags |= CFLAG_EXEC;
- lastval = (func[type - CURSH]) (cmd);
+ do_exec = 1;
+ lastval = (execfuncs[type - WC_CURSH])(state, do_exec);
} else if (is_builtin || is_shfunc) {
LinkList restorelist = 0, removelist = 0;
/* builtin or shell function */
@@ -1786,24 +2206,29 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
if (!forked && ((cflags & BINF_COMMAND) ||
(unset(POSIXBUILTINS) && !assign) ||
(isset(POSIXBUILTINS) && !is_shfunc &&
- !(hn->flags & BINF_PSPECIAL))))
- save_params(cmd, &restorelist, &removelist);
-
- if (cmd->vars) {
+ !(hn->flags & BINF_PSPECIAL)))) {
+ if (varspc)
+ save_params(state, varspc, &restorelist, &removelist);
+ else
+ restorelist = removelist = NULL;
+ }
+ if (varspc) {
/* Export this if the command is a shell function,
* but not if it's a builtin.
*/
- addvars(cmd->vars, is_shfunc);
+ addvars(state, varspc, is_shfunc);
if (errflag) {
- restore_params(restorelist, removelist);
+ if (restorelist)
+ restore_params(restorelist, removelist);
lastval = 1;
fixfds(save);
- return;
+ goto done;
}
}
if (is_shfunc) {
/* It's a shell function */
+
#ifdef PATH_DEV_FD
int i;
@@ -1814,7 +2239,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((Shfunc) hn, args);
#ifdef PATH_DEV_FD
for (i = 10; i <= max_zsh_fd; i++)
if (fdtable[i] > 1)
@@ -1843,30 +2268,31 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
clearerr(stdout);
}
- if (cmd->flags & CFLAG_EXEC) {
+ if (do_exec) {
if (subsh)
_exit(lastval);
/* If we are exec'ing a command, and we are not in a subshell, *
* then check if we should save the history file. */
if (isset(RCS) && interact && !nohistsave)
- savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
+ savehistfile(NULL, 1, HFILE_USE_OPTIONS);
exit(lastval);
}
-
- restore_params(restorelist, removelist);
+ if (restorelist)
+ restore_params(restorelist, removelist);
} else {
- if (cmd->flags & CFLAG_EXEC) {
+ if (!forked)
setiparam("SHLVL", --shlvl);
+ if (do_exec) {
/* If we are exec'ing a command, and we are not *
* in a subshell, then save the history file. */
if (!subsh && isset(RCS) && interact && !nohistsave)
- savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
+ savehistfile(NULL, 1, HFILE_USE_OPTIONS);
}
- if (type == SIMPLE) {
- if (cmd->vars) {
- addvars(cmd->vars, -1);
+ if (type == WC_SIMPLE) {
+ if (varspc) {
+ addvars(state, varspc, -1);
if (errflag)
_exit(1);
}
@@ -1881,7 +2307,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(varspc,
"BUG: assigment before complex command");
list_pipe = 0;
if (subsh_close >= 0)
@@ -1889,7 +2315,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
subsh_close = -1;
/* If we're forked (and we should be), no need to return */
DPUTS(last1 != 1 && !forked, "BUG: not exiting?");
- execlist(cmd->u.list, 0, 1);
+ execlist(state, 0, 1);
}
}
}
@@ -1898,54 +2324,48 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
if (forked)
_exit(lastval);
fixfds(save);
+
+ done:
+ if (xtrerr != oxtrerr) {
+ fil = fileno(xtrerr);
+ fclose(xtrerr);
+ xtrerr = oxtrerr;
+ zclose(fil);
+ }
}
/* Arrange to have variables restored. */
/**/
static void
-save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p)
+save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
{
Param pm;
- LinkNode node;
char *s;
-
- MUSTUSEHEAP("save_params()");
+ wordcode ac;
*restore_p = newlinklist();
*remove_p = newlinklist();
- for (node = firstnode(cmd->vars); node; incnode(node)) {
- s = ((Varasg) getdata(node))->name;
+ while (wc_code(ac = *pc) == WC_ASSIGN) {
+ s = ecrawstr(state->prog, pc + 1, NULL);
if ((pm = (Param) paramtab->getnode(paramtab, s))) {
if (!(pm->flags & PM_SPECIAL)) {
paramtab->removenode(paramtab, s);
} else if (!(pm->flags & PM_READONLY) &&
(unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) {
- Param tpm = (Param) alloc(sizeof *tpm);
-
+ Param tpm = (Param) zhalloc(sizeof *tpm);
tpm->nam = s;
- tpm->flags = pm->flags;
- switch (PM_TYPE(pm->flags)) {
- case PM_SCALAR:
- tpm->u.str = ztrdup(pm->gets.cfn(pm));
- break;
- case PM_INTEGER:
- tpm->u.val = pm->gets.ifn(pm);
- break;
- case PM_ARRAY:
- PERMALLOC {
- tpm->u.arr = arrdup(pm->gets.afn(pm));
- } LASTALLOC;
- break;
- }
+ copyparam(tpm, pm, 1);
pm = tpm;
}
addlinknode(*remove_p, s);
addlinknode(*restore_p, pm);
- } else {
+ } else
addlinknode(*remove_p, s);
- }
+
+ pc += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
+ 3 : WC_ASSIGN_NUM(ac) + 2);
}
}
@@ -1958,14 +2378,12 @@ restore_params(LinkList restorelist, LinkList removelist)
Param pm;
char *s;
- if (removelist) {
- /* remove temporary parameters */
- while ((s = (char *) ugetnode(removelist))) {
- if ((pm = (Param) paramtab->getnode(paramtab, s)) &&
- !(pm->flags & PM_SPECIAL)) {
- pm->flags &= ~PM_READONLY;
- unsetparam_pm(pm, 0, 0);
- }
+ /* remove temporary parameters */
+ while ((s = (char *) ugetnode(removelist))) {
+ if ((pm = (Param) paramtab->getnode(paramtab, s)) &&
+ !(pm->flags & PM_SPECIAL)) {
+ pm->flags &= ~PM_READONLY;
+ unsetparam_pm(pm, 0, 0);
}
}
@@ -1986,14 +2404,21 @@ restore_params(LinkList restorelist, LinkList removelist)
case PM_INTEGER:
tpm->sets.ifn(tpm, pm->u.val);
break;
+ case PM_EFLOAT:
+ case PM_FFLOAT:
+ tpm->sets.ffn(tpm, pm->u.dval);
+ break;
case PM_ARRAY:
tpm->sets.afn(tpm, pm->u.arr);
break;
+ case PM_HASHED:
+ tpm->sets.hfn(tpm, pm->u.hash);
+ break;
}
} else
paramtab->addnode(paramtab, pm->nam, pm);
- if (pm->flags & PM_EXPORTED)
- pm->env = addenv(pm->nam, getsparam(pm->nam));
+ if ((pm->flags & PM_EXPORTED) && ((s = getsparam(pm->nam))))
+ pm->env = addenv(pm->nam, s, pm->flags);
}
}
}
@@ -2037,18 +2462,17 @@ entersubsh(int how, int cl, int fake)
}
} else if (thisjob != -1 && cl) {
if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) {
- if (kill(jobtab[list_pipe_job].gleader, 0) == -1 ||
+ if (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ||
setpgrp(0L, jobtab[list_pipe_job].gleader) == -1) {
jobtab[list_pipe_job].gleader =
- jobtab[thisjob].gleader = mypgrp;
- setpgrp(0L, mypgrp);
-
+ jobtab[thisjob].gleader = (list_pipe_child ? mypgrp : getpid());
+ setpgrp(0L, jobtab[list_pipe_job].gleader);
if (how & Z_SYNC)
attachtty(jobtab[thisjob].gleader);
}
}
else if (!jobtab[thisjob].gleader ||
- (setpgrp(0L, jobtab[thisjob].gleader) == -1)) {
+ setpgrp(0L, jobtab[thisjob].gleader) == -1) {
jobtab[thisjob].gleader = getpid();
if (list_pipe_job != thisjob &&
!jobtab[list_pipe_job].gleader)
@@ -2086,7 +2510,7 @@ entersubsh(int how, int cl, int fake)
/* close internal shell fds */
/**/
-void
+mod_export void
closem(int how)
{
int i;
@@ -2147,8 +2571,14 @@ gethere(char *str, int typ)
if (t > buf && t[-1] == '\n')
t--;
*t = '\0';
- if (!qt)
+ if (!qt) {
+ int ef = errflag;
+
parsestr(buf);
+
+ if (!errflag)
+ errflag = ef;
+ }
s = dupstring(buf);
zfree(buf, bsiz);
return s;
@@ -2184,24 +2614,26 @@ getherestr(struct redir *fn)
LinkList
getoutput(char *cmd, int qt)
{
- List list;
+ Eprog prog;
int pipes[2];
pid_t pid;
- Cmd c;
- Redir r;
+ Wordcode pc;
- if (!(list = parse_string(cmd)))
+ if (!(prog = parse_string(cmd, 0)))
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) &&
- !nextnode(firstnode(c->redir)) &&
- (r = (Redir) getdata(firstnode(c->redir)))->fd1 == 0 &&
- r->type == READ) {
+
+ pc = prog->prog;
+ if (prog != &dummy_eprog &&
+ wc_code(pc[0]) == WC_LIST && (WC_LIST_TYPE(pc[0]) & Z_END) &&
+ wc_code(pc[1]) == WC_SUBLIST && !WC_SUBLIST_FLAGS(pc[1]) &&
+ WC_SUBLIST_TYPE(pc[1]) == WC_SUBLIST_END &&
+ wc_code(pc[2]) == WC_PIPE && WC_PIPE_TYPE(pc[2]) == WC_PIPE_END &&
+ wc_code(pc[3]) == WC_REDIR && WC_REDIR_TYPE(pc[3]) == READ &&
+ !pc[4] &&
+ wc_code(pc[6]) == WC_SIMPLE && !WC_SIMPLE_ARGC(pc[6])) {
/* $(< word) */
int stream;
- char *s = r->name;
+ char *s = dupstring(ecrawstr(prog, pc + 5, NULL));
singsub(&s);
if (errflag)
@@ -2213,7 +2645,6 @@ getoutput(char *cmd, int qt)
}
return readoutput(stream, qt);
}
-
mpipe(pipes);
child_block();
cmdoutval = 0;
@@ -2231,18 +2662,19 @@ getoutput(char *cmd, int qt)
zclose(pipes[1]);
retval = readoutput(pipes[0], qt);
fdtable[pipes[0]] = 0;
- child_suspend(0); /* unblocks */
+ waitforpid(pid); /* unblocks */
lastval = cmdoutval;
return retval;
}
-
/* pid == 0 */
child_unblock();
zclose(pipes[0]);
redup(pipes[1], 1);
opts[MONITOR] = 0;
entersubsh(Z_SYNC, 1, 0);
- execlist(list, 0, 1);
+ cmdpush(CS_CMDSUBST);
+ execode(prog, 0, 1);
+ cmdpop();
close(1);
_exit(lastval);
zerr("exit returned in child!!", NULL, 0);
@@ -2253,7 +2685,7 @@ getoutput(char *cmd, int qt)
/* read output of command substitution */
/**/
-static LinkList
+mod_export LinkList
readoutput(int in, int qt)
{
LinkList ret;
@@ -2263,7 +2695,7 @@ readoutput(int in, int qt)
fin = fdopen(in, "r");
ret = newlinklist();
- ptr = buf = (char *) ncalloc(bsiz = 64);
+ ptr = buf = (char *) hcalloc(bsiz = 64);
while ((c = fgetc(fin)) != EOF || errno == EINTR) {
if (c == EOF) {
errno = 0;
@@ -2276,7 +2708,7 @@ readoutput(int in, int qt)
cnt++;
}
if (++cnt >= bsiz) {
- char *pp = (char *) ncalloc(bsiz *= 2);
+ char *pp = (char *) hcalloc(bsiz *= 2);
memcpy(pp, buf, cnt - 1);
ptr = (buf = pp) + cnt - 1;
@@ -2294,7 +2726,7 @@ readoutput(int in, int qt)
}
addlinknode(ret, buf);
} else {
- char **words = spacesplit(buf, 0);
+ char **words = spacesplit(buf, 0, 1);
while (*words) {
if (isset(GLOBSUBST))
@@ -2306,11 +2738,11 @@ readoutput(int in, int qt)
}
/**/
-static List
+static Eprog
parsecmd(char *cmd)
{
char *str;
- List list;
+ Eprog prog;
for (str = cmd + 2; *str && *str != Outpar; str++);
if (!*str || cmd[1] != Inpar) {
@@ -2318,11 +2750,11 @@ parsecmd(char *cmd)
return NULL;
}
*str = '\0';
- if (str[1] || !(list = parse_string(cmd + 2))) {
+ if (str[1] || !(prog = parse_string(cmd + 2, 0))) {
zerr("parse error in process substitution", NULL, 0);
return NULL;
}
- return list;
+ return prog;
}
/* =(...) */
@@ -2333,22 +2765,22 @@ getoutputfile(char *cmd)
{
pid_t pid;
char *nam;
- List list;
+ Eprog prog;
int fd;
if (thisjob == -1)
return NULL;
- if (!(list = parsecmd(cmd)))
+ if (!(prog = parsecmd(cmd)))
return NULL;
if (!(nam = gettempname()))
return NULL;
nam = ztrdup(nam);
- PERMALLOC {
- if (!jobtab[thisjob].filelist)
- jobtab[thisjob].filelist = newlinklist();
- addlinknode(jobtab[thisjob].filelist, nam);
- } LASTALLOC;
+
+ if (!jobtab[thisjob].filelist)
+ jobtab[thisjob].filelist = znewlinklist();
+ zaddlinknode(jobtab[thisjob].filelist, nam);
+
child_block();
fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600);
@@ -2371,7 +2803,9 @@ getoutputfile(char *cmd)
redup(fd, 1);
opts[MONITOR] = 0;
entersubsh(Z_SYNC, 1, 0);
- execlist(list, 0, 1);
+ cmdpush(CS_CMDSUBST);
+ execode(prog, 0, 1);
+ cmdpop();
close(1);
_exit(lastval);
zerr("exit returned in child!!", NULL, 0);
@@ -2407,7 +2841,7 @@ getproc(char *cmd)
zerr("doesn't look like your system supports FIFOs.", NULL, 0);
return NULL;
#else
- List list;
+ Eprog prog;
int out = *cmd == Inang;
char *pnam;
#ifndef PATH_DEV_FD
@@ -2422,16 +2856,15 @@ getproc(char *cmd)
if (!(pnam = namedpipe()))
return NULL;
#else
- pnam = ncalloc(strlen(PATH_DEV_FD) + 6);
+ pnam = hcalloc(strlen(PATH_DEV_FD) + 6);
#endif
- if (!(list = parsecmd(cmd)))
+ if (!(prog = parsecmd(cmd)))
return NULL;
#ifndef PATH_DEV_FD
- PERMALLOC {
- if (!jobtab[thisjob].filelist)
- jobtab[thisjob].filelist = newlinklist();
- addlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
- } LASTALLOC;
+ if (!jobtab[thisjob].filelist)
+ jobtab[thisjob].filelist = znewlinklist();
+ zaddlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
+
if (zfork()) {
#else
mpipe(pipes);
@@ -2456,7 +2889,9 @@ getproc(char *cmd)
redup(pipes[out], out);
closem(0); /* this closes pipes[!out] as well */
#endif
- execlist(list, 0, 1);
+ cmdpush(CS_CMDSUBST);
+ execode(prog, 0, 1);
+ cmdpop();
zclose(out);
_exit(lastval);
return NULL;
@@ -2469,10 +2904,10 @@ getproc(char *cmd)
static int
getpipe(char *cmd)
{
- List list;
+ Eprog prog;
int pipes[2], out = *cmd == Inang;
- if (!(list = parsecmd(cmd)))
+ if (!(prog = parsecmd(cmd)))
return -1;
mpipe(pipes);
if (zfork()) {
@@ -2482,7 +2917,9 @@ getpipe(char *cmd)
entersubsh(Z_ASYNC, 1, 0);
redup(pipes[out], out);
closem(0); /* this closes pipes[!out] as well */
- execlist(list, 0, 1);
+ cmdpush(CS_CMDSUBST);
+ execode(prog, 0, 1);
+ cmdpop();
_exit(lastval);
return 0;
}
@@ -2518,26 +2955,62 @@ spawnpipes(LinkList l)
}
}
+extern int tracingcond;
+
/* evaluate a [[ ... ]] */
/**/
static int
-execcond(Cmd cmd)
+execcond(Estate state, int do_exec)
{
- return !evalcond(cmd->u.cond);
+ int stat;
+
+ state->pc--;
+ if (isset(XTRACE)) {
+ printprompt4();
+ fprintf(xtrerr, "[[");
+ tracingcond++;
+ }
+ cmdpush(CS_COND);
+ stat = !evalcond(state);
+ cmdpop();
+ if (isset(XTRACE)) {
+ fprintf(xtrerr, " ]]\n");
+ fflush(xtrerr);
+ tracingcond--;
+ }
+ return stat;
}
/* evaluate a ((...)) arithmetic command */
/**/
static int
-execarith(Cmd cmd)
+execarith(Estate state, int do_exec)
{
char *e;
- long val = 0;
+ zlong val = 0;
+ int htok = 0;
+
+ if (isset(XTRACE)) {
+ printprompt4();
+ fprintf(xtrerr, "((");
+ }
+ cmdpush(CS_MATH);
+ e = ecgetstr(state, EC_DUPTOK, &htok);
+ if (htok)
+ singsub(&e);
+ if (isset(XTRACE))
+ fprintf(xtrerr, " %s", e);
+
+ val = mathevali(e);
- while ((e = (char *) ugetnode(cmd->args)))
- val = matheval(e);
+ cmdpop();
+
+ if (isset(XTRACE)) {
+ fprintf(xtrerr, " ))\n");
+ fflush(xtrerr);
+ }
errflag = 0;
return !val;
}
@@ -2546,16 +3019,16 @@ execarith(Cmd cmd)
/**/
static int
-exectime(Cmd cmd)
+exectime(Estate state, int do_exec)
{
int jb;
jb = thisjob;
- if (!cmd->u.pline) {
+ if (WC_TIMED_TYPE(state->pc[-1]) == WC_TIMED_EMPTY) {
shelltime();
return 0;
}
- execpline(cmd->u.pline, Z_TIMED|Z_SYNC, 0);
+ execpline(state, *state->pc++, Z_TIMED|Z_SYNC, 0);
thisjob = jb;
return lastval;
}
@@ -2564,32 +3037,74 @@ exectime(Cmd cmd)
/**/
static int
-execfuncdef(Cmd cmd)
+execfuncdef(Estate state, int do_exec)
{
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;
+ int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0;
+ Wordcode beg = state->pc, end;
+ Eprog prog;
+ Patprog *pp;
+ LinkList names;
+
+ end = beg + WC_FUNCDEF_SKIP(state->pc[-1]);
+ names = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok);
+ nprg = end - beg;
+ sbeg = *state->pc++;
+ nstrs = *state->pc++;
+ npats = *state->pc++;
+
+ nprg = (end - state->pc);
+ plen = nprg * sizeof(wordcode);
+ len = plen + (npats * sizeof(Patprog)) + nstrs;
+
+ if (htok)
+ execsubst(names);
+
+ while ((s = (char *) ugetnode(names))) {
+ prog = (Eprog) zalloc(sizeof(*prog));
+ prog->npats = npats;
+ prog->len = len;
+ if (state->prog->dump) {
+ prog->flags = EF_MAP;
+ incrdumpcount(state->prog->dump);
+ prog->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
+ prog->prog = state->pc;
+ prog->strs = state->strs + sbeg;
+ prog->dump = state->prog->dump;
+ } else {
+ prog->flags = EF_REAL;
+ prog->pats = pp = (Patprog *) zalloc(len);
+ prog->prog = (Wordcode) (prog->pats + npats);
+ prog->strs = (char *) (prog->prog + nprg);
+ prog->dump = NULL;
+ memcpy(prog->prog, state->pc, plen);
+ memcpy(prog->strs, state->strs + sbeg, nstrs);
+ }
+ for (i = npats; i--; pp++)
+ *pp = dummy_patprog1;
+ prog->shf = NULL;
+
+ shf = (Shfunc) zalloc(sizeof(*shf));
+ shf->funcdef = prog;
+ 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)) {
+ freeeprog(shf->funcdef);
+ zfree(shf, sizeof(*shf));
+ state->pc = end;
+ return 1;
}
- shfunctab->addnode(shfunctab, ztrdup(s), shf);
+ sigtrapped[signum] |= ZSIG_FUNC;
}
- } LASTALLOC;
- if(isset(HISTNOFUNCTIONS))
+ shfunctab->addnode(shfunctab, ztrdup(s), shf);
+ }
+ if (isset(HISTNOFUNCTIONS))
remhist();
+ state->pc = end;
return 0;
}
@@ -2597,22 +3112,45 @@ execfuncdef(Cmd cmd)
/**/
static void
-execshfunc(Cmd cmd, Shfunc shf)
+execshfunc(Shfunc shf, LinkList args)
{
LinkList last_file_list = NULL;
+ unsigned char *ocs;
+ int ocsp, osfc;
if (errflag)
return;
- if (!list_pipe) {
+ if (!list_pipe && thisjob != list_pipe_job) {
/* Without this deletejob the process table *
* would be filled by a recursive function. */
last_file_list = jobtab[thisjob].filelist;
jobtab[thisjob].filelist = NULL;
deletejob(jobtab + thisjob);
}
-
- doshfunc(shf->funcdef, cmd->args, shf->flags, 0);
+ if (isset(XTRACE)) {
+ LinkNode lptr;
+ printprompt4();
+ if (args)
+ for (lptr = firstnode(args); lptr; incnode(lptr)) {
+ if (lptr != firstnode(args))
+ fputc(' ', xtrerr);
+ fprintf(xtrerr, "%s", (char *)getdata(lptr));
+ }
+ fputc('\n', xtrerr);
+ fflush(xtrerr);
+ }
+ ocs = cmdstack;
+ ocsp = cmdsp;
+ cmdstack = (unsigned char *) zalloc(CMDSTACKSZ);
+ cmdsp = 0;
+ if ((osfc = sfcontext) == SFC_NONE)
+ sfcontext = SFC_DIRECT;
+ doshfunc(shf->nam, shf->funcdef, args, shf->flags, 0);
+ sfcontext = osfc;
+ free(cmdstack);
+ cmdstack = ocs;
+ cmdsp = ocsp;
if (!list_pipe)
deletefilelist(last_file_list);
@@ -2626,168 +3164,244 @@ execshfunc(Cmd cmd, Shfunc shf)
/**/
static int
-execautofn(Cmd cmd)
+execautofn(Estate state, int do_exec)
{
- Shfunc shf = cmd->u.autofn->shf;
- List l = getfpfunc(shf->nam);
- if(l == &dummy_list) {
- zerr("%s: function definition file not found", shf->nam, 0);
+ Shfunc shf;
+ char *oldscriptname;
+
+ if (!(shf = loadautofn(state->prog->shf, 1, 0)))
return 1;
+
+ oldscriptname = scriptname;
+ scriptname = dupstring(state->prog->shf->nam);
+ execode(shf->funcdef, 1, 0);
+ scriptname = oldscriptname;
+
+ return lastval;
+}
+
+/**/
+Shfunc
+loadautofn(Shfunc shf, int fksh, int autol)
+{
+ int noalias = noaliases, ksh = 1;
+ Eprog prog;
+
+ pushheap();
+
+ noaliases = (shf->flags & PM_UNALIASED);
+ prog = getfpfunc(shf->nam, &ksh);
+ noaliases = noalias;
+
+ if (ksh == 1)
+ ksh = fksh;
+
+ if (prog == &dummy_eprog) {
+ zerr("%s: function definition file not found", shf->nam, 0);
+ popheap();
+ return NULL;
}
- if(isset(KSHAUTOLOAD)) {
- VARARR(char, n, strlen(shf->nam) + 1);
- strcpy(n, shf->nam);
- execlist(l, 1, 0);
- shf = (Shfunc) shfunctab->getnode(shfunctab, n);
- if(!shf || (shf->flags & PM_UNDEFINED)) {
- zerr("%s: function not defined by file", n, 0);
- return 1;
+ if (!prog)
+ prog = &dummy_eprog;
+ if (ksh == 2 || (ksh == 1 && isset(KSHAUTOLOAD))) {
+ if (autol) {
+ prog->flags |= EF_RUN;
+
+ freeeprog(shf->funcdef);
+ if (prog->flags & EF_MAP)
+ shf->funcdef = prog;
+ else
+ shf->funcdef = dupeprog(prog, 0);
+ shf->flags &= ~PM_UNDEFINED;
+ } else {
+ VARARR(char, n, strlen(shf->nam) + 1);
+ strcpy(n, shf->nam);
+ execode(prog, 1, 0);
+ shf = (Shfunc) shfunctab->getnode(shfunctab, n);
+ if (!shf || (shf->flags & PM_UNDEFINED)) {
+ zerr("%s: function not defined by file", n, 0);
+ popheap();
+ return NULL;
+ }
}
} else {
- freestruct(shf->funcdef);
- PERMALLOC {
- shf->funcdef = dupstruct(stripkshdef(l, shf->nam));
- } LASTALLOC;
+ freeeprog(shf->funcdef);
+ if (prog->flags & EF_MAP)
+ shf->funcdef = stripkshdef(prog, shf->nam);
+ else
+ shf->funcdef = dupeprog(stripkshdef(prog, shf->nam), 0);
shf->flags &= ~PM_UNDEFINED;
}
- HEAPALLOC {
- execlist(dupstruct(shf->funcdef), 1, 0);
- } LASTALLOC;
- return lastval;
+ popheap();
+
+ return shf;
}
/* execute a shell function */
/**/
-void
-doshfunc(List list, LinkList doshargs, int flags, int noreturnval)
+mod_export void
+doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
/* If noreturnval is nonzero, then reset the current return *
* value (lastval) to its value before the shell function *
* was executed. */
{
- char **tab, **x, *oargv0 = NULL;
- int xexittr, newexittr, oldzoptind, oldlastval;
- char *ou;
- void *xexitfn, *newexitfn;
- char saveopts[OPT_SIZE];
- int obreaks = breaks;
-
- HEAPALLOC {
- pushheap();
- if (trapreturn < 0)
- trapreturn--;
- oldlastval = lastval;
- xexittr = sigtrapped[SIGEXIT];
- if (xexittr & ZSIG_FUNC)
- xexitfn = shfunctab->removenode(shfunctab, "TRAPEXIT");
- else
- xexitfn = sigfuncs[SIGEXIT];
- sigtrapped[SIGEXIT] = 0;
- sigfuncs[SIGEXIT] = NULL;
- tab = pparams;
- oldzoptind = zoptind;
- zoptind = 1;
-
- /* 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));
-
- if (flags & PM_TAGGED)
- opts[XTRACE] = 1;
- opts[PRINTEXITVALUE] = 0;
- if (doshargs) {
- LinkNode node;
-
- node = doshargs->first;
- pparams = x = (char **) zcalloc(((sizeof *x) * (1 + countlinknodes(doshargs))));
- if (isset(FUNCTIONARGZERO)) {
- oargv0 = argzero;
- argzero = ztrdup((char *) node->dat);
- }
- node = node->next;
- for (; node; node = node->next, x++)
- *x = ztrdup((char *) node->dat);
- } else {
- pparams = (char **) zcalloc(sizeof *pparams);
- if (isset(FUNCTIONARGZERO)) {
- oargv0 = argzero;
- argzero = ztrdup(argzero);
- }
+ char **tab, **x, *oargv0;
+ int oldzoptind, oldlastval, oldoptcind;
+ char saveopts[OPT_SIZE], *oldscriptname = NULL, *fname = dupstring(name);
+ int obreaks;
+ struct funcstack fstack;
+
+ pushheap();
+
+ oargv0 = NULL;
+ obreaks = breaks;;
+ if (trapreturn < 0)
+ trapreturn--;
+ oldlastval = lastval;
+
+ starttrapscope();
+
+ tab = pparams;
+ if (!(flags & PM_UNDEFINED)) {
+ oldscriptname = scriptname;
+ scriptname = dupstring(name);
+ }
+ oldzoptind = zoptind;
+ zoptind = 1;
+ oldoptcind = optcind;
+ 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));
+
+ if (flags & PM_TAGGED)
+ opts[XTRACE] = 1;
+ opts[PRINTEXITVALUE] = 0;
+ if (doshargs) {
+ LinkNode node;
+
+ node = doshargs->first;
+ pparams = x = (char **) zcalloc(((sizeof *x) *
+ (1 + countlinknodes(doshargs))));
+ if (isset(FUNCTIONARGZERO)) {
+ oargv0 = argzero;
+ argzero = ztrdup((char *) node->dat);
}
- startparamscope();
- ou = underscore;
- underscore = ztrdup(underscore);
- execlist(dupstruct(list), 1, 0);
- zsfree(underscore);
- underscore = ou;
- endparamscope();
-
- if (retflag) {
- retflag = 0;
- breaks = obreaks;
- }
- freearray(pparams);
- if (oargv0) {
- zsfree(argzero);
- argzero = oargv0;
- }
- zoptind = oldzoptind;
- pparams = tab;
-
- if (isset(LOCALOPTIONS)) {
- /* restore all shell options except PRIVILEGED and RESTRICTED */
- saveopts[PRIVILEGED] = opts[PRIVILEGED];
- saveopts[RESTRICTED] = opts[RESTRICTED];
- memcpy(opts, saveopts, sizeof(opts));
- } else {
- /* just restore a couple. */
- opts[XTRACE] = saveopts[XTRACE];
- opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
- opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+ node = node->next;
+ for (; node; node = node->next, x++)
+ *x = ztrdup((char *) node->dat);
+ } else {
+ pparams = (char **) zcalloc(sizeof *pparams);
+ if (isset(FUNCTIONARGZERO)) {
+ oargv0 = argzero;
+ argzero = ztrdup(argzero);
}
+ }
+ fstack.name = dupstring(name);
+ fstack.prev = funcstack;
+ funcstack = &fstack;
- /*
- * The trap '...' EXIT runs in the environment of the caller,
- * so remember it here but run it after resetting the
- * traps for the parent.
- */
- newexittr = sigtrapped[SIGEXIT];
- newexitfn = sigfuncs[SIGEXIT];
- if (newexittr & ZSIG_FUNC)
- shfunctab->removenode(shfunctab, "TRAPEXIT");
-
- sigtrapped[SIGEXIT] = xexittr;
- if (xexittr & ZSIG_FUNC) {
- shfunctab->addnode(shfunctab, ztrdup("TRAPEXIT"), xexitfn);
- sigfuncs[SIGEXIT] = ((Shfunc) xexitfn)->funcdef;
- } else
- sigfuncs[SIGEXIT] = (List) xexitfn;
+ if (prog->flags & EF_RUN) {
+ Shfunc shf;
+
+ runshfunc(prog, NULL, fstack.name);
- if (newexitfn) {
- dotrapargs(SIGEXIT, &newexittr, newexitfn);
- freestruct(newexitfn);
+ prog->flags &= ~EF_RUN;
+
+ if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
+ (name = fname)))) {
+ zerr("%s: function not defined by file", name, 0);
+ if (!noreturnval)
+ lastval = 1;
+ popheap();
+ return;
}
+ prog = shf->funcdef;
+ }
+ runshfunc(prog, wrappers, fstack.name);
+ funcstack = fstack.prev;
+ if (retflag) {
+ retflag = 0;
+ breaks = obreaks;
+ }
+ freearray(pparams);
+ if (oargv0) {
+ zsfree(argzero);
+ argzero = oargv0;
+ }
+ pparams = tab;
+ optcind = oldoptcind;
+ zoptind = oldzoptind;
+ if (oldscriptname)
+ scriptname = oldscriptname;
+
+ if (isset(LOCALOPTIONS)) {
+ /* restore all shell options except PRIVILEGED and RESTRICTED */
+ saveopts[PRIVILEGED] = opts[PRIVILEGED];
+ saveopts[RESTRICTED] = opts[RESTRICTED];
+ memcpy(opts, saveopts, sizeof(opts));
+ } else {
+ /* just restore a couple. */
+ opts[XTRACE] = saveopts[XTRACE];
+ opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
+ opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+ }
- if (trapreturn < -1)
- trapreturn++;
- if (noreturnval)
- lastval = oldlastval;
- popheap();
- } LASTALLOC;
+ endtrapscope();
+
+ if (trapreturn < -1)
+ trapreturn++;
+ if (noreturnval)
+ lastval = oldlastval;
+ popheap();
+}
+
+/* This finally executes a shell function and any function wrappers *
+ * defined by modules. This works by calling the wrapper function which *
+ * in turn has to call back this function with the arguments it gets. */
+
+/**/
+mod_export void
+runshfunc(Eprog prog, FuncWrap wrap, char *name)
+{
+ int cont;
+ VARARR(char, ou, underscoreused);
+
+ memcpy(ou, underscore, underscoreused);
+
+ while (wrap) {
+ wrap->module->wrapper++;
+ cont = wrap->handler(prog, wrap->next, name);
+ wrap->module->wrapper--;
+
+ if (!wrap->module->wrapper &&
+ (wrap->module->flags & MOD_UNLOAD))
+ unload_module(wrap->module, NULL);
+
+ if (!cont)
+ return;
+ wrap = wrap->next;
+ }
+ startparamscope();
+ execode(prog, 1, 0);
+ setunderscore(ou);
+ endparamscope();
}
/* Search fpath for an undefined function. Finds the file, and returns the *
* list of its contents. */
/**/
-static List
-getfpfunc(char *s)
+Eprog
+getfpfunc(char *s, int *ksh)
{
char **pp, buf[PATH_MAX];
off_t len;
char *d;
- List r;
+ Eprog r;
int fd;
pp = fpath;
@@ -2798,29 +3412,36 @@ getfpfunc(char *s)
sprintf(buf, "%s/%s", *pp, s);
else
strcpy(buf, s);
+ if ((r = try_dump_file(*pp, s, buf, ksh)))
+ return r;
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) {
+ char *oldscriptname = scriptname;
+
close(fd);
+ d[len] = '\0';
d = metafy(d, len, META_REALLOC);
- HEAPALLOC {
- r = parse_string(d);
- } LASTALLOC;
+
+ scriptname = dupstring(s);
+ r = parse_string(d, 1);
+ scriptname = oldscriptname;
+
zfree(d, len + 1);
+
return r;
- } else {
- zfree(d, len + 1);
+ } else
close(fd);
- }
- } else {
+
+ zfree(d, len + 1);
+ } else
close(fd);
- }
}
}
- return &dummy_list;
+ return &dummy_eprog;
}
/* Handle the most common type of ksh-style autoloading, when doing a *
@@ -2830,29 +3451,60 @@ getfpfunc(char *s)
* contents of that definition. Otherwise, use the entire file. */
/**/
-static List
-stripkshdef(List l, char *name)
+Eprog
+stripkshdef(Eprog prog, char *name)
{
- Sublist s;
- Pline p;
- Cmd c;
- if(!l)
+ Wordcode pc = prog->prog;
+ wordcode code;
+
+ if (!prog)
return NULL;
- if(l->type != Z_SYNC || l->right)
- return l;
- s = l->left;
- if(s->flags || s->right)
- return l;
- p = s->left;
- 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) ||
- strcmp(name, peekfirst(c->args)))
- return l;
- return c->u.list;
+ code = *pc++;
+ if (wc_code(code) != WC_LIST ||
+ (WC_LIST_TYPE(code) & (Z_SYNC|Z_END|Z_SIMPLE)) != (Z_SYNC|Z_END|Z_SIMPLE))
+ return prog;
+ pc++;
+ code = *pc++;
+ if (wc_code(code) != WC_FUNCDEF ||
+ *pc != 1 || strcmp(name, ecrawstr(prog, pc + 1, NULL)))
+ return prog;
+
+ {
+ Eprog ret;
+ Wordcode end = pc + WC_FUNCDEF_SKIP(code);
+ int sbeg = pc[2], nstrs = pc[3], nprg, npats = pc[4], plen, len, i;
+ Patprog *pp;
+
+ pc += 5;
+
+ nprg = end - pc;
+ plen = nprg * sizeof(wordcode);
+ len = plen + (npats * sizeof(Patprog)) + nstrs;
+
+ if (prog->flags & EF_MAP) {
+ ret = prog;
+ free(prog->pats);
+ ret->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
+ ret->prog = pc;
+ ret->strs = prog->strs + sbeg;
+ } else {
+ ret = (Eprog) zhalloc(sizeof(*ret));
+ ret->flags = EF_HEAP;
+ ret->pats = pp = (Patprog *) zhalloc(len);
+ ret->prog = (Wordcode) (ret->pats + npats);
+ ret->strs = (char *) (ret->prog + nprg);
+ memcpy(ret->prog, pc, plen);
+ memcpy(ret->strs, prog->strs + sbeg, nstrs);
+ ret->dump = NULL;
+ }
+ ret->len = len;
+ ret->npats = npats;
+ for (i = npats; i--; pp++)
+ *pp = dummy_patprog1;
+ ret->shf = NULL;
+
+ return ret;
+ }
}
/* check to see if AUTOCD applies here */
@@ -2901,9 +3553,26 @@ static int
cancd2(char *s)
{
struct stat buf;
- char *us = unmeta(s);
+ char *us, *us2 = NULL;
+ int ret;
- return !(access(us, X_OK) || stat(us, &buf) || !S_ISDIR(buf.st_mode));
+ /*
+ * If CHASEDOTS and CHASELINKS are not set, we want to rationalize the
+ * path by removing foo/.. combinations in the logical rather than
+ * the physical path. If either is set, we test the physical path.
+ */
+ if (!isset(CHASEDOTS) && !isset(CHASELINKS)) {
+ if (*s != '/')
+ us = tricat(pwd[1] ? pwd : "", "/", s);
+ else
+ us = ztrdup(s);
+ fixdir(us2 = us);
+ } else
+ us = unmeta(s);
+ ret = !(access(us, X_OK) || stat(us, &buf) || !S_ISDIR(buf.st_mode));
+ if (us2)
+ free(us2);
+ return ret;
}
/**/
@@ -2928,8 +3597,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;
@@ -2957,8 +3625,8 @@ execrestore(void)
trapreturn = exstack->trapreturn;
noerrs = exstack->noerrs;
subsh_close = exstack->subsh_close;
- zsfree(underscore);
- underscore = exstack->underscore;
+ setunderscore(exstack->underscore);
+ zsfree(exstack->underscore);
en = exstack->next;
free(exstack);
exstack = en;