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/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/options.c') diff --git a/Src/options.c b/Src/options.c index c6db75372..609c28fd1 100644 --- a/Src/options.c +++ b/Src/options.c @@ -532,7 +532,7 @@ emulate(const char *zsh_name, int fully) * close enough. */ Shfunc shf = (Shfunc)shfunctab->getnode(shfunctab, funcstack->name); - if (shf && (shf->node.flags & PM_TAGGED)) { + if (shf && (shf->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))) { /* Tracing is on, so set xtrace */ opts[XTRACE] = 1; } -- cgit v1.2.3 From 76ac7bf74265440be6177c060fe72a074caa6d4f Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 5 Oct 2012 21:42:59 +0000 Subject: 30716: make IGNORECLOSEBRACES an emulation option --- ChangeLog | 5 ++++- Src/options.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Src/options.c') diff --git a/ChangeLog b/ChangeLog index ebfcfea66..9b026ff6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2012-10-05 Peter Stephenson + * 30716: Src/options.c: IGNORECLOSEBRACES should be an emulation + option since it changes what syntax is valid. + * 30715: Src/init.c, Src/lex.c, Src/parse.c, Src/subst.c, Src/zsh.h, Src/Zle/zle_tricky.c: use a named enum for lexical tokens. @@ -223,5 +226,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5734 $ +* $Revision: 1.5735 $ ***************************************************** diff --git a/Src/options.c b/Src/options.c index 609c28fd1..6075a7fcb 100644 --- a/Src/options.c +++ b/Src/options.c @@ -160,7 +160,7 @@ static struct optname optns[] = { {{NULL, "histverify", 0}, HISTVERIFY}, {{NULL, "hup", OPT_EMULATE|OPT_ZSH}, HUP}, {{NULL, "ignorebraces", OPT_EMULATE|OPT_SH}, IGNOREBRACES}, -{{NULL, "ignoreclosebraces", 0}, IGNORECLOSEBRACES}, +{{NULL, "ignoreclosebraces", OPT_EMULATE}, IGNORECLOSEBRACES}, {{NULL, "ignoreeof", 0}, IGNOREEOF}, {{NULL, "incappendhistory", 0}, INCAPPENDHISTORY}, {{NULL, "interactive", OPT_SPECIAL}, INTERACTIVE}, -- 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/options.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 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/options.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 7c56d771840a9f335b2e21290c8cbf714264bc66 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 15 Nov 2012 21:08:15 +0000 Subject: 30789: Add CONTINUE_ON_ERROR for old behaviour. New behaviour is for scripts to exit on error instead of returning to top level and executing the next command. --- ChangeLog | 8 +++++++- Doc/Zsh/grammar.yo | 53 +++++++++++++++++++++++++++++++++++++++++++++++++-- Doc/Zsh/options.yo | 16 ++++++++++++++++ Src/hist.c | 2 +- Src/init.c | 9 +++++++-- Src/options.c | 1 + Src/zsh.h | 1 + Test/A04redirect.ztst | 12 ++++++------ 8 files changed, 90 insertions(+), 12 deletions(-) (limited to 'Src/options.c') diff --git a/ChangeLog b/ChangeLog index d65cfa957..36bac2884 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2012-11-15 Peter Stephenson + * 30789: Doc/Zsh/grammar.yo, Doc/Zsh/options.yo, Src/hist.c, + Src/init.c, Src/options.c, Src/zsh.h, Test/A04redirect.zsh: add + CONTINUE_ON_ERROR option for compatibility but turn it off: + scripts exit on an error instead of returning to the top-level + like interactive shells. + * 30800: Michal Halenka: Completion/Unix/Command/_arping: fix option. @@ -335,5 +341,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5760 $ +* $Revision: 1.5761 $ ***************************************************** diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo index 1eb358ea3..e1b2f0ea6 100644 --- a/Doc/Zsh/grammar.yo +++ b/Doc/Zsh/grammar.yo @@ -438,7 +438,7 @@ where var(term) is at least one newline or tt(;). A short form of tt(select). ) enditem() -texinode(Reserved Words)(Comments)(Alternate Forms For Complex Commands)(Shell Grammar) +texinode(Reserved Words)(Errors)(Alternate Forms For Complex Commands)(Shell Grammar) sect(Reserved Words) cindex(reserved words) findex(disable, use of) @@ -451,7 +451,56 @@ select coproc nocorrect foreach end ! [[ { }) Additionally, `tt(})' is recognized in any position if neither the tt(IGNORE_BRACES) option nor the tt(IGNORE_CLOSE_BRACES) option is set. -texinode(Comments)(Aliasing)(Reserved Words)(Shell Grammar) +texinode(Errors)(Comments)(Reserved Words)(Shell Grammar) +sect(Errors) +cindex(errors, handling of) +Certain errors are treated as fatal by the shell: in an interactive +shell, they cause control to return to the command line, and in a +non-interactive shell they cause the shell to be aborted. In older +versions of zsh, a non-interactive shell running a script would not +abort completely, but would resume execution at the next command to be +read from the script, skipping the remainder of any functions or +shell constructs such as loops or conditions; this somewhat illogical +behaviour can be recovered by setting the option tt(CONTINUE_ON_ERROR). + +Fatal errors found in non-interactive shells include: +startlist() +list(Failure to parse shell options passed when invoking the shell) +list(Failure to change options with the tt(set) builtin) +list(Parse errors of all sorts, including failures to parse +mathematical expressions) +list(Failures to set or modify variable behaviour with tt(typeset), +tt(local), tt(declare), tt(export), tt(integer), tt(float)) +list(Execution of incorrectly positioned loop control structures +(tt(continue), tt(break))) +list(Attempts to use regular expression with no regular expression +module available) +list(Disallowed operations when the tt(RESTRICTED) options is set) +list(Failure to create a pipe needed for a pipeline) +list(Failure to create a multio) +list(Failure to autoload a module needed for a declared shell feature) +list(Errors creating command or process substitutions) +list(Syntax errors in glob qualifiers) +list(File generation errors where not caught by the option tt(BAD_PATTERN)) +list(All bad patterns used for matching within case statements) +list(File generation failures where not caused by tt(NO_MATCH) or +list(All file generation errors where the pattern was used to create a +multio) +list(Memory errors where detected by the shell) +list(Invalid subscripts to shell variables) +list(Attempts to assign read-only variables) +list(Logical errors with variables such as assignment to the wrong type) +list(Use of invalid variable names) +list(Errors in variable substitution syntax) +list(Failure to convert characters in tt($')...tt(') expressions) +similar options) +endlist() + +If the tt(POSIX_BUILTINS) option is set, more errors associated with +shell builtin commands are treated as fatal, as specified by the POSIX +standard. + +texinode(Comments)(Aliasing)(Errors)(Shell Grammar) sect(Comments) cindex(comments) pindex(INTERACTIVE_COMMENTS, use of) diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index 3114ecc05..6c8d423cb 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -1733,6 +1733,22 @@ Make the tt(echo) builtin compatible with the BSD manref(echo)(1) command. This disables backslashed escape sequences in echo strings unless the tt(-e) option is specified. ) +pindex(CONTINUE_ON_ERROR) +pindex(NO_CONTINUE_ON_ERROR) +pindex(CONTINUEONERROR) +pindex(NOCONTINUEONERROR) +cindex(error, option to continue script on) +item(tt(CONTINUE_ON_ERROR))( +If a fatal error is encountered (see +ifnzman(noderef(Errors))\ +ifzman(the section ERRORS in zmanref(zshmisc))), and the code is running +in a script, the shell will resume execution at the next statement +in the script at the top level, in other words outside all functions +or shell constructs such as loops and conditions. This mimics the +behaviour of interactive shells, where the shell returns to the +line editor to read a new command; it was the normal behaviour in versions +of zsh before 5.0.1. +) pindex(CSH_JUNKIE_HISTORY) pindex(NO_CSH_JUNKIE_HISTORY) pindex(CSHJUNKIEHISTORY) diff --git a/Src/hist.c b/Src/hist.c index 0e63dca37..561e2acd5 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -573,7 +573,7 @@ histsubchar(int c) } else { herrflush(); unqueue_signals(); - zerr("Ambiguous history reference"); + zerr("ambiguous history reference"); return -1; } diff --git a/Src/init.c b/Src/init.c index 6c2ba13e4..8467a739c 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1608,15 +1608,20 @@ zsh_main(UNUSED(int argc), char **argv) * We only do this at top level, because if we are * executing stuff we may refer to them by job pointer. */ + int errexit = 0; maybeshrinkjobtab(); do { /* Reset return from top level which gets us back here */ retflag = 0; loop(1,0); + if (errflag && !interact && !isset(CONTINUEONERROR)) { + errexit = 1; + break; + } } while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN))); - if (tok == LEXERR) { - /* Make sure a parse error exits with non-zero status */ + if (tok == LEXERR || errexit) { + /* Make sure a fatal error exits with non-zero status */ if (!lastval) lastval = 1; stopmsg = 1; diff --git a/Src/options.c b/Src/options.c index 80fef3d00..b36bd9944 100644 --- a/Src/options.c +++ b/Src/options.c @@ -113,6 +113,7 @@ static struct optname optns[] = { {{NULL, "combiningchars", 0}, COMBININGCHARS}, {{NULL, "completealiases", 0}, COMPLETEALIASES}, {{NULL, "completeinword", 0}, COMPLETEINWORD}, +{{NULL, "continueonerror", 0}, CONTINUEONERROR}, {{NULL, "correct", 0}, CORRECT}, {{NULL, "correctall", 0}, CORRECTALL}, {{NULL, "cshjunkiehistory", OPT_EMULATE|OPT_CSH}, CSHJUNKIEHISTORY}, diff --git a/Src/zsh.h b/Src/zsh.h index e51572bcf..207ef1836 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1971,6 +1971,7 @@ enum { COMPLETEINWORD, CORRECT, CORRECTALL, + CONTINUEONERROR, CPRECEDENCES, CSHJUNKIEHISTORY, CSHJUNKIELOOPS, diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst index d3c0a4a99..b8086e724 100644 --- a/Test/A04redirect.ztst +++ b/Test/A04redirect.ztst @@ -419,26 +419,26 @@ >output ?zsh:.:2: no such file or directory: /nonexistent/nonexistent - $ZTST_testdir/../Src/zsh -f <<<' + $ZTST_testdir/../Src/zsh -f -o CONTINUE_ON_ERROR <<<' readonly foo foo=bar set output echo output' -0:failed assignment on posix special, NO_POSIX_BUILTINS +0:failed assignment on posix special, CONTINUE_ON_ERROR >output ?zsh: read-only variable: foo - $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS <<<' + $ZTST_testdir/../Src/zsh -f <<<' readonly foo foo=bar set output echo output' -1:failed assignment on posix special, POSIX_BUILTINS +1:failed assignment on posix special, NO_CONTINUE_ON_ERROR ?zsh: read-only variable: foo - $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS <<<' + $ZTST_testdir/../Src/zsh -f -o CONTINUE_ON_ERROR <<<' readonly foo foo=bar echo output echo output' -0:failed assignment on non-posix-special, POSIX_BUILTINS +0:failed assignment on non-posix-special, CONTINUE_ON_ERROR >output ?zsh: read-only variable: foo -- cgit v1.2.3