From 6f3ff6b653ca5e6f528bc46ec6295cb6d263a9fd Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 21 Aug 2012 18:03:01 +0000 Subject: 30633: "functions -T" only traces marked function, not called functions --- Src/exec.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/Src/exec.c b/Src/exec.c index 6ebc9c014..a40838f91 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4484,11 +4484,12 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) int *oldpipestats = NULL; char saveopts[OPT_SIZE], *oldscriptname = scriptname; char *name = shfunc->node.nam; - int flags = shfunc->node.flags; + int flags = shfunc->node.flags, ooflags; char *fname = dupstring(name); int obreaks, saveemulation, savesticky_emulation, restore_sticky; Eprog prog; struct funcstack fstack; + static int oflags; #ifdef MAX_FUNCTION_DEPTH static int funcdepth; #endif @@ -4547,8 +4548,17 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) } else restore_sticky = 0; - if (flags & PM_TAGGED) + if (flags & (PM_TAGGED|PM_TAGGED_LOCAL)) opts[XTRACE] = 1; + else if (oflags & PM_TAGGED_LOCAL) + opts[XTRACE] = 0; + ooflags = oflags; + /* + * oflags is static, because we compare it on the next recursive + * call. Hence also we maintain ooflags for restoring the previous + * value of oflags after the call. + */ + oflags = flags; opts[PRINTEXITVALUE] = 0; if (doshargs) { LinkNode node; @@ -4633,6 +4643,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) optcind = oldoptcind; zoptind = oldzoptind; scriptname = oldscriptname; + oflags = ooflags; if (restore_sticky) { /* -- cgit v1.2.3 From 4e2cdd795677e655f89b76b57611a196ce578432 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 7 Oct 2012 19:46:46 +0000 Subject: 30722: fix some cases where emulations or options were not propagated properly from the emulate command --- ChangeLog | 7 ++++- Src/Modules/parameter.c | 6 ++--- Src/builtin.c | 31 +++++++++++++-------- Src/exec.c | 2 +- Src/init.c | 69 ++++++++++++++++++++++++++++++----------------- Src/options.c | 72 +++++++++++++++++++++++++++++++------------------ Test/B07emulate.ztst | 25 +++++++++++++++++ 7 files changed, 145 insertions(+), 67 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 31896e953..109bce3c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-10-07 Peter Stephenson + * 30722: Src/builtin.c, Src/exec.c, Src/init.c, Src/options.c, + Src/Modules/parameter.c, Test/B07emulate.ztst: fix some cases + where options or emulations where not propagated properly + from the emulate command. + * 30718: README, Doc/Zsh/builtins.yo, Src/builtin.c, Test/C04funcdef.ztst: emulate command evaluations should apply sticky emulation to autoloads, too. @@ -239,5 +244,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5738 $ +* $Revision: 1.5739 $ ***************************************************** diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 4d29ba635..f19dfce4f 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -771,7 +771,7 @@ setpmoption(Param pm, char *value) zwarn("invalid value: %s", value); else if (!(n = optlookup(pm->node.nam))) zwarn("no such option: %s", pm->node.nam); - else if (dosetopt(n, (value && strcmp(value, "off")), 0)) + else if (dosetopt(n, (value && strcmp(value, "off")), 0, opts)) zwarn("can't change option: %s", pm->node.nam); zsfree(value); } @@ -784,7 +784,7 @@ unsetpmoption(Param pm, UNUSED(int exp)) if (!(n = optlookup(pm->node.nam))) zwarn("no such option: %s", pm->node.nam); - else if (dosetopt(n, 0, 0)) + else if (dosetopt(n, 0, 0, opts)) zwarn("can't change option: %s", pm->node.nam); } @@ -812,7 +812,7 @@ setpmoptions(UNUSED(Param pm), HashTable ht) if (!val || (strcmp(val, "on") && strcmp(val, "off"))) zwarn("invalid value: %s", val); else if (dosetopt(optlookup(hn->nam), - (val && strcmp(val, "off")), 0)) + (val && strcmp(val, "off")), 0, opts)) zwarn("can't change option: %s", hn->nam); } deleteparamtable(ht); diff --git a/Src/builtin.c b/Src/builtin.c index e9ad8f3de..334321db9 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -548,8 +548,8 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) /* Obsolescent sh compatibility: set - is the same as set +xv * * and set - args is the same as set +xv -- args */ if (!EMULATION(EMULATE_ZSH) && *args && **args == '-' && !args[0][1]) { - dosetopt(VERBOSE, 0, 0); - dosetopt(XTRACE, 0, 0); + dosetopt(VERBOSE, 0, 0, opts); + dosetopt(XTRACE, 0, 0, opts); if (!args[1]) return 0; } @@ -580,7 +580,7 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } if(!(optno = optlookup(*args))) zerrnam(nam, "no such option: %s", *args); - else if(dosetopt(optno, action, 0)) + else if(dosetopt(optno, action, 0, opts)) zerrnam(nam, "can't change option: %s", *args); break; } else if(**args == 'A') { @@ -601,7 +601,7 @@ bin_set(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) else { if (!(optno = optlookupc(**args))) zerrnam(nam, "bad option: -%c", **args); - else if(dosetopt(optno, action, 0)) + else if(dosetopt(optno, action, 0, opts)) zerrnam(nam, "can't change option: -%c", **args); } } @@ -5008,8 +5008,8 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) int opt_L = OPT_ISSET(ops, 'L'); int opt_R = OPT_ISSET(ops, 'R'); int saveemulation, savesticky_emulation, savehackchar; - int ret = 1; - char saveopts[OPT_SIZE]; + int ret = 1, new_emulation; + char saveopts[OPT_SIZE], new_opts[OPT_SIZE], savesticky_opts[OPT_SIZE]; char *cmd = 0; const char *shname = *argv; @@ -5044,7 +5044,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) /* with single argument set current emulation */ if (!argv[1]) { - emulate(shname, OPT_ISSET(ops,'R')); + emulate(shname, OPT_ISSET(ops,'R'), &emulation, opts); if (OPT_ISSET(ops,'L')) opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1; return 0; @@ -5052,8 +5052,13 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) argv++; memcpy(saveopts, opts, sizeof(opts)); + memcpy(new_opts, opts, sizeof(opts)); savehackchar = keyboardhackchar; - cmd = parseopts("emulate", &argv); + emulate(shname, OPT_ISSET(ops,'R'), &new_emulation, new_opts); + if (parseopts("emulate", &argv, new_opts, &cmd)) { + ret = 1; + goto restore; + } /* parseopts() has consumed anything that looks like an option */ if (*argv) { @@ -5061,6 +5066,9 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) goto restore; } + saveemulation = emulation; + emulation = new_emulation; + memcpy(opts, new_opts, sizeof(opts)); /* If "-c command" is given, evaluate command using specified * emulation mode. */ @@ -5073,15 +5081,16 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) } else return 0; - saveemulation = emulation; savesticky_emulation = sticky_emulation; - emulate(shname, OPT_ISSET(ops,'R')); sticky_emulation = emulation; + memcpy(savesticky_opts, sticky_opts, sizeof(opts)); + memcpy(sticky_opts, opts, sizeof(opts)); ret = eval(argv); sticky_emulation = savesticky_emulation; emulation = saveemulation; - restore: memcpy(opts, saveopts, sizeof(opts)); + memcpy(sticky_opts, savesticky_opts, sizeof(opts)); +restore: keyboardhackchar = savehackchar; inittyptab(); /* restore banghist */ return ret; diff --git a/Src/exec.c b/Src/exec.c index a40838f91..0f7c84a9f 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4544,7 +4544,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) */ emulation = sticky_emulation = shfunc->emulation; restore_sticky = 1; - installemulation(); + installemulation(emulation, opts); } else restore_sticky = 0; diff --git a/Src/init.c b/Src/init.c index d1e2bed3c..8f6c0ec6d 100644 --- a/Src/init.c +++ b/Src/init.c @@ -246,7 +246,8 @@ parseargs(char **argv, char **runscript) opts[SHINSTDIN] = 0; opts[SINGLECOMMAND] = 0; - cmd = parseopts(NULL, &argv); + if (parseopts(NULL, &argv, opts, &cmd)) + exit(1); paramlist = znewlinklist(); if (*argv) { @@ -276,18 +277,36 @@ parseargs(char **argv, char **runscript) argzero = ztrdup(argzero); } +/* + * Parse shell options. + * If nam is not NULL, this is called from a command; don't + * exit on failure. + */ + /**/ -mod_export char * -parseopts(char *nam, char ***argvp) +mod_export int +parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp) { int optionbreak = 0; int action, optno; - char *cmd = 0; /* deliberately hides static */ char **argv = *argvp; -#define WARN_OPTION(F, S) if (nam) zwarnnam(nam, F, S); else zerr(F, S) -#define LAST_OPTION(N) \ - if (nam) { if (*argv) argv++; goto doneargv; } else exit(N) + *cmdp = 0; +#define WARN_OPTION(F, S) \ + do { \ + if (nam) \ + zwarnnam(nam, F, S); \ + else \ + zerr(F, S); \ + } while (0) +#define LAST_OPTION(N) \ + do { \ + if (nam) { \ + if (*argv) \ + argv++; \ + goto doneargv; \ + } else exit(N); \ + } while(0) /* loop through command line options (begins with "-" or "+") */ while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) { @@ -327,25 +346,25 @@ parseopts(char *nam, char ***argvp) optionbreak = 1; } else if (**argv == 'c') { /* -c command */ - cmd = *argv; - opts[INTERACTIVE] &= 1; + *cmdp = *argv; + new_opts[INTERACTIVE] &= 1; scriptname = scriptfilename = ztrdup("zsh"); } else if (**argv == 'o') { if (!*++*argv) argv++; if (!*argv) { WARN_OPTION("string expected after -o", NULL); - LAST_OPTION(1); + return 1; } longoptions: if (!(optno = optlookup(*argv))) { WARN_OPTION("no such option: %s", *argv); - LAST_OPTION(1); + return 1; } else if (optno == RESTRICTED && !nam) { restricted = action; } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { WARN_OPTION("can't change option: %s", *argv); - } else if (dosetopt(optno, action, !nam) && nam) { + } else if (dosetopt(optno, action, !nam, new_opts) && nam) { WARN_OPTION("can't change option: %s", *argv); } break; @@ -355,18 +374,18 @@ parseopts(char *nam, char ***argvp) if (!isspace(STOUC(**argv))) { badoptionstring: WARN_OPTION("bad option string: '%s'", args); - LAST_OPTION(1); + return 1; } break; } else { if (!(optno = optlookupc(**argv))) { WARN_OPTION("bad option: -%c", **argv); - LAST_OPTION(1); + return 1; } else if (optno == RESTRICTED && !nam) { restricted = action; } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { WARN_OPTION("can't change option: %s", *argv); - } else if (dosetopt(optno, action, !nam) && nam) { + } else if (dosetopt(optno, action, !nam, new_opts) && nam) { WARN_OPTION("can't change option: -%c", **argv); } } @@ -374,18 +393,18 @@ parseopts(char *nam, char ***argvp) argv++; } doneoptions: - if (cmd) { + if (*cmdp) { if (!*argv) { - WARN_OPTION("string expected after -%s", cmd); - LAST_OPTION(1); + WARN_OPTION("string expected after -%s", *cmdp); + exit(1); } - cmd = *argv++; + *cmdp = *argv++; } doneargv: *argvp = argv; - return cmd; + return 0; } - + /**/ static void printhelp(void) @@ -1162,7 +1181,7 @@ init_misc(void) #else if (*zsh_name == 'r' || restricted) #endif - dosetopt(RESTRICTED, 1, 0); + dosetopt(RESTRICTED, 1, 0, opts); if (cmd) { if (SHIN >= 10) fclose(bshin); @@ -1225,7 +1244,7 @@ source(char *s) subsh = 0; lineno = 1; loops = 0; - dosetopt(SHINSTDIN, 0, 1); + dosetopt(SHINSTDIN, 0, 1, opts); scriptname = s; scriptfilename = s; @@ -1297,7 +1316,7 @@ source(char *s) thisjob = cj; /* current job number */ lineno = oldlineno; /* our current lineno */ loops = oloops; /* the # of nested loops we are in */ - dosetopt(SHINSTDIN, oldshst, 1); /* SHINSTDIN option */ + dosetopt(SHINSTDIN, oldshst, 1, opts); /* SHINSTDIN option */ errflag = 0; if (!exit_pending) retflag = 0; @@ -1535,7 +1554,7 @@ zsh_main(UNUSED(int argc), char **argv) fdtable = zshcalloc(fdtable_size*sizeof(*fdtable)); createoptiontable(); - emulate(zsh_name, 1); /* initialises most options */ + emulate(zsh_name, 1, &emulation, opts); /* initialises most options */ opts[LOGINSHELL] = (**argv == '-'); opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid()); opts[USEZLE] = 1; /* may be unset in init_io() */ diff --git a/Src/options.c b/Src/options.c index 6075a7fcb..87e9abe2d 100644 --- a/Src/options.c +++ b/Src/options.c @@ -44,6 +44,14 @@ mod_export int sticky_emulation; /**/ mod_export char opts[OPT_SIZE]; + +/* + * the options that need setting for current sticky emulation, if any: + * same format as opts. + */ + +/**/ +mod_export char sticky_opts[OPT_SIZE]; /* Option name hash table */ @@ -70,7 +78,7 @@ mod_export HashTable optiontab; /* option is an alias to an other option */ #define OPT_ALIAS (EMULATE_UNUSED<<2) -#define defset(X) (!!((X)->node.flags & emulation)) +#define defset(X, my_emulation) (!!((X)->node.flags & my_emulation)) /* * Note that option names should usually be fewer than 20 characters long @@ -439,11 +447,11 @@ printoptionnode(HashNode hn, int set) if (optno < 0) optno = -optno; if (isset(KSHOPTIONPRINT)) { - if (defset(on)) + if (defset(on, emulation)) printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on"); else printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off"); - } else if (set == (isset(optno) ^ defset(on))) { + } else if (set == (isset(optno) ^ defset(on, emulation))) { if (set ^ isset(optno)) fputs("no", stdout); puts(on->node.nam); @@ -475,6 +483,15 @@ createoptiontable(void) optiontab->addnode(optiontab, on->node.nam, on); } +/* Emulation appropriate to the setemulate function */ + +static int setemulate_emulation; + +/* Option array manipulated within the setemulate function */ + +/**/ +static char *setemulate_opts; + /* Setting of default options */ /**/ @@ -490,20 +507,22 @@ setemulate(HashNode hn, int fully) if (!(on->node.flags & OPT_ALIAS) && ((fully && !(on->node.flags & OPT_SPECIAL)) || (on->node.flags & OPT_EMULATE))) - opts[on->optno] = defset(on); + setemulate_opts[on->optno] = defset(on, setemulate_emulation); } /**/ void -installemulation(void) +installemulation(int new_emulation, char *new_opts) { + setemulate_emulation = new_emulation; + setemulate_opts = new_opts; scanhashtable(optiontab, 0, 0, 0, setemulate, - !!(emulation & EMULATE_FULLY)); + !!(new_emulation & EMULATE_FULLY)); } /**/ void -emulate(const char *zsh_name, int fully) +emulate(const char *zsh_name, int fully, int *new_emulation, char *new_opts) { char ch = *zsh_name; @@ -512,17 +531,17 @@ emulate(const char *zsh_name, int fully) /* Work out the new emulation mode */ if (ch == 'c') - emulation = EMULATE_CSH; + *new_emulation = EMULATE_CSH; else if (ch == 'k') - emulation = EMULATE_KSH; + *new_emulation = EMULATE_KSH; else if (ch == 's' || ch == 'b') - emulation = EMULATE_SH; + *new_emulation = EMULATE_SH; else - emulation = EMULATE_ZSH; + *new_emulation = EMULATE_ZSH; if (fully) - emulation |= EMULATE_FULLY; - installemulation(); + *new_emulation |= EMULATE_FULLY; + installemulation(*new_emulation, new_opts); if (funcstack && funcstack->tp == FS_FUNC) { /* @@ -534,7 +553,7 @@ emulate(const char *zsh_name, int fully) Shfunc shf = (Shfunc)shfunctab->getnode(shfunctab, funcstack->name); if (shf && (shf->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))) { /* Tracing is on, so set xtrace */ - opts[XTRACE] = 1; + new_opts[XTRACE] = 1; } } } @@ -545,7 +564,7 @@ emulate(const char *zsh_name, int fully) static void setoption(HashNode hn, int value) { - dosetopt(((Optname) hn)->optno, value, 0); + dosetopt(((Optname) hn)->optno, value, 0, opts); } /**/ @@ -582,7 +601,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) } if(!(optno = optlookup(*args))) zwarnnam(nam, "no such option: %s", *args); - else if(dosetopt(optno, action, 0)) + else if(dosetopt(optno, action, 0, opts)) zwarnnam(nam, "can't change option: %s", *args); break; } else if(**args == 'm') { @@ -590,7 +609,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) } else { if (!(optno = optlookupc(**args))) zwarnnam(nam, "bad option: -%c", **args); - else if(dosetopt(optno, action, 0)) + else if(dosetopt(optno, action, 0, opts)) zwarnnam(nam, "can't change option: -%c", **args); } } @@ -603,7 +622,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) while (*args) { if(!(optno = optlookup(*args++))) zwarnnam(nam, "no such option: %s", args[-1]); - else if(dosetopt(optno, !isun, 0)) + else if(dosetopt(optno, !isun, 0, opts)) zwarnnam(nam, "can't change option: %s", args[-1]); } } else { @@ -713,7 +732,7 @@ static char *rparams[] = { /**/ mod_export int -dosetopt(int optno, int value, int force) +dosetopt(int optno, int value, int force, char *new_opts) { if(!optno) return -1; @@ -735,7 +754,7 @@ dosetopt(int optno, int value, int force) return -1; } else if(!force && (optno == INTERACTIVE || optno == SHINSTDIN || optno == SINGLECOMMAND)) { - if (opts[optno] == value) + if (new_opts[optno] == value) return 0; /* it is not permitted to change the value of these options */ return -1; @@ -751,7 +770,7 @@ dosetopt(int optno, int value, int force) #endif /* HAVE_SETUID */ #ifdef JOB_CONTROL } else if (!force && optno == MONITOR && value) { - if (opts[optno] == value) + if (new_opts[optno] == value) return 0; if (SHTTY != -1) { origpgrp = GETPGRP(); @@ -770,12 +789,12 @@ dosetopt(int optno, int value, int force) if (sticky_emulation) return -1; zleentry(ZLE_CMD_SET_KEYMAP, optno); - opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0; + new_opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0; } else if (optno == SUNKEYBOARDHACK) { /* for backward compatibility */ keyboardhackchar = (value ? '`' : '\0'); } - opts[optno] = value; + new_opts[optno] = value; if (optno == BANGHIST || optno == SHINSTDIN) inittyptab(); return 0; @@ -817,10 +836,11 @@ printoptionnodestate(HashNode hn, int hadplus) int optno = on->optno; if (hadplus) { - if (defset(on) != isset(optno)) - printf("set -o %s%s\n", defset(on) ? "no" : "", on->node.nam); + if (defset(on, emulation) != isset(optno)) + printf("set -o %s%s\n", defset(on, emulation) ? + "no" : "", on->node.nam); } else { - if (defset(on)) + if (defset(on, emulation)) printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on"); else printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off"); diff --git a/Test/B07emulate.ztst b/Test/B07emulate.ztst index dec809ea4..569640bb4 100644 --- a/Test/B07emulate.ztst +++ b/Test/B07emulate.ztst @@ -176,3 +176,28 @@ 0:Sticky emulation not triggered if sticky emulation unchanged >on >off + + ( + setopt ignorebraces + emulate zsh -o extendedglob -c ' + [[ -o ignorebraces ]] || print "Yay, ignorebraces was reset" + [[ -o extendedglob ]] && print "Yay, extendedglob is set" + ' + ) +0:emulate -c with options +>Yay, ignorebraces was reset +>Yay, extendedglob is set + + ( + setopt ignorebraces + emulate zsh -o extendedglob + [[ -o ignorebraces ]] || print "Yay, ignorebraces is no longer set" + [[ -o extendedglob ]] && print "Yay, extendedglob is set" + ) +0:emulate with options but no -c +>Yay, ignorebraces is no longer set +>Yay, extendedglob is set + + emulate zsh -o fixallmybugs 'print This was executed, bad' +1:emulate -c with incorrect options +?(eval):emulate:1: no such option: fixallmybugs -- cgit v1.2.3 From ad92cb3203e5d95be91019633e8f1f5835b12794 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 11 Oct 2012 16:36:14 +0000 Subject: 30724: shell code optimisd to use execsimple() doesn't have a valid thisjob --- ChangeLog | 7 ++++++- Src/exec.c | 27 ++++++++++++++++++++++++--- Src/jobs.c | 8 +++++++- 3 files changed, 37 insertions(+), 5 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 9768aa8e0..5a69f0174 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-10-11 Peter Stephenson + + * 30724: Src/exec.c, Src/jobs.c: shell code optimised to use + execsimple() doesn't have a valid thisjob. + 2012-10-09 Peter Stephenson * users/17318: Src/Zle/zle_utils.c: don't increment the undo @@ -255,5 +260,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5743 $ +* $Revision: 1.5744 $ ***************************************************** diff --git a/Src/exec.c b/Src/exec.c index 0f7c84a9f..b2224cfb3 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -404,7 +404,17 @@ execcursh(Estate state, int do_exec) /* Skip word only used for try/always */ state->pc++; - if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob)) + /* + * The test thisjob != -1 was added because sometimes thisjob + * can be invalid at this point. The case in question was + * in a precmd function after operations involving background + * jobs. + * + * This is because sometimes we bypass job control to execute + * very simple functions via execssimple(). + */ + if (!list_pipe && thisjob != -1 && thisjob != list_pipe_job && + !hasprocs(thisjob)) deletejob(jobtab + thisjob, 0); cmdpush(CS_CURSH); execlist(state, 1, do_exec); @@ -1064,7 +1074,7 @@ static int execsimple(Estate state) { wordcode code = *state->pc++; - int lv; + int lv, otj; if (errflag) return (lastval = 1); @@ -1075,6 +1085,13 @@ execsimple(Estate state) code = wc_code(*state->pc++); + /* + * Because we're bypassing job control, ensure the called + * code doesn't see the current job. + */ + otj = thisjob; + thisjob = -1; + if (code == WC_ASSIGN) { cmdoutval = 0; addvars(state, state->pc - 1, 0); @@ -1086,6 +1103,8 @@ execsimple(Estate state) } else lv = (execfuncs[code - WC_CURSH])(state, 0); + thisjob = otj; + return lastval = lv; } @@ -4313,7 +4332,9 @@ execshfunc(Shfunc shf, LinkList args) if (errflag) return; - if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob)) { + /* thisjob may be invalid if we're called via execsimple: see execcursh */ + if (!list_pipe && thisjob != -1 && thisjob != list_pipe_job && + !hasprocs(thisjob)) { /* Without this deletejob the process table * * would be filled by a recursive function. */ last_file_list = jobtab[thisjob].filelist; diff --git a/Src/jobs.c b/Src/jobs.c index ddd997c49..0464d18d8 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -209,7 +209,13 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux) int hasprocs(int job) { - Job jn = jobtab + job; + Job jn; + + if (job < 0) { + DPUTS(1, "job number invalid in hasprocs"); + return 0; + } + jn = jobtab + job; return jn->procs || jn->auxprocs; } -- cgit v1.2.3 From 4b86cc48f704152ccca13c50bc3acd59b4217ecc Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 11 Oct 2012 20:14:01 +0000 Subject: 30726: make shell options passed to emulate stick along with the emulation --- ChangeLog | 11 ++++- Doc/Zsh/builtins.yo | 4 ++ Src/Modules/parameter.c | 2 +- Src/builtin.c | 50 +++++++++++++++++----- Src/exec.c | 107 +++++++++++++++++++++++++++++++++++++++++++++--- Src/hashtable.c | 9 ++++ Src/init.c | 44 ++++++++++++++++---- Src/options.c | 18 +++----- Src/parse.c | 2 +- Src/signals.c | 5 ++- Src/zsh.h | 30 +++++++++++++- Test/B07emulate.ztst | 46 +++++++++++++++++++++ 12 files changed, 287 insertions(+), 41 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 5a69f0174..4b1508a47 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2012-10-11 Peter Stephenson + + * 30726: Doc/Zsh/builtins.yo, Src/builtin.c, Src/exec.c, + Src/hashtable.c, Src/init.c, Src/options.c, Src/parse.c, + Src/signals.c, Src/zsh.h, Src/Modules/parameter.c, + Test/B07emulate.ztst: extend 30722 to handle the case + where shell options passed to the emulate command need + propagating to sticky emulation. + 2012-10-11 Peter Stephenson * 30724: Src/exec.c, Src/jobs.c: shell code optimised to use @@ -260,5 +269,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5744 $ +* $Revision: 1.5745 $ ***************************************************** diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index f7924a072..37319c9b0 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -462,6 +462,10 @@ sitem(4.)(The presence or absence of the tt(-R) switch to tt(emulate) corresponds to different sticky emulation modes, so for example `tt(emulate sh -c)', `tt(emulate -R sh -c)' and `tt(emulate csh -c)' are treated as three distinct sticky emulations.) +sitem(5.)(Difference in shell options supplied in addition to the +basic emulation also mean the sticky emulations are different, so for +example `tt(emulate zsh -c)' and `tt(emulate zsh -o cbases -c)' are +treated as distinct sticky emulations.) endsitem() ) findex(enable) diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index f19dfce4f..a029c9cb4 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -289,7 +289,7 @@ setfunction(char *name, char *val, int dis) shf = (Shfunc) zshcalloc(sizeof(*shf)); shf->funcdef = dupeprog(prog, 0); shf->node.flags = dis; - shf->emulation = sticky_emulation; + shfunc_set_sticky(shf); if (!strncmp(name, "TRAP", 4) && (sn = getsignum(name + 4)) != -1) { diff --git a/Src/builtin.c b/Src/builtin.c index 5cb643f23..8a83df711 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2944,7 +2944,7 @@ bin_functions(char *name, char **argv, Options ops, int func) shf = (Shfunc) zshcalloc(sizeof *shf); shf->node.flags = on; shf->funcdef = mkautofn(shf); - shf->emulation = sticky_emulation; + shfunc_set_sticky(shf); shfunctab->addnode(shfunctab, ztrdup(*argv), shf); if (signum != -1) { @@ -5007,11 +5007,15 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) { int opt_L = OPT_ISSET(ops, 'L'); int opt_R = OPT_ISSET(ops, 'R'); - int saveemulation, savesticky_emulation, savehackchar; + int saveemulation, savehackchar; int ret = 1, new_emulation; - char saveopts[OPT_SIZE], new_opts[OPT_SIZE], savesticky_opts[OPT_SIZE]; + char saveopts[OPT_SIZE], new_opts[OPT_SIZE]; char *cmd = 0; const char *shname = *argv; + LinkList optlist; + LinkNode optnode; + Emulation_options save_sticky; + OptIndex *on_ptr, *off_ptr; /* without arguments just print current emulation */ if (!shname) { @@ -5055,7 +5059,8 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) memcpy(new_opts, opts, sizeof(opts)); savehackchar = keyboardhackchar; emulate(shname, OPT_ISSET(ops,'R'), &new_emulation, new_opts); - if (parseopts("emulate", &argv, new_opts, &cmd)) { + optlist = newlinklist(); + if (parseopts("emulate", &argv, new_opts, &cmd, optlist)) { ret = 1; goto restore; } @@ -5081,15 +5086,40 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) } else return 0; - savesticky_emulation = sticky_emulation; - sticky_emulation = emulation; - memcpy(savesticky_opts, sticky_opts, sizeof(opts)); - memcpy(sticky_opts, opts, sizeof(opts)); + save_sticky = sticky; + sticky = hcalloc(sizeof(*sticky)); + sticky->emulation = emulation; + for (optnode = firstnode(optlist); optnode; incnode(optnode)) { + /* Data is index into new_opts */ + char *optptr = (char *)getdata(optnode); + if (*optptr) + sticky->n_on_opts++; + else + sticky->n_off_opts++; + } + if (sticky->n_on_opts) + on_ptr = sticky->on_opts = + zhalloc(sticky->n_on_opts * sizeof(*sticky->on_opts)); + else + on_ptr = NULL; + if (sticky->n_off_opts) + off_ptr = sticky->off_opts = zhalloc(sticky->n_off_opts * + sizeof(*sticky->off_opts)); + else + off_ptr = NULL; + for (optnode = firstnode(optlist); optnode; incnode(optnode)) { + /* Data is index into new_opts */ + char *optptr = (char *)getdata(optnode); + int optno = optptr - new_opts; + if (*optptr) + *on_ptr++ = optno; + else + *off_ptr++ = optno; + } ret = eval(argv); - sticky_emulation = savesticky_emulation; + sticky = save_sticky; emulation = saveemulation; memcpy(opts, saveopts, sizeof(opts)); - memcpy(sticky_opts, savesticky_opts, sizeof(opts)); restore: keyboardhackchar = savehackchar; inittyptab(); /* restore banghist */ diff --git a/Src/exec.c b/Src/exec.c index b2224cfb3..74b14d54d 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4267,7 +4267,7 @@ execfuncdef(Estate state, UNUSED(int do_exec)) shf->node.flags = 0; shf->filename = ztrdup(scriptfilename); shf->lineno = lineno; - shf->emulation = sticky_emulation; + shfunc_set_sticky(shf); if (!names) { /* @@ -4319,6 +4319,46 @@ execfuncdef(Estate state, UNUSED(int do_exec)) return ret; } +/* Duplicate a sticky emulation */ + +/**/ + +mod_export Emulation_options +sticky_emulation_dup(Emulation_options src, int useheap) +{ + Emulation_options newsticky = useheap ? + hcalloc(sizeof(*src)) : zshcalloc(sizeof(*src)); + newsticky->emulation = src->emulation; + if (src->n_on_opts) { + size_t sz = src->n_on_opts * sizeof(*src->on_opts); + newsticky->n_on_opts = src->n_on_opts; + newsticky->on_opts = useheap ? zhalloc(sz) : zalloc(sz); + memcpy(newsticky->on_opts, src->on_opts, sz); + } + if (src->n_off_opts) { + size_t sz = src->n_off_opts * sizeof(*src->off_opts); + newsticky->n_off_opts = src->n_off_opts; + newsticky->off_opts = useheap ? zhalloc(sz) : zalloc(sz); + memcpy(newsticky->off_opts, src->off_opts, sz); + } + + return newsticky; +} + +/* Set the sticky emulation attributes for a shell function */ + +/**/ + +mod_export void +shfunc_set_sticky(Shfunc shf) +{ + if (sticky) + shf->sticky = sticky_emulation_dup(sticky, 0); + else + shf->sticky = NULL; +} + + /* Main entry point to execute a shell function. */ /**/ @@ -4478,6 +4518,45 @@ loadautofn(Shfunc shf, int fksh, int autol) return shf; } +/* + * Check if a sticky emulation differs from the current one. + */ + +/**/ + +int sticky_emulation_differs(Emulation_options sticky2) +{ + /* If no new sticky emulation, not a different emulation */ + if (!sticky2) + return 0; + /* If no current sticky emulation, different */ + if (!sticky) + return 1; + /* If basic emulation different, different */ + if (sticky->emulation != sticky2->emulation) + return 1; + /* If differing numbers of options, different */ + if (sticky->n_on_opts != sticky2->n_on_opts || + sticky->n_off_opts != sticky2->n_off_opts) + return 1; + /* + * We need to compare option arrays, if non-null. + * We made parseopts() create the list of options in option + * order to make this easy. + */ + /* If different options turned on, different */ + if (sticky->n_on_opts && + memcmp(sticky->on_opts, sticky2->on_opts, + sticky->n_on_opts * sizeof(*sticky->on_opts)) != 0) + return 1; + /* If different options turned on, different */ + if (sticky->n_off_opts && + memcmp(sticky->off_opts, sticky2->off_opts, + sticky->n_off_opts * sizeof(*sticky->off_opts)) != 0) + return 1; + return 0; +} + /* * execute a shell function * @@ -4507,10 +4586,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) char *name = shfunc->node.nam; int flags = shfunc->node.flags, ooflags; char *fname = dupstring(name); - int obreaks, saveemulation, savesticky_emulation, restore_sticky; + int obreaks, saveemulation, restore_sticky; Eprog prog; struct funcstack fstack; static int oflags; + Emulation_options save_sticky = NULL; #ifdef MAX_FUNCTION_DEPTH static int funcdepth; #endif @@ -4548,9 +4628,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) * function we need to restore the original options on exit. */ memcpy(saveopts, opts, sizeof(opts)); saveemulation = emulation; - savesticky_emulation = sticky_emulation; + save_sticky = sticky; - if (shfunc->emulation && sticky_emulation != shfunc->emulation) { + if (sticky_emulation_differs(shfunc->sticky)) { /* * Function is marked for sticky emulation. * Enable it now. @@ -4563,9 +4643,24 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) * * This propagates the sticky emulation to subfunctions. */ - emulation = sticky_emulation = shfunc->emulation; + sticky = sticky_emulation_dup(shfunc->sticky, 1); + emulation = sticky->emulation; restore_sticky = 1; installemulation(emulation, opts); + if (sticky->n_on_opts) { + OptIndex *onptr; + for (onptr = sticky->on_opts; + onptr < sticky->on_opts + sticky->n_on_opts; + onptr++) + opts[*onptr] = 1; + } + if (sticky->n_off_opts) { + OptIndex *offptr; + for (offptr = sticky->off_opts; + offptr < sticky->off_opts + sticky->n_off_opts; + offptr++) + opts[*offptr] = 0; + } } else restore_sticky = 0; @@ -4674,7 +4769,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) */ memcpy(opts, saveopts, sizeof(opts)); emulation = saveemulation; - sticky_emulation = savesticky_emulation; + sticky = save_sticky; } else if (isset(LOCALOPTIONS)) { /* restore all shell options except PRIVILEGED and RESTRICTED */ saveopts[PRIVILEGED] = opts[PRIVILEGED]; diff --git a/Src/hashtable.c b/Src/hashtable.c index b472e40b9..ef187927b 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -888,6 +888,15 @@ freeshfuncnode(HashNode hn) if (shf->funcdef) freeeprog(shf->funcdef); zsfree(shf->filename); + if (shf->sticky) { + if (shf->sticky->n_on_opts) + zfree(shf->sticky->on_opts, + shf->sticky->n_on_opts * sizeof(*shf->sticky->on_opts)); + if (shf->sticky->n_off_opts) + zfree(shf->sticky->off_opts, + shf->sticky->n_off_opts * sizeof(*shf->sticky->off_opts)); + zfree(shf->sticky, sizeof(*shf->sticky)); + } zfree(shf, sizeof(struct shfunc)); } diff --git a/Src/init.c b/Src/init.c index 8f6c0ec6d..6c2ba13e4 100644 --- a/Src/init.c +++ b/Src/init.c @@ -246,7 +246,7 @@ parseargs(char **argv, char **runscript) opts[SHINSTDIN] = 0; opts[SINGLECOMMAND] = 0; - if (parseopts(NULL, &argv, opts, &cmd)) + if (parseopts(NULL, &argv, opts, &cmd, NULL)) exit(1); paramlist = znewlinklist(); @@ -277,15 +277,37 @@ parseargs(char **argv, char **runscript) argzero = ztrdup(argzero); } +/* Insert into list in order of pointer value */ + +/**/ +static void +parseopts_insert(LinkList optlist, void *ptr) +{ + LinkNode node; + + for (node = firstnode(optlist); node; incnode(node)) { + if (ptr < getdata(node)) { + insertlinknode(optlist, prevnode(node), ptr); + return; + } + } + + addlinknode(optlist, ptr); +} + /* * Parse shell options. * If nam is not NULL, this is called from a command; don't * exit on failure. + * + * If optlist is not NULL, it used to form a list of pointers + * into new_opts indicating which options have been changed. */ /**/ mod_export int -parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp) +parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, + LinkList optlist) { int optionbreak = 0; int action, optno; @@ -364,8 +386,12 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp) restricted = action; } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { WARN_OPTION("can't change option: %s", *argv); - } else if (dosetopt(optno, action, !nam, new_opts) && nam) { - WARN_OPTION("can't change option: %s", *argv); + } else { + if (dosetopt(optno, action, !nam, new_opts) && nam) { + WARN_OPTION("can't change option: %s", *argv); + } else if (optlist) { + parseopts_insert(optlist, new_opts+optno); + } } break; } else if (isspace(STOUC(**argv))) { @@ -385,8 +411,12 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp) restricted = action; } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { WARN_OPTION("can't change option: %s", *argv); - } else if (dosetopt(optno, action, !nam, new_opts) && nam) { - WARN_OPTION("can't change option: -%c", **argv); + } else { + if (dosetopt(optno, action, !nam, new_opts) && nam) { + WARN_OPTION("can't change option: -%c", **argv); + } else if (optlist) { + parseopts_insert(optlist, new_opts+optno); + } } } } @@ -396,7 +426,7 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp) if (*cmdp) { if (!*argv) { WARN_OPTION("string expected after -%s", *cmdp); - exit(1); + return 1; } *cmdp = *argv++; } diff --git a/Src/options.c b/Src/options.c index 87e9abe2d..80fef3d00 100644 --- a/Src/options.c +++ b/Src/options.c @@ -35,29 +35,21 @@ /**/ mod_export int emulation; -/* current sticky emulation: 0 means none */ +/* current sticky emulation: sticky = NULL means none */ /**/ -mod_export int sticky_emulation; +mod_export Emulation_options sticky; /* the options; e.g. if opts[SHGLOB] != 0, SH_GLOB is turned on */ - + /**/ mod_export char opts[OPT_SIZE]; -/* - * the options that need setting for current sticky emulation, if any: - * same format as opts. - */ - -/**/ -mod_export char sticky_opts[OPT_SIZE]; - /* Option name hash table */ /**/ mod_export HashTable optiontab; - + /* The canonical option name table */ #define OPT_CSH EMULATE_CSH @@ -786,7 +778,7 @@ dosetopt(int optno, int value, int force, char *new_opts) return -1; #endif /* GETPWNAM_FAKED */ } else if ((optno == EMACSMODE || optno == VIMODE) && value) { - if (sticky_emulation) + if (sticky && sticky->emulation) return -1; zleentry(ZLE_CMD_SET_KEYMAP, optno); new_opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0; diff --git a/Src/parse.c b/Src/parse.c index 8d2878cd7..096faa072 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -3482,7 +3482,7 @@ dump_autoload(char *nam, char *file, int on, Options ops, int func) shf = (Shfunc) zshcalloc(sizeof *shf); shf->node.flags = on; shf->funcdef = mkautofn(shf); - shf->emulation = 0; + shf->sticky = NULL; shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf); if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->node.nam, ops, func)) ret = 1; diff --git a/Src/signals.c b/Src/signals.c index ad688094b..046ee6a4a 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -755,7 +755,10 @@ dosavetrap(int sig, int level) newshf->node.flags = shf->node.flags; newshf->funcdef = dupeprog(shf->funcdef, 0); newshf->filename = ztrdup(shf->filename); - newshf->emulation = shf->emulation; + if (shf->sticky) { + newshf->sticky = sticky_emulation_dup(shf->sticky, 0); + } else + newshf->sticky = 0; if (shf->node.flags & PM_UNDEFINED) newshf->funcdef->shf = newshf; } diff --git a/Src/zsh.h b/Src/zsh.h index fee27ac10..e51572bcf 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -407,6 +407,7 @@ typedef struct cmdnam *Cmdnam; typedef struct complist *Complist; typedef struct conddef *Conddef; typedef struct dirsav *Dirsav; +typedef struct emulation_options *Emulation_options; typedef struct features *Features; typedef struct feature_enables *Feature_enables; typedef struct funcstack *Funcstack; @@ -1099,7 +1100,7 @@ struct shfunc { char *filename; /* Name of file located in */ zlong lineno; /* line number in above file */ Eprog funcdef; /* function definition */ - int emulation; /* sticky emulation for function */ + Emulation_options sticky; /* sticky emulation definitions, if any */ }; /* Shell function context types. */ @@ -2104,6 +2105,12 @@ enum { OPT_SIZE }; +/* + * Size required to fit an option number. + * If OPT_SIZE goes above 256 this will need to expand. + */ +typedef unsigned char OptIndex; + #undef isset #define isset(X) (opts[X]) #define unset(X) (!opts[X]) @@ -2112,6 +2119,27 @@ enum { #define jobbing (isset(MONITOR)) #define islogin (isset(LOGINSHELL)) +/* + * Record of emulation and options that need to be set + * for a full "emulate". + */ +struct emulation_options { + /* The emulation itself */ + int emulation; + /* The number of options in on_opts. */ + int n_on_opts; + /* The number of options in off_opts. */ + int n_off_opts; + /* + * Array of options to be turned on. + * Only options specified explicitly in the emulate command + * are recorded. Null if n_on_opts is zero. + */ + OptIndex *on_opts; + /* Array of options to be turned off, similar. */ + OptIndex *off_opts; +}; + /***********************************************/ /* Definitions for terminal and display control */ /***********************************************/ diff --git a/Test/B07emulate.ztst b/Test/B07emulate.ztst index 569640bb4..315206a20 100644 --- a/Test/B07emulate.ztst +++ b/Test/B07emulate.ztst @@ -201,3 +201,49 @@ emulate zsh -o fixallmybugs 'print This was executed, bad' 1:emulate -c with incorrect options ?(eval):emulate:1: no such option: fixallmybugs + + emulate zsh -c ' + func() { [[ -o extendedglob ]] || print extendedglob is off } + ' + func + emulate zsh -o extendedglob -c ' + func() { [[ -o extendedglob ]] && print extendedglob is on } + ' + func +0:options specified alongside emulation are also sticky +>extendedglob is off +>extendedglob is on + + emulate zsh -o extendedglob -c ' + func_inner() { setopt nobareglobqual } + ' + emulate zsh -o extendedglob -c ' + func_outer() { + func_inner + [[ -o bareglobqual ]] || print bareglobqual was turned off + [[ -o extendedglob ]] && print extendedglob is on, though + } + ' + [[ -o extendedglob ]] || print extendedglob is initially off + func_outer +0:options propagate between identical emulations +>extendedglob is initially off +>bareglobqual was turned off +>extendedglob is on, though + + emulate zsh -o extendedglob -c ' + func_inner() { setopt nobareglobqual } + ' + emulate zsh -o extendedglob -o cbases -c ' + func_outer() { + func_inner + [[ -o bareglobqual ]] && print bareglobqual is still on + [[ -o extendedglob ]] && print extendedglob is on, too + } + ' + [[ -o extendedglob ]] || print extendedglob is initially off + func_outer +0:options do not propagate between different emulations +>extendedglob is initially off +>bareglobqual is still on +>extendedglob is on, too -- cgit v1.2.3 From 1869eeb393e2499e9949cc3458cdd74685342540 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 13 Dec 2012 10:36:59 +0000 Subject: 30876: fix obscure failures to propagate non-zero status from optimised simple commands within lists --- ChangeLog | 8 +++++++- Completion/Unix/Command/_perforce | 2 +- Src/exec.c | 6 +++--- Test/A06assign.ztst | 4 ++-- Test/C03traps.ztst | 11 +++++++++++ 5 files changed, 24 insertions(+), 7 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index f80e1a5c7..da6c87e89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-12-13 Peter Stephenson + + * 30876: Src/exec.c, Test/A06assign.ztst, Test/C03traps.ztst: + obscure failures to process non-zero return values could result + from optimising a list to a simple command. + 2012-12-08 Bart Schaefer * users/17445: Src/math.c, Test/C01arith.ztst: fix handling of @@ -368,5 +374,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5766 $ +* $Revision: 1.5767 $ ***************************************************** diff --git a/Completion/Unix/Command/_perforce b/Completion/Unix/Command/_perforce index 78f6cd71e..d2943472c 100644 --- a/Completion/Unix/Command/_perforce +++ b/Completion/Unix/Command/_perforce @@ -2019,7 +2019,7 @@ _perforce_cmd_fix() { '-s[set job status]:status:_perforce_statuses' \ '1::-c required:(-c)' \ '2::change:_perforce_changes' \ - "3::job:_perforce_jobs$job" + "*::job:_perforce_jobs$job" } diff --git a/Src/exec.c b/Src/exec.c index 74b14d54d..1ecbc3967 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1207,6 +1207,9 @@ execlist(Estate state, int dont_change_job, int exiting) } else donedebug = intrap ? 1 : 0; + /* Reset donetrap: this ensures that a trap is only * + * called once for each sublist that fails. */ + donetrap = 0; if (ltype & Z_SIMPLE) { next = state->pc + WC_LIST_SKIP(code); if (donedebug != 2) @@ -1214,9 +1217,6 @@ execlist(Estate state, int dont_change_job, int exiting) state->pc = next; goto sublist_done; } - /* Reset donetrap: this ensures that a trap is only * - * called once for each sublist that fails. */ - donetrap = 0; /* Loop through code followed by &&, ||, or end of sublist. */ code = *state->pc++; diff --git a/Test/A06assign.ztst b/Test/A06assign.ztst index 84500f605..9a0a4f0cc 100644 --- a/Test/A06assign.ztst +++ b/Test/A06assign.ztst @@ -184,8 +184,8 @@ typeset -A hash hash=(one 1) - h+=string - [[ $h[@] == string ]] + hash+=string + [[ $hash[@] == string ]] 0:add scalar to association # tests of var+=(array) diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 321f5e956..757f75ca4 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -388,6 +388,17 @@ >} >No, really exited + (set -e + printf "a\nb\n" | while read line + do + [[ $line = a* ]] || continue + ((ctr++)) + [[ $line = foo ]] + done + echo "ctr = $ctr" + ) +1:ERREXIT in loop with simple commands + %clean rm -f TRAPEXIT -- cgit v1.2.3