* 'emulate sh -c' and $0 @ 2014-05-29 23:04 Richard Hansen 2014-05-30 3:45 ` Bart Schaefer 0 siblings, 1 reply; 17+ messages in thread From: Richard Hansen @ 2014-05-29 23:04 UTC (permalink / raw) To: zsh-workers Hi all, I just encountered what I think is a bug in Zsh 5.0.5. The following command: zsh -c ' emulate sh -c "echo \"\$0\"" bar() { emulate sh -c "echo \"\$0\""; } bar ' foo arg1 produces the following output: foo bar I expected it to produce: foo foo This is relevant when sourcing a file containing (POSIX) sh code that might examine $0 (e.g., for logging or to 'exec "$0" "$@"' after exporting/unsetting environment variables). Perhaps Zsh should save the original value of $0 somewhere and restore it when entering sh emulation mode. Thanks, Richard ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-29 23:04 'emulate sh -c' and $0 Richard Hansen @ 2014-05-30 3:45 ` Bart Schaefer 2014-05-30 8:49 ` Richard Hansen 0 siblings, 1 reply; 17+ messages in thread From: Bart Schaefer @ 2014-05-30 3:45 UTC (permalink / raw) To: zsh-workers On May 29, 7:04pm, Richard Hansen wrote: } } I just encountered what I think is a bug in Zsh 5.0.5. To the extent that it's working exactly as documented, it's not a bug ... } zsh -c ' } emulate sh -c "echo \"\$0\"" } bar() { emulate sh -c "echo \"\$0\""; } } bar } ' foo arg1 } } I expected it to produce: } } foo } foo If you throw in "unsetopt functionargzero" any time before calling "bar" then it does produce that output. If you rewrite your example as zsh -c ' emulate sh -c "echo \"\$0\"" emulate sh -c "bar() { echo \"\$0\"; }" bar ' foo arg1 then it also produces your expected output; you just need to define the function in the right scope. } This is relevant when sourcing a file containing (POSIX) sh code that } might examine $0 (e.g., for logging or to 'exec "$0" "$@"' after } exporting/unsetting environment variables). } } Perhaps Zsh should save the original value of $0 somewhere and restore } it when entering sh emulation mode. I don't find those examples particularly compelling, but the original value of $0 is already stashed; what would need to change is that the *local* value of $0 gets temporarily replaced by the global one. (The [un]setting of functionargzero controls whether a local value is ever created in the first place.) ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-30 3:45 ` Bart Schaefer @ 2014-05-30 8:49 ` Richard Hansen 2014-05-30 17:00 ` Bart Schaefer 0 siblings, 1 reply; 17+ messages in thread From: Richard Hansen @ 2014-05-30 8:49 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers (please cc me in replies as I am not subscribed to the list) On 2014-05-29 23:45, Bart Schaefer wrote: > On May 29, 7:04pm, Richard Hansen wrote: >> >> I just encountered what I think is a bug in Zsh 5.0.5. > > To the extent that it's working exactly as documented, it's not a bug ... Would you mind pointing me to where this specific behavior is documented? It was non-obvious to me when I was digging around. (I am aware of the documentation for the FUNCTION_ARGZERO option. I'm more interested in what it really means to be running in sh emulation mode, as that's where I think the bug is.) >> zsh -c ' >> emulate sh -c "echo \"\$0\"" >> bar() { emulate sh -c "echo \"\$0\""; } >> bar >> ' foo arg1 >> >> I expected it to produce: >> >> foo >> foo > > If you throw in "unsetopt functionargzero" any time before calling "bar" > then it does produce that output. > > If you rewrite your example as > > zsh -c ' > emulate sh -c "echo \"\$0\"" > emulate sh -c "bar() { echo \"\$0\"; }" > bar > ' foo arg1 > > then it also produces your expected output; you just need to define the > function in the right scope. It is not always possible to unset that option in a meaningful way -- the code that sources the file with POSIX shell code may itself be in a file that has been sourced. By that time, $0 has already been overridden. Moving the unsetopt up another level may not be desirable/feasible. For example: cat <<\EOF >foo.zsh # zsh-specific code goes here unsetopt FUNCTION_ARGZERO . ./bar.sh # zsh-specific code goes here EOF cat <<\EOF >bar.sh printf %s\\n "$0" EOF zsh -c '. ./foo.zsh' baz >> This is relevant when sourcing a file containing (POSIX) sh code that >> might examine $0 (e.g., for logging or to 'exec "$0" "$@"' after >> exporting/unsetting environment variables). >> >> Perhaps Zsh should save the original value of $0 somewhere and restore >> it when entering sh emulation mode. > > I don't find those examples particularly compelling, Here's the real-world problem that motivated my bug report; perhaps it is a more compelling example (or perhaps you'll think of a better way to solve the problem I was addressing): http://article.gmane.org/gmane.comp.version-control.git/250409 > but the original > value of $0 is already stashed; what would need to change is that the > *local* value of $0 gets temporarily replaced by the global one. That's good news; that should make it easier to write a patch that temporarily replaces the local value with the global value. Would you (or anyone else in the community) be opposed to such a patch? If not, can you point me to the relevant bits of code to help me get started? Thanks, Richard ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-30 8:49 ` Richard Hansen @ 2014-05-30 17:00 ` Bart Schaefer 2014-05-30 21:14 ` Richard Hansen 0 siblings, 1 reply; 17+ messages in thread From: Bart Schaefer @ 2014-05-30 17:00 UTC (permalink / raw) To: Richard Hansen; +Cc: zsh-workers On May 30, 4:49am, Richard Hansen wrote: } } On 2014-05-29 23:45, Bart Schaefer wrote: } > On May 29, 7:04pm, Richard Hansen wrote: } >> } >> I just encountered what I think is a bug in Zsh 5.0.5. } > } > To the extent that it's working exactly as documented, it's not a bug ... } } Would you mind pointing me to where this specific behavior is } documented? It was non-obvious to me when I was digging around. I don't pretend there couldn't be more clarity in the zsh documentation, but under "Parameters" there's first this: In the parameter lists that follow, the mark `<S>' indicates that the parameter is special. Special parameters cannot have their type changed or their readonly attribute turned off, and if a special parameter is unset, then later recreated, the special properties will be retained. `<Z>' indicates that the parameter does not exist when the shell initializes in sh or ksh emulation mode. And then in the "Parameters Set by the Shell" subsection there is: 0 <S> The name used to invoke the current shell. If the FUNCTION_ARGZERO option is set, this is set temporarily within a shell function to the name of the function, and within a sourced script to the name of the script. There's no <Z> there, and there's no mention in the "Compatibility" section about the behavior of $0, only that NO_FUNCTION_ARGZERO is set. Finally the entry for the emulate builtin says: With single argument set up zsh options to emulate the specified shell as much as possible. `csh' will never be fully emulated. If the argument is not one of the shells listed above, zsh will be used as a default; more precisely, the tests performed on the argument are the same as those used to determine the emulation at startup based on the shell name, see Compatibility. } (I am aware of the documentation for the FUNCTION_ARGZERO option. I'm } more interested in what it really means to be running in sh emulation } mode, as that's where I think the bug is.) In general, emulation is at its most complete if and only if the shell is actually started as an emulator (e.g., the path name to the shell binary itself is not zsh, or ARGV0 is set in the environment). The "emulate" builtin only changes setopts to the closest possible. } > I don't find those examples particularly compelling, } } Here's the real-world problem that motivated my bug report; perhaps it } is a more compelling example (or perhaps you'll think of a better way to } solve the problem I was addressing): } } http://article.gmane.org/gmane.comp.version-control.git/250409 Instead of "compelling" I perhaps should have said "likely to come up in common usage." You have a fairly rare special case there. In that example, ARGV0=sh exec zsh "$0" "$ <at> " might do what you want, but I'm not entirely following from the diff context what's intended. } > but the original } > value of $0 is already stashed; what would need to change is that the } > *local* value of $0 gets temporarily replaced by the global one. } } That's good news; that should make it easier to write a patch that } temporarily replaces the local value with the global value. Unfortunately the way the local value is implemented is usually to use C local variable scoping to stash and restore the contents of a C global pointer, so this would mean at least one additional C global. } Would you (or anyone else in the community) be opposed to such a patch? The use cases in both directions seem pretty unusual to me. Losing the ability to "localize" $0 for scripts feels almost as likely to create questions as does your situation. I suppose if both values were in the C global state, it would be possible to have the "correct" one appear at the instant functionargzero changes, instead of being determined by the setting at the time the function is entered. OTOH that would be a larger behavior difference / lack of backward compatibilty. } If not, can you point me to the relevant bits of code to help me get } started? Search Src/*.c for references to "argzero", with particular attention to builtin.c:bin_emulate. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-30 17:00 ` Bart Schaefer @ 2014-05-30 21:14 ` Richard Hansen 2014-05-31 5:13 ` Bart Schaefer 0 siblings, 1 reply; 17+ messages in thread From: Richard Hansen @ 2014-05-30 21:14 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers On 2014-05-30 13:00, Bart Schaefer wrote: > Finally the entry for the emulate builtin says: > > With single argument set up zsh options to emulate the specified > shell as much as possible. `csh' will never be fully emulated. > If the argument is not one of the shells listed above, zsh will be > used as a default; more precisely, the tests performed on the > argument are the same as those used to determine the emulation at > startup based on the shell name, see Compatibility. Thanks for the documentation references. I had read "to emulate the specified shell as much as possible" without paying enough attention to the qualifying "set up zsh options". So you are right: The documentation says that emulate only toggles options, and the behavior of $0 with FUNCTION_ARGZERO is clear, so there's no reason to expect Zsh to reset $0 to the original $0 when in sh emulation mode. That being said, I still think there's value in changing Zsh's behavior. > >> (I am aware of the documentation for the FUNCTION_ARGZERO option. I'm >> more interested in what it really means to be running in sh emulation >> mode, as that's where I think the bug is.) > > In general, emulation is at its most complete if and only if the shell > is actually started as an emulator (e.g., the path name to the shell > binary itself is not zsh, or ARGV0 is set in the environment). The > "emulate" builtin only changes setopts to the closest possible. Would it add too much complexity to the code or documentation if the emulate builtin did more than just toggle options (specifically: temporarily change the binding of $0 to the original value)? Perhaps the behavior of FUNCTION_ARGZERO could be altered so that $0 expands as follows: If option FUNCTION_ARGZERO is enabled and $0 is expanded inside the body of a function, $0 expands to the name of the enclosing function. Otherwise, if option FUNCTION_ARGZERO is enabled and $0 is expanded inside a sourced file, $0 expands to the pathname given to the 'source' or '.' builtin command. Otherwise, if the shell was invoked with an argument naming a script containing shell commands to be executed, $0 expands to the value of that argument. Otherwise, if the shell was invoked with the '-c' flag and at least one non-option non-flag argument was given, $0 expands to the value of the first non-option non-flag argument. Otherwise, $0 expands to the value of the first argument passed to zsh from its parent (argv[0] in C). This modification would make it possible to toggle the setting back and forth to examine the local or original value as desired, even within the same function. I wouldn't expect this change to break many scripts, but maybe any backward incompatibility is unacceptable. >>> I don't find those examples particularly compelling, >> >> Here's the real-world problem that motivated my bug report; perhaps it >> is a more compelling example (or perhaps you'll think of a better way to >> solve the problem I was addressing): >> >> http://article.gmane.org/gmane.comp.version-control.git/250409 > > Instead of "compelling" I perhaps should have said "likely to come up > in common usage." You have a fairly rare special case there. Good point. :) > In that example, > > ARGV0=sh exec zsh "$0" "$@" > > might do what you want, but I'm not entirely following from the diff > context what's intended. Some more context if you're curious: The Git distribution comes with t/test-lib.sh, a file containing POSIX shell code implementing common test infrastructure (print error messages, declare and run test cases, etc.). The test scripts are POSIX shell scripts that source this shared file, with two exceptions: * t/t9903-bash-prompt.sh starts off running under /bin/sh, but it does the following early on: exec bash "$0" "$@" so that it can run and test Bash-specific shell code. After reinvoking itself under Bash, the code sources test-lib.sh in order to reuse the shared test infrastructure code. (The code in test-lib.sh is interpreted as Bash code, not POSIX shell code, but that doesn't really matter because the code is compatible with both shells.) * t/t9904-zsh-prompt.sh (new in that linked patch series) is similar to t9903, except it restarts itself under Zsh instead of Bash. Like t9903, it sources test-lib.sh, but because the code in test-lib.sh is incompatible with Zsh, it uses Zsh's sh emulation to source test-lib.sh. The point of these two test scripts is to run Bash and Zsh in their native modes as much as possible -- emulation is explicitly avoided except as necessary to run the shared test infrastructure. So 'ARGV0=sh exec zsh "$0" "$@"' doesn't work for two reasons: * at the time that line is executed, the script is being interpreted by /bin/sh and not Zsh, so the ARGV0 assignment won't have the desired effect * we want as little as possible to run in sh emulation mode so that we can test Zsh-specific code > >>> but the original >>> value of $0 is already stashed; what would need to change is that the >>> *local* value of $0 gets temporarily replaced by the global one. >> >> That's good news; that should make it easier to write a patch that >> temporarily replaces the local value with the global value. > > Unfortunately the way the local value is implemented is usually to use > C local variable scoping to stash and restore the contents of a C global > pointer, so this would mean at least one additional C global. > >> Would you (or anyone else in the community) be opposed to such a patch? > > The use cases in both directions seem pretty unusual to me. Losing the > ability to "localize" $0 for scripts feels almost as likely to create > questions as does your situation. I'm not sure what you mean by losing the ability to localize $0. I see a few OK options: * Option #1: 1. Add a new global variable 'orig_argzero' to hold the original value of $0. This variable is never modified once set. 2. The existing global variable 'argzero' continues to serve its current role of holding the "localized" value of $0 (it is updated when executing functions or sourcing files if FUNCTION_ARGZERO is enabled). 3. When 'emulate sh' starts, temporarily set argzero to orig_argzero. Restore argzero when 'emulate sh' returns. This would result in behavior that is identical to the current behavior except $0 would match the POSIX spec when in sh emulation mode (and only in sh emulation mode). * Option #2: 1. Add a new global variable 'orig_argzero' to hold the original value of $0. This variable is never modified once set. 2. The existing global variable 'argzero' continues to serve its current role of holding the "localized" value of $0 (it is updated when executing functions or sourcing files if FUNCTION_ARGZERO is enabled). 3. Add a new option; let's call it LOCALIZE_ARGZERO for now. If LOCALIZE_ARGZERO is enabled, use argzero to expand $0. If LOCALIZE_ARGZERO is disabled, use orig_argzero to expand $0. 4. Enable LOCALIZE_ARGZERO by default, but disable it in sh emulation mode. 5. Stop disabling FUNCTION_ARGZERO by default in sh emulation mode. * Option #3: 1. Add a new global variable 'orig_argzero' to hold the original value of $0. This variable is never modified once set. 2. Whenever a function is called or a file sourced, update the global variable holding the "localized" $0 ('argzero'), even if FUNCTION_ARGZERO is disabled. 3. Modify the expansion rules for $0 as follows: If FUNCTION_ARGZERO is enabled, use argzero to expand $0. If FUNCTION_ARGZERO is disabled, use orig_argzero to expand $0. Pros and cons: Option #1 is simplest to implement, simple for users, and (mostly) backward compatible, but less powerful than options #2 and #3 and 'emulate' no longer just sets options. Option #2 is complex but powerful (scripts can read both the original $0 and the localized $0 in the same chunk of code) and (mostly) backward compatible. Note that option #1 can be used as a stepping stone to option #2. Option #3 is simple for users but not backward compatible. I think my preference is to go with option #1 with a possible future step to option #2 (at which time FUNCTION_ARGZERO can be deprecated in favor of LOCALIZE_ARGZERO). > I suppose if both values were in the > C global state, it would be possible to have the "correct" one appear > at the instant functionargzero changes, instead of being determined by > the setting at the time the function is entered. OTOH that would be a > larger behavior difference / lack of backward compatibilty. Oops, I should have thoroughly read your email before proposing the same thing but with more words. :) > >> If not, can you point me to the relevant bits of code to help me get >> started? > > Search Src/*.c for references to "argzero", with particular attention to > builtin.c:bin_emulate. Thanks. No promises that I'll have the time to submit a patch soon (or even at all), but I plan on taking a crack at it this weekend. -Richard ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-30 21:14 ` Richard Hansen @ 2014-05-31 5:13 ` Bart Schaefer 2014-05-31 23:47 ` Bart Schaefer 2014-06-03 20:15 ` Richard Hansen 0 siblings, 2 replies; 17+ messages in thread From: Bart Schaefer @ 2014-05-31 5:13 UTC (permalink / raw) To: Richard Hansen; +Cc: zsh-workers On May 30, 5:14pm, Richard Hansen wrote: } } Would it add too much complexity to the code or documentation if the } emulate builtin did more than just toggle options (specifically: } temporarily change the binding of $0 to the original value)? No, probably not. We could certainly get away with making the change to $0 be an additional effect of the (relatively new) -c option, i.e., emulate sh changes only the options, but emulate sh -c 'some command' changes both options and $0 in the scope of 'some command'. In fact I like that idea a lot, now that I've written it down ... but it'd be a bit complicated to add that to "sticky emulation" so a simpler plan is probably better. } > The use cases in both directions seem pretty unusual to me. Losing the } > ability to "localize" $0 for scripts feels almost as likely to create } > questions as does your situation. } } I'm not sure what you mean by losing the ability to localize $0. You gave two examples in your original message on this thread: the current behavior and the behavior you expected. Someone else might be expecting the current behavior, and I don't see any clear criteria for deciding which one is "best." If we make any of the suggested changes here, the current behavior is lost. } I see a few OK options: } } * Option #1: } 3. When 'emulate sh' starts, temporarily set argzero to } orig_argzero. Restore argzero when 'emulate sh' returns. } } * Option #2: } 3. Add a new option; let's call it LOCALIZE_ARGZERO for now. If } LOCALIZE_ARGZERO is enabled, use argzero to expand $0. If } LOCALIZE_ARGZERO is disabled, use orig_argzero to expand $0. } 4. Enable LOCALIZE_ARGZERO by default, but disable it in sh } emulation mode. } 5. Stop disabling FUNCTION_ARGZERO by default in sh emulation mode. } } * Option #3: } 3. Modify the expansion rules for $0 as follows: If } FUNCTION_ARGZERO is enabled, use argzero to expand $0. If } FUNCTION_ARGZERO is disabled, use orig_argzero to expand $0. I was initially leaning toward #3, because #1 takes away the current behavior and because I'd rather not add yet another option as in #2 ... but then I had a different idea ... It seems to me that the ideal situation would be that emulate sh works exactly as it does now ("With SINGLE ARGUMENT set up zsh options" says the doc, emphasis mine) but that emulate sh -c 'some command' alters the behavior of $0 as well. The advantage of this is that the -c option to emulate is relatively new; any scripts relying on the current $0 behavior are likely old and won't use -c. The drawback to this is "sticky emulation" for functions, which is based entirely on option settings; but that can be made to work if we add an option. Hence: If we leave FUNCTION_ARGZERO as it is (that is, off by default for sh emulation) and add an option POSIX_ARGZERO which exposes the global argzero when set (inverting your Option #2) but which is never on by default, then bin_emulate can set POSIX_ARGZERO in the -c scope when emulating sh/ksh, and it will be sticky for functions defined there. We wouldn't even have to build those smarts into bin_emulate; a user who wanted the POSIX semantics could explicitly do emulate sh -o POSIX_ARGZERO -c '...' The only "magic" necessary is that POSIX_ARGZERO exposes the original value of $0 in spite of the current FUNCTION_ARGZERO setting. Here are the bits outside bin_emulate, and not yet with doc. I suppose there may be some places where posixzero needs to be saved / changed / restored, which this hasn't covered. diff --git a/Src/init.c b/Src/init.c index fd12412..5e92f59 100644 --- a/Src/init.c +++ b/Src/init.c @@ -226,7 +226,7 @@ parseargs(char **argv, char **runscript) char **x; LinkList paramlist; - argzero = *argv++; + argzero = posixzero = *argv++; SHIN = 0; /* There's a bit of trickery with opts[INTERACTIVE] here. It starts * @@ -253,7 +253,7 @@ parseargs(char **argv, char **runscript) if (*argv) { if (unset(SHINSTDIN)) { if (cmd) - argzero = *argv; + argzero = posixzero = *argv; else *runscript = *argv; opts[INTERACTIVE] &= 1; @@ -275,6 +275,7 @@ parseargs(char **argv, char **runscript) while ((*x++ = (char *)getlinknode(paramlist))); free(paramlist); argzero = ztrdup(argzero); + posixzero = ztrdup(posixzero); } /* Insert into list in order of pointer value */ diff --git a/Src/options.c b/Src/options.c index ce73d99..e83dc58 100644 --- a/Src/options.c +++ b/Src/options.c @@ -207,6 +207,7 @@ static struct optname optns[] = { {{NULL, "pathscript", OPT_EMULATE|OPT_BOURNE}, PATHSCRIPT}, {{NULL, "pipefail", OPT_EMULATE}, PIPEFAIL}, {{NULL, "posixaliases", OPT_EMULATE|OPT_BOURNE}, POSIXALIASES}, +{{NULL, "posixargzero", OPT_EMULATE}, POSIXARGZERO}, {{NULL, "posixbuiltins", OPT_EMULATE|OPT_BOURNE}, POSIXBUILTINS}, {{NULL, "posixcd", OPT_EMULATE|OPT_BOURNE}, POSIXCD}, {{NULL, "posixidentifiers", OPT_EMULATE|OPT_BOURNE}, POSIXIDENTIFIERS}, diff --git a/Src/params.c b/Src/params.c index 7901029..0699ead 100644 --- a/Src/params.c +++ b/Src/params.c @@ -67,6 +67,7 @@ char **path, /* $path */ /**/ mod_export char *argzero, /* $0 */ + *posixzero, /* $0 */ *home, /* $HOME */ *nullcmd, /* $NULLCMD */ *oldpwd, /* $OLDPWD */ @@ -194,6 +195,8 @@ static const struct gsu_integer euid_gsu = static const struct gsu_integer ttyidle_gsu = { ttyidlegetfn, nullintsetfn, stdunsetfn }; +static const struct gsu_scalar argzero_gsu = +{ argzerogetfn, nullstrsetfn, nullunsetfn }; static const struct gsu_scalar username_gsu = { usernamegetfn, usernamesetfn, stdunsetfn }; static const struct gsu_scalar dash_gsu = @@ -285,6 +288,7 @@ IPDEF2("WORDCHARS", wordchars_gsu, 0), IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT), IPDEF2("_", underscore_gsu, PM_DONTIMPORT), IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT), +IPDEF2("0", argzero_gsu, 0), #ifdef USE_LOCALE # define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET) @@ -340,7 +344,6 @@ IPDEF7U("RPROMPT2", &rprompt2), IPDEF7("PS3", &prompt3), IPDEF7("PS4", &prompt4), IPDEF7("SPROMPT", &sprompt), -IPDEF7("0", &argzero), #define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0} IPDEF8("CDPATH", &cdpath, "cdpath", 0), @@ -3981,6 +3984,17 @@ lcsetfn(Param pm, char *x) } #endif /* USE_LOCALE */ +/* Function to get value for special parameter `0' */ + +/**/ +static char * +argzerogetfn(UNUSED(Param pm)) +{ + if (isset(POSIXARGZERO)) + return posixzero; + return argzero; +} + /* Function to get value for special parameter `HISTSIZE' */ /**/ diff --git a/Src/zsh.h b/Src/zsh.h index 5fbff57..620883b 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2151,6 +2151,7 @@ enum { PATHSCRIPT, PIPEFAIL, POSIXALIASES, + POSIXARGZERO, POSIXBUILTINS, POSIXCD, POSIXIDENTIFIERS, ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-31 5:13 ` Bart Schaefer @ 2014-05-31 23:47 ` Bart Schaefer 2014-06-03 20:15 ` Richard Hansen 1 sibling, 0 replies; 17+ messages in thread From: Bart Schaefer @ 2014-05-31 23:47 UTC (permalink / raw) To: zsh-workers On May 30, 10:13pm, Bart Schaefer wrote: } Subject: Re: 'emulate sh -c' and $0 } } emulate sh } } changes only the options, but } } emulate sh -c 'some command' } } changes both options and $0 in the scope of 'some command'. } [...] } } It seems to me that the ideal situation would be that } } emulate sh } } works exactly as it does now ("With SINGLE ARGUMENT set up zsh options" } says the doc, emphasis mine) but that } } emulate sh -c 'some command' } } alters the behavior of $0 as well. Wow, I thought I'd deleted that top part before I wrote the later part. That's what I get for rushing off to a concert in the middle of composing an email message, I guess. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-05-31 5:13 ` Bart Schaefer 2014-05-31 23:47 ` Bart Schaefer @ 2014-06-03 20:15 ` Richard Hansen 2014-06-03 20:26 ` Peter Stephenson 2014-06-03 21:21 ` Bart Schaefer 1 sibling, 2 replies; 17+ messages in thread From: Richard Hansen @ 2014-06-03 20:15 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers On 2014-05-31 01:13, Bart Schaefer wrote: > If we leave FUNCTION_ARGZERO as it is (that is, off by default for sh > emulation) and add an option POSIX_ARGZERO which exposes the global > argzero when set (inverting your Option #2) but which is never on by > default, then bin_emulate can set POSIX_ARGZERO in the -c scope when > emulating sh/ksh, and it will be sticky for functions defined there. > > We wouldn't even have to build those smarts into bin_emulate; a user > who wanted the POSIX semantics could explicitly do > > emulate sh -o POSIX_ARGZERO -c '...' > > The only "magic" necessary is that POSIX_ARGZERO exposes the original > value of $0 in spite of the current FUNCTION_ARGZERO setting. > > Here are the bits outside bin_emulate, and not yet with doc. I suppose > there may be some places where posixzero needs to be saved / changed / > restored, which this hasn't covered. Wow, thank you for committing this change to master! It works well in my limited testing, except for the documented limitation that POSIX_ARGZERO stays enabled when calling a non-emulated function from a function defined in 'emulate <shell> -c'. I'm not sure how much this will matter in practice, but if backward compatibility wasn't a concern it'd be nice if zsh temporarily restored options when invoking a function outside the 'emulate <shell> -c' boundary. Although it would be a behavior change, I think it would be best if both 'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default: I suspect that someone who runs 'emulate sh' cares more about accurate sh emulation than compatibility with previous sh emulation behavior. :) Thanks, Richard ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 20:15 ` Richard Hansen @ 2014-06-03 20:26 ` Peter Stephenson 2014-06-03 21:10 ` Bart Schaefer 2014-06-03 21:21 ` Bart Schaefer 1 sibling, 1 reply; 17+ messages in thread From: Peter Stephenson @ 2014-06-03 20:26 UTC (permalink / raw) To: zsh-workers On Tue, 03 Jun 2014 16:15:25 -0400 Richard Hansen <rhansen@bbn.com> wrote: > Although it would be a behavior change, I think it would be best if both > 'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default: I > suspect that someone who runs 'emulate sh' cares more about accurate sh > emulation than compatibility with previous sh emulation behavior. :) Yes, that's the policy --- backward compatibility is for native mode, sh compatibility can be improved without worrying about that. I'm not sure why we missed this one. Most of the POSIX options are on in sh emulations. pws ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 20:26 ` Peter Stephenson @ 2014-06-03 21:10 ` Bart Schaefer 2014-06-03 23:35 ` Richard Hansen 0 siblings, 1 reply; 17+ messages in thread From: Bart Schaefer @ 2014-06-03 21:10 UTC (permalink / raw) To: zsh-workers [-- Attachment #1: Type: text/plain, Size: 1260 bytes --] On Jun 3, 2014 1:27 PM, "Peter Stephenson" <p.w.stephenson@ntlworld.com> wrote: > > On Tue, 03 Jun 2014 16:15:25 -0400 > Richard Hansen <rhansen@bbn.com> wrote: > > Although it would be a behavior change, I think it would be best if both > > 'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default > > Yes, that's the policy --- backward compatibility is for native mode, sh > compatibility can be improved without worrying about that. The complexity here is that we're not just dealing with a particular emulation, we're dealing with switching from one emulation to another (and possibly back again) in the middle of a running shell session, and the effect that has on a dynamically scoped variable that crosses the emulation boundaries. If I start in zsh mode and change $0, or $PATH, or any other parameter, and then enter a different emulation, the values of those parameters don't normally change. > I'm not sure why we missed this one. Most of the POSIX options are on > in sh emulations. We didn't really miss it -- FUNCTION_ARGZERO is correctly turned off when in sh emulation. The complication is that it affects $0 only upon entry to the scope, so although $0 doesn't change *again*, it also doesn't revert if it was changed previously. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 21:10 ` Bart Schaefer @ 2014-06-03 23:35 ` Richard Hansen 2014-06-04 0:09 ` Bart Schaefer 0 siblings, 1 reply; 17+ messages in thread From: Richard Hansen @ 2014-06-03 23:35 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers On 2014-06-03 17:10, Bart Schaefer wrote: > On Jun 3, 2014 1:27 PM, "Peter Stephenson" <p.w.stephenson@ntlworld.com> > wrote: >> On Tue, 03 Jun 2014 16:15:25 -0400 >> Richard Hansen <rhansen@bbn.com> wrote: >>> Although it would be a behavior change, I think it would be best if both >>> 'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default >> >> Yes, that's the policy --- backward compatibility is for native mode, sh >> compatibility can be improved without worrying about that. > > The complexity here is that we're not just dealing with a particular > emulation, we're dealing with switching from one emulation to another (and > possibly back again) in the middle of a running shell session, and the > effect that has on a dynamically scoped variable that crosses the emulation > boundaries. Isn't this a general problem with how zsh supports mix-and-match shell code? Here's a contrived example: echo_stuff() { printf %s\\n "$*"; } foo() { ${CMD} words here; } CMD=echo_stuff IFS=_ printf "outside sh emulation: "; foo printf "inside sh emulation: "; emulate sh -c foo As stated in detail #2 in the documentation for the emulate builtin, options aren't restored when calling foo from sh emulation mode. That causes the above script to produce the following output: outside sh emulation: words_here inside sh emulation: stuff words here Because foo was defined outside of emulate I would have expected zsh to treat the body of foo as native zsh code regardless of the emulation mode of the calling code. If I hadn't read the detailed emulate rules and didn't understand how emulate worked with regard to options, I would have expected the following output: outside sh emulation: words_here inside sh emulation: words_here (same output for the same function in the same script) To get the behavior I expect, I have to do the following: define_functions() { echo_stuff() { printf %s\\n "$*"; } foo() { ${CMD} words here; } } emulate zsh -c define_functions CMD=echo_stuff IFS=_ printf "outside sh emulation: "; foo printf "inside sh emulation: "; emulate sh -c foo If zsh restored options when a non-sticky function is called from within emulation then I wouldn't have to do the above define_functions hack. (And $0 would act like I expect assuming POSIX_ARGZERO is enabled in sh emulation mode.) -Richard ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 23:35 ` Richard Hansen @ 2014-06-04 0:09 ` Bart Schaefer 0 siblings, 0 replies; 17+ messages in thread From: Bart Schaefer @ 2014-06-04 0:09 UTC (permalink / raw) To: zsh-workers [-- Attachment #1: Type: text/plain, Size: 320 bytes --] On Jun 3, 2014 4:35 PM, "Richard Hansen" <rhansen@bbn.com> wrote: > > Isn't this a general problem with how zsh supports mix-and-match shell > code? One man's problem is another man's solution. The shell has always been a dynamically scoped language. If that's not what you want, you should be using a different one. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 20:15 ` Richard Hansen 2014-06-03 20:26 ` Peter Stephenson @ 2014-06-03 21:21 ` Bart Schaefer 2014-06-03 22:54 ` Richard Hansen 1 sibling, 1 reply; 17+ messages in thread From: Bart Schaefer @ 2014-06-03 21:21 UTC (permalink / raw) To: zsh-workers [-- Attachment #1: Type: text/plain, Size: 957 bytes --] On Jun 3, 2014 1:15 PM, "Richard Hansen" <rhansen@bbn.com> wrote: > > Wow, thank you for committing this change to master! It works well in > my limited testing, except for the documented limitation that > POSIX_ARGZERO stays enabled when calling a non-emulated function from a > function defined in 'emulate <shell> -c'. I'm not sure how much this > will matter in practice, but if backward compatibility wasn't a concern > it'd be nice if zsh temporarily restored options when invoking a > function outside the 'emulate <shell> -c' boundary. What this is effectively requesting is that all functions have "sticky" options, always. We already rejected that idea for reasons of dynamic scoping when originally designing "emulate ... -c". I suppose a special case could be made of POSIX_ARGZERO such that it is always sticky even when other options are not, but that seems like an awful lot of effort for something that doesn't matter most of the time. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 21:21 ` Bart Schaefer @ 2014-06-03 22:54 ` Richard Hansen 2014-06-04 0:03 ` Bart Schaefer 2014-06-04 1:23 ` Bart Schaefer 0 siblings, 2 replies; 17+ messages in thread From: Richard Hansen @ 2014-06-03 22:54 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers On 2014-06-03 17:21, Bart Schaefer wrote: > On Jun 3, 2014 1:15 PM, "Richard Hansen" <rhansen@bbn.com> wrote: >> >> Wow, thank you for committing this change to master! It works well in >> my limited testing, except for the documented limitation that >> POSIX_ARGZERO stays enabled when calling a non-emulated function from a >> function defined in 'emulate <shell> -c'. I'm not sure how much this >> will matter in practice, but if backward compatibility wasn't a concern >> it'd be nice if zsh temporarily restored options when invoking a >> function outside the 'emulate <shell> -c' boundary. > > What this is effectively requesting is that all functions have "sticky" > options, always. Not necessarily -- I was thinking more along the lines of temporarily restoring the top-level (non-emulated) option state when calling a function that was not defined inside of 'emulate <shell> -c'. (Maybe there's not a significant implementation difference between what I'm thinking and assigning sticky options to all functions.) I'm not familiar with Zsh's implementation, but this is my current (probably flawed) mental model: * there is a structure type (e.g., 'struct option_state') that is effectively an array of booleans (one for each option) that is intended to record which options are enabled/disabled * there is a global variable (e.g., 'global_option_state') of the above structure type that stores which options are enabled/disabled when *not* running in an emulation mode * there is a global variable (e.g., 'current_option_state') of type pointer to the above structure type that is used to indicate which options are currently active * when it's time to call a function, the following happens: if the function was defined under an emulation mode and that emulation mode differs from the current emulation mode (if applicable): 1. create a new struct option_state 2. load the sticky options into the new struct option_state 3. back up the current_option_state pointer 4. set current_option_state to point to the new struct option_state 5. call the function 6. restore current_option_state 7. delete the new struct option_state else: 1. call the function If my mental model is roughly correct, then the following could be inserted between the above 'if' case and the 'else' case to temporarily restore options when invoking a function outside the 'emulate -c' boundary: else if the function was not defined under an emulation mode but we're currently running under an emulation mode: 1. back up the current_option_state pointer 2. set current_option_state to point to global_option_state 3. call the function 4. restore current_option_state > We already rejected that idea for reasons of dynamic > scoping when originally designing "emulate ... -c". I suppose a special > case could be made of POSIX_ARGZERO such that it is always sticky even when > other options are not, but that seems like an awful lot of effort for > something that doesn't matter most of the time. Yeah, that doesn't seem worthwhile. In general I dislike special cases, and it seems like the other options would also benefit from being temporarily restored to their non-emulation state when calling a function defined outside of 'emulate <shell> -c'. -Richard ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 22:54 ` Richard Hansen @ 2014-06-04 0:03 ` Bart Schaefer 2014-06-04 1:10 ` Bart Schaefer 2014-06-04 1:23 ` Bart Schaefer 1 sibling, 1 reply; 17+ messages in thread From: Bart Schaefer @ 2014-06-04 0:03 UTC (permalink / raw) To: zsh-workers [-- Attachment #1: Type: text/plain, Size: 1207 bytes --] On Jun 3, 2014 3:54 PM, "Richard Hansen" <rhansen@bbn.com> wrote: > > I was thinking more along the lines of temporarily > restoring the top-level (non-emulated) option state when calling a > function that was not defined inside of 'emulate <shell> -c'. (Maybe > there's not a significant implementation difference between what I'm > thinking and assigning sticky options to all functions.) Implementation aside, operationally this still violates dynamic scoping. It means for example that the completion system can't set extendedglob on entry and be sure it remains in effect throughout any helper functions it calls. The reason sticky emulation works the way it does is because it allows the function author to explicitly assert that dynamic scoping should not apply to the options in effect in that function, but the default scope is still dynamic for all other functions. It might be possible to introduce another builtin/precommand that temporarily unwinds one level of option state before entering the next, sort of a "go play at Grandma's house" wrapper ... but I haven't really thought about how that could be done. It would require exporting a bunch of the local C state of doshfunc(), I bet. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-04 0:03 ` Bart Schaefer @ 2014-06-04 1:10 ` Bart Schaefer 0 siblings, 0 replies; 17+ messages in thread From: Bart Schaefer @ 2014-06-04 1:10 UTC (permalink / raw) To: zsh-workers On Jun 3, 5:03pm, Bart Schaefer wrote: } } On Jun 3, 2014 3:54 PM, "Richard Hansen" <rhansen@bbn.com> wrote: } > } > I was thinking more along the lines of temporarily } > restoring the top-level (non-emulated) option state when calling a } > function that was not defined inside of 'emulate <shell> -c'. (Maybe } > there's not a significant implementation difference between what I'm } > thinking and assigning sticky options to all functions.) } } Implementation aside, operationally this still violates dynamic scoping. } It means for example that the completion system can't set extendedglob on } entry and be sure it remains in effect throughout any helper functions it } calls. OK, that's not quite true. What you're suggesting is not that the called function has made the global options sticky, rather that if the calling function has sticky options, it automatically reverts them upon making a nested call. So that would only mess up completion if somebody did "emulate zsh -c compinit" to load it. That still prevents the calling function from intentionally propagating a particular set of options down to the called function, which I think is the more common use case (certainly so far it has been the *only* use case, though that may just be because no other is possible). And as I suspected "reverts them" currently involves completing the C fuction scope of doshfunc(), though that could be disentangled with a bit of effort. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: 'emulate sh -c' and $0 2014-06-03 22:54 ` Richard Hansen 2014-06-04 0:03 ` Bart Schaefer @ 2014-06-04 1:23 ` Bart Schaefer 1 sibling, 0 replies; 17+ messages in thread From: Bart Schaefer @ 2014-06-04 1:23 UTC (permalink / raw) To: zsh-workers On Jun 3, 6:54pm, Richard Hansen wrote: } } else if the function was not defined under an emulation mode but } we're currently running under an emulation mode: } 1. back up the current_option_state pointer } 2. set current_option_state to point to global_option_state } 3. call the function } 4. restore current_option_state The flaw in this model is that (1) there is no global option state object, only a local state object on the C call stack that represents the global state at the time the function was entered; and (2) even if there were a global state, pointing to that would still be wrong; what you want is to point to (i.e., overwrite the current global state with) the option state from one frame earlier in the call stack. Next you have the issue of the LOCAL_OPTIONS option, and what that means to your emulated state when that is not set in the frame from which you restored. ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2014-06-04 1:24 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-05-29 23:04 'emulate sh -c' and $0 Richard Hansen 2014-05-30 3:45 ` Bart Schaefer 2014-05-30 8:49 ` Richard Hansen 2014-05-30 17:00 ` Bart Schaefer 2014-05-30 21:14 ` Richard Hansen 2014-05-31 5:13 ` Bart Schaefer 2014-05-31 23:47 ` Bart Schaefer 2014-06-03 20:15 ` Richard Hansen 2014-06-03 20:26 ` Peter Stephenson 2014-06-03 21:10 ` Bart Schaefer 2014-06-03 23:35 ` Richard Hansen 2014-06-04 0:09 ` Bart Schaefer 2014-06-03 21:21 ` Bart Schaefer 2014-06-03 22:54 ` Richard Hansen 2014-06-04 0:03 ` Bart Schaefer 2014-06-04 1:10 ` Bart Schaefer 2014-06-04 1:23 ` Bart Schaefer
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).