From 63acd1060174cd9d3595abb3fe71174c595e8131 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Mon, 17 Jan 2000 18:25:25 +0000 Subject: zsh-workers/9332 --- Src/exec.c | 666 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 397 insertions(+), 269 deletions(-) (limited to 'Src/exec.c') diff --git a/Src/exec.c b/Src/exec.c index 0c87f4500..b076f4af9 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -132,22 +132,22 @@ static int doneps4; /* parse string into a list */ /**/ -mod_export List +mod_export Eprog parse_string(char *s, int ln) { - List l; + Eprog p; int oldlineno = lineno; lexsave(); inpush(s, (ln ? INP_LINENO : 0), NULL); strinbeg(0); lineno = ln ? 1 : -1; - l = parse_list(); + p = parse_list(); lineno = oldlineno; strinend(); inpop(); lexrestore(); - return l; + return p; } /**/ @@ -300,12 +300,12 @@ static char list_pipe_text[JOBTEXTSIZE]; /**/ static int -execcursh(Cmd cmd, LinkList args, int flags) +execcursh(Estate state, int do_exec) { if (!list_pipe && thisjob != list_pipe_job) deletejob(jobtab + thisjob); cmdpush(CS_CURSH); - execlist(cmd->u.list, 1, flags & CFLAG_EXEC); + execlist(state, 1, do_exec); cmdpop(); return lastval; @@ -686,14 +686,27 @@ hashcmd(char *arg0, char **pp) mod_export void execstring(char *s, int dont_change_job, int exiting) { - List list; + Eprog prog; pushheap(); - if ((list = parse_string(s, 0))) - 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); +} + /* 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 * @@ -703,11 +716,12 @@ 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, csp; + 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 && @@ -727,31 +741,41 @@ execlist(List list, int dont_change_job, int exiting) /* 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) { /* Reset donetrap: this ensures that a trap is only * * called once for each sublist that fails. */ donetrap = 0; - slist = list->left; csp = cmdsp; + ltype = WC_LIST_TYPE(code); /* Loop through code followed by &&, ||, or end of sublist. */ - while (slist) { + code = *state->pc++; + while (wc_code(code) == WC_SUBLIST) { + next = state->pc + WC_SUBLIST_SKIP(code); if (!oldnoerrexit) - noerrexit = (slist->type != END); - switch (slist->type) { - case END: + 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); + 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 = 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. */ @@ -761,26 +785,34 @@ execlist(List list, int dont_change_job, int exiting) } 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 = 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; @@ -806,9 +838,12 @@ sublist_done: exit(lastval); } } - - list = list->right; + if (ltype & Z_END) + break; + code = *state->pc++; } + if (wc_code(code) == WC_END) + state->pc--; pline_level = old_pline_level; list_pipe = old_list_pipe; @@ -829,15 +864,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; + 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; @@ -846,10 +883,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); @@ -869,15 +907,15 @@ execpline(Sublist l, int how, int last1) list_pipe_job = newjob; list_pipe_pid = 0; nowait = 0; - simple_pline = (l->left->type == END); + simple_pline = (WC_PIPE_TYPE(code) == WC_PIPE_END); } lastwj = lpforked = 0; - execpline2(l->left, how, opipe[0], ipipe[1], last1); + 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]); } @@ -1027,7 +1065,7 @@ execpline(Sublist l, int how, int last1) thisjob = pj; } - if (l->flags & PFLAG_NOT) + if (slflags & WC_SUBLIST_NOT) lastval = !lastval; } if (!pline_level) @@ -1041,7 +1079,8 @@ 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]; @@ -1049,26 +1088,31 @@ execpline2(Pline pline, int how, int input, int output, int last1) if (breaks || retflag) return; - if (pline->left->lineno >= 0) - lineno = pline->left->lineno; + if (WC_PIPE_LINENO(pcode)) + lineno = WC_PIPE_LINENO(pcode) - 1; if (pline_level == 1) { if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel)) - strcpy(list_pipe_text, getjobtext((void *) pline->left)); + strcpy(list_pipe_text, getjobtext(state->prog, state->pc - 1)); else list_pipe_text[0] = '\0'; } - if (pline->type == END) - execcmd(pline->left, input, output, how, last1 ? 1 : 2); + 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); @@ -1079,7 +1123,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 - 2); addproc(pid, text); close(synch[1]); read(synch[0], &dummy, 1); @@ -1089,26 +1133,26 @@ 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. */ subsh_close = pipes[0]; - execcmd(pline->left, input, pipes[1], how, 0); + execcmd(state, input, pipes[1], how, 0); } 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 */ - cmdpush(CS_PIPE); - list_pipe = 1; - execpline2(pline->right, how, pipes[0], output, last1); - list_pipe = old_list_pipe; - cmdpop(); - 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; } } @@ -1122,8 +1166,8 @@ 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 **) ncalloc((countlinknodes(list) + 4) * + sizeof(char *)); if (isset(XTRACE)) { if (!doneps4) printprompt4(); @@ -1321,42 +1365,46 @@ 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; - LinkNode n; LinkList vl; - int xtr; + int xtr, isstr; char **arr, **ptr, *name; + Wordcode opc = state->pc; + wordcode ac; xtr = isset(XTRACE); - if (xtr && nonempty(l)) { + if (xtr) { printprompt4(); doneps4 = 1; } - - for (n = firstnode(l); n; incnode(n)) { - v = (Varasg) getdata(n); - name = dupstring(v->name); + state->pc = pc; + while (wc_code(ac = *state->pc++) == WC_ASSIGN) { + name = ecgetstr(state, 1); untokenize(name); if (xtr) fprintf(stderr, "%s=", name); - if (v->type == PM_SCALAR) { + if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) { vl = newlinklist(); - addlinknode(vl, dupstring(v->str)); + addlinknode(vl, ecgetstr(state, 1)); } else - vl = listdup(v->arr); + vl = ecgetlist(state, WC_ASSIGN_NUM(ac), 1); + if (vl) { - prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) : - PF_ASSIGN); - if (errflag) + prefork(vl, (isstr ? (PF_SINGLE|PF_ASSIGN) : + PF_ASSIGN)); + if (errflag) { + state->pc = opc; return; - if (isset(GLOBASSIGN) || v->type != PM_SCALAR) + } + if (isset(GLOBASSIGN) || !isstr) globlist(vl); - if (errflag) + if (errflag) { + state->pc = opc; return; + } } - if (v->type == PM_SCALAR && (empty(vl) || !nextnode(firstnode(vl)))) { + if (isstr && (empty(vl) || !nextnode(firstnode(vl)))) { Param pm; char *val; int allexp; @@ -1375,6 +1423,7 @@ addvars(LinkList l, int export) (pm->flags & PM_RESTRICTED)) { zerr("%s: restricted", pm->nam, 0); zsfree(val); + state->pc = opc; return; } allexp = opts[ALLEXPORT]; @@ -1383,8 +1432,10 @@ addvars(LinkList l, int export) opts[ALLEXPORT] = allexp; } else pm = setsparam(name, val); - if (errflag) + if (errflag) { + state->pc = opc; return; + } continue; } if (vl) { @@ -1404,9 +1455,12 @@ addvars(LinkList l, int export) fprintf(stderr, ") "); } setaparam(name, arr); - if (errflag) + if (errflag) { + state->pc = opc; return; + } } + state->pc = opc; } /**/ @@ -1430,9 +1484,25 @@ setunderscore(char *str) } } +static int esprefork, esglob; + +/**/ +void +execsubst(LinkList strs) +{ + if (strs) { + prefork(strs, esprefork); + if (esglob) { + LinkList ostrs = strs; + globlist(strs); + 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; @@ -1440,19 +1510,31 @@ 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, flags, i; + int fil, dfil, is_cursh, type, do_exec = 0, 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; + LinkList redir; + wordcode code; + Wordcode beg = state->pc, varspc; doneps4 = 0; - args = listdup(cmd->args); - type = cmd->type; - flags = cmd->flags; - redir = dupheaplist(cmd->redir); - vars = cmd->vars; + 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); + + args = (type == WC_SIMPLE ? + ecgetlist(state, WC_SIMPLE_ARGC(code), 1) : NULL); for (i = 0; i < 10; i++) { save[i] = -2; @@ -1461,7 +1543,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 && args && nonempty(args) && + if (type == WC_SIMPLE && args && nonempty(args) && *(char *)peekfirst(args) == '%') { pushnode(args, dupstring((how & Z_DISOWN) ? "disown" : (how & Z_ASYNC) ? "bg" : "fg")); @@ -1472,9 +1554,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) && - args && nonempty(args) && - (!cmd->redir || 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(); @@ -1487,7 +1568,7 @@ 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) { + if (type == WC_SIMPLE) { while (args && nonempty(args)) { char *cmdarg = (char *) peekfirst(args); checked = !has_token(cmdarg); @@ -1524,10 +1605,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) } /* Do prefork substitutions */ + esprefork = (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0; if (args) - prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0); + prefork(args, esprefork); - if (type == SIMPLE) { + if (type == WC_SIMPLE) { int unglobbed = 0; for (;;) { @@ -1546,16 +1628,16 @@ 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) - flags |= CFLAG_EXEC; + do_exec = 1; /* Empty command */ if (!args || empty(args)) { if (redir && nonempty(redir)) { - if (flags & CFLAG_EXEC) { + if (do_exec) { /* Was this "exec < foobar"? */ nullexec = 1; break; - } else if (vars && nonempty(vars)) { + } else if (varspc) { nullexec = 2; break; } else if (!nullcmd || !*nullcmd || @@ -1579,8 +1661,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) return; } else { cmdoutval = 0; - if (vars) - addvars(vars, 0); + if (varspc) + addvars(state, varspc, 0); if (errflag) lastval = errflag; else @@ -1591,9 +1673,9 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) } return; } - } else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && - (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; } @@ -1641,7 +1723,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) /* Get the text associated with this command. */ if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel && (jobbing || (how & Z_TIMED)))) - text = getjobtext((void *) cmd); + text = getjobtext(state->prog, beg); else text = NULL; @@ -1650,10 +1732,9 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) setunderscore((args && nonempty(args)) ? ((char *) getdata(lastnode(args))) : ""); /* Warn about "rm *" */ - if (type == SIMPLE && interact && unset(RMSTARSILENT) - && isset(SHINSTDIN) && args && 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) { @@ -1682,12 +1763,11 @@ 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) - && (!redir || empty(redir)) && args && !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((!args || empty(args)), "BUG: empty(args) in exec.c"); if (!hn) { @@ -1724,7 +1804,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: * @@ -1747,10 +1827,11 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) * current shell. * **************************************************************************/ - if ((how & Z_ASYNC) || (!(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]; @@ -1772,23 +1853,26 @@ 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 && - vars && nonempty(vars)) { + } else if (!jobtab[thisjob].stty_in_env && varspc) { /* search for STTY=... */ - LinkNode n; + Wordcode p = varspc; + wordcode ac; - for (n = firstnode(vars); n; incnode(n)) - if (!strcmp(((Varasg) getdata(n))->name, "STTY")) { + while (wc_code(ac = *p) == WC_ASSIGN) { + if (!strcmp(ecrawstr(state->prog, p + 1), "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) @@ -1811,7 +1895,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) is_exec = 1; } - if (args && !(cflags & BINF_NOGLOB)) { + if (args && (esglob = !(cflags & BINF_NOGLOB))) { LinkList oargs = args; globlist(args); args=oargs; @@ -1980,8 +2064,8 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) * If nullexec is 2, we have variables to add with the redirections * in place. */ - if (vars) - addvars(vars, 0); + if (varspc) + addvars(state, varspc, 0); lastval = errflag ? errflag : cmdoutval; if (isset(XTRACE)) { fputc('\n', stderr); @@ -1994,17 +2078,17 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) * 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, LinkList, int)) = { - execcursh, exectime, execfuncdef, execfor, execwhile, - execrepeat, execif, execcase, execselect, execcond, + entersubsh(how, (type != WC_SUBSH) ? 2 : 1, 1); + if (type >= WC_CURSH) { + static int (*func[]) _((Estate, int)) = { + execcursh, exectime, execfuncdef, execfor, execselect, + execwhile, execrepeat, execcase, execif, execcond, execarith, execautofn }; if (last1 == 1) - flags |= CFLAG_EXEC; - lastval = (func[type - CURSH]) (cmd, args, flags); + do_exec = 1; + lastval = (func[type - WC_CURSH])(state, do_exec); } else if (is_builtin || is_shfunc) { LinkList restorelist = 0, removelist = 0; /* builtin or shell function */ @@ -2013,13 +2097,13 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) (unset(POSIXBUILTINS) && !assign) || (isset(POSIXBUILTINS) && !is_shfunc && !(hn->flags & BINF_PSPECIAL)))) - save_params(cmd, &restorelist, &removelist); + save_params(state, varspc, &restorelist, &removelist); - if (vars) { + if (varspc) { /* Export this if the command is a shell function, * but not if it's a builtin. */ - addvars(vars, is_shfunc); + addvars(state, varspc, is_shfunc); if (errflag) { restore_params(restorelist, removelist); lastval = 1; @@ -2041,7 +2125,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, args); + execshfunc((Shfunc) hn, args); #ifdef PATH_DEV_FD for (i = 10; i <= max_zsh_fd; i++) if (fdtable[i] > 1) @@ -2070,7 +2154,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) clearerr(stdout); } - if (flags & CFLAG_EXEC) { + if (do_exec) { if (subsh) _exit(lastval); @@ -2080,21 +2164,20 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) savehistfile(NULL, 1, HFILE_USE_OPTIONS); exit(lastval); } - restore_params(restorelist, removelist); } else { if (!forked) setiparam("SHLVL", --shlvl); - if (flags & CFLAG_EXEC) { + 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(NULL, 1, HFILE_USE_OPTIONS); } - if (type == SIMPLE) { - if (vars) { - addvars(vars, -1); + if (type == WC_SIMPLE) { + if (varspc) { + addvars(state, varspc, -1); if (errflag) _exit(1); } @@ -2109,7 +2192,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) #endif execute((Cmdnam) hn, cflags & BINF_DASH); } else { /* ( ... ) */ - DPUTS(vars && nonempty(vars), + DPUTS(varspc, "BUG: assigment before complex command"); list_pipe = 0; if (subsh_close >= 0) @@ -2117,7 +2200,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); } } } @@ -2132,23 +2215,23 @@ execcmd(Cmd cmd, int input, int output, int how, int last1) /**/ 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; + wordcode ac; MUSTUSEHEAP("save_params()"); - if (!cmd->vars) { + if (!pc) { *restore_p = *remove_p = NULL; return; } *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); if ((pm = (Param) paramtab->getnode(paramtab, s))) { if (!(pm->flags & PM_SPECIAL)) { paramtab->removenode(paramtab, s); @@ -2161,9 +2244,11 @@ save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p) } 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); } } @@ -2408,25 +2493,27 @@ 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, 0))) + 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 && - (!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) { + + 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]) && + wc_code(pc[7]) == WC_END) { /* $(< word) */ int stream; - char *s = r->name; + char *s = dupstring(ecrawstr(prog, pc + 5)); singsub(&s); if (errflag) @@ -2438,7 +2525,6 @@ getoutput(char *cmd, int qt) } return readoutput(stream, qt); } - mpipe(pipes); child_block(); cmdoutval = 0; @@ -2460,14 +2546,13 @@ getoutput(char *cmd, int qt) 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); + execode(prog, 0, 1); close(1); _exit(lastval); zerr("exit returned in child!!", NULL, 0); @@ -2531,11 +2616,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) { @@ -2543,11 +2628,11 @@ parsecmd(char *cmd) return NULL; } *str = '\0'; - if (str[1] || !(list = parse_string(cmd + 2, 0))) { + if (str[1] || !(prog = parse_string(cmd + 2, 0))) { zerr("parse error in process substitution", NULL, 0); return NULL; } - return list; + return prog; } /* =(...) */ @@ -2558,12 +2643,12 @@ 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; @@ -2596,7 +2681,7 @@ getoutputfile(char *cmd) redup(fd, 1); opts[MONITOR] = 0; entersubsh(Z_SYNC, 1, 0); - execlist(list, 0, 1); + execode(prog, 0, 1); close(1); _exit(lastval); zerr("exit returned in child!!", NULL, 0); @@ -2632,7 +2717,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 @@ -2649,7 +2734,7 @@ getproc(char *cmd) #else pnam = ncalloc(strlen(PATH_DEV_FD) + 6); #endif - if (!(list = parsecmd(cmd))) + if (!(prog = parsecmd(cmd))) return NULL; #ifndef PATH_DEV_FD PERMALLOC { @@ -2681,7 +2766,7 @@ getproc(char *cmd) redup(pipes[out], out); closem(0); /* this closes pipes[!out] as well */ #endif - execlist(list, 0, 1); + execode(prog, 0, 1); zclose(out); _exit(lastval); return NULL; @@ -2694,10 +2779,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()) { @@ -2707,7 +2792,7 @@ getpipe(char *cmd) entersubsh(Z_ASYNC, 1, 0); redup(pipes[out], out); closem(0); /* this closes pipes[!out] as well */ - execlist(list, 0, 1); + execode(prog, 0, 1); _exit(lastval); return 0; } @@ -2749,15 +2834,17 @@ extern int tracingcond; /**/ static int -execcond(Cmd cmd, LinkList args, int flags) +execcond(Estate state, int do_exec) { int stat; + + state->pc--; if (isset(XTRACE)) { printprompt4(); fprintf(stderr, "[["); tracingcond++; } - stat = !evalcond(cmd->u.cond); + stat = !evalcond(state); if (isset(XTRACE)) { fprintf(stderr, " ]]\n"); fflush(stderr); @@ -2770,7 +2857,7 @@ execcond(Cmd cmd, LinkList args, int flags) /**/ static int -execarith(Cmd cmd, LinkList args, int flags) +execarith(Estate state, int do_exec) { char *e; zlong val = 0; @@ -2779,12 +2866,13 @@ execarith(Cmd cmd, LinkList args, int flags) printprompt4(); fprintf(stderr, "(("); } - if (args) - while ((e = (char *) ugetnode(args))) { - if (isset(XTRACE)) - fprintf(stderr, " %s", e); - val = mathevali(e); - } + e = ecgetstr(state, 1); + singsub(&e); + if (isset(XTRACE)) + fprintf(stderr, " %s", e); + + val = mathevali(e); + if (isset(XTRACE)) { fprintf(stderr, " ))\n"); fflush(stderr); @@ -2797,16 +2885,16 @@ execarith(Cmd cmd, LinkList args, int flags) /**/ static int -exectime(Cmd cmd, LinkList args, int flags) +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; } @@ -2815,35 +2903,63 @@ exectime(Cmd cmd, LinkList args, int flags) /**/ static int -execfuncdef(Cmd cmd, LinkList args, int flags) +execfuncdef(Estate state, int do_exec) { Shfunc shf; char *s; - int signum; + int signum, nprg, npats, num, len, plen, i; + Wordcode beg = state->pc, end, names; + Eprog prog; + Patprog *pp; + + end = beg + WC_FUNCDEF_SKIP(state->pc[-1]); + num = state->pc[0]; + names = state->pc + 1; + nprg = state->pc[1 + num] - 4; + npats = state->pc[2 + num]; + + state->pc += num + 3; + + plen = (end - state->pc) * sizeof(wordcode); + len = plen + (npats * sizeof(Patprog)); + + PERMALLOC { + while (num--) { + s = ecrawstr(state->prog, names++); + prog = (Eprog) zalloc(sizeof(*prog)); + prog->heap = 0; + prog->len = len; + prog->npats = npats; + prog->pats = pp = (Patprog *) zalloc(len); + prog->prog = (Wordcode) (prog->pats + npats); + for (i = npats; i--; pp++) + *pp = dummy_patprog1; + memcpy(prog->prog, state->pc, plen); + prog->strs = (char *) (prog->prog + nprg); + 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; + 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(); + state->pc = end; return 0; } @@ -2851,7 +2967,7 @@ execfuncdef(Cmd cmd, LinkList args, int flags) /**/ static void -execshfunc(Cmd cmd, Shfunc shf, LinkList args) +execshfunc(Shfunc shf, LinkList args) { LinkList last_file_list = NULL; unsigned char *ocs; @@ -2903,27 +3019,29 @@ execshfunc(Cmd cmd, Shfunc shf, LinkList args) /**/ static int -execautofn(Cmd cmd, LinkList args, int flags) +execautofn(Estate state, int do_exec) { - Shfunc shf = cmd->u.autofn->shf; + Shfunc shf = state->prog->shf; int noalias = noaliases; - List l; + Eprog prog; pushheap(); noaliases = (shf->flags & PM_UNALIASED); - l = getfpfunc(shf->nam); + prog = getfpfunc(shf->nam); noaliases = noalias; - if (l == &dummy_list) { + if (prog == &dummy_eprog) { zerr("%s: function definition file not found", shf->nam, 0); popheap(); return 1; } + if (!prog) + prog = &dummy_eprog; if (isset(KSHAUTOLOAD)) { VARARR(char, n, strlen(shf->nam) + 1); strcpy(n, shf->nam); - execlist(l, 1, 0); + 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); @@ -2931,15 +3049,15 @@ execautofn(Cmd cmd, LinkList args, int flags) return 1; } } else { - freestruct(shf->funcdef); + freeeprog(shf->funcdef); PERMALLOC { - shf->funcdef = dupstruct(stripkshdef(l, shf->nam)); + shf->funcdef = dupeprog(stripkshdef(prog, shf->nam)); } LASTALLOC; shf->flags &= ~PM_UNDEFINED; } popheap(); - execlist(shf->funcdef, 1, 0); + execode(shf->funcdef, 1, 0); return lastval; } @@ -2950,20 +3068,20 @@ loadautofn(Shfunc shf) /* Copied from execautofn() -- should consolidate someday */ int noalias = noaliases; - List l; + Eprog prog; pushheap(); noaliases = (shf->flags & PM_UNALIASED); - l = getfpfunc(shf->nam); + prog = getfpfunc(shf->nam); noaliases = noalias; - if (l == &dummy_list) { + if (prog == &dummy_eprog) { zerr("%s: function definition file not found", shf->nam, 0); return 1; } PERMALLOC { - shf->funcdef = dupstruct(stripkshdef(l, shf->nam)); + shf->funcdef = dupeprog(stripkshdef(prog, shf->nam)); } LASTALLOC; shf->flags &= ~PM_UNDEFINED; @@ -2976,7 +3094,7 @@ loadautofn(Shfunc shf) /**/ mod_export void -doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval) +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. */ @@ -3030,7 +3148,7 @@ doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval) argzero = ztrdup(argzero); } } - runshfunc(list, wrappers, dupstring(name)); + runshfunc(prog, wrappers, dupstring(name)); if (retflag) { retflag = 0; breaks = obreaks; @@ -3073,7 +3191,7 @@ doshfunc(char *name, List list, LinkList doshargs, int flags, int noreturnval) /**/ mod_export void -runshfunc(List list, FuncWrap wrap, char *name) +runshfunc(Eprog prog, FuncWrap wrap, char *name) { int cont; VARARR(char, ou, underscoreused); @@ -3082,7 +3200,7 @@ runshfunc(List list, FuncWrap wrap, char *name) while (wrap) { wrap->module->wrapper++; - cont = wrap->handler(list, wrap->next, name); + cont = wrap->handler(prog, wrap->next, name); wrap->module->wrapper--; if (!wrap->module->wrapper && @@ -3094,7 +3212,7 @@ runshfunc(List list, FuncWrap wrap, char *name) wrap = wrap->next; } startparamscope(); - execlist(list, 1, 0); + execode(prog, 1, 0); setunderscore(ou); endparamscope(); } @@ -3103,13 +3221,13 @@ runshfunc(List list, FuncWrap wrap, char *name) * list of its contents. */ /**/ -static List +static Eprog getfpfunc(char *s) { char **pp, buf[PATH_MAX]; off_t len; char *d; - List r; + Eprog r; int fd; pp = fpath; @@ -3140,12 +3258,11 @@ getfpfunc(char *s) close(fd); zfree(d, len + 1); - } else { + } else close(fd); - } } } - return &dummy_list; + return &dummy_eprog; } /* Handle the most common type of ksh-style autoloading, when doing a * @@ -3155,30 +3272,41 @@ getfpfunc(char *s) * contents of that definition. Otherwise, use the entire file. */ /**/ -static List -stripkshdef(List l, char *name) +static Eprog +stripkshdef(Eprog prog, char *name) { - Sublist s; - Pline p; - Cmd c; - if(!l) + Wordcode pc = prog->prog; + wordcode code; + Eprog ret; + + 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 || - (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; + code = *pc++; + if (wc_code(code) != WC_LIST || + (WC_LIST_TYPE(code) & (Z_SYNC|Z_END)) != (Z_SYNC|Z_END)) + return prog; + code = *pc++; + if (wc_code(code) != WC_SUBLIST || + WC_SUBLIST_FLAGS(code) || WC_SUBLIST_TYPE(code) != WC_SUBLIST_END) + return prog; + code = *pc++; + if (wc_code(code) != WC_PIPE || WC_PIPE_TYPE(code) != WC_PIPE_END) + return prog; + code = *pc++; + if (wc_code(code) != WC_FUNCDEF || + *pc != 1 || strcmp(name, ecrawstr(prog, pc + 1))) + return prog; + + ret = (Eprog) zhalloc(sizeof(*prog)); + ret->len = (WC_FUNCDEF_SKIP(code) - 3) * sizeof(wordcode); + ret->prog = pc + 3; + ret->strs = (char *) (pc + pc[3]); + ret->shf = NULL; + ret->pats = prog->pats; + ret->npats = prog->npats; + ret->heap = 1; + + return ret; } /* check to see if AUTOCD applies here */ -- cgit 1.4.1