summaryrefslogtreecommitdiff
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 {