diff options
-rw-r--r-- | Src/Modules/example.c | 4 | ||||
-rw-r--r-- | Src/Modules/parameter.c | 18 | ||||
-rw-r--r-- | Src/Modules/zftp.c | 30 | ||||
-rw-r--r-- | Src/Modules/zprof.c | 4 | ||||
-rw-r--r-- | Src/Zle/compcore.c | 6 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 12 | ||||
-rw-r--r-- | Src/Zle/complete.c | 4 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 6 | ||||
-rw-r--r-- | Src/Zle/zle_misc.c | 6 | ||||
-rw-r--r-- | Src/builtin.c | 86 | ||||
-rw-r--r-- | Src/cond.c | 125 | ||||
-rw-r--r-- | Src/exec.c | 666 | ||||
-rw-r--r-- | Src/glob.c | 6 | ||||
-rw-r--r-- | Src/hashtable.c | 4 | ||||
-rw-r--r-- | Src/init.c | 16 | ||||
-rw-r--r-- | Src/loop.c | 283 | ||||
-rw-r--r-- | Src/parse.c | 1064 | ||||
-rw-r--r-- | Src/signals.c | 16 | ||||
-rw-r--r-- | Src/text.c | 850 | ||||
-rw-r--r-- | Src/utils.c | 272 | ||||
-rw-r--r-- | Src/zsh.h | 350 |
21 files changed, 2472 insertions, 1356 deletions
diff --git a/Src/Modules/example.c b/Src/Modules/example.c index bf4ad60fb..0b15fa064 100644 --- a/Src/Modules/example.c +++ b/Src/Modules/example.c @@ -143,7 +143,7 @@ math_length(char *name, char *arg, int id) /**/ static int -ex_wrapper(List list, FuncWrap w, char *name) +ex_wrapper(Eprog prog, FuncWrap w, char *name) { if (strncmp(name, "example", 7)) return 1; @@ -151,7 +151,7 @@ ex_wrapper(List list, FuncWrap w, char *name) int ogd = opts[GLOBDOTS]; opts[GLOBDOTS] = 1; - runshfunc(list, w, name); + runshfunc(prog, w, name); opts[GLOBDOTS] = ogd; return 0; diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index b0ea78ac7..b67d9557c 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -339,23 +339,23 @@ setfunction(char *name, char *val, int dis) { char *value = dupstring(val); Shfunc shf; - List list; + Eprog prog; int sn; val = metafy(val, strlen(val), META_REALLOC); HEAPALLOC { - list = parse_string(val, 1); + prog = parse_string(val, 1); } LASTALLOC; - if (!list || list == &dummy_list) { + if (!prog || prog == &dummy_eprog) { zwarn("invalid function definition", value, 0); zsfree(val); return; } PERMALLOC { shf = (Shfunc) zalloc(sizeof(*shf)); - shf->funcdef = (List) dupstruct(list); + shf->funcdef = dupeprog(prog); shf->flags = dis; if (!strncmp(name, "TRAP", 4) && @@ -463,8 +463,7 @@ getfunction(HashTable ht, char *name, int dis) ((shf->flags & PM_TAGGED) ? "Ut" : "U") : ((shf->flags & PM_TAGGED) ? "t" : ""))); } else { - char *t = getpermtext((void *) dupstruct((void *) - shf->funcdef)), *h; + char *t = getpermtext(shf->funcdef, NULL), *h; h = dupstring(t); zsfree(t); @@ -528,8 +527,7 @@ scanfunctions(HashTable ht, ScanFunc func, int flags, int dis) ((shf->flags & PM_TAGGED) ? "Ut" : "U") : ((shf->flags & PM_TAGGED) ? "t" : ""))); } else { - char *t = getpermtext((void *) - dupstruct((void *) ((Shfunc) hn)->funcdef)); + char *t = getpermtext(((Shfunc) hn)->funcdef, NULL); pm.u.str = dupstring(t); unmetafy(pm.u.str, NULL); @@ -577,13 +575,13 @@ funcstackgetfn(Param pm) /**/ static int -func_wrapper(List list, FuncWrap w, char *name) +func_wrapper(Eprog prog, FuncWrap w, char *name) { PERMALLOC { pushnode(funcstack, ztrdup(name)); } LASTALLOC; - runshfunc(list, w, name); + runshfunc(prog, w, name); DPUTS(strcmp(name, (char *) getdata(firstnode(funcstack))), "funcstack wrapper with wrong function"); diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index debb1a6bb..0df035c74 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -1600,9 +1600,9 @@ zfsenddata(char *name, int recv, int progress, off_t startat) char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr; off_t sofar = 0, last_sofar = 0; readwrite_t read_ptr = zfread, write_ptr = zfwrite; - List l; + Eprog prog; - if (progress && (l = getshfunc("zftp_progress")) != &dummy_list) { + if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) { /* * progress to set up: ZFTP_COUNT is zero. * We do this here in case we needed to wait for a RETR @@ -1611,7 +1611,7 @@ zfsenddata(char *name, int recv, int progress, off_t startat) int osc = sfcontext; sfcontext = SFC_HOOK; - doshfunc("zftp_progress", l, NULL, 0, 1); + doshfunc("zftp_progress", prog, NULL, 0, 1); sfcontext = osc; /* Now add in the bit of the file we've got/sent already */ sofar = last_sofar = startat; @@ -1739,12 +1739,12 @@ zfsenddata(char *name, int recv, int progress, off_t startat) } else break; if (!ret && sofar != last_sofar && progress && - (l = getshfunc("zftp_progress")) != &dummy_list) { + (prog = getshfunc("zftp_progress")) != &dummy_eprog) { int osc = sfcontext; zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER); sfcontext = SFC_HOOK; - doshfunc("zftp_progress", l, NULL, 0, 1); + doshfunc("zftp_progress", prog, NULL, 0, 1); sfcontext = osc; last_sofar = sofar; } @@ -2444,7 +2444,7 @@ zfgetcwd(void) { char *ptr, *eptr; int endc; - List l; + Eprog prog; if (zfprefs & ZFPF_DUMB) return 1; @@ -2471,11 +2471,11 @@ zfgetcwd(void) * front end. By putting it here, and in close when ZFTP_PWD is unset, * we at least cover the bases. */ - if ((l = getshfunc("zftp_chpwd")) != &dummy_list) { + if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) { int osc = sfcontext; sfcontext = SFC_HOOK; - doshfunc("zftp_chpwd", l, NULL, 0, 1); + doshfunc("zftp_chpwd", prog, NULL, 0, 1); sfcontext = osc; } return 0; @@ -2629,7 +2629,7 @@ zftp_getput(char *name, char **args, int flags) { int ret = 0, recv = (flags & ZFTP_RECV), getsize = 0, progress = 1; char *cmd = recv ? "RETR " : (flags & ZFTP_APPE) ? "APPE " : "STOR "; - List l; + Eprog prog; /* * At this point I'd like to set progress to 0 if we're @@ -2647,7 +2647,7 @@ zftp_getput(char *name, char **args, int flags) for (; *args; args++) { char *ln, *rest = NULL; off_t startat = 0; - if (progress && (l = getshfunc("zftp_progress")) != &dummy_list) { + if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) { off_t sz; /* * This calls the SIZE command to get the size for remote @@ -2688,14 +2688,14 @@ zftp_getput(char *name, char **args, int flags) * if and only if we called zfsenddata(); */ if (progress && ret != 2 && - (l = getshfunc("zftp_progress")) != &dummy_list) { + (prog = getshfunc("zftp_progress")) != &dummy_eprog) { /* progress to finish: ZFTP_TRANSFER set to GF or PF */ int osc = sfcontext; zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"), ZFPM_READONLY); sfcontext = SFC_HOOK; - doshfunc("zftp_progress", l, NULL, 0, 1); + doshfunc("zftp_progress", prog, NULL, 0, 1); sfcontext = osc; } if (rest) { @@ -2795,7 +2795,7 @@ static void zfclose(int leaveparams) { char **aptr; - List l; + Eprog prog; if (zfsess->cfd == -1) return; @@ -2837,11 +2837,11 @@ zfclose(int leaveparams) zfunsetparam(*aptr); /* Now ZFTP_PWD is unset. It's up to zftp_chpwd to notice. */ - if ((l = getshfunc("zftp_chpwd")) != &dummy_list) { + if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) { int osc = sfcontext; sfcontext = SFC_HOOK; - doshfunc("zftp_chpwd", l, NULL, 0, 1); + doshfunc("zftp_chpwd", prog, NULL, 0, 1); sfcontext = osc; } } diff --git a/Src/Modules/zprof.c b/Src/Modules/zprof.c index 276ada4d6..59fea3154 100644 --- a/Src/Modules/zprof.c +++ b/Src/Modules/zprof.c @@ -214,7 +214,7 @@ bin_zprof(char *nam, char **args, char *ops, int func) /**/ static int -zprof_wrapper(List list, FuncWrap w, char *name) +zprof_wrapper(Eprog prog, FuncWrap w, char *name) { struct sfunc sf, *sp; Pfunc f; @@ -257,7 +257,7 @@ zprof_wrapper(List list, FuncWrap w, char *name) gettimeofday(&tv, &dummy); sf.beg = prev = ((((double) tv.tv_sec) * 1000.0) + (((double) tv.tv_usec) / 1000.0)); - runshfunc(list, w, name); + runshfunc(prog, w, name); tv.tv_sec = tv.tv_usec = 0; gettimeofday(&tv, &dummy); diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 4d7ee469b..670dac1da 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -491,11 +491,11 @@ after_complete(Hookdef dummy, Compldat dat) static void callcompfunc(char *s, char *fn) { - List list; + Eprog prog; int lv = lastval; char buf[20]; - if ((list = getshfunc(fn)) != &dummy_list) { + if ((prog = getshfunc(fn)) != &dummy_eprog) { char **p, *tmp; int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; unsigned int rset, kset; @@ -724,7 +724,7 @@ callcompfunc(char *s, char *fn) while (*p) addlinknode(largs, dupstring(*p++)); } - doshfunc(fn, list, largs, 0, 0); + doshfunc(fn, prog, largs, 0, 0); cfret = lastval; lastval = olv; } OLDHEAPS; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 69db9e04a..77a76c156 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -3431,12 +3431,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } if (cc->func) { /* This handles the compctl -K flag. */ - List list; + Eprog prog; char **r; int lv = lastval; /* Get the function. */ - if ((list = getshfunc(cc->func)) != &dummy_list) { + if ((prog = getshfunc(cc->func)) != &dummy_eprog) { /* We have it, so build a argument list. */ LinkList args = newlinklist(); int osc = sfcontext; @@ -3460,7 +3460,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) incompctlfunc = 1; sfcontext = SFC_COMPLETE; /* Call the function. */ - doshfunc(cc->func, list, args, 0, 1); + doshfunc(cc->func, prog, args, 0, 1); sfcontext = osc; incompctlfunc = 0; /* And get the result from the reply parameter. */ @@ -3601,12 +3601,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* generate the user-defined display list: if anything fails, * * we silently allow the normal completion list to be used. */ char **yaptr = NULL, *uv = NULL; - List list; + Eprog prog; if (cc->ylist[0] == '$' || cc->ylist[0] == '(') { /* from variable */ uv = cc->ylist + (cc->ylist[0] == '$'); - } else if ((list = getshfunc(cc->ylist)) != &dummy_list) { + } else if ((prog = getshfunc(cc->ylist)) != &dummy_eprog) { /* from function: pass completions as arg list */ LinkList args = newlinklist(); LinkNode ln; @@ -3630,7 +3630,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) if (incompfunc != 1) incompctlfunc = 1; sfcontext = SFC_COMPLETE; - doshfunc(cc->ylist, list, args, 0, 1); + doshfunc(cc->ylist, prog, args, 0, 1); sfcontext = osc; incompctlfunc = 0; uv = "reply"; diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index d4c9f76c8..75bda321e 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -1177,7 +1177,7 @@ comp_setunset(int rset, int runset, int kset, int kunset) /**/ static int -comp_wrapper(List list, FuncWrap w, char *name) +comp_wrapper(Eprog prog, FuncWrap w, char *name) { if (incompfunc != 1) return 1; @@ -1214,7 +1214,7 @@ comp_wrapper(List list, FuncWrap w, char *name) owords = arrdup(compwords); } LASTALLOC; - runshfunc(list, w, name); + runshfunc(prog, w, name); if (comprestore && !strcmp(comprestore, "auto")) { compcurrent = ocur; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 722612421..abf870655 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -649,9 +649,9 @@ execzlefunc(Thingy func, char **args) lastcmd = wflags; r = 1; } else { - List l = getshfunc(w->u.fnnam); + Eprog prog = getshfunc(w->u.fnnam); - if(l == &dummy_list) { + if(prog == &dummy_eprog) { /* the shell function doesn't exist */ char *nm = niceztrdup(w->u.fnnam); char *msg = tricat("No such shell function `", nm, "'"); @@ -673,7 +673,7 @@ execzlefunc(Thingy func, char **args) startparamscope(); makezleparams(0); sfcontext = SFC_WIDGET; - doshfunc(w->u.fnnam, l, largs, 0, 0); + doshfunc(w->u.fnnam, prog, largs, 0, 0); ret = lastval; lastval = olv; sfcontext = osc; diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index eec325192..4d0669fb6 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -925,9 +925,9 @@ mod_export void iremovesuffix(int c, int keep) { if (suffixfunc) { - List l = getshfunc(suffixfunc); + Eprog prog = getshfunc(suffixfunc); - if (l != &dummy_list) { + if (prog != &dummy_eprog) { LinkList args = newlinklist(); char buf[20]; int osc = sfcontext; @@ -939,7 +939,7 @@ iremovesuffix(int c, int keep) startparamscope(); makezleparams(0); sfcontext = SFC_COMPLETE; - doshfunc(suffixfunc, l, args, 0, 1); + doshfunc(suffixfunc, prog, args, 0, 1); sfcontext = osc; endparamscope(); } diff --git a/Src/builtin.c b/Src/builtin.c index dd16efddb..a373d9dd2 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -971,7 +971,7 @@ cd_try_chdir(char *pfix, char *dest, int hard) static void cd_new_pwd(int func, LinkNode dir) { - List l; + Eprog prog; char *new_pwd, *s; int dirstacksize; @@ -1015,13 +1015,13 @@ cd_new_pwd(int func, LinkNode dir) } /* execute the chpwd function */ - if ((l = getshfunc("chpwd")) != &dummy_list) { + if ((prog = getshfunc("chpwd")) != &dummy_eprog) { int osc = sfcontext; fflush(stdout); fflush(stderr); sfcontext = SFC_HOOK; - doshfunc("chpwd", l, NULL, 0, 1); + doshfunc("chpwd", prog, NULL, 0, 1); sfcontext = osc; } @@ -2003,7 +2003,7 @@ eval_autoload(Shfunc shf, char *name, char *ops, int func) return 1; if (shf->funcdef) - freestruct(shf->funcdef); + freeeprog(shf->funcdef); if (ops['X'] == 1) { char *fargv[3]; @@ -2140,30 +2140,27 @@ bin_functions(char *name, char **argv, char *ops, int func) } /**/ -static List +static Eprog mkautofn(Shfunc shf) { - List l; - Sublist s; - Pline p; - Cmd c; - AutoFn a; - PERMALLOC { - a = (AutoFn)allocnode(N_AUTOFN); - a->shf = shf; - c = (Cmd)allocnode(N_CMD); - c->type = AUTOFN; - c->u.autofn = a; - p = (Pline)allocnode(N_PLINE); - p->left = c; - p->type = END; - s = (Sublist)allocnode(N_SUBLIST); - s->left = p; - l = (List)allocnode(N_LIST); - l->left = s; - l->type = Z_SYNC; - } LASTALLOC; - return l; + Eprog p; + + p = (Eprog) zalloc(sizeof(*p)); + p->len = 5 * sizeof(wordcode); + p->prog = (Wordcode) zalloc(p->len); + p->strs = NULL; + p->shf = shf; + p->npats = 0; + p->pats = NULL; + p->heap = 0; + + p->prog[0] = WCB_LIST(Z_SYNC | Z_END); + p->prog[1] = WCB_SUBLIST(WC_SUBLIST_END, 0, 3); + p->prog[2] = WCB_PIPE(WC_PIPE_END, 0); + p->prog[3] = WCB_AUTOFN(); + p->prog[4] = WCB_END(); + + return p; } /* unset: unset parameters */ @@ -3328,14 +3325,14 @@ bin_emulate(char *nam, char **argv, char *ops, int func) int bin_eval(char *nam, char **argv, char *ops, int func) { - List list; + Eprog prog; - list = parse_string(zjoin(argv, ' '), 0); - if (!list) { + prog = parse_string(zjoin(argv, ' '), 0); + if (!prog) { errflag = 0; return 1; } - execlist(list, 1, 0); + execode(prog, 1, 0); if (errflag) { lastval = errflag; errflag = 0; @@ -3761,7 +3758,8 @@ int bin_test(char *name, char **argv, char *ops, int func) { char **s; - Cond c; + Eprog prog; + struct estate state; /* if "test" was invoked as "[", it needs a matching "]" * * which is subsequently ignored */ @@ -3781,7 +3779,7 @@ bin_test(char *name, char **argv, char *ops, int func) tok = NULLTOK; condlex = testlex; testlex(); - c = par_cond(); + prog = parse_cond(); condlex = yylex; if (errflag) { @@ -3789,13 +3787,19 @@ bin_test(char *name, char **argv, char *ops, int func) return 1; } - if (!c || tok == LEXERR) { + if (!prog || tok == LEXERR) { zwarnnam(name, tokstr ? "parse error" : "argument expected", NULL, 0); return 1; } /* syntax is OK, so evaluate */ - return !evalcond(c); + + state.prog = prog; + state.pc = prog->prog; + state.strs = prog->strs; + + + return !evalcond(&state); } /* display a time, provided in units of 1/60s, as minutes and seconds */ @@ -3830,7 +3834,7 @@ bin_times(char *name, char **argv, char *ops, int func) int bin_trap(char *name, char **argv, char *ops, int func) { - List l; + Eprog prog; char *arg, *s; int sig; @@ -3852,7 +3856,7 @@ bin_trap(char *name, char **argv, char *ops, int func) if (!sigfuncs[sig]) printf("trap -- '' %s\n", sigs[sig]); else { - s = getpermtext((void *) sigfuncs[sig]); + s = getpermtext(sigfuncs[sig], NULL); printf("trap -- "); quotedzputs(s, stdout); printf(" %s\n", sigs[sig]); @@ -3878,15 +3882,15 @@ bin_trap(char *name, char **argv, char *ops, int func) /* Sort out the command to execute on trap */ arg = *argv++; if (!*arg) - l = NULL; - else if (!(l = parse_string(arg, 0))) { + prog = NULL; + else if (!(prog = parse_string(arg, 0))) { zwarnnam(name, "couldn't parse trap command", NULL, 0); return 1; } /* set traps */ for (; *argv; argv++) { - List t; + Eprog t; sig = getsignum(*argv); if (sig == -1) { @@ -3894,10 +3898,10 @@ bin_trap(char *name, char **argv, char *ops, int func) break; } PERMALLOC { - t = (List) dupstruct(l); + t = dupeprog(prog); } LASTALLOC; if (settrap(sig, t)) - freestruct(t); + freeeprog(t); } return *argv != NULL; } diff --git a/Src/cond.c b/Src/cond.c index 4a6144bb1..4a78bd5e7 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -39,95 +39,108 @@ static char *condstr[COND_MOD] = { /**/ int -evalcond(Cond c) +evalcond(Estate state) { struct stat *st; char *left, *right = NULL; + wordcode code = *state->pc++; + int ctype = WC_COND_TYPE(code); - switch (c->type) { + switch (ctype) { case COND_NOT: if (tracingcond) - fprintf(stderr, " %s", condstr[c->type]); - return !evalcond(c->left); + fprintf(stderr, " %s", condstr[ctype]); + return !evalcond(state); case COND_AND: - if (evalcond(c->left)) { + if (evalcond(state)) { if (tracingcond) - fprintf(stderr, " %s", condstr[c->type]); - return evalcond(c->right); - } else + fprintf(stderr, " %s", condstr[ctype]); + return evalcond(state); + } else { + state->pc += WC_COND_SKIP(code) - 1; return 0; + } case COND_OR: - if (!evalcond(c->left)) { + if (!evalcond(state)) { if (tracingcond) - fprintf(stderr, " %s", condstr[c->type]); - return evalcond(c->right); - } else + fprintf(stderr, " %s", condstr[ctype]); + return evalcond(state); + } else { + state->pc += WC_COND_SKIP(code) - 1; return 1; + } case COND_MOD: case COND_MODI: { Conddef cd; + char *name = ecgetstr(state, 0), **strs; + int l = WC_COND_SKIP(code); - if ((cd = getconddef((c->type == COND_MODI), - ((char *) c->left) + 1, 1))) { - if (c->type == COND_MOD) { - int l = arrlen((char **) c->right); + if (ctype == COND_MOD) + strs = ecgetarr(state, l, 1); + else { + char *sbuf[3]; - if (l < cd->min || (cd->max >= 0 && l > cd->max)) { - zerr("unrecognized condition: `%s'", (char *) c->left, 0); - return 0; - } + sbuf[0] = ecgetstr(state, 0); + sbuf[1] = ecgetstr(state, 0); + sbuf[2] = NULL; + + strs = arrdup(sbuf); + l = 2; + } + if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) { + if (ctype == COND_MOD && + (l < cd->min || (cd->max >= 0 && l > cd->max))) { + zerr("unrecognized condition: `%s'", name, 0); + return 0; } if (tracingcond) - tracemodcond((char *)c->left, (char **)c->right, - c->type == COND_MODI); - return cd->handler((char **) c->right, cd->condid); + tracemodcond(name, strs, ctype == COND_MODI); + return cd->handler(strs, cd->condid); } else { - char **a = (char **) c->right, *s = a[0]; + char *s = strs[0]; - if (s && s[0] == '-' && - (cd = getconddef(0, s + 1, 1))) { - int l = arrlen(a); + strs[0] = dupstring(name); + name = s; + if (name && name[0] == '-' && + (cd = getconddef(0, name + 1, 1))) { if (l < cd->min || (cd->max >= 0 && l > cd->max)) { - zerr("unrecognized condition: `%s'", (char *) c->left, 0); + zerr("unrecognized condition: `%s'", name, 0); return 0; } if (tracingcond) - tracemodcond((char *)c->left, a, c->type == COND_MODI); - a[0] = (char *) c->left; - return cd->handler(a, cd->condid); + tracemodcond(name, strs, ctype == COND_MODI); + return cd->handler(strs, cd->condid); } else - zerr("unrecognized condition: `%s'", (char *) c->left, 0); + zerr("unrecognized condition: `%s'", name, 0); } return 0; } } - left = dupstring((char *) c->left); + left = ecgetstr(state, 1); singsub(&left); untokenize(left); - if (c->right && c->type != COND_STREQ && c->type != COND_STRNEQ) { - right = dupstring((char *) c->right); + if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) { + right = ecgetstr(state, 1); singsub(&right); untokenize(right); } - if (tracingcond) { - if (c->type < COND_MOD) { + if (ctype < COND_MOD) { char *rt = (char *) right; - if (c->type == COND_STREQ || c->type == COND_STRNEQ) { - rt = dupstring(c->right); + if (ctype == COND_STREQ || ctype == COND_STRNEQ) { + rt = dupstring(ecrawstr(state->prog, state->pc)); singsub(&rt); untokenize(rt); } - fprintf(stderr, " %s %s %s", (char *)left, condstr[c->type], - rt); + fprintf(stderr, " %s %s %s", left, condstr[ctype], rt); } else - fprintf(stderr, " -%c %s", c->type, (char *)left); + fprintf(stderr, " -%c %s", ctype, left); } - if (c->type >= COND_EQ && c->type <= COND_GE) { + if (ctype >= COND_EQ && ctype <= COND_GE) { mnumber mn1, mn2; mn1 = matheval(left); mn2 = matheval(right); @@ -144,7 +157,7 @@ evalcond(Cond c) mn2.u.d = (double)mn2.u.l; } } - switch(c->type) { + switch(ctype) { case COND_EQ: return (mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) : (mn1.u.l == mn2.u.l); @@ -166,30 +179,32 @@ evalcond(Cond c) } } - switch (c->type) { + switch (ctype) { case COND_STREQ: case COND_STRNEQ: { - Patprog pprog = c->prog; - int test; + int test, npat = state->pc[1]; + Patprog pprog = state->prog->pats[npat]; if (pprog == dummy_patprog1 || pprog == dummy_patprog2) { char *opat; int save; - right = opat = dupstring((char *) c->right); + right = opat = dupstring(ecrawstr(state->prog, state->pc)); singsub(&right); - save = (!strcmp(opat, right) && pprog != dummy_patprog2); + save = (!state->prog->heap && + !strcmp(opat, right) && pprog != dummy_patprog2); if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC), NULL))) zerr("bad pattern: %s", right, 0); else if (save) - c->prog = pprog; - } + state->prog->pats[npat] = pprog; + } + state->pc += 2; test = (pprog && pattry(pprog, left)); - return (c->type == COND_STREQ ? test : !test); + return (ctype == COND_STREQ ? test : !test); } case COND_STRLT: return strcmp(left, right) < 0; @@ -255,7 +270,7 @@ evalcond(Cond c) a = st->st_mtime; if (!(st = getstat(right))) return 0; - return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime; + return (ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime; } case COND_EF: { @@ -271,7 +286,7 @@ evalcond(Cond c) return d == st->st_dev && i == st->st_ino; } default: - zerr("bad cond structure", NULL, 0); + zerr("bad cond code", NULL, 0); } return 0; } @@ -390,7 +405,7 @@ tracemodcond(char *name, char **args, int inf) { char **aptr; MUSTUSEHEAP("tracemodcond"); - args = duparray(args, (VFunc) dupstring); + args = arrdup(args); for (aptr = args; *aptr; aptr++) untokenize(*aptr); if (inf) { 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 */ diff --git a/Src/glob.c b/Src/glob.c index 571091cc4..73a752536 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2551,15 +2551,15 @@ qualtime(char *name, struct stat *buf, off_t days, char *dummy) static int qualsheval(char *name, struct stat *buf, off_t days, char *str) { - List list; + Eprog prog; - if ((list = parse_string(str, 0))) { + if ((prog = parse_string(str, 0))) { int ef = errflag, lv = lastval, ret; unsetparam("reply"); setsparam("REPLY", ztrdup(name)); - execlist(list, 1, 0); + execode(prog, 1, 0); ret = lastval; errflag = ef; diff --git a/Src/hashtable.c b/Src/hashtable.c index e9f33aa15..07c8dc25b 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -842,7 +842,7 @@ freeshfuncnode(HashNode hn) zsfree(shf->nam); if (shf->funcdef) - freestruct(shf->funcdef); + freeeprog(shf->funcdef); zfree(shf, sizeof(struct shfunc)); } @@ -879,7 +879,7 @@ printshfuncnode(HashNode hn, int printflags) if (!f->funcdef) t = 0; else - t = getpermtext((void *) f->funcdef); + t = getpermtext(f->funcdef, NULL); } quotedzputs(f->nam, stdout); diff --git a/Src/init.c b/Src/init.c index 3ac846758..20e996fdd 100644 --- a/Src/init.c +++ b/Src/init.c @@ -95,7 +95,7 @@ mod_export int alloc_stackp; void loop(int toplevel, int justonce) { - List list; + Eprog prog; #ifdef DEBUG int oasp = toplevel ? 0 : alloc_stackp; #endif @@ -112,7 +112,7 @@ loop(int toplevel, int justonce) hbegin(1); /* init history mech */ intr(); /* interrupts on */ lexinit(); /* initialize lexical state */ - if (!(list = parse_event())) { /* if we couldn't parse a list */ + if (!(prog = parse_event())) { /* if we couldn't parse a list */ hend(); if ((tok == ENDINPUT && !errflag) || (tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) || @@ -122,9 +122,9 @@ loop(int toplevel, int justonce) } if (hend()) { int toksav = tok; - List prelist; + Eprog preprog; - if (toplevel && (prelist = getshfunc("preexec")) != &dummy_list) { + if (toplevel && (preprog = getshfunc("preexec")) != &dummy_eprog) { LinkList args; int osc = sfcontext; @@ -135,16 +135,16 @@ loop(int toplevel, int justonce) addlinknode(args, hist_ring->text); } LASTALLOC; sfcontext = SFC_HOOK; - doshfunc("preexec", prelist, args, 0, 1); + doshfunc("preexec", preprog, args, 0, 1); sfcontext = osc; freelinklist(args, (FreeFunc) NULL); errflag = 0; } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; - execlist(list, 0, 0); + execode(prog, 0, 0); if (toplevel) - freestructs(); + freeeprogs(); tok = toksav; if (toplevel) noexitct = 0; @@ -560,6 +560,8 @@ setupvals(void) # endif #endif + init_eprog(); + getkeyptr = NULL; lineno = 1; diff --git a/Src/loop.c b/Src/loop.c index b8e7f956f..f2958114c 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -47,15 +47,20 @@ mod_export int breaks; /**/ int -execfor(Cmd cmd, LinkList args, int flags) +execfor(Estate state, int do_exec) { - Forcmd node; - char *str; + Wordcode end, loop; + wordcode code = state->pc[-1]; + int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND); + char *name, *str, *cond, *advance; zlong val = 0; + LinkList args; - node = cmd->u.forcmd; - if (node->condition) { - str = dupstring(node->name); + name = ecgetstr(state, 0); + end = state->pc + WC_FOR_SKIP(code); + + if (iscond) { + str = dupstring(name); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); @@ -66,9 +71,19 @@ execfor(Cmd cmd, LinkList args, int flags) } if (!errflag) matheval(str); - if (errflag) + if (errflag) { + state->pc = end; return lastval = errflag; - } else if (!node->inflag) { + } + cond = ecgetstr(state, 0); + advance = ecgetstr(state, 0); + } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) { + if (!(args = ecgetlist(state, *state->pc++, 1))) { + state->pc = end; + return 0; + } + execsubst(args); + } else { char **x; args = newlinklist(); @@ -79,9 +94,10 @@ execfor(Cmd cmd, LinkList args, int flags) loops++; pushheap(); cmdpush(CS_FOR); + loop = state->pc; for (;;) { - if (node->condition) { - str = dupstring(node->condition); + if (iscond) { + str = dupstring(cond); singsub(&str); if (!errflag) { while (iblank(*str)) @@ -109,21 +125,21 @@ execfor(Cmd cmd, LinkList args, int flags) break; if (isset(XTRACE)) { printprompt4(); - fprintf(stderr, "%s=%s\n", node->name, str); + fprintf(stderr, "%s=%s\n", name, str); fflush(stderr); } - setsparam(node->name, ztrdup(str)); + setsparam(name, ztrdup(str)); } - execlist(node->list, 1, - (flags & CFLAG_EXEC) && args && empty(args)); + state->pc = loop; + execlist(state, 1, do_exec && args && empty(args)); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } - if (node->condition && !errflag) { - str = dupstring(node->advance); + if (iscond && !errflag) { + str = dupstring(advance); if (isset(XTRACE)) { printprompt4(); fprintf(stderr, "%s\n", str); @@ -149,25 +165,37 @@ execfor(Cmd cmd, LinkList args, int flags) /**/ int -execselect(Cmd cmd, LinkList args, int flags) +execselect(Estate state, int do_exec) { - Forcmd node; - char *str, *s; + Wordcode end, loop; + wordcode code = state->pc[-1]; + char *str, *s, *name; LinkNode n; int i, usezle; FILE *inp; size_t more; + LinkList args; - node = cmd->u.forcmd; - if (!node->inflag) { + end = state->pc + WC_FOR_SKIP(code); + name = ecgetstr(state, 0); + + if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); + } else { + if (!(args = ecgetlist(state, *state->pc++, 1))) { + state->pc = end; + return 0; + } + execsubst(args); } - if (!args || empty(args)) + if (!args || empty(args)) { + state->pc = end; return 1; + } loops++; lastval = 0; pushheap(); @@ -175,6 +203,7 @@ execselect(Cmd cmd, LinkList args, int flags) usezle = interact && SHTTY != -1 && isset(USEZLE); inp = fdopen(dup(usezle ? SHTTY : 0), "r"); more = selectlist(args, 0); + loop = state->pc; for (;;) { for (;;) { if (empty(bufstack)) { @@ -219,8 +248,9 @@ execselect(Cmd cmd, LinkList args, int flags) else str = ""; } - setsparam(node->name, ztrdup(str)); - execlist(node->list, 1, 0); + setsparam(name, ztrdup(str)); + state->pc = loop; + execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; @@ -236,6 +266,7 @@ execselect(Cmd cmd, LinkList args, int flags) popheap(); fclose(inp); loops--; + state->pc = end; return lastval; } @@ -302,28 +333,31 @@ selectlist(LinkList l, size_t start) /**/ int -execwhile(Cmd cmd, LinkList args, int flags) +execwhile(Estate state, int do_exec) { - struct whilecmd *node; - int olderrexit, oldval; + Wordcode end, loop; + wordcode code = state->pc[-1]; + int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL); + end = state->pc + WC_WHILE_SKIP(code); olderrexit = noerrexit; - node = cmd->u.whilecmd; oldval = 0; pushheap(); - cmdpush(node->cond ? CS_UNTIL : CS_WHILE); + cmdpush(isuntil ? CS_UNTIL : CS_WHILE); loops++; + loop = state->pc; for (;;) { + state->pc = loop; noerrexit = 1; - execlist(node->cont, 1, 0); + execlist(state, 1, 0); noerrexit = olderrexit; - if (!((lastval == 0) ^ node->cond)) { + if (!((lastval == 0) ^ isuntil)) { if (breaks) breaks--; lastval = oldval; break; } - execlist(node->loop, 1, 0); + execlist(state, 1, 0); if (breaks) { breaks--; if (breaks || !contflag) @@ -345,21 +379,26 @@ execwhile(Cmd cmd, LinkList args, int flags) /**/ int -execrepeat(Cmd cmd, LinkList args, int flags) +execrepeat(Estate state, int do_exec) { + Wordcode end, loop; + wordcode code = state->pc[-1]; int count; + char *tmp; + + end = state->pc + WC_REPEAT_SKIP(code); lastval = 0; - if (!args || empty(args) || nextnode(firstnode(args))) { - zerr("bad argument for repeat", NULL, 0); - return 1; - } - count = atoi(peekfirst(args)); + tmp = ecgetstr(state, 1); + singsub(&tmp); + count = atoi(tmp); pushheap(); cmdpush(CS_REPEAT); loops++; + loop = state->pc; while (count-- > 0) { - execlist(cmd->u.list, 1, 0); + state->pc = loop; + execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; @@ -375,114 +414,140 @@ execrepeat(Cmd cmd, LinkList args, int flags) cmdpop(); popheap(); loops--; + state->pc = end; return lastval; } /**/ int -execif(Cmd cmd, LinkList args, int flags) +execif(Estate state, int do_exec) { - struct ifcmd *node; - int olderrexit, s = 0; - List *i, *t; + Wordcode end, next; + wordcode code = state->pc[-1]; + int olderrexit, s = 0, run = 0; olderrexit = noerrexit; - node = cmd->u.ifcmd; - i = node->ifls; - t = node->thenls; + end = state->pc + WC_IF_SKIP(code); if (!noerrexit) noerrexit = 1; - while (*i) { + while (state->pc < end) { + code = *state->pc++; + if (wc_code(code) != WC_IF || + (run = (WC_IF_TYPE(code) == WC_IF_ELSE))) { + if (run) + run = 2; + break; + } + next = state->pc + WC_IF_SKIP(code); cmdpush(s ? CS_ELIF : CS_IF); - execlist(*i, 1, 0); + execlist(state, 1, 0); cmdpop(); - if (!lastval) + if (!lastval) { + run = 1; break; + } s = 1; - i++; - t++; + state->pc = next; } noerrexit = olderrexit; - if (*t) { - cmdpush(*i ? (s ? CS_ELIFTHEN : CS_IFTHEN) : CS_ELSE); - execlist(*t, 1, flags & CFLAG_EXEC); + if (run) { + cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN)); + execlist(state, 1, do_exec); cmdpop(); } else lastval = 0; + state->pc = end; return lastval; } /**/ int -execcase(Cmd cmd, LinkList args, int flags) +execcase(Estate state, int do_exec) { - struct casecmd *node; - char *word; - List *l; - char **p; - Patprog *pp, pprog; - int save; - - node = cmd->u.casecmd; - l = node->lists; - p = node->pats; - pp = node->progs; - - word = dupstring(*p++); + Wordcode end, next; + wordcode code = state->pc[-1]; + char *word, *pat; + int npat, save; + Patprog *spprog, pprog; + + end = state->pc + WC_CASE_SKIP(code); + + word = ecgetstr(state, 1); singsub(&word); untokenize(word); lastval = 0; - if (node) { - cmdpush(CS_CASE); - while (*p) { - char *pat = NULL, *opat; + cmdpush(CS_CASE); + while (state->pc < end) { + code = *state->pc++; + if (wc_code(code) != WC_CASE) + break; - pprog = NULL; - save = 0; + pat = NULL; + pprog = NULL; + save = 0; + npat = state->pc[1]; + spprog = state->prog->pats + npat; - if (isset(XTRACE)) { - char *pat2; + next = state->pc + WC_CASE_SKIP(code); - opat = pat = dupstring(*p + 1); - singsub(&pat); - save = (!strcmp(pat, opat) && *pp != dummy_patprog2); + if (isset(XTRACE)) { + char *pat2, *opat; - pat2 = dupstring(pat); - untokenize(pat2); - printprompt4(); - fprintf(stderr, "case %s (%s)\n", word, pat2); - fflush(stderr); - } - if (*pp != dummy_patprog1 && *pp != dummy_patprog2) - pprog = *pp; - - if (!pprog) { - if (!pat) { - opat = pat = dupstring(*p + 1); - singsub(&pat); - save = (!strcmp(pat, opat) && *pp != dummy_patprog2); - } - if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), - NULL))) - zerr("bad pattern: %s", pat, 0); - else if (save) - *pp = pprog; - } - if (pprog && pattry(pprog, word)) { - do { - execlist(*l++, 1, **p == ';' && (flags & CFLAG_EXEC)); - } while(**p++ == '&' && *p); - break; + opat = pat = ecgetstr(state, 1); + singsub(&pat); + save = (!state->prog->heap && + !strcmp(pat, opat) && *spprog != dummy_patprog2); + + pat2 = dupstring(pat); + untokenize(pat2); + printprompt4(); + fprintf(stderr, "case %s (%s)\n", word, pat2); + fflush(stderr); + state->pc++; + } else + state->pc += 2; + + if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) + pprog = *spprog; + + if (!pprog) { + if (!pat) { + char *opat; + + opat = pat = dupstring(ecrawstr(state->prog, state->pc - 2)); + singsub(&pat); + save = (!state->prog->heap && + !strcmp(pat, opat) && *spprog != dummy_patprog2); } - p++; - pp++; - l++; + if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), + NULL))) + zerr("bad pattern: %s", pat, 0); + else if (save) + *spprog = pprog; } - cmdpop(); + if (pprog && pattry(pprog, word)) { + execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && + do_exec)); + while (wc_code(code) == WC_CASE && + WC_CASE_TYPE(code) == WC_CASE_AND) { + state->pc = next; + code = *state->pc; + state->pc += 3; + next = state->pc + WC_CASE_SKIP(code) - 1; + execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && + do_exec)); + } + break; + } else + state->pc = next; } + cmdpop(); + + state->pc = end; + return lastval; } diff --git a/Src/parse.c b/Src/parse.c index abaca9ece..11aa0b60f 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -28,6 +28,182 @@ */ #include "zsh.mdh" + +/********************************/ +/* Definitions for syntax trees */ +/********************************/ + +typedef struct cond *Cond; +typedef struct cmd *Cmd; +typedef struct pline *Pline; +typedef struct sublist *Sublist; +typedef struct list *List; +typedef struct forcmd *Forcmd; +typedef struct autofn *AutoFn; +typedef struct varasg *Varasg; + + +/* struct list, struct sublist, struct pline, etc. all fit the form * + * of this structure and are used interchangably. The ptrs may hold * + * integers or pointers, depending on the type of the node. */ + +/* Generic node structure for syntax trees */ +struct node { + int ntype; /* node type */ +}; + +#define N_LIST 0 +#define N_SUBLIST 1 +#define N_PLINE 2 +#define N_CMD 3 +#define N_REDIR 4 +#define N_COND 5 +#define N_FOR 6 +#define N_CASE 7 +#define N_IF 8 +#define N_WHILE 9 +#define N_VARASG 10 +#define N_AUTOFN 11 +#define N_COUNT 12 + +/* values for types[4] */ + +#define NT_EMPTY 0 +#define NT_NODE 1 +#define NT_STR 2 +#define NT_PAT 3 +#define NT_LIST 4 +#define NT_ARR 8 + +#define NT_TYPE(T) ((T) & 0xff) +#define NT_N(T, N) (((T) >> (8 + (N) * 4)) & 0xf) +#define NT_SET(T0, T1, T2, T3, T4) \ + ((T0) | ((T1) << 8) | ((T2) << 12) | ((T3) << 16) | ((T4) << 20)) + +/* tree element for lists */ + +struct list { + int ntype; /* node type */ + int type; + Sublist left; + List right; +}; + +/* tree element for sublists */ + +struct sublist { + int ntype; /* node type */ + int type; + int flags; /* see PFLAGs below */ + Pline left; + Sublist right; +}; + +#define ORNEXT 10 /* || */ +#define ANDNEXT 11 /* && */ + +#define PFLAG_NOT 1 /* ! ... */ +#define PFLAG_COPROC 32 /* coproc ... */ + +/* tree element for pipes */ + +struct pline { + int ntype; /* node type */ + int type; + Cmd left; + Pline right; +}; + +#define END 0 /* pnode *right is null */ +#define PIPE 1 /* pnode *right is the rest of the pipeline */ + +/* tree element for commands */ + +struct cmd { + int ntype; /* node type */ + int type; + int flags; /* see CFLAGs below */ + int lineno; /* lineno of script for command */ + union { + List list; /* for SUBSH/CURSH/SHFUNC */ + Forcmd forcmd; + struct casecmd *casecmd; + struct ifcmd *ifcmd; + struct whilecmd *whilecmd; + Sublist pline; + Cond cond; + AutoFn autofn; + void *generic; + } u; + LinkList args; /* command & argmument List (char *'s) */ + LinkList redir; /* i/o redirections (struct redir *'s) */ + LinkList vars; /* param assignments (struct varasg *'s) */ +}; + +/* cmd types */ +#define SIMPLE 0 +#define SUBSH 1 +#define CURSH 2 +#define ZCTIME 3 +#define FUNCDEF 4 +#define CFOR 5 +#define CWHILE 6 +#define CREPEAT 7 +#define CIF 8 +#define CCASE 9 +#define CSELECT 10 +#define COND 11 +#define CARITH 12 + +/* tree element for conditionals */ + +struct cond { + int ntype; /* node type */ + int type; /* can be cond_type, or a single */ + /* letter (-a, -b, ...) */ + void *left, *right; +}; + +struct forcmd { /* for/select */ +/* Cmd->args contains list of words to loop thru */ + int ntype; /* node type */ + int inflag; /* if there is an in ... clause */ + char *name; /* initializer or parameter name */ + char *condition; /* arithmetic terminating condition */ + char *advance; /* evaluated after each loop */ + List list; /* list to look through for each name */ +}; + +struct casecmd { +/* Cmd->args contains word to test */ + int ntype; /* node type */ + char **pats; /* pattern strings */ + List *lists; /* list to execute */ +}; + +struct ifcmd { + int ntype; /* node type */ + List *ifls; + List *thenls; +}; + +struct whilecmd { + int ntype; /* node type */ + int cond; /* 0 for while, 1 for until */ + List cont; /* condition */ + List loop; /* list to execute until condition met */ +}; + +/* variable assignment tree element */ + +struct varasg { + int ntype; /* node type */ + int type; /* nonzero means array */ + char *name; + char *str; /* should've been a union here. oh well */ + LinkList arr; +}; + #include "parse.pro" /* != 0 if we are about to read a command word */ @@ -68,7 +244,7 @@ struct heredocs *hdocs; /* used in arrays of lists instead of NULL pointers */ /**/ -mod_export struct list dummy_list; +static struct list dummy_list; #define YYERROR { tok = LEXERR; return NULL; } #define YYERRORV { tok = LEXERR; return; } @@ -80,16 +256,26 @@ mod_export struct list dummy_list; YYERROR \ } while(0) -#define make_list() allocnode(N_LIST) -#define make_sublist() allocnode(N_SUBLIST) -#define make_pline() allocnode(N_PLINE) -#define make_cmd() allocnode(N_CMD) -#define make_forcmd() allocnode(N_FOR) -#define make_casecmd() allocnode(N_CASE) -#define make_ifcmd() allocnode(N_IF) -#define make_whilecmd() allocnode(N_WHILE) -#define make_varnode() allocnode(N_VARASG) -#define make_cond() allocnode(N_COND) +#define make_list() allocnode(sizeof(struct list), N_LIST) +#define make_sublist() allocnode(sizeof(struct sublist), N_SUBLIST) +#define make_pline() allocnode(sizeof(struct pline), N_PLINE) +#define make_cmd() allocnode(sizeof(struct cmd), N_CMD) +#define make_forcmd() allocnode(sizeof(struct forcmd), N_FOR) +#define make_casecmd() allocnode(sizeof(struct casecmd), N_CASE) +#define make_ifcmd() allocnode(sizeof(struct ifcmd), N_IF) +#define make_whilecmd() allocnode(sizeof(struct whilecmd), N_WHILE) +#define make_varnode() allocnode(sizeof(struct varasg), N_VARASG) +#define make_cond() allocnode(sizeof(struct cond), N_COND) + +static void * +allocnode(size_t s, int t) +{ + struct node *r = (struct node *) hcalloc(s); + + r->ntype = t; + + return (void *) r; +} /* * event : ENDINPUT @@ -97,13 +283,14 @@ mod_export struct list dummy_list; * | sublist [ SEPER | AMPER | AMPERBANG ] */ /**/ -List +Eprog parse_event(void) { + List ret; tok = ENDINPUT; incmdpos = 1; yylex(); - return par_event(); + return ((ret = par_event()) ? execompile(ret) : NULL); } /**/ @@ -161,7 +348,7 @@ par_event(void) } /**/ -List +mod_export Eprog parse_list(void) { List ret; @@ -174,7 +361,19 @@ parse_list(void) yyerror(0); return NULL; } - return ret; + return execompile(ret); +} + +/**/ +mod_export Eprog +parse_cond(void) +{ + Cond c = par_cond(); + + if (!c) + return NULL; + + return execompile((List) c); } /* @@ -301,7 +500,8 @@ par_pline(void) p->type = PIPE; return p; } else if (tok == BARAMP) { - struct redir *rdr = (struct redir *)allocnode(N_REDIR); + struct redir *rdr = (struct redir *) + allocnode(sizeof(struct redir), N_REDIR); rdr->type = MERGEOUT; rdr->fd1 = 2; @@ -539,7 +739,6 @@ par_case(Cmd c) LinkList pats, lists; int n = 1; char **pp; - Patprog *ppp; List *ll; LinkNode no; struct casecmd *cc; @@ -661,15 +860,11 @@ par_case(Cmd c) yylex(); cc->pats = (char **) alloc((n + 1) * sizeof(char *)); - cc->progs = (Patprog *) alloc((n + 1) * sizeof(Patprog)); - for (pp = cc->pats, ppp = cc->progs, no = firstnode(pats); - no; incnode(no)) { + for (pp = cc->pats, no = firstnode(pats); + no; incnode(no)) *pp++ = (char *)getdata(no); - *ppp++ = dummy_patprog1; - } *pp = NULL; - *ppp = NULL; cc->lists = (List *) alloc((n + 1) * sizeof(List)); for (ll = cc->lists, no = firstnode(lists); no; incnode(no), ll++) @@ -1071,11 +1266,11 @@ par_simple(Cmd c) Sublist sl; Pline pl; - l = (List) allocnode(N_LIST); + l = (List) allocnode(sizeof(*l), N_LIST); l->type = Z_SYNC; - l->left = sl = (Sublist) allocnode(N_SUBLIST); + l->left = sl = (Sublist) allocnode(sizeof(*sl), N_SUBLIST); sl->type = END; - sl->left = pl = (Pline) allocnode(N_PLINE); + sl->left = pl = (Pline) allocnode(sizeof(*pl), N_PLINE); pl->type = END; pl->left = par_cmd(); c->u.list = l; @@ -1106,7 +1301,7 @@ void (*condlex) _((void)) = yylex; */ /**/ -Cond +static Cond par_cond(void) { Cond c, c2; @@ -1303,7 +1498,8 @@ static int redirtab[TRINANG - OUTANG + 1] = { static void par_redir(LinkList l) { - struct redir *fn = (struct redir *)allocnode(N_REDIR); + struct redir *fn = (struct redir *) + allocnode(sizeof(struct redir), N_REDIR); int oldcmdpos, oldnc; oldcmdpos = incmdpos; @@ -1448,7 +1644,6 @@ par_cond_triple(char *a, char *b, char *c) n->left = (void *) a; n->right = (void *) c; - n->prog = dummy_patprog1; if ((b[0] == Equals || b[0] == '=') && (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) { n->ntype = NT_SET(N_COND, NT_STR, NT_STR, NT_PAT, 0); @@ -1521,3 +1716,814 @@ yyerror(int noerr) if (!noerr && noerrs != 2) errflag = 1; } + +/* + * Word code. + * + * For now we simply post-process the syntax tree produced by the + * parser. We compile it into a struct eprog. Some day the parser + * above should be changed to emit the word code directly. + * + * Word code layout: + * + * WC_END + * - only used for empty functions + * + * WC_LIST + * - data contains type (sync, ...) + * - follwed by code for this list + * - if not (type & Z_END), followed by next WC_LIST + * + * WC_SUBLIST + * - data contains type (&&, ||, END) and flags (coprog, not) + * - followed by code for sublist + * - if not (type == END), followed by next WC_SUBLIST + * + * WC_PIPE + * - data contains type (end, mid) and LINENO + * - if not (type == END), followed by offset to next WC_PIPE + * - followed by command + * - if not (type == END), followed by next WC_PIPE + * + * WC_REDIR + * - must precede command-code (or WC_ASSIGN) + * - data contains type (<, >, ...) + * - followed by fd1 and name from struct redir + * + * WC_ASSIGN + * - data contains type (scalar, array) and number of array-elements + * - followed by name and value + * + * WC_SIMPLE + * - data contains the number of arguments (plus command) + * - followed by strings + * + * WC_SUBSH + * - data unused + * - followed by list + * + * WC_CURSH + * - data unused + * - followed by list + * + * WC_TIMED + * - data contains type (followed by pipe or not) + * - if (type == PIPE), followed by pipe + * + * WC_FUNCDEF + * - data contains offset to after body-strings + * - followed by number of names + * - followed by names + * - followed by number of codes for body + * - followed by number of patterns for body + * - follwoed by codes for body + * - followed by strings for body + * + * WC_FOR + * - data contains type (list, ...) and offset to after body + * - if (type == COND), followed by init, cond, advance expressions + * - else if (type == PPARAM), followed by param name + * - else if (type == LIST), followed by param name, num strings, strings + * - followed by body + * + * WC_SELECT + * - data contains type (list, ...) and offset to after body + * - if (type == PPARAM), followed by param name + * - else if (type == LIST), followed by param name, num strings, strings + * - followed by body + * + * WC_WHILE + * - data contains type (while, until) and ofsset to after body + * - followed by condition + * - followed by body + * + * WC_REPEAT + * - data contains offset to after body + * - followed by number-string + * - followed by body + * + * WC_CASE + * - first CASE is always of type HEAD, data contains offset to esac + * - after that CASEs of type OR (;;) and AND (;&), data is offset to + * next case + * - each OR/AND case is followed by pattern, pattern-number, list + * + * WC_IF + * - first IF is of type HEAD, data contains offset to fi + * - after that IFs of type IF, ELIF, ELSE, data is offset to next + * - each non-HEAD is followed by condition (only IF, ELIF) and body + * + * WC_COND + * - data contains type + * - if (type == AND/OR), data contains offset to after this one, + * followed by two CONDs + * - else if (type == NOT), followed by COND + * - else if (type == MOD), followed by name and strings + * - else if (type == MODI), followed by name, left, right + * - else if (type == STR[N]EQ), followed by left, right, pattern-number + * - else if (has two args) followed by left, right + * - else followed by string + * + * WC_ARITH + * - followed by string (there's only one) + * + * WC_AUTOFN + * - only used by the autoload builtin + * + * In each of the above, strings are encoded as one word code. For empty + * strings this is the bit pattern 0xfe000000. For short strings (one to + * three characters), this is the marker 0xff000000 with the lower three + * bytes containing the characters. Longer strings are encoded as the + * offset into the strs character array stored in the eprog struct. + * The ecstr() function that adds the code for a string uses a simple + * list of strings already added so that long strings are encoded only + * once. + * + * Note also that in the eprog struct the pattern, code, and string + * arrays all point to the same memory block. + */ + +static int eclen, ecused, ecfree, ecnpats; +static Wordcode ecbuf; + +typedef struct eccstr *Eccstr; + +struct eccstr { + Eccstr next; + char *str; + wordcode offs; +}; + +static Eccstr ecstrs; +static int ecsoffs; + +/* Make at least n bytes free (aligned to sizeof(wordcode)). */ + +static int +ecspace(int n) +{ + n = (n + sizeof(wordcode) - 1) / sizeof(wordcode); + + if (ecfree < n) { + int a = (n > 256 ? n : 256); + + ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), + (eclen + a) * sizeof(wordcode)); + eclen += a; + ecfree += a; + } + ecused += n; + ecfree -= n; + + return ecused - 1; +} + +/* Add one wordcode. */ + +static int +ecadd(wordcode c) +{ + if (ecfree < 1) { + ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode), + (eclen + 256) * sizeof(wordcode)); + eclen += 256; + ecfree += 256; + } + ecbuf[ecused] = c; + ecused++; + ecfree--; + + return ecused - 1; +} + +/* Add a string and the wordcode for it. */ + +static int +ecstr(char *s) +{ + int l; + + if ((l = strlen(s) + 1) && l <= 4) { + wordcode c = 0xff000000; + switch (l) { + case 4: c |= ((wordcode) STOUC(s[2])) << 16; + case 3: c |= ((wordcode) STOUC(s[1])) << 8; + case 2: c |= ((wordcode) STOUC(s[0])); break; + case 1: c = 0xfe000000; break; + } + return ecadd(c); + } else { + Eccstr p, q = NULL; + + for (p = ecstrs; p; q = p, p = p->next) + if (!strcmp(s, p->str)) + return ecadd(p->offs); + + p = (Eccstr) zhalloc(sizeof(*p)); + p->next = NULL; + if (q) + q->next = p; + else + ecstrs = p; + p->offs = ecsoffs; + p->str = s; + ecsoffs += l; + + return ecadd(p->offs); + } +} + +#define ec(N) ecomp((struct node *) (N)) + +#define _Cond(X) ((Cond) (X)) +#define _Cmd(X) ((Cmd) (X)) +#define _Pline(X) ((Pline) (X)) +#define _Sublist(X) ((Sublist) (X)) +#define _List(X) ((List) (X)) +#define _casecmd(X) ((struct casecmd *) (X)) +#define _ifcmd(X) ((struct ifcmd *) (X)) +#define _whilecmd(X) ((struct whilecmd *) (X)) + +#define cont(N) do { n = (struct node *) (N); goto rec; } while (0) + +/* Compile a node. */ + +static void +ecomp(struct node *n) +{ + int p, c; + + rec: + + if (!n || ((List) n) == &dummy_list) + return; + + switch (NT_TYPE(n->ntype)) { + case N_LIST: + ecadd(WCB_LIST(_List(n)->type | (_List(n)->right ? 0 : Z_END))); + if (_List(n)->right) { + ec(_List(n)->left); + cont(_List(n)->right); + } else + cont(_List(n)->left); + break; + case N_SUBLIST: + p = ecadd(0); + ec(_Sublist(n)->left); + ecbuf[p] = WCB_SUBLIST((_Sublist(n)->right ? + ((_Sublist(n)->type == ORNEXT) ? + WC_SUBLIST_OR : WC_SUBLIST_AND) : + WC_SUBLIST_END), + (((_Sublist(n)->flags & PFLAG_NOT) ? + WC_SUBLIST_NOT : 0) | + ((_Sublist(n)->flags & PFLAG_COPROC) ? + WC_SUBLIST_COPROC : 0)), + (ecused - 1 - p)); + if (_Sublist(n)->right) + cont(_Sublist(n)->right); + break; + case N_PLINE: + ecadd(WCB_PIPE((_Pline(n)->right ? WC_PIPE_MID : WC_PIPE_END), + (_Cmd(_Pline(n)->left)->lineno >= 0 ? + _Cmd(_Pline(n)->left)->lineno + 1 : 0))); + if (_Pline(n)->right) { + p = ecadd(0); + ec(_Pline(n)->left); + ecbuf[p] = (wordcode) (ecused - p); + cont(_Pline(n)->right); + } else + cont(_Pline(n)->left); + break; + case N_CMD: + { + Cmd nn = _Cmd(n); + + /* Note that the execution and text code require that the + * redirs and assignments are in exactly this order and that + * they are before the command. */ + + ecredirs(nn->redir); + + switch (nn->type) { + case SIMPLE: + { + int num = 0; + + ecassigns(nn->vars); + p = ecadd(0); + + if (nn->args) { + LinkNode ap; + + for (ap = firstnode(nn->args); ap; + incnode(ap), num++) + ecstr((char *) getdata(ap)); + } + ecbuf[p] = WCB_SIMPLE(num); + } + break; + case SUBSH: + ecadd(WCB_SUBSH()); + ec(nn->u.list); + break; + case ZCTIME: + ecadd(WCB_TIMED(nn->u.pline ? WC_TIMED_PIPE : WC_TIMED_EMPTY)); + if (nn->u.pline) + ec(nn->u.pline); + break; + case FUNCDEF: + { + LinkNode np; + int num, sbeg, oecu, onp; + Eccstr ostrs; + + /* Defined functions and their strings are stored + * inline. */ + + p = ecadd(0); + ecadd(0); + + for (np = firstnode(nn->args), num = 0; np; + incnode(np), num++) + ecstr((char *) getdata(np)); + + ecadd(0); + ecadd(0); + + sbeg = ecsoffs; + ecsoffs = 0; + ostrs = ecstrs; + ecstrs = NULL; + onp = ecnpats; + ecnpats = 0; + + oecu = ecused; + ec(nn->u.list); + if (oecu == ecused) + ecadd(WCB_END()); + + ecbuf[p + num + 2] = ecused - num - p; + ecbuf[p + num + 3] = ecnpats; + ecbuf[p + 1] = num; + + if (ecsoffs) { + int beg = ecused, l; + Eccstr sp; + char *sq; + + ecspace(ecsoffs); + + for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp; + sp = sp->next, sq += l) { + l = strlen(sp->str) + 1; + memcpy(sq, sp->str, l); + } + } + ecsoffs = sbeg; + ecstrs = ostrs; + ecnpats = onp; + + ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); + } + break; + case CURSH: + ecadd(WCB_CURSH()); + ec(nn->u.list); + break; + case CFOR: + { + int type; + + p = ecadd(0); + ecstr(nn->u.forcmd->name); + + if (nn->u.forcmd->condition) { + type = WC_FOR_COND; + ecstr(nn->u.forcmd->condition); + ecstr(nn->u.forcmd->advance); + } else { + if (nn->args) { + LinkNode fp; + int num; + + type = WC_FOR_LIST; + + ecadd(0); + + for (fp = firstnode(nn->args), num = 0; fp; + incnode(fp), num++) + ecstr((char *) getdata(fp)); + + ecbuf[p + 2] = num; + } else + type = WC_FOR_PPARAM; + } + ec(nn->u.forcmd->list); + + ecbuf[p] = WCB_FOR(type, ecused - 1 - p); + } + break; + case CSELECT: + { + int type; + + p = ecadd(0); + ecstr(nn->u.forcmd->name); + + if (nn->args) { + LinkNode fp; + int num; + + type = WC_SELECT_LIST; + ecadd(0); + + for (fp = firstnode(nn->args), num = 0; fp; + incnode(fp), num++) + ecstr((char *) getdata(fp)); + + ecbuf[p + 2] = num; + } else + type = WC_SELECT_PPARAM; + + ec(nn->u.forcmd->list); + + ecbuf[p] = WCB_SELECT(type, ecused - 1 - p); + } + break; + case CIF: + { + List *i, *t; + int type = WC_IF_IF; + + c = ecadd(0); + + for (i = nn->u.ifcmd->ifls, t = nn->u.ifcmd->thenls; + *i; i++, t++) { + p = ecadd(0); + ec(*i); + ec(*t); + ecbuf[p] = WCB_IF(type, ecused - 1 - p); + type = WC_IF_ELIF; + } + if (*t) { + p = ecadd(0); + ec(*t); + ecbuf[p] = WCB_IF(WC_IF_ELSE, ecused - 1 - p); + } + ecbuf[c] = WCB_IF(WC_IF_HEAD, ecused - 1 - c); + } + break; + case CCASE: + { + List *l; + char **pp = nn->u.casecmd->pats; + + p = ecadd(0); + ecstr(*pp++); + + for (l = nn->u.casecmd->lists; l && *l; l++, pp++) { + c = ecadd(0); + ecstr(*pp + 1); + ecadd(ecnpats++); + ec(*l); + ecbuf[c] = WCB_CASE((**pp == ';' ? + WC_CASE_OR : WC_CASE_AND), + ecused - 1 - c); + } + ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p); + } + break; + case COND: + eccond(nn->u.cond); + break; + case CARITH: + ecadd(WCB_ARITH()); + ecstr((char *) getdata(firstnode(nn->args))); + break; + case CREPEAT: + p = ecadd(0); + ecstr((char *) getdata(firstnode(nn->args))); + ec(nn->u.list); + ecbuf[p] = WCB_REPEAT(ecused - 1 - p); + break; + case CWHILE: + p = ecadd(0); + ec(nn->u.whilecmd->cont); + ec(nn->u.whilecmd->loop); + ecbuf[p] = WCB_WHILE((nn->u.whilecmd->cond ? + WC_WHILE_UNTIL : WC_WHILE_WHILE), + ecused - 1 - p); + break; + } + } + break; + } +} + +/**/ +static void +ecredirs(LinkList l) +{ + LinkNode n; + Redir f; + + if (!l) + return; + + for (n = firstnode(l); n; incnode(n)) { + f = (Redir) getdata(n); + + ecadd(WCB_REDIR(f->type)); + ecadd(f->fd1); + ecstr(f->name); + } +} + +/**/ +static void +ecassigns(LinkList l) +{ + int p; + LinkNode n; + Varasg v; + + if (!l) + return; + + for (n = firstnode(l); n; incnode(n)) { + v = (Varasg) getdata(n); + + p = ecadd(0); + ecstr(v->name); + + if (PM_TYPE(v->type) == PM_ARRAY) { + LinkNode vp; + int num; + + for (vp = firstnode(v->arr), num = 0; vp; incnode(vp), num++) + ecstr((char *) getdata(vp)); + ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, num); + } else { + ecstr(v->str); + ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_SCALAR, 0); + } + } +} + +/**/ +static void +eccond(Cond c) +{ + int p; + + switch (c->type) { + case COND_NOT: + ecadd(WCB_COND(COND_NOT, 0)); + eccond(c->left); + break; + case COND_AND: + case COND_OR: + p = ecadd(0); + eccond(c->left); + eccond(c->right); + ecbuf[p] = WCB_COND(c->type, ecused - 1 - p); + break; + case COND_MOD: + { + char **pp; + int num; + + p = ecadd(0); + ecstr((char *) c->left); + for (pp = (char **) c->right, num = 0; *pp; pp++, num++) + ecstr(*pp); + ecbuf[p] = WCB_COND(COND_MOD, num); + } + break; + case COND_MODI: + ecadd(WCB_COND(COND_MODI, 0)); + ecstr((char *) c->left); + ecstr(((char **) c->right)[0]); + ecstr(((char **) c->right)[1]); + break; + default: + ecadd(WCB_COND(c->type, 0)); + ecstr((char *) c->left); + if (c->type <= COND_GE) { + ecstr((char *) c->right); + if (c->type == COND_STREQ || c->type == COND_STRNEQ) + ecadd(ecnpats++); + } + break; + } +} + +/**/ +static Eprog +execompile(List list) +{ + Eprog ret; + Eccstr p; + char *q; + int l; + + MUSTUSEHEAP("execompile"); + + ecbuf = (Wordcode) zhalloc((eclen = ecfree = 256) * sizeof(wordcode)); + ecused = 0; + ecstrs = NULL; + ecsoffs = ecnpats = 0; + + ec(list); + if (!ecused) + ecadd(WCB_END()); + + ret = (Eprog) zhalloc(sizeof(*ret)); + ret->len = ((ecnpats * sizeof(Patprog)) + + (ecused * sizeof(wordcode)) + + ecsoffs); + ret->npats = ecnpats; + ret->pats = (Patprog *) zhalloc(ret->len); + ret->prog = (Wordcode) (ret->pats + ecnpats); + ret->strs = (char *) (ret->prog + ecused); + ret->shf = NULL; + ret->heap = 1; + for (l = 0; l < ecnpats; l++) + ret->pats[l] = dummy_patprog1; + memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode)); + for (p = ecstrs, q = ret->strs; p; p = p->next, q += l) { + l = strlen(p->str) + 1; + memcpy(q, p->str, l); + } + return ret; +} + +/**/ +Eprog +dupeprog(Eprog p) +{ + Eprog r; + int i; + Patprog *pp; + + if (p == &dummy_eprog) + return p; + + r = (Eprog) ncalloc(sizeof(*r)); + r->heap = useheap; + r->len = p->len; + r->npats = p->npats; + pp = r->pats = (Patprog *) ncalloc(r->len); + r->prog = (Wordcode) (r->pats + r->npats); + r->strs = ((char *) r->prog) + (p->strs - ((char *) p->prog)); + memcpy(r->prog, p->prog, r->len - (p->npats * sizeof(Patprog))); + + for (i = r->npats; i--; pp++) + *pp = dummy_patprog1; + + return r; +} + +static LinkList eprog_free; + +/**/ +mod_export void +freeeprog(Eprog p) +{ + if (p && p != &dummy_eprog) { + PERMALLOC { + addlinknode(eprog_free, p); + } LASTALLOC; + } +} + +/**/ +void +freeeprogs(void) +{ + Eprog p; + int i; + Patprog *pp; + + while ((p = (Eprog) getlinknode(eprog_free))) { + for (i = p->npats, pp = p->pats; i--; pp++) + freepatprog(*pp); + zfree(p->pats, p->len); + zfree(p, sizeof(*p)); + } +} + +/**/ +char * +ecgetstr(Estate s, int dup) +{ + static char buf[4]; + wordcode c = *s->pc++; + char *r; + + if (c == 0xfe000000) + r = ""; + else if (c >= 0xff000000) { + buf[0] = (char) (c & 0xff); + buf[1] = (char) ((c >> 8) & 0xff); + buf[2] = (char) ((c >> 16) & 0xff); + buf[3] = '\0'; + r = dupstring(buf); + dup = 0; + } else + r = s->strs + c; + + return (dup ? dupstring(r) : r); +} + +/**/ +char * +ecrawstr(Eprog p, Wordcode pc) +{ + static char buf[4]; + wordcode c = *pc; + + if (c == 0xfe000000) + return ""; + else if (c >= 0xff000000) { + buf[0] = (char) (c & 0xff); + buf[1] = (char) ((c >> 8) & 0xff); + buf[2] = (char) ((c >> 16) & 0xff); + buf[3] = '\0'; + return buf; + } else + return p->strs + c; +} + +/**/ +char ** +ecgetarr(Estate s, int num, int dup) +{ + char **ret, **rp; + + ret = rp = (char **) zhalloc(num * sizeof(char *)); + + while (num--) + *rp++ = ecgetstr(s, dup); + + return ret; +} + +/**/ +LinkList +ecgetlist(Estate s, int num, int dup) +{ + if (num) { + LinkList ret; + + ret = newlinklist(); + + while (num--) + addlinknode(ret, ecgetstr(s, dup)); + + return ret; + } + return NULL; +} + +/**/ +LinkList +ecgetredirs(Estate s) +{ + LinkList ret = newlinklist(); + wordcode code = *s->pc++; + + while (wc_code(code) == WC_REDIR) { + Redir r = (Redir) zhalloc(sizeof(*r)); + + r->type = WC_REDIR_TYPE(code); + r->fd1 = *s->pc++; + r->name = ecgetstr(s, 1); + + addlinknode(ret, r); + + code = *s->pc++; + } + s->pc--; + + return ret; +} + +/**/ +mod_export struct eprog dummy_eprog; + +static wordcode dummy_eprog_code; + +/**/ +void +init_eprog(void) +{ + dummy_eprog_code = WCB_END(); + dummy_eprog.len = sizeof(wordcode); + dummy_eprog.prog = &dummy_eprog_code; + dummy_eprog.strs = NULL; + + PERMALLOC { + eprog_free = newlinklist(); + } LASTALLOC; +} diff --git a/Src/signals.c b/Src/signals.c index 58d21e82d..853c54061 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -39,7 +39,7 @@ mod_export int sigtrapped[VSIGCOUNT]; /* trap functions for each signal */ /**/ -mod_export List sigfuncs[VSIGCOUNT]; +mod_export Eprog sigfuncs[VSIGCOUNT]; /* Variables used by signal queueing */ @@ -674,7 +674,7 @@ dosavetrap(int sig, int level) /**/ mod_export int -settrap(int sig, List l) +settrap(int sig, Eprog l) { if (sig == -1) return 1; @@ -773,7 +773,7 @@ unsettrap(int sig) if ((hn = removehashnode(shfunctab, func))) shfunctab->freenode(hn); } else if (sigfuncs[sig]) { - freestruct(sigfuncs[sig]); + freeeprog(sigfuncs[sig]); sigfuncs[sig] = NULL; } } @@ -834,12 +834,12 @@ endtrapscope(void) unsettrap(sig); sigtrapped[sig] = st->flags; if (st->flags) { - List list = (st->flags & ZSIG_FUNC) ? - ((Shfunc) st->list)->funcdef : (List) st->list; + Eprog prog = (st->flags & ZSIG_FUNC) ? + ((Shfunc) st->list)->funcdef : (Eprog) st->list; /* prevent settrap from saving this */ int oldlt = opts[LOCALTRAPS]; opts[LOCALTRAPS] = 0; - settrap(sig, list); + settrap(sig, prog); opts[LOCALTRAPS] = oldlt; if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC) shfunctab->addnode(shfunctab, ((Shfunc)st->list)->nam, @@ -851,11 +851,11 @@ endtrapscope(void) if (exittr) { dotrapargs(SIGEXIT, &exittr, (exittr & ZSIG_FUNC) ? - ((Shfunc)exitfn)->funcdef : (List) exitfn); + ((Shfunc)exitfn)->funcdef : (Eprog) exitfn); if (exittr & ZSIG_FUNC) shfunctab->freenode((HashNode)exitfn); else - freestruct(exitfn); + freeeprog(exitfn); } } diff --git a/Src/text.c b/Src/text.c index fb1fdbb14..ba3bb03e9 100644 --- a/Src/text.c +++ b/Src/text.c @@ -31,7 +31,7 @@ #include "text.pro" static char *tptr, *tbuf, *tlim; -static int tsiz, tindent, tnewlins; +static int tsiz, tindent, tnewlins, tjob; /* add a character to the text buffer */ @@ -72,18 +72,18 @@ taddstr(char *s) tptr += sl; } -/* add an integer to the text buffer */ - -#if 0 /**/ -void -taddint(int x) +/**/ +static void +taddlist(Estate state, int num) { - char buf[DIGBUFSIZE]; - - sprintf(buf, "%d", x); - taddstr(buf); + if (num) { + while (num--) { + taddstr(ecgetstr(state, 0)); + taddchr(' '); + } + tptr--; + } } -#endif /* add a newline, or something equivalent, to the text buffer */ @@ -105,14 +105,24 @@ taddnl(void) /**/ mod_export char * -getpermtext(struct node *n) +getpermtext(Eprog prog, Wordcode c) { + struct estate s; + + if (!c) + c = prog->prog; + + s.prog = prog; + s.pc = c; + s.strs = prog->strs; + tnewlins = 1; tbuf = (char *)zalloc(tsiz = 32); tptr = tbuf; tlim = tbuf + tsiz; tindent = 1; - gettext2(n); + tjob = 0; + gettext2(&s); *tptr = '\0'; untokenize(tbuf); return tbuf; @@ -122,366 +132,566 @@ getpermtext(struct node *n) /**/ char * -getjobtext(struct node *n) +getjobtext(Eprog prog, Wordcode c) { static char jbuf[JOBTEXTSIZE]; + struct estate s; + + if (!c) + c = prog->prog; + + s.prog = prog; + s.pc = c; + s.strs = prog->strs; + tnewlins = 0; tbuf = NULL; tptr = jbuf; tlim = tptr + JOBTEXTSIZE - 1; tindent = 1; - gettext2(n); + tjob = 1; + gettext2(&s); *tptr = '\0'; untokenize(jbuf); return jbuf; } -#define gt2(X) gettext2((struct node *) (X)) - /* - "gettext2" or "type checking and how to avoid it" - an epic function by Paul Falstad -*/ - -#define _Cond(X) ((Cond) (X)) -#define _Cmd(X) ((Cmd) (X)) -#define _Pline(X) ((Pline) (X)) -#define _Sublist(X) ((Sublist) (X)) -#define _List(X) ((List) (X)) -#define _casecmd(X) ((struct casecmd *) (X)) -#define _ifcmd(X) ((struct ifcmd *) (X)) -#define _whilecmd(X) ((struct whilecmd *) (X)) + * gettext2() shows one way to walk through the word code without + * recursion. We start by reading a word code and executing the + * action for it. Some codes have sub-structures (like, e.g. WC_FOR) + * and require something to be done after the sub-structure has been + * handled. For these codes a tstack structure which describes what + * has to be done is pushed onto a stack. Codes without sub-structures + * arrange for the next structure being taken from the stack so that + * the action for it is executed instead of the one for the next + * word code. If the stack is empty at this point, we have handled + * the whole structure we were called for. + */ + +typedef struct tstack *Tstack; + +struct tstack { + Tstack prev; + wordcode code; + int pop; + union { + struct { + LinkList list; + } _redir; + struct { + char *strs; + } _funcdef; + struct { + Wordcode end; + } _case; + struct { + int cond; + Wordcode end; + } _if; + struct { + int par; + } _cond; + } u; +}; + +static Tstack tstack, tfree; + +static Tstack +tpush(wordcode code, int pop) +{ + Tstack s; + + if ((s = tfree)) + tfree = s->prev; + else + s = (Tstack) zalloc(sizeof(*s)); + + s->prev = tstack; + tstack = s; + s->code = code; + s->pop = pop; + + return s; +} /**/ static void -gettext2(struct node *n) +gettext2(Estate state) { - Cmd nn; - - if (!n || ((List) n) == &dummy_list) - return; - switch (NT_TYPE(n->ntype)) { - case N_LIST: - gt2(_List(n)->left); - if (_List(n)->type & Z_ASYNC) { - taddstr(" &"); - if (_List(n)->type & Z_DISOWN) - taddstr("|"); - } - if (_List(n)->right) { - if (tnewlins) - taddnl(); - else - taddstr((_List(n)->type & Z_ASYNC) ? " " : "; "); - gt2(_List(n)->right); - } - break; - case N_SUBLIST: - if (_Sublist(n)->flags & PFLAG_NOT) - taddstr("! "); - if (_Sublist(n)->flags & PFLAG_COPROC) - taddstr("coproc "); - gt2(_Sublist(n)->left); - if (_Sublist(n)->right) { - taddstr((_Sublist(n)->type == ORNEXT) ? " || " : " && "); - gt2(_Sublist(n)->right); - } - break; - case N_PLINE: - gt2(_Pline(n)->left); - if (_Pline(n)->type == PIPE) { - taddstr(" | "); - gt2(_Pline(n)->right); + Tstack s, n; + int stack = 0; + wordcode code; + + while (1) { + if (stack) { + if (!(s = tstack)) + return; + if (s->pop) { + tstack = s->prev; + s->prev = tfree; + tfree = s; + } + code = s->code; + stack = 0; + } else { + s = NULL; + code = *state->pc++; } - break; - case N_CMD: - nn = _Cmd(n); - switch (nn->type) { - case SIMPLE: - getsimptext(nn); + switch (wc_code(code)) { + case WC_LIST: + if (!s) { + tpush(code, (WC_LIST_TYPE(code) & Z_END)); + stack = 0; + } else { + if (WC_LIST_TYPE(code) & Z_ASYNC) { + taddstr(" &"); + if (WC_LIST_TYPE(code) & Z_DISOWN) + taddstr("|"); + } + if (!(stack = (WC_LIST_TYPE(code) & Z_END))) { + if (tnewlins) + taddnl(); + else + taddstr((WC_LIST_TYPE(code) & Z_ASYNC) ? " " : "; "); + s->code = *state->pc++; + s->pop = (WC_LIST_TYPE(s->code) & Z_END); + } + } + break; + case WC_SUBLIST: + if (!s) { + if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) + taddstr("! "); + if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC) + taddstr("coproc "); + tpush(code, (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END)); + } else { + if (!(stack = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END))) { + taddstr((WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) ? + " || " : " && "); + s->code = *state->pc++; + s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END); + if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT) + taddstr("! "); + if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC) + taddstr("coproc "); + } + } + break; + case WC_PIPE: + if (!s) { + tpush(code, (WC_PIPE_TYPE(code) == WC_PIPE_END)); + if (WC_PIPE_TYPE(code) == WC_PIPE_MID) + state->pc++; + } else { + if (!(stack = (WC_PIPE_TYPE(code) == WC_PIPE_END))) { + taddstr(" | "); + s->code = *state->pc++; + if (!(s->pop = (WC_PIPE_TYPE(s->code) == WC_PIPE_END))) + state->pc++; + } + } + break; + case WC_REDIR: + if (!s) { + state->pc--; + n = tpush(code, 1); + n->u._redir.list = ecgetredirs(state); + } else { + getredirs(s->u._redir.list); + stack = 1; + } break; - case SUBSH: - taddstr("( "); - tindent++; - gt2(nn->u.list); - tindent--; - taddstr(" )"); + case WC_ASSIGN: + taddstr(ecgetstr(state, 0)); + taddchr('='); + if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) { + taddchr('('); + taddlist(state, WC_ASSIGN_NUM(code)); + taddstr(") "); + } else { + taddstr(ecgetstr(state, 0)); + taddchr(' '); + } break; - case ZCTIME: - taddstr("time "); - tindent++; - gt2(nn->u.pline); - tindent--; + case WC_SIMPLE: + taddlist(state, WC_SIMPLE_ARGC(code)); + stack = 1; break; - case FUNCDEF: - taddlist(nn->args); - taddstr(" () {"); - tindent++; - taddnl(); - gt2(nn->u.list); - tindent--; - taddnl(); - taddstr("}"); + case WC_SUBSH: + if (!s) { + taddstr("( "); + tindent++; + tpush(code, 1); + } else { + tindent--; + taddstr(" )"); + stack = 1; + } break; - case CURSH: - taddstr("{ "); - tindent++; - gt2(nn->u.list); - tindent--; - taddstr(" }"); + case WC_CURSH: + if (!s) { + taddstr("{ "); + tindent++; + tpush(code, 1); + } else { + tindent--; + taddstr(" }"); + stack = 1; + } break; - case CFOR: - case CSELECT: - taddstr((nn->type == CFOR) ? "for " : "select "); - if (nn->u.forcmd->condition) { - taddstr("(("); - taddstr(nn->u.forcmd->name); - taddstr("; "); - taddstr(nn->u.forcmd->condition); - taddstr("; "); - taddstr(nn->u.forcmd->advance); - taddstr(")) do"); + case WC_TIMED: + if (!s) { + taddstr("time"); + if (WC_TIMED_TYPE(code) == WC_TIMED_PIPE) { + taddchr(' '); + tindent++; + tpush(code, 1); + } else + stack = 1; } else { - taddstr(nn->u.forcmd->name); - if (nn->u.forcmd->inflag) { - taddstr(" in "); - taddlist(nn->args); + tindent--; + stack = 1; + } + break; + case WC_FUNCDEF: + if (!s) { + Wordcode p = state->pc; + Wordcode end = p + WC_FUNCDEF_SKIP(code); + + taddlist(state, *state->pc++); + if (tjob) { + taddstr(" () { ... }"); + state->pc = end; + stack = 1; + } else { + taddstr(" () {"); + tindent++; + taddnl(); + n = tpush(code, 1); + n->u._funcdef.strs = state->strs; + state->strs = (char *) (p + (*state->pc)); + state->pc += 2; } + } else { + state->strs = s->u._funcdef.strs; + tindent--; taddnl(); - taddstr("do"); + taddstr("}"); + stack = 1; } - tindent++; - taddnl(); - gt2(nn->u.forcmd->list); - tindent--; - taddnl(); - taddstr("done"); - break; - case CIF: - gt2(nn->u.ifcmd); - taddstr("fi"); - break; - case CCASE: - gt2(nn->u.casecmd); break; - case COND: - taddstr("[[ "); - gt2(nn->u.cond); - taddstr(" ]]"); + case WC_FOR: + if (!s) { + taddstr("for "); + if (WC_FOR_TYPE(code) == WC_FOR_COND) { + taddstr("(("); + taddstr(ecgetstr(state, 0)); + taddstr("; "); + taddstr(ecgetstr(state, 0)); + taddstr("; "); + taddstr(ecgetstr(state, 0)); + taddstr(")) do"); + } else { + taddstr(ecgetstr(state, 0)); + if (WC_FOR_TYPE(code) == WC_FOR_LIST) { + taddstr(" in "); + taddlist(state, *state->pc++); + } + taddnl(); + taddstr("do"); + } + tindent++; + taddnl(); + tpush(code, 1); + } else { + tindent--; + taddnl(); + taddstr("done"); + stack = 1; + } break; - case CARITH: - taddstr("(("); - taddlist(nn->args); - taddstr("))"); + case WC_SELECT: + if (!s) { + taddstr("select "); + taddstr(ecgetstr(state, 0)); + if (WC_SELECT_TYPE(code) == WC_SELECT_LIST) { + taddstr(" in "); + taddlist(state, *state->pc++); + } + tindent++; + taddnl(); + tpush(code, 1); + } else { + tindent--; + taddnl(); + taddstr("done"); + stack = 1; + } break; - case CREPEAT: - taddstr("repeat "); - taddlist(nn->args); - taddnl(); - taddstr("do"); - tindent++; - taddnl(); - gt2(nn->u.list); - tindent--; - taddnl(); - taddstr("done"); + case WC_WHILE: + if (!s) { + taddstr(WC_WHILE_TYPE(code) == WC_WHILE_UNTIL ? + "until " : "while "); + tindent++; + tpush(code, 0); + } else if (!s->pop) { + tindent--; + taddnl(); + taddstr("do"); + tindent++; + taddnl(); + s->pop = 1; + } else { + tindent--; + taddnl(); + taddstr("done"); + stack = 1; + } break; - case CWHILE: - gt2(nn->u.whilecmd); + case WC_REPEAT: + if (!s) { + taddstr("repeat "); + taddstr(ecgetstr(state, 0)); + taddnl(); + taddstr("do"); + tindent++; + taddnl(); + tpush(code, 1); + } else { + tindent--; + taddnl(); + taddstr("done"); + stack = 1; + } break; - } - getredirs(nn); - break; - case N_COND: - getcond(_Cond(n), 0); - break; - case N_CASE: - { - List *l; - char **p; - - l = _casecmd(n)->lists; - p = _casecmd(n)->pats; - - taddstr("case "); - taddstr(*p++); - taddstr(" in"); - tindent++; - for (; l && *l; p++, l++) { + case WC_CASE: + if (!s) { + Wordcode end = state->pc + WC_CASE_SKIP(code); + + taddstr("case "); + taddstr(ecgetstr(state, 0)); + taddstr(" in"); + + if (state->pc >= end) { + if (tnewlins) + taddnl(); + else + taddchr(' '); + taddstr("esac"); + stack = 1; + } else { + tindent++; + if (tnewlins) + taddnl(); + else + taddchr(' '); + code = *state->pc++; + taddstr(ecgetstr(state, 0)); + state->pc++; + taddstr(") "); + tindent++; + n = tpush(code, 0); + n->u._case.end = end; + n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end); + } + } else if (state->pc < s->u._case.end) { + tindent--; + taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&"); if (tnewlins) taddnl(); else taddchr(' '); - taddstr(*p + 1); + code = *state->pc++; + taddstr(ecgetstr(state, 0)); + state->pc++; taddstr(") "); tindent++; - gt2(*l); + s->code = code; + s->pop = ((state->pc - 2 + WC_CASE_SKIP(code)) >= + s->u._case.end); + } else { + tindent--; + taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&"); tindent--; - taddstr(" ;"); - taddchr(**p); + if (tnewlins) + taddnl(); + else + taddchr(' '); + taddstr("esac"); + stack = 1; } - tindent--; - if (tnewlins) - taddnl(); - else - taddchr(' '); - taddstr("esac"); break; - } - case N_IF: - { - List *i, *t; + case WC_IF: + if (!s) { + Wordcode end = state->pc + WC_IF_SKIP(code); - taddstr("if "); - for (i = _ifcmd(n)->ifls, t = _ifcmd(n)->thenls; *i; i++, t++) { + taddstr("if "); tindent++; - gt2(*i); + state->pc++; + + n = tpush(code, 0); + n->u._if.end = end; + n->u._if.cond = 1; + } else if (s->pop) { + stack = 1; + } else if (s->u._if.cond) { tindent--; taddnl(); taddstr("then"); tindent++; taddnl(); - gt2(*t); + s->u._if.cond = 0; + } else if (state->pc < s->u._if.end) { tindent--; taddnl(); - if (i[1]) { + code = *state->pc++; + if (WC_IF_TYPE(code) == WC_IF_ELIF) { taddstr("elif "); + tindent++; + s->u._if.cond = 1; + } else { + taddstr("else"); + tindent++; + taddnl(); } - } - if (*t) { - taddstr("else"); - tindent++; - taddnl(); - gt2(*t); + } else { + s->pop = 1; tindent--; taddnl(); + taddstr("fi"); + stack = 1; } break; - } - case N_WHILE: - taddstr((_whilecmd(n)->cond) ? "until " : "while "); - tindent++; - gt2(_whilecmd(n)->cont); - tindent--; - taddnl(); - taddstr("do"); - tindent++; - taddnl(); - gt2(_whilecmd(n)->loop); - tindent--; - taddnl(); - taddstr("done"); - break; - } -} - -/* Print a condition bracketed by [[ ... ]]. * - * With addpar non-zero, parenthesise the subexpression. */ - -/**/ -static void -getcond(Cond nm, int addpar) -{ - static char *c1[] = - { - "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq", - "-ne", "-lt", "-gt", "-le", "-ge" - }; - - if (addpar) - taddstr("( "); - switch (nm->type) { - case COND_NOT: - taddstr("! "); - getcond(nm->left, _Cond(nm->left)->type <= COND_OR); - break; - case COND_AND: - getcond(nm->left, _Cond(nm->left)->type == COND_OR); - taddstr(" && "); - getcond(nm->right, _Cond(nm->right)->type == COND_OR); - break; - case COND_OR: - /* This is deliberately over-generous with parentheses: * - * in fact omitting them gives correct precedence. */ - getcond(nm->left, _Cond(nm->left)->type == COND_AND); - taddstr(" || "); - getcond(nm->right, _Cond(nm->right)->type == COND_AND); - break; - case COND_MOD: - { - /* Module defined prefix condition. */ - char **p = (char **) nm->right; - - taddstr(nm->left); - for (; *p; p++) { - taddstr(" "); - taddstr(*p); + case WC_COND: + { + static char *c1[] = { + "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq", + "-ne", "-lt", "-gt", "-le", "-ge" + }; + + int ctype; + + if (!s) { + taddstr("[[ "); + n = tpush(code, 1); + n->u._cond.par = 2; + } else if (s->u._cond.par == 2) { + taddstr(" ]]"); + stack = 1; + break; + } else if (s->u._cond.par == 1) { + taddstr(" )"); + stack = 1; + break; + } else if (WC_COND_TYPE(s->code) == COND_AND) { + taddstr(" && "); + code = *state->pc++; + if (WC_COND_TYPE(code) == COND_OR) { + taddstr("( "); + n = tpush(code, 1); + n->u._cond.par = 1; + } + } else if (WC_COND_TYPE(s->code) == COND_OR) { + taddstr(" || "); + code = *state->pc++; + if (WC_COND_TYPE(code) == COND_AND) { + taddstr("( "); + n = tpush(code, 1); + n->u._cond.par = 1; + } + } + while (!stack) { + switch ((ctype = WC_COND_TYPE(code))) { + case COND_NOT: + taddstr("! "); + code = *state->pc++; + if (WC_COND_TYPE(code) <= COND_OR) { + taddstr("( "); + n = tpush(code, 1); + n->u._cond.par = 1; + } + break; + case COND_AND: + tpush(code, 1); + code = *state->pc++; + if (WC_COND_TYPE(code) == COND_OR) { + taddstr("( "); + n = tpush(code, 1); + n->u._cond.par = 1; + } + break; + case COND_OR: + tpush(code, 1); + code = *state->pc++; + if (WC_COND_TYPE(code) == COND_AND) { + taddstr("( "); + n = tpush(code, 1); + n->u._cond.par = 1; + } + break; + case COND_MOD: + taddstr(ecgetstr(state, 0)); + taddlist(state, WC_COND_SKIP(code)); + stack = 1; + break; + case COND_MODI: + { + char *name = ecgetstr(state, 0); + + taddstr(ecgetstr(state, 0)); + taddchr(' '); + taddstr(name); + taddchr(' '); + taddstr(ecgetstr(state, 0)); + stack = 1; + } + break; + default: + if (ctype <= COND_GE) { + /* Binary test: `a = b' etc. */ + taddstr(ecgetstr(state, 0)); + taddstr(" "); + taddstr(c1[ctype - COND_STREQ]); + taddstr(" "); + taddstr(ecgetstr(state, 0)); + if (ctype == COND_STREQ || + ctype == COND_STRNEQ) + state->pc++; + } else { + /* Unary test: `-f foo' etc. */ + char c2[4]; + + c2[0] = '-'; + c2[1] = ctype; + c2[2] = ' '; + c2[3] = '\0'; + taddstr(c2); + taddstr(ecgetstr(state, 0)); + } + stack = 1; + break; + } + } } + break; + case WC_ARITH: + taddstr("(("); + taddstr(ecgetstr(state, 0)); + taddstr("))"); + stack = 1; + break; + default: + return; } - break; - case COND_MODI: - /* Module defined infix condition. */ - taddstr(((char **) nm->right)[0]); - taddstr(" "); - taddstr(nm->left); - taddstr(" "); - taddstr(((char **) nm->right)[1]); - break; - default: - if (nm->type <= COND_GE) { - /* Binary test: `a = b' etc. */ - taddstr(nm->left); - taddstr(" "); - taddstr(c1[nm->type - COND_STREQ]); - taddstr(" "); - taddstr(nm->right); - } else { - /* Unary test: `-f foo' etc. */ - char c2[4]; - - c2[0] = '-'; - c2[1] = nm->type; - c2[2] = ' '; - c2[3] = '\0'; - taddstr(c2); - taddstr(nm->left); - } - break; } - if (addpar) - taddstr(" )"); -} - -/**/ -static void -getsimptext(Cmd cmd) -{ - LinkNode n; - - if (cmd->vars) - for (n = firstnode(cmd->vars); n; incnode(n)) { - struct varasg *v = (struct varasg *)getdata(n); - - taddstr(v->name); - taddchr('='); - if (PM_TYPE(v->type) == PM_ARRAY) { - taddchr('('); - taddlist(v->arr); - taddstr(") "); - } else if (PM_TYPE(v->type) == PM_HASHED) { - /* XXX */ - } else { - taddstr(v->str); - taddchr(' '); - } - } - taddlist(cmd->args); } /**/ void -getredirs(Cmd cmd) +getredirs(LinkList redirs) { LinkNode n; static char *fstr[] = @@ -489,12 +699,9 @@ getredirs(Cmd cmd) ">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<", "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">" }; - - if (!cmd->redir) - return; taddchr(' '); - for (n = firstnode(cmd->redir); n; incnode(n)) { - struct redir *f = (struct redir *)getdata(n); + for (n = firstnode(redirs); n; incnode(n)) { + Redir f = (Redir) getdata(n); switch (f->type) { case WRITE: @@ -532,18 +739,3 @@ getredirs(Cmd cmd) } tptr--; } - -/**/ -static void -taddlist(LinkList l) -{ - LinkNode n; - - if (!l || !(n = firstnode(l))) - return; - for (; n; incnode(n)) { - taddstr(getdata(n)); - taddchr(' '); - } - tptr--; -} diff --git a/Src/utils.c b/Src/utils.c index 2a2d40f29..9d8432cc3 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -630,7 +630,7 @@ preprompt(void) { static time_t lastperiodic; LinkNode ln; - List list; + Eprog prog; int period = getiparam("PERIOD"); int mailcheck = getiparam("MAILCHECK"); @@ -643,11 +643,11 @@ preprompt(void) /* If a shell function named "precmd" exists, * * then execute it. */ - if ((list = getshfunc("precmd")) != &dummy_list) { + if ((prog = getshfunc("precmd")) != &dummy_eprog) { int osc = sfcontext; sfcontext = SFC_HOOK; - doshfunc("precmd", list, NULL, 0, 1); + doshfunc("precmd", prog, NULL, 0, 1); sfcontext = osc; } if (errflag) @@ -657,11 +657,11 @@ preprompt(void) * "periodic" exists, 3) it's been greater than PERIOD since we * * executed "periodic", then execute it now. */ if (period && (time(NULL) > lastperiodic + period) && - (list = getshfunc("periodic")) != &dummy_list) { + (prog = getshfunc("periodic")) != &dummy_eprog) { int osc = sfcontext; sfcontext = SFC_HOOK; - doshfunc("periodic", list, NULL, 0, 1); + doshfunc("periodic", prog, NULL, 0, 1); sfcontext = osc; lastperiodic = time(NULL); } @@ -1890,275 +1890,17 @@ sepsplit(char *s, char *sep, int allownull) /* Get the definition of a shell function */ /**/ -mod_export List +mod_export Eprog getshfunc(char *nam) { Shfunc shf; if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, nam))) - return &dummy_list; + return &dummy_eprog; return shf->funcdef; } -/* allocate a tree element */ - -static int sizetab[N_COUNT] = { - sizeof(struct list), - sizeof(struct sublist), - sizeof(struct pline), - sizeof(struct cmd), - sizeof(struct redir), - sizeof(struct cond), - sizeof(struct forcmd), - sizeof(struct casecmd), - sizeof(struct ifcmd), - sizeof(struct whilecmd), - sizeof(struct varasg), - sizeof(struct autofn), -}; - -static int offstab[N_COUNT] = { - offsetof(struct list, left), - offsetof(struct sublist, left), - offsetof(struct pline, left), - offsetof(struct cmd, u), - offsetof(struct redir, name), - offsetof(struct cond, left), - offsetof(struct forcmd, name), - offsetof(struct casecmd, pats), - offsetof(struct ifcmd, ifls), - offsetof(struct whilecmd, cont), - offsetof(struct varasg, name), - sizeof(struct autofn), -}; - -static int flagtab[N_COUNT] = { - NT_SET(N_LIST, NT_NODE, NT_NODE, 0, 0), - NT_SET(N_SUBLIST, NT_NODE, NT_NODE, 0, 0), - NT_SET(N_PLINE, NT_NODE, NT_NODE, 0, 0), - NT_SET(N_CMD, NT_NODE, NT_STR | NT_LIST, NT_NODE | NT_LIST, NT_NODE | NT_LIST), - NT_SET(N_REDIR, NT_STR, 0, 0, 0), - NT_SET(N_COND, NT_NODE, NT_NODE, NT_PAT, 0), - NT_SET(N_FOR, NT_STR, NT_STR, NT_STR, NT_NODE), - NT_SET(N_CASE, NT_STR | NT_ARR, NT_PAT | NT_ARR, NT_NODE | NT_ARR, 0), - NT_SET(N_IF, NT_NODE | NT_ARR, NT_NODE | NT_ARR, 0, 0), - NT_SET(N_WHILE, NT_NODE, NT_NODE, 0, 0), - NT_SET(N_VARASG, NT_STR, NT_STR, NT_STR | NT_LIST, 0), - NT_SET(N_AUTOFN, 0, 0, 0, 0), -}; - -/**/ -void * -allocnode(int type) -{ - struct node *n; - - n = (struct node *) ncalloc(sizetab[type]); - memset((void *) n, 0, sizetab[type]); - n->ntype = flagtab[type]; - - return (void *) n; -} - -/* duplicate a syntax tree */ - -/**/ -mod_export void * -dupstruct(void *a) -{ - void **onodes, **nnodes, *ret, *n, *on; - int type; - size_t nodeoffs; - - if (!a || ((List) a) == &dummy_list) - return a; - type = *(int *)a; - ret = alloc(sizetab[NT_TYPE(type)]); - memcpy(ret, a, nodeoffs = offstab[NT_TYPE(type)]); - onodes = (void **) ((char *)a + nodeoffs); - nnodes = (void **) ((char *)ret + nodeoffs); - for (type = (type & 0xffff00) >> 4; (type >>= 4); *nnodes++ = n) { - if (!(on = *onodes++)) - n = NULL; - else { - switch (type & 0xf) { - case NT_NODE: - n = dupstruct(on); - break; - case NT_STR: - n = dupstring(on); - break; - case NT_PAT: - n = duppatprog(on); - break; - case NT_LIST | NT_NODE: - n = duplist(on, (VFunc) dupstruct); - break; - case NT_LIST | NT_STR: - n = duplist(on, (VFunc) (useheap ? dupstring : ztrdup)); - break; - case NT_LIST | NT_PAT: - n = duplist(on, (VFunc) duppatprog); - break; - case NT_NODE | NT_ARR: - n = duparray(on, (VFunc) dupstruct); - break; - case NT_STR | NT_ARR: - n = duparray(on, (VFunc) (useheap ? dupstring : ztrdup)); - break; - case NT_PAT | NT_ARR: - n = duparray(on, (VFunc) duppatprog); - break; - default: - DPUTS(1, "BUG: bad node type in dupstruct()"); - abort(); - } - } - } - return ret; -} - -/* Free a syntax tree. Now, freestruct() only registers everything that - * has to be freed. Later, freestructs() will be called to do the real - * work. This is to avoid having functions that are currently executed - * free themselves by re-defining themselves. */ - -static LinkList freeslist = NULL; - -/**/ -mod_export void -freestruct(void *a) -{ - if (!a || ((List) a) == &dummy_list) - return; - - PERMALLOC { - if (!freeslist) - freeslist = newlinklist(); - addlinknode(freeslist, a); - } LASTALLOC; -} - -/**/ -void -freestructs(void) -{ - void *a; - - if (freeslist) - while ((a = getlinknode(freeslist))) - ifreestruct(a); -} - -/**/ -static void -ifreestruct(void *a) -{ - void **nodes, *n; - int type, size; - - type = *(int *) a; - nodes = (void **) ((char *)a + offstab[NT_TYPE(type)]); - size = sizetab[NT_TYPE(type)]; - for (type = (type & 0xffff00) >> 4; (type >>= 4);) { - if ((n = *nodes++)) { - switch (type & 0xf) { - case NT_NODE: - freestruct(n); - break; - case NT_STR: - zsfree((char *) n); - break; - case NT_PAT: - freepatprog((Patprog) n); - break; - case NT_LIST | NT_NODE: - freelinklist((LinkList) n, (FreeFunc) freestruct); - break; - case NT_LIST | NT_STR: - freelinklist((LinkList) n, (FreeFunc) zsfree); - break; - case NT_LIST | NT_PAT: - freelinklist((LinkList) n, (FreeFunc) freepatprog); - break; - case NT_NODE | NT_ARR: - { - void **p = (void **) n; - - while (*p) - freestruct(*p++); - zfree(n, sizeof(void *) * (p + 1 - (void **) n)); - break; - } - case NT_STR | NT_ARR: - freearray((char **) n); - break; - case NT_PAT | NT_ARR: - { - Patprog *p = (Patprog *) n; - - while (*p) - freepatprog(*p++); - zfree(n, sizeof(void *) * ((void **) p + 1 - (void **) n)); - break; - } - default: - DPUTS(1, "BUG: bad node type in freenode()"); - abort(); - } - } - } -#if 0 - DPUTS(size != ((char *) nodes) - ((char *) a), - "BUG: size wrong in freenode()"); -#endif - zfree(a, size); -} - -/**/ -LinkList -dupheaplist(LinkList l) -{ - if (!l) - return NULL; - - return duplist(l, (VFunc) dupstruct); -} - -/**/ -static LinkList -duplist(LinkList l, VFunc func) -{ - if (l && nonempty(l)) { - LinkList ret; - LinkNode node; - - ret = newlinklist(); - for (node = firstnode(l); node; incnode(node)) - addlinknode(ret, func(getdata(node))); - return ret; - } - return NULL; -} - -/**/ -mod_export char ** -duparray(char **arr, VFunc func) -{ - if (arr && *arr) { - char **ret, **rr, *p; - - ret = (char **) alloc((arrlen(arr) + 1) * sizeof(char *)); - for (rr = ret; (p = *arr++);) - *rr++ = (char *)func(p); - *rr = NULL; - - return ret; - } - return NULL; -} - /**/ char ** mkarray(char *s) diff --git a/Src/zsh.h b/Src/zsh.h index 88842e7d4..4be365901 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -306,20 +306,12 @@ typedef struct patprog *Patprog; typedef struct process *Process; typedef struct job *Job; typedef struct value *Value; -typedef struct varasg *Varasg; -typedef struct cond *Cond; typedef struct conddef *Conddef; -typedef struct cmd *Cmd; -typedef struct pline *Pline; -typedef struct sublist *Sublist; -typedef struct list *List; typedef struct redir *Redir; typedef struct complist *Complist; typedef struct heap *Heap; typedef struct heapstack *Heapstack; typedef struct histent *Histent; -typedef struct forcmd *Forcmd; -typedef struct autofn *AutoFn; typedef struct hookdef *Hookdef; typedef struct asgment *Asgment; @@ -365,148 +357,16 @@ struct linklist { /* Definitions for syntax trees */ /********************************/ -/* struct list, struct sublist, struct pline, etc. all fit the form * - * of this structure and are used interchangably. The ptrs may hold * - * integers or pointers, depending on the type of the node. */ - -/* Generic node structure for syntax trees */ -struct node { - int ntype; /* node type */ -}; - -#define N_LIST 0 -#define N_SUBLIST 1 -#define N_PLINE 2 -#define N_CMD 3 -#define N_REDIR 4 -#define N_COND 5 -#define N_FOR 6 -#define N_CASE 7 -#define N_IF 8 -#define N_WHILE 9 -#define N_VARASG 10 -#define N_AUTOFN 11 -#define N_COUNT 12 - -/* values for types[4] */ - -#define NT_EMPTY 0 -#define NT_NODE 1 -#define NT_STR 2 -#define NT_PAT 3 -#define NT_LIST 4 -#define NT_ARR 8 - -#define NT_TYPE(T) ((T) & 0xff) -#define NT_N(T, N) (((T) >> (8 + (N) * 4)) & 0xf) -#define NT_SET(T0, T1, T2, T3, T4) \ - ((T0) | ((T1) << 8) | ((T2) << 12) | ((T3) << 16) | ((T4) << 20)) - -/* tree element for lists */ - -struct list { - int ntype; /* node type */ - int type; - Sublist left; - List right; -}; - /* These are control flags that are passed * * down the execution pipeline. */ -#define Z_TIMED (1<<0) /* pipeline is being timed */ -#define Z_SYNC (1<<1) /* run this sublist synchronously (;) */ -#define Z_ASYNC (1<<2) /* run this sublist asynchronously (&) */ +#define Z_TIMED (1<<0) /* pipeline is being timed */ +#define Z_SYNC (1<<1) /* run this sublist synchronously (;) */ +#define Z_ASYNC (1<<2) /* run this sublist asynchronously (&) */ #define Z_DISOWN (1<<3) /* run this sublist without job control (&|) */ -/* tree element for sublists */ - -struct sublist { - int ntype; /* node type */ - int type; - int flags; /* see PFLAGs below */ - Pline left; - Sublist right; -}; - -#define ORNEXT 10 /* || */ -#define ANDNEXT 11 /* && */ - -#define PFLAG_NOT 1 /* ! ... */ -#define PFLAG_COPROC 32 /* coproc ... */ - -/* tree element for pipes */ - -struct pline { - int ntype; /* node type */ - int type; - Cmd left; - Pline right; -}; - -#define END 0 /* pnode *right is null */ -#define PIPE 1 /* pnode *right is the rest of the pipeline */ - -/* tree element for commands */ - -struct cmd { - int ntype; /* node type */ - int type; - int flags; /* see CFLAGs below */ - int lineno; /* lineno of script for command */ - union { - List list; /* for SUBSH/CURSH/SHFUNC */ - Forcmd forcmd; - struct casecmd *casecmd; - struct ifcmd *ifcmd; - struct whilecmd *whilecmd; - Sublist pline; - Cond cond; - AutoFn autofn; - void *generic; - } u; - LinkList args; /* command & argmument List (char *'s) */ - LinkList redir; /* i/o redirections (struct redir *'s) */ - LinkList vars; /* param assignments (struct varasg *'s) */ -}; - -/* cmd types */ -#define SIMPLE 0 -#define SUBSH 1 -#define CURSH 2 -#define ZCTIME 3 -#define FUNCDEF 4 -#define CFOR 5 -#define CWHILE 6 -#define CREPEAT 7 -#define CIF 8 -#define CCASE 9 -#define CSELECT 10 -#define COND 11 -#define CARITH 12 -#define AUTOFN 13 - /* flags for command modifiers */ #define CFLAG_EXEC (1<<0) /* exec ... */ -/* tree element for redirection lists */ - -struct redir { - int ntype; /* node type */ - int type; - int fd1, fd2; - char *name; -}; - -/* tree element for conditionals */ - -struct cond { - int ntype; /* node type */ - int type; /* can be cond_type, or a single */ - /* letter (-a, -b, ...) */ - void *left, *right; - Patprog prog; /* compiled pattern for `==' and `!=' */ -}; - #define COND_NOT 0 #define COND_AND 1 #define COND_OR 2 @@ -545,42 +405,12 @@ struct conddef { #define CONDDEF(name, flags, handler, min, max, condid) \ { NULL, name, flags, handler, min, max, condid, NULL } -struct forcmd { /* for/select */ -/* Cmd->args contains list of words to loop thru */ - int ntype; /* node type */ - int inflag; /* if there is an in ... clause */ - char *name; /* initializer or parameter name */ - char *condition; /* arithmetic terminating condition */ - char *advance; /* evaluated after each loop */ - List list; /* list to look through for each name */ -}; - -struct casecmd { -/* Cmd->args contains word to test */ - int ntype; /* node type */ - char **pats; /* pattern strings */ - Patprog *progs; /* compiled patterns (on demand) */ - List *lists; /* list to execute */ -}; - -struct ifcmd { - int ntype; /* node type */ - List *ifls; - List *thenls; -}; - -struct whilecmd { - int ntype; /* node type */ - int cond; /* 0 for while, 1 for until */ - List cont; /* condition */ - List loop; /* list to execute until condition met */ -}; - -/* node for autoloading functions */ +/* tree element for redirection lists */ -struct autofn { - int ntype; /* node type */ - Shfunc shf; /* the shell function to define */ +struct redir { + int type; + int fd1, fd2; + char *name; }; /* The number of fds space is allocated for * @@ -602,14 +432,12 @@ struct multio { int fds[MULTIOUNIT]; /* list of src/dests redirected to/from this fd */ }; -/* variable assignment tree element */ +/* structure for foo=bar assignments */ -struct varasg { - int ntype; /* node type */ - int type; /* nonzero means array */ +struct asgment { + struct asgment *next; char *name; - char *str; /* should've been a union here. oh well */ - LinkList arr; + char *value; }; /* lvalue for variable assignment/expansion */ @@ -623,16 +451,152 @@ struct value { char **arr; /* cache for hash turned into array */ }; -/* structure for foo=bar assignments */ +#define MAX_ARRLEN 262144 -struct asgment { - struct asgment *next; - char *name; - char *value; +/********************************************/ +/* Defintions for byte code */ +/********************************************/ + +typedef unsigned int wordcode; +typedef wordcode *Wordcode; + +typedef struct eprog *Eprog; + +struct eprog { + int heap; /* != 0 if this is in heap memory */ + int len; /* total block length */ + int npats; /* Patprog cache size */ + Patprog *pats; /* the memory block, the patterns */ + Wordcode prog; /* memory block ctd, the code */ + char *strs; /* memory block ctd, the strings */ + Shfunc shf; /* shell function for autoload */ }; -#define MAX_ARRLEN 262144 +typedef struct estate *Estate; + +struct estate { + Eprog prog; /* the eprog executed */ + Wordcode pc; /* program counter, current pos */ + char *strs; /* strings from prog */ +}; +#define WC_CODEBITS 5 + +#define wc_code(C) ((C) & ((wordcode) ((1 << WC_CODEBITS) - 1))) +#define wc_data(C) ((C) >> WC_CODEBITS) +#define wc_bld(C, D) (((wordcode) (C)) | (((wordcode) (D)) << WC_CODEBITS)) + +#define WC_END 0 +#define WC_LIST 1 +#define WC_SUBLIST 2 +#define WC_PIPE 3 +#define WC_REDIR 4 +#define WC_ASSIGN 5 +#define WC_SIMPLE 6 +#define WC_SUBSH 7 +#define WC_CURSH 8 +#define WC_TIMED 9 +#define WC_FUNCDEF 10 +#define WC_FOR 11 +#define WC_SELECT 12 +#define WC_WHILE 13 +#define WC_REPEAT 14 +#define WC_CASE 15 +#define WC_IF 16 +#define WC_COND 17 +#define WC_ARITH 18 +#define WC_AUTOFN 19 + +#define WCB_END() wc_bld(WC_END, 0) + +#define WC_LIST_TYPE(C) wc_data(C) +#define Z_END (1<<4) +#define WCB_LIST(T) wc_bld(WC_LIST, (T)) + +#define WC_SUBLIST_TYPE(C) (wc_data(C) & ((wordcode) 3)) +#define WC_SUBLIST_END 0 +#define WC_SUBLIST_AND 1 +#define WC_SUBLIST_OR 2 +#define WC_SUBLIST_FLAGS(C) (wc_data(C) & ((wordcode) 12)) +#define WC_SUBLIST_COPROC 4 +#define WC_SUBLIST_NOT 8 +#define WC_SUBLIST_SKIP(C) (wc_data(C) >> 4) +#define WCB_SUBLIST(T,F,O) wc_bld(WC_SUBLIST, ((T) | (F) | ((O) << 4))) + +#define WC_PIPE_TYPE(C) (wc_data(C) & ((wordcode) 1)) +#define WC_PIPE_END 0 +#define WC_PIPE_MID 1 +#define WC_PIPE_LINENO(C) (wc_data(C) >> 1) +#define WCB_PIPE(T,L) wc_bld(WC_PIPE, ((T) | ((L) << 1))) + +#define WC_REDIR_TYPE(C) wc_data(C) +#define WCB_REDIR(T) wc_bld(WC_REDIR, (T)) + +#define WC_ASSIGN_TYPE(C) (wc_data(C) & ((wordcode) 1)) +#define WC_ASSIGN_SCALAR 0 +#define WC_ASSIGN_ARRAY 1 +#define WC_ASSIGN_NUM(C) (wc_data(C) >> 1) +#define WCB_ASSIGN(T,N) wc_bld(WC_ASSIGN, ((T) | ((N) << 1))) + +#define WC_SIMPLE_ARGC(C) wc_data(C) +#define WCB_SIMPLE(N) wc_bld(WC_SIMPLE, (N)) + +#define WCB_SUBSH() wc_bld(WC_SUBSH, 0) + +#define WCB_CURSH() wc_bld(WC_CURSH, 0) + +#define WC_TIMED_TYPE(C) wc_data(C) +#define WC_TIMED_EMPTY 0 +#define WC_TIMED_PIPE 1 +#define WCB_TIMED(T) wc_bld(WC_TIMED, (T)) + +#define WC_FUNCDEF_SKIP(C) wc_data(C) +#define WCB_FUNCDEF(O) wc_bld(WC_FUNCDEF, (O)) + +#define WC_FOR_TYPE(C) (wc_data(C) & 3) +#define WC_FOR_PPARAM 0 +#define WC_FOR_LIST 1 +#define WC_FOR_COND 2 +#define WC_FOR_SKIP(C) (wc_data(C) >> 2) +#define WCB_FOR(T,O) wc_bld(WC_FOR, ((T) | ((O) << 2))) + +#define WC_SELECT_TYPE(C) (wc_data(C) & 1) +#define WC_SELECT_PPARAM 0 +#define WC_SELECT_LIST 1 +#define WC_SELECT_SKIP(C) (wc_data(C) >> 1) +#define WCB_SELECT(T,O) wc_bld(WC_SELECT, ((T) | ((O) << 1))) + +#define WC_WHILE_TYPE(C) (wc_data(C) & 1) +#define WC_WHILE_WHILE 0 +#define WC_WHILE_UNTIL 1 +#define WC_WHILE_SKIP(C) (wc_data(C) >> 1) +#define WCB_WHILE(T,O) wc_bld(WC_WHILE, ((T) | ((O) << 1))) + +#define WC_REPEAT_SKIP(C) wc_data(C) +#define WCB_REPEAT(O) wc_bld(WC_REPEAT, (O)) + +#define WC_CASE_TYPE(C) (wc_data(C) & 3) +#define WC_CASE_HEAD 0 +#define WC_CASE_OR 1 +#define WC_CASE_AND 2 +#define WC_CASE_SKIP(C) (wc_data(C) >> 2) +#define WCB_CASE(T,O) wc_bld(WC_CASE, ((T) | ((O) << 2))) + +#define WC_IF_TYPE(C) (wc_data(C) & 3) +#define WC_IF_HEAD 0 +#define WC_IF_IF 1 +#define WC_IF_ELIF 2 +#define WC_IF_ELSE 3 +#define WC_IF_SKIP(C) (wc_data(C) >> 2) +#define WCB_IF(T,O) wc_bld(WC_IF, ((T) | ((O) << 2))) + +#define WC_COND_TYPE(C) (wc_data(C) & 127) +#define WC_COND_SKIP(C) (wc_data(C) >> 7) +#define WCB_COND(T,O) wc_bld(WC_COND, ((T) | ((O) << 7))) + +#define WCB_ARITH() wc_bld(WC_ARITH, 0) + +#define WCB_AUTOFN() wc_bld(WC_AUTOFN, 0) /********************************************/ /* Defintions for job table and job control */ @@ -845,7 +809,7 @@ struct shfunc { HashNode next; /* next in hash chain */ char *nam; /* name of shell function */ int flags; /* various flags */ - List funcdef; /* function definition */ + Eprog funcdef; /* function definition */ }; /* Shell function context types. */ @@ -860,7 +824,7 @@ struct shfunc { /* node in list of function call wrappers */ -typedef int (*WrapFunc) _((List, FuncWrap, char *)); +typedef int (*WrapFunc) _((Eprog, FuncWrap, char *)); struct funcwrap { FuncWrap next; @@ -996,7 +960,7 @@ struct patprog { #define GF_MATCHREF 0x0800 /* Dummy Patprog pointers. Used mainly in executions trees, but the - * pattern code needs to knwo about it, too. */ + * pattern code needs to know about it, too. */ #define dummy_patprog1 ((Patprog) 1) #define dummy_patprog2 ((Patprog) 2) |