diff options
author | Peter Stephenson <pws@users.sourceforge.net> | 2009-02-11 20:42:15 +0000 |
---|---|---|
committer | Peter Stephenson <pws@users.sourceforge.net> | 2009-02-11 20:42:15 +0000 |
commit | c7d8b0dfb8ae9670e2bc11ecf563200069a3a12f (patch) | |
tree | 822403086b3d6d77bb14846b6e286d59389da12c /Src | |
parent | 0d02cf343eda943c32f7edfd24f28dbbd7004e32 (diff) | |
download | zsh-c7d8b0dfb8ae9670e2bc11ecf563200069a3a12f.tar.gz zsh-c7d8b0dfb8ae9670e2bc11ecf563200069a3a12f.tar.xz zsh-c7d8b0dfb8ae9670e2bc11ecf563200069a3a12f.zip |
26546, 26556: sticky emulation for functions defined in emulate ... -c ...
environments, plus documentation
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/newuser.c | 2 | ||||
-rw-r--r-- | Src/Modules/parameter.c | 1 | ||||
-rw-r--r-- | Src/builtin.c | 34 | ||||
-rw-r--r-- | Src/exec.c | 34 | ||||
-rw-r--r-- | Src/hashtable.c | 2 | ||||
-rw-r--r-- | Src/init.c | 15 | ||||
-rw-r--r-- | Src/mkbltnmlst.sh | 2 | ||||
-rw-r--r-- | Src/options.c | 26 | ||||
-rw-r--r-- | Src/params.c | 8 | ||||
-rw-r--r-- | Src/parse.c | 1 | ||||
-rw-r--r-- | Src/signals.c | 3 | ||||
-rw-r--r-- | Src/subst.c | 2 | ||||
-rw-r--r-- | Src/zsh.h | 15 |
13 files changed, 116 insertions, 29 deletions
diff --git a/Src/Modules/newuser.c b/Src/Modules/newuser.c index e19c34df3..cc020d5bd 100644 --- a/Src/Modules/newuser.c +++ b/Src/Modules/newuser.c @@ -78,7 +78,7 @@ boot_(UNUSED(Module m)) 0 }; const char **sp; - if (emulation != EMULATE_ZSH) + if (!EMULATION(EMULATE_ZSH)) return 0; if (!dotdir) { diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index e3fb909ea..38b462001 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -289,6 +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; if (!strncmp(name, "TRAP", 4) && (sn = getsignum(name + 4)) != -1) { diff --git a/Src/builtin.c b/Src/builtin.c index 99af38e3a..b402d56e2 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -536,7 +536,7 @@ 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]) { + if (!EMULATION(EMULATE_ZSH) && *args && **args == '-' && !args[0][1]) { dosetopt(VERBOSE, 0, 0); dosetopt(XTRACE, 0, 0); if (!args[1]) @@ -2861,6 +2861,8 @@ bin_functions(char *name, char **argv, Options ops, int func) shf = (Shfunc) zshcalloc(sizeof *shf); shf->node.flags = on; shf->funcdef = mkautofn(shf); + /* No sticky emulation for autoloaded functions */ + shf->emulation = 0; shfunctab->addnode(shfunctab, ztrdup(*argv), shf); if (signum != -1) { @@ -4834,21 +4836,38 @@ 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 ; + int saveemulation, savesticky_emulation; int ret; char saveopts[OPT_SIZE]; /* without arguments just print current emulation */ if (!*argv) { + const char *shname; + if (opt_L || opt_R) { zwarnnam("emulate", "not enough arguments"); return 1; } - printf("%s\n", emulation == EMULATE_CSH ? "csh" : - emulation == EMULATE_KSH ? "ksh" : - emulation == EMULATE_SH ? "sh" : - "zsh"); + switch(SHELL_EMULATION()) { + case EMULATE_CSH: + shname = "csh"; + break; + + case EMULATE_KSH: + shname = "ksh"; + break; + + case EMULATE_SH: + shname = "sh"; + break; + + default: + shname = "zsh"; + break; + } + + printf("%s\n", shname); return 0; } @@ -4880,9 +4899,12 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) memcpy(saveopts, opts, sizeof(opts)); saveemulation = emulation; + savesticky_emulation = sticky_emulation; emulate(*argv, OPT_ISSET(ops,'R')); + sticky_emulation = emulation; ret = eval(argv+2); memcpy(opts, saveopts, sizeof(opts)); + sticky_emulation = savesticky_emulation; emulation = saveemulation; return ret; } diff --git a/Src/exec.c b/Src/exec.c index 5aec655a2..b86e5350c 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3999,6 +3999,7 @@ execfuncdef(Estate state, UNUSED(int do_exec)) shf->node.flags = 0; shf->filename = ztrdup(scriptfilename); shf->lineno = lineno; + shf->emulation = sticky_emulation; if (!names) { /* @@ -4221,7 +4222,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) char *name = shfunc->node.nam; int flags = shfunc->node.flags; char *fname = dupstring(name); - int obreaks, saveemulation ; + int obreaks, saveemulation, savesticky_emulation, restore_sticky; Eprog prog; struct funcstack fstack; #ifdef MAX_FUNCTION_DEPTH @@ -4261,6 +4262,26 @@ 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; + + if (shfunc->emulation && sticky_emulation != shfunc->emulation) { + /* + * Function is marked for sticky emulation. + * Enable it now. + * + * We deliberately do not do this if the sticky emulation + * in effect is the same as that requested. This enables + * option setting naturally within emulation environments. + * Note that a difference in EMULATE_FULLY (emulate with + * or without -R) counts as a different environment. + * + * This propagates the sticky emulation to subfunctions. + */ + emulation = sticky_emulation = shfunc->emulation; + restore_sticky = 1; + installemulation(); + } else + restore_sticky = 0; if (flags & PM_TAGGED) opts[XTRACE] = 1; @@ -4349,7 +4370,16 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) zoptind = oldzoptind; scriptname = oldscriptname; - if (isset(LOCALOPTIONS)) { + if (restore_sticky) { + /* + * If we switched to an emulation environment just for + * this function, we interpret the option and emulation + * switch as being a firewall between environments. + */ + memcpy(opts, saveopts, sizeof(opts)); + emulation = saveemulation; + sticky_emulation = savesticky_emulation; + } else if (isset(LOCALOPTIONS)) { /* restore all shell options except PRIVILEGED and RESTRICTED */ saveopts[PRIVILEGED] = opts[PRIVILEGED]; saveopts[RESTRICTED] = opts[RESTRICTED]; diff --git a/Src/hashtable.c b/Src/hashtable.c index e12aca852..2eb70c3b0 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -588,7 +588,7 @@ mod_export HashTable cmdnamtab; /**/ mod_export char **pathchecked; - + /* Create a new command hash table */ /**/ diff --git a/Src/init.c b/Src/init.c index 215514f6d..341446cb9 100644 --- a/Src/init.c +++ b/Src/init.c @@ -775,7 +775,7 @@ setupvals(void) if(unset(INTERACTIVE)) { prompt = ztrdup(""); prompt2 = ztrdup(""); - } else if (emulation == EMULATE_KSH || emulation == EMULATE_SH) { + } else if (EMULATION(EMULATE_KSH|EMULATE_SH)) { prompt = ztrdup(privasserted() ? "# " : "$ "); prompt2 = ztrdup("> "); } else { @@ -783,7 +783,7 @@ setupvals(void) prompt2 = ztrdup("%_> "); } prompt3 = ztrdup("?# "); - prompt4 = (emulation == EMULATE_KSH || emulation == EMULATE_SH) + prompt4 = EMULATION(EMULATE_KSH|EMULATE_SH) ? ztrdup("+ ") : ztrdup("+%N:%i> "); sprompt = ztrdup("zsh: correct '%R' to '%r' [nyae]? "); @@ -811,14 +811,14 @@ setupvals(void) /* Get password entry and set info for `USERNAME' */ #ifdef USE_GETPWUID if ((pswd = getpwuid(cached_uid))) { - if (emulation == EMULATE_ZSH) + if (EMULATION(EMULATE_ZSH)) home = metafy(pswd->pw_dir, -1, META_DUP); cached_username = ztrdup(pswd->pw_name); } else #endif /* USE_GETPWUID */ { - if (emulation == EMULATE_ZSH) + if (EMULATION(EMULATE_ZSH)) home = ztrdup("/"); cached_username = ztrdup(""); } @@ -828,7 +828,7 @@ setupvals(void) * In non-native emulations HOME must come from the environment; * we're not allowed to set it locally. */ - if (emulation == EMULATE_ZSH) + if (EMULATION(EMULATE_ZSH)) ptr = home; else ptr = zgetenv("HOME"); @@ -954,7 +954,7 @@ run_init_scripts(void) { noerrexit = -1; - if (emulation == EMULATE_KSH || emulation == EMULATE_SH) { + if (EMULATION(EMULATE_KSH|EMULATE_SH)) { if (islogin) source("/etc/profile"); if (unset(PRIVILEGED)) { @@ -1160,8 +1160,7 @@ sourcehome(char *s) char *h; queue_signals(); - if (emulation == EMULATE_SH || emulation == EMULATE_KSH || - !(h = getsparam("ZDOTDIR"))) { + if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam("ZDOTDIR"))) { h = home; if (!h) return; diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh index 005e2ef81..d9c5b13e9 100644 --- a/Src/mkbltnmlst.sh +++ b/Src/mkbltnmlst.sh @@ -40,7 +40,7 @@ for x_mod in $x_mods; do unset moddeps autofeatures . $srcdir/../$modfile if test "x$autofeatures" != x; then - echo " if (emulation == EMULATE_ZSH) {" + echo " if (EMULATION(EMULATE_ZSH)) {" echo " char *features[] = { " for feature in $autofeatures; do echo " \"$feature\"," diff --git a/Src/options.c b/Src/options.c index 3c7f88048..f852ec830 100644 --- a/Src/options.c +++ b/Src/options.c @@ -35,6 +35,11 @@ /**/ mod_export int emulation; +/* current sticky emulation: 0 means none */ + +/**/ +mod_export int sticky_emulation; + /* the options; e.g. if opts[SHGLOB] != 0, SH_GLOB is turned on */ /**/ @@ -58,9 +63,12 @@ mod_export HashTable optiontab; #define OPT_NONBOURNE (OPT_ALL & ~OPT_BOURNE) #define OPT_NONZSH (OPT_ALL & ~OPT_ZSH) -#define OPT_EMULATE (1<<5) /* option is relevant to emulation */ -#define OPT_SPECIAL (1<<6) /* option should never be set by emulate() */ -#define OPT_ALIAS (1<<7) /* option is an alias to an other option */ +/* option is relevant to emulation */ +#define OPT_EMULATE (EMULATE_UNUSED) +/* option should never be set by emulate() */ +#define OPT_SPECIAL (EMULATE_UNUSED<<1) +/* option is an alias to an other option */ +#define OPT_ALIAS (EMULATE_UNUSED<<2) #define defset(X) (!!((X)->node.flags & emulation)) @@ -477,6 +485,14 @@ setemulate(HashNode hn, int fully) /**/ void +installemulation(void) +{ + scanhashtable(optiontab, 0, 0, 0, setemulate, + !!(emulation & EMULATE_FULLY)); +} + +/**/ +void emulate(const char *zsh_name, int fully) { char ch = *zsh_name; @@ -494,7 +510,9 @@ emulate(const char *zsh_name, int fully) else emulation = EMULATE_ZSH; - scanhashtable(optiontab, 0, 0, 0, setemulate, fully); + if (fully) + emulation |= EMULATE_FULLY; + installemulation(); } /* setopt, unsetopt */ diff --git a/Src/params.c b/Src/params.c index 1e902e871..6a7ab0fa6 100644 --- a/Src/params.c +++ b/Src/params.c @@ -642,7 +642,7 @@ createparamtable(void) /* Add the special parameters to the hash table */ for (ip = special_params; ip->node.nam; ip++) paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip); - if (emulation != EMULATE_SH && emulation != EMULATE_KSH) + if (!EMULATION(EMULATE_SH|EMULATE_KSH)) while ((++ip)->node.nam) paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip); @@ -720,7 +720,7 @@ createparamtable(void) #endif opts[ALLEXPORT] = oae; - if (emulation == EMULATE_ZSH) + if (EMULATION(EMULATE_ZSH)) { /* * For native emulation we always set the variable home @@ -1881,7 +1881,7 @@ getstrvalue(Value v) switch(PM_TYPE(v->pm->node.flags)) { case PM_HASHED: /* (!v->isarr) should be impossible unless emulating ksh */ - if (!v->isarr && emulation == EMULATE_KSH) { + if (!v->isarr && EMULATION(EMULATE_KSH)) { s = dupstring("[0]"); if (getindex(&s, v, 0) == 0) s = getstrvalue(v); @@ -2164,7 +2164,7 @@ export_param(Param pm) if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) { #if 0 /* Requires changes elsewhere in params.c and builtin.c */ - if (emulation == EMULATE_KSH /* isset(KSHARRAYS) */) { + if (EMULATION(EMULATE_KSH) /* isset(KSHARRAYS) */) { struct value v; v.isarr = 1; v.flags = 0; diff --git a/Src/parse.c b/Src/parse.c index 722809a78..59459870a 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -3415,6 +3415,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; 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 ac5ffaa21..5d1797f2f 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -706,6 +706,7 @@ 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->node.flags & PM_UNDEFINED) newshf->funcdef->shf = newshf; } @@ -1201,7 +1202,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) /* return triggered */ retflag = 1; } else { - if (traperr && emulation != EMULATE_SH) + if (traperr && !EMULATION(EMULATE_SH)) lastval = 1; if (try_tryflag) errflag = traperr; diff --git a/Src/subst.c b/Src/subst.c index 42f880965..89e9e46eb 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1534,7 +1534,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) * doesn't have parameter flags it might be neater to * handle this with the ^, =, ~ stuff, below. */ - if ((c = *s) == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) { + if ((c = *s) == '!' && s[1] != Outbrace && EMULATION(EMULATE_KSH)) { hkeys = SCANPM_WANTKEYS; s++; } else if (c == '(' || c == Inpar) { diff --git a/Src/zsh.h b/Src/zsh.h index 36755c719..159806f2c 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1067,6 +1067,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 */ }; /* Shell function context types. */ @@ -1790,6 +1791,20 @@ struct histent { #define EMULATE_SH (1<<3) /* Bourne shell */ #define EMULATE_ZSH (1<<4) /* `native' mode */ +/* Test for a shell emulation. Use this rather than emulation directly. */ +#define EMULATION(X) (emulation & (X)) + +/* Return only base shell emulation field. */ +#define SHELL_EMULATION() (emulation & ((1<<5)-1)) + +/* Additional flags */ + +#define EMULATE_FULLY (1<<5) /* "emulate -R" in effect */ +/* + * Higher bits are used in options.c, record lowest unused bit... + */ +#define EMULATE_UNUSED (1<<6) + /* option indices */ enum { |