summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/newuser.c2
-rw-r--r--Src/Modules/parameter.c1
-rw-r--r--Src/builtin.c34
-rw-r--r--Src/exec.c34
-rw-r--r--Src/hashtable.c2
-rw-r--r--Src/init.c15
-rw-r--r--Src/mkbltnmlst.sh2
-rw-r--r--Src/options.c26
-rw-r--r--Src/params.c8
-rw-r--r--Src/parse.c1
-rw-r--r--Src/signals.c3
-rw-r--r--Src/subst.c2
-rw-r--r--Src/zsh.h15
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 {