From 09960dc5b966fb1a1c20a0af654165e5981a999b Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 12 May 2010 10:06:59 +0000 Subject: 27951: Add $ZSH_EVAL_CONTEXT and $zsh_eval_contxt --- ChangeLog | 10 +++++- Doc/Zsh/expn.yo | 20 +++++++---- Doc/Zsh/params.yo | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Src/Builtins/sched.c | 2 +- Src/Modules/zpty.c | 2 +- Src/Modules/zutil.c | 13 ++++---- Src/builtin.c | 4 +-- Src/exec.c | 47 ++++++++++++++++++++------ Src/glob.c | 5 +-- Src/init.c | 6 ++-- Src/params.c | 21 ++++++++++-- Src/signals.c | 2 +- 12 files changed, 188 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index d34e9c20a..a1a0e6875 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2010-05-12 Peter Stephenson + + * 27951: Doc/Zsh/expn.yo, Doc/Zsh/params.yo, Src/builtin.c, + Src/exec.c, Src/glob.c, Src/init.c, Src/params.c, Src/signals.c, + Src/Builtins/sched.c, Src/Modules/zpty.c, Src/Modules/zutil.c: + Add $ZSH_EVAL_CONTEXT and $zsh_eval_context to provide context + stack. + 2010-05-10 Peter Stephenson * c.f. 27950: Test/C03traps.ztst some bogus whitespace got added @@ -13122,5 +13130,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.4975 $ +* $Revision: 1.4976 $ ***************************************************** diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index f04d6ea17..98c8ab2df 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -2149,12 +2149,17 @@ xitem(tt(e)var(string)) item(tt(PLUS())var(cmd))( The var(string) will be executed as shell code. The filename will be included in the list if and only if the code returns a zero status (usually -the status of the last command). The first character after the `tt(e)' +the status of the last command). + +In the first form, the first character after the `tt(e)' will be used as a separator and anything up to the next matching separator will be taken as the var(string); `tt([)', `tt({)', and `tt(<)' match `tt(])', `tt(})', and `tt(>)', respectively, while any other character matches itself. Note that expansions must be quoted in the var(string) to prevent them from being expanded before globbing is done. +var(string) is then executed as shell code. The string tt(globqual) +is appended to the array tt(zsh_eval_context) the duration of +execution. vindex(REPLY, use of) vindex(reply, use of) @@ -2288,12 +2293,13 @@ specifiers may occur to resolve ties. tt(oe) and tt(o+) are special cases; they are each followed by shell code, delimited as for the tt(e) glob qualifier and the tt(+) glob qualifier respectively (see above). The code is executed for each matched file with -the parameter tt(REPLY) set to the name of the file on entry. The code -should modify the parameter tt(REPLY) in some fashion. On return, the value -of the parameter is used instead of the file name as the string on which to -sort. Unlike other sort operators, tt(oe) and tt(o+) may be repeated, but -note that the maximum number of sort operators of any kind that may appear -in any glob expression is 12. +the parameter tt(REPLY) set to the name of the file on entry and +tt(globsort) appended to tt(zsh_eval_context). The code +should modify the parameter tt(REPLY) in some fashion. On return, the +value of the parameter is used instead of the file name as the string on +which to sort. Unlike other sort operators, tt(oe) and tt(o+) may be +repeated, but note that the maximum number of sort operators of any kind +that may appear in any glob expression is 12. ) item(tt(O)var(c))( like `tt(o)', but sorts in descending order; i.e. `tt(*(^oc))' is the diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 99a6e6958..55d5cda6a 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -722,6 +722,100 @@ vindex(VENDOR) item(tt(VENDOR))( The vendor, as determined at compile time. ) +vindex(zsh_eval_context) +vindex(ZSH_EVAL_CONTEXT) +item(tt(zsh_eval_context) (tt(ZSH_EVAL_CONTEXT) ))( +An array (colon-separated list) indicating the context of shell +code that is being run. Each time a piece of shell code that +is stored within the shell is executed a string is temporarily appended to +the array to indicate the type of operation that is being performed. +Read in order the array gives an indication of the stack of +operations being performed with the most immediate context last. + +The context is one of the following: +startitem() +item(tt(cmdarg))( +Code specified by the tt(-c) option to the command line that invoked +the shell. +) +item(tt(cmdsubst))( +Command substitution using the tt(`)var(...)tt(`) or +tt($+LPAR())var(...)tt(RPAR()) construct. +) +item(tt(equalsubst))( +File substitution using the tt(=+LPAR())var(...)tt(RPAR()) construct. +) +item(tt(eval))( +Code executed by the tt(eval) builtin. +) +item(tt(evalautofunc))( +Code executed with the tt(KSH_AUTOLOAD) mechanism in order to define +an autoloaded function. +) +item(tt(fc))( +Code from the shell history executed by the tt(-e) option to the tt(fc) +builtin. +) +item(tt(file))( +Lines of code being read directly from a file, for example by +the tt(source) builtin. +) +item(tt(filecode))( +Lines of code being read from a tt(.zwc) file instead of directly +from the source file. +) +item(tt(globqual))( +Code executed by the tt(e) or tt(+) glob qualifier. +) +item(tt(globsort))( +Code executed to order files by the tt(o) glob qualifier. +) +item(tt(insubst))( +File substitution using the tt(LPAR())var(...)tt(RPAR()) construct. +) +item(tt(sched))( +Code executed by the tt(sched) builtin. +) +item(tt(shfunc))( +A shell function. +) +item(tt(stty))( +Code passed to tt(stty) by the tt(STTY) environment variable. +Normally this is passed directly to the system's tt(stty) command, +so this value is unlikely to be seen in practice. +) +item(tt(style))( +Code executed as part of a style retrieved by the tt(zstyle) builtin +from the tt(zsh/zutil) module. +) +item(tt(toplevel))( +The highest execution level of a script or interactive shell. +) +item(tt(trap))( +Code executed as a trap defined by the tt(trap) builtin. Traps +defined as functions have the context tt(shfunc). As traps are +asynchronous they may have a different hierarchy from other +code. +) +item(tt(zpty))( +Code executed by the tt(zpty) builtin from the tt(zsh/zpty) module. +) +item(tt(zregesparse-guard))( +Code executed as a guard by the tt(zregexparse) command from the +tt(zsh/zutil) module. +) +item(tt(zregexparse-action))( +Code executed as an action by the tt(zregexparse) command from the +tt(zsh/zutil) module. +) +enditem() +) vindex(ZSH_NAME) item(tt(ZSH_NAME))( Expands to the basename of the command used to invoke this instance diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c index 99167e110..1ec3269bd 100644 --- a/Src/Builtins/sched.c +++ b/Src/Builtins/sched.c @@ -119,7 +119,7 @@ checksched(void) if ((sch->flags & SCHEDFLAG_TRASH_ZLE) && zleactive) zleentry(ZLE_CMD_TRASH); - execstring(sch->cmd, 0, 0); + execstring(sch->cmd, 0, 0, "sched"); zsfree(sch->cmd); zfree(sch, sizeof(struct schedcmd)); diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index f25d442b2..2a81e68cb 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -396,7 +396,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) setsparam("TTY", ztrdup(ttystrname)); opts[INTERACTIVE] = 0; - execode(prog, 1, 0); + execode(prog, 1, 0, "zpty"); stopmsg = 2; zexit(lastval, 0); } diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 698b7e3bd..76ca92f79 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -343,7 +343,7 @@ evalstyle(Stypat p) char **ret, *str; unsetparam("reply"); - execode(p->eval, 1, 0); + execode(p->eval, 1, 0, "style"); if (errflag) { errflag = ef; return NULL; @@ -1253,7 +1253,7 @@ rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) char *action = getdata(ln); if (action) - execstring(action, 1, 0); + execstring(action, 1, 0, "zregexparse-action"); } return 0; } @@ -1278,7 +1278,8 @@ rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) return 3; } if (next->pattern && pattry(next->patprog, subj) && - (!next->guard || (execstring(next->guard, 1, 0), !lastval))) { + (!next->guard || (execstring(next->guard, 1, 0, + "zregesparse-guard"), !lastval))) { LinkNode aln; char **mend; int len; @@ -1299,7 +1300,7 @@ rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) char *action = getdata(aln); if (action) - execstring(action, 1, 0); + execstring(action, 1, 0, "zregexparse-action"); } restorematch(&match2); @@ -1328,7 +1329,7 @@ rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) char *action = getdata(ln); if (action) - execstring(action, 1, 0); + execstring(action, 1, 0, "zregexparse-action"); } return 0; } @@ -1339,7 +1340,7 @@ rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) for (ln = firstnode(nexts); ln; ln = nextnode(ln)) { br = getdata(ln); if (br->state->action) - execstring(br->state->action, 1, 0); + execstring(br->state->action, 1, 0, "zregexparse-action"); } } return empty(nexts) ? 2 : 1; diff --git a/Src/builtin.c b/Src/builtin.c index d293a7a78..3f26f0304 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1755,7 +1755,7 @@ fcedit(char *ename, char *fn) return 1; s = tricat(ename, " ", fn); - execstring(s, 1, 0); + execstring(s, 1, 0, "fc"); zsfree(s); return !lastval; @@ -4883,7 +4883,7 @@ eval(char **argv) /* No code to execute */ lastval = 0; } else { - execode(prog, 1, 0); + execode(prog, 1, 0, "eval"); if (errflag && !lastval) lastval = errflag; diff --git a/Src/exec.c b/Src/exec.c index 19afc4ca4..8fd52420b 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -564,7 +564,7 @@ execute(LinkList args, int flags, int defpath) STTYval = 0; /* this prevents infinite recursion */ zsfree(s); - execstring(t, 1, 0); + execstring(t, 1, 0, "stty"); zsfree(t); } else if (s) { STTYval = 0; @@ -970,21 +970,40 @@ entersubsh(int flags) /**/ mod_export void -execstring(char *s, int dont_change_job, int exiting) +execstring(char *s, int dont_change_job, int exiting, char *context) { Eprog prog; pushheap(); if ((prog = parse_string(s, 0))) - execode(prog, dont_change_job, exiting); + execode(prog, dont_change_job, exiting, context); popheap(); } /**/ mod_export void -execode(Eprog p, int dont_change_job, int exiting) +execode(Eprog p, int dont_change_job, int exiting, char *context) { struct estate s; + static int zsh_eval_context_len; + int alen; + + if (!zsh_eval_context_len) { + zsh_eval_context_len = 16; + alen = 0; + zsh_eval_context = (char **)zalloc(zsh_eval_context_len * + sizeof(*zsh_eval_context)); + } else { + alen = arrlen(zsh_eval_context); + if (zsh_eval_context_len == alen + 1) { + zsh_eval_context_len *= 2; + zsh_eval_context = zrealloc(zsh_eval_context, + zsh_eval_context_len * + sizeof(*zsh_eval_context)); + } + } + zsh_eval_context[alen] = context; + zsh_eval_context[alen+1] = NULL; s.prog = p; s.pc = p->prog; @@ -994,6 +1013,12 @@ execode(Eprog p, int dont_change_job, int exiting) execlist(&s, dont_change_job, exiting); freeeprog(p); /* Free if now unused */ + + /* + * zsh_eval_context may have been altered by a recursive + * call, but that's OK since we're using the global value. + */ + zsh_eval_context[alen] = NULL; } /* Execute a simplified command. This is used to execute things that @@ -3571,7 +3596,7 @@ getoutput(char *cmd, int qt) redup(pipes[1], 1); entersubsh(ESUB_PGRP|ESUB_NOMONITOR); cmdpush(CS_CMDSUBST); - execode(prog, 0, 1); + execode(prog, 0, 1, "cmdsubst"); cmdpop(); close(1); _exit(lastval); @@ -3725,7 +3750,7 @@ getoutputfile(char *cmd, char **eptr) redup(fd, 1); entersubsh(ESUB_PGRP|ESUB_NOMONITOR); cmdpush(CS_CMDSUBST); - execode(prog, 0, 1); + execode(prog, 0, 1, "equalsubst"); cmdpop(); close(1); _exit(lastval); @@ -3827,7 +3852,7 @@ getproc(char *cmd, char **eptr) #endif /* PATH_DEV_FD */ cmdpush(CS_CMDSUBST); - execode(prog, 0, 1); + execode(prog, 0, 1, out ? "outsubst" : "insubst"); cmdpop(); zclose(out); _exit(lastval); @@ -3875,7 +3900,7 @@ getpipe(char *cmd, int nullexec) redup(pipes[out], out); closem(FDT_UNUSED); /* this closes pipes[!out] as well */ cmdpush(CS_CMDSUBST); - execode(prog, 0, 1); + execode(prog, 0, 1, out ? "outsubst" : "insubst"); cmdpop(); _exit(lastval); return 0; @@ -4196,7 +4221,7 @@ execautofn(Estate state, UNUSED(int do_exec)) oldscriptname = scriptname; oldscriptfilename = scriptfilename; scriptname = scriptfilename = dupstring(shf->node.nam); - execode(shf->funcdef, 1, 0); + execode(shf->funcdef, 1, 0, "loadautofunc"); scriptname = oldscriptname; scriptfilename = oldscriptfilename; @@ -4250,7 +4275,7 @@ loadautofn(Shfunc shf, int fksh, int autol) } else { VARARR(char, n, strlen(shf->node.nam) + 1); strcpy(n, shf->node.nam); - execode(prog, 1, 0); + execode(prog, 1, 0, "evalautofunc"); shf = (Shfunc) shfunctab->getnode(shfunctab, n); if (!shf || (shf->node.flags & PM_UNDEFINED)) { /* We're not actually in the function; decrement locallevel */ @@ -4538,7 +4563,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) wrap = wrap->next; } startparamscope(); - execode(prog, 1, 0); + execode(prog, 1, 0, "shfunc"); if (ou) { setunderscore(ou); zfree(ou, ouu); diff --git a/Src/glob.c b/Src/glob.c index 036f88ccc..c552e6cf1 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1806,7 +1806,7 @@ zglob(LinkList list, LinkNode np, int nountok) /* Parsed OK, execute for each name */ for (tmpptr = matchbuf; tmpptr < matchptr; tmpptr++) { setsparam("REPLY", ztrdup(tmpptr->name)); - execode(prog, 1, 0); + execode(prog, 1, 0, "globsort"); if (!errflag) tmpptr->sortstrs[iexec] = dupstring(getsparam("REPLY")); @@ -3497,7 +3497,7 @@ qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str) unsetparam("reply"); setsparam("REPLY", ztrdup(name)); - execode(prog, 1, 0); + execode(prog, 1, 0, "globqual"); ret = lastval; errflag = ef; @@ -3516,6 +3516,7 @@ qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str) inserts = tmparr; } } + return !ret; } return 0; diff --git a/Src/init.c b/Src/init.c index 56c8c1822..dea9aff40 100644 --- a/Src/init.c +++ b/Src/init.c @@ -182,7 +182,7 @@ loop(int toplevel, int justonce) } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; - execode(prog, 0, 0); + execode(prog, 0, 0, toplevel ? "toplevel" : "file"); tok = toksav; if (toplevel) noexitct = 0; @@ -1125,7 +1125,7 @@ init_misc(void) fclose(bshin); SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY)); bshin = fdopen(SHIN, "r"); - execstring(cmd, 0, 1); + execstring(cmd, 0, 1, "cmdarg"); stopmsg = 1; zexit(lastval, 0); } @@ -1213,7 +1213,7 @@ source(char *s) if (prog) { pushheap(); errflag = 0; - execode(prog, 1, 0); + execode(prog, 1, 0, "filecode"); popheap(); if (errflag) ret = SOURCE_ERROR; diff --git a/Src/params.c b/Src/params.c index b19881ee7..576de2f52 100644 --- a/Src/params.c +++ b/Src/params.c @@ -57,7 +57,8 @@ char **pparams, /* $argv */ **mailpath, /* $mailpath */ **manpath, /* $manpath */ **psvar, /* $psvar */ - **watch; /* $watch */ + **watch, /* $watch */ + **zsh_eval_context; /* $zsh_eval_context */ /**/ mod_export char **path, /* $path */ @@ -341,6 +342,7 @@ IPDEF8("MAILPATH", &mailpath, "mailpath", 0), IPDEF8("WATCH", &watch, "watch", 0), IPDEF8("PATH", &path, "path", PM_RESTRICTED), IPDEF8("PSVAR", &psvar, "psvar", 0), +IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY), /* MODULE_PATH is not imported for security reasons */ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), @@ -349,12 +351,21 @@ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED), #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0) IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY), + +/* + * This empty row indicates the end of parameters available in + * all emulations. + */ {{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, #define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0} -/* The following parameters are not available in sh/ksh compatibility * - * mode. All of these have sh compatible equivalents. */ +/* + * The following parameters are not available in sh/ksh compatibility * + * mode. + */ + +/* All of these have sh compatible equivalents. */ IPDEF1("ARGC", argc_gsu, PM_READONLY), IPDEF2("HISTCHARS", histchars_gsu, PM_DONTIMPORT), IPDEF4("status", &lastval), @@ -373,9 +384,13 @@ IPDEF9("manpath", &manpath, "MANPATH"), IPDEF9("psvar", &psvar, "PSVAR"), IPDEF9("watch", &watch, "WATCH"), +IPDEF9F("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_READONLY), + IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED), IPDEF9F("path", &path, "PATH", PM_RESTRICTED), +/* These are known to zsh alone. */ + IPDEF10("pipestatus", pipestatus_gsu), {{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0}, diff --git a/Src/signals.c b/Src/signals.c index f67a3e8ca..74aeadde7 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -1198,7 +1198,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) trap_state = TRAP_STATE_PRIMED; trapisfunc = isfunc = 0; - execode((Eprog)sigfn, 1, 0); + execode((Eprog)sigfn, 1, 0, "trap"); } runhookdef(AFTERTRAPHOOK, NULL); -- cgit 1.4.1