Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: emulate with options other than -c is broken
On Sat, 6 Oct 2012 00:01:25 +0100
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx> wrote:
> Regardless of the autoload thing,
>
> emulate zsh -o extendedglob -c '[[ -o extendedglob ]] ||
> print "extendedglob is NOT set"'
>
> prints
>
> extendedglob is NOT set
>
> (though zsh emulation did take effect) while
>
> setopt ignorebraces
> emulate zsh -o extendedglob
> [[ -o ignorebraces ]] && print "ignorebraces IS still set"
>
> prints
>
> ignorebraces IS still set
>
> (though extendedglob did get set).
>
> Also, I'm not happy that parse errors in the option parsing are
> handled properly.
This should fix and test all three.
There's one thing still only half fixed:
emulate zsh -o extendedglob -c 'func() { [[ -o extendedglob ]] && print is on }'
func
doesn't print "is on" yet. This sure as heck looks like a bug: if you
get to pass options uniformly with the emulation, why would the
emulation but not the options be sticky? (It's half fixed because
I've created and initialised a sticky_opts array but not used it.)
This will mean storing the full set of options with the function
definition. I'd propose to do that compactly, i.e. as a bit array
rather than a char array (consuming 22 characters, it would seem, which
doesn't strike me as excessive --- I can restrict it to when sticky
emulation is in effect).
Open question: where else would it be sensible to use a bit array rather
than a char array for options? In doshfunc we save "char
saveopts[OPT_SIZE]" (OPT_SIZE appears to be 170) for every function on
the stack, which seems pretty wasteful, but I'm not 100% sure, given the
size of memory on modern systems, whether compacting this is worth the
extra time taken.
(I thought of always maintaining both the non-compact and compact forms,
since the compact form is 8 times smaller; then we only need to loop
over all options when we restore from a compact copy, not when we save
which can just copy the current compact form. I think this is workable
but it might be more than we really need.)
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.264
diff -p -u -r1.264 builtin.c
--- Src/builtin.c 7 Oct 2012 17:50:19 -0000 1.264
+++ Src/builtin.c 7 Oct 2012 19:04:12 -0000
@@ -548,8 +548,8 @@ bin_set(char *nam, char **args, UNUSED(O
/* 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(O
}
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(O
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 **ar
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 **ar
/* 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 **ar
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 **ar
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 **ar
} 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;
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.211
diff -p -u -r1.211 exec.c
--- Src/exec.c 21 Aug 2012 18:03:03 -0000 1.211
+++ Src/exec.c 7 Oct 2012 19:04:12 -0000
@@ -4544,7 +4544,7 @@ doshfunc(Shfunc shfunc, LinkList dosharg
*/
emulation = sticky_emulation = shfunc->emulation;
restore_sticky = 1;
- installemulation();
+ installemulation(emulation, opts);
} else
restore_sticky = 0;
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.125
diff -p -u -r1.125 init.c
--- Src/init.c 5 Oct 2012 21:35:06 -0000 1.125
+++ Src/init.c 7 Oct 2012 19:04:12 -0000
@@ -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() */
Index: Src/options.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/options.c,v
retrieving revision 1.63
diff -p -u -r1.63 options.c
--- Src/options.c 5 Oct 2012 21:43:00 -0000 1.63
+++ Src/options.c 7 Oct 2012 19:04:12 -0000
@@ -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, UNUSE
}
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, UNUSE
} 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, UNUSE
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 ha
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");
Index: Src/Modules/parameter.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/parameter.c,v
retrieving revision 1.54
diff -p -u -r1.54 parameter.c
--- Src/Modules/parameter.c 5 Mar 2012 10:06:29 -0000 1.54
+++ Src/Modules/parameter.c 7 Oct 2012 19:04:12 -0000
@@ -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
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);
Index: Test/B07emulate.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/B07emulate.ztst,v
retrieving revision 1.2
diff -p -u -r1.2 B07emulate.ztst
--- Test/B07emulate.ztst 11 Feb 2009 20:42:17 -0000 1.2
+++ Test/B07emulate.ztst 7 Oct 2012 19:04:12 -0000
@@ -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
Messages sorted by:
Reverse Date,
Date,
Thread,
Author