From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6341 invoked by alias); 11 Sep 2017 08:58:59 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 41668 Received: (qmail 15817 invoked by uid 1010); 11 Sep 2017 08:58:59 -0000 X-Qmail-Scanner-Diagnostics: from mailout2.w1.samsung.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.99.2/21882. spamassassin: 3.4.1. Clear:RC:0(210.118.77.12):SA:0(-6.9/5.0):. Processed in 1.930402 secs); 11 Sep 2017 08:58:59 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.1 X-Envelope-From: p.stephenson@samsung.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | X-AuditID: cbfec7f1-f793a6d00000326b-21-59b6504bedc5 Date: Mon, 11 Sep 2017 09:58:45 +0100 From: Peter Stephenson To: Zsh Hackers' List Subject: Re: Running "unset path" breaks PATH despite emulation being enabled Message-id: <20170911095845.6dc8d960@pwslap01u.europe.root.pri> In-reply-to: <20170908171703.4b4918ae@pwslap01u.europe.root.pri> Organization: Samsung Cambridge Solution Centre X-Mailer: Claws Mail 3.7.9 (GTK+ 2.22.0; i386-redhat-linux-gnu) MIME-version: 1.0 Content-type: text/plain; charset="US-ASCII" Content-transfer-encoding: 7bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLIsWRmVeSWpSXmKPExsWy7djPc7reAdsiDZackLM42PyQyYHRY9XB D0wBjFFcNimpOZllqUX6dglcGbMOPWUsaEiqmLztK3MD4xWPLkYODgkBE4ntv0K6GDmBTDGJ C/fWs3UxcnEICSxllHh8vY8Fwullkpjz+TkLRJWJxM2795lAbCGBZYwSv3+bQhRNY5LY+/Aq VPsZRonJS+6wQzhnGSUu9D9iA2lhEVCVOH+mnx3EZhMwlJi6aTYjyB0iAtoS7R/FQMLCAv4S dxe9YQSxeQXsJbbOagDbxingIPH55x5mEJtfQF/i6t9PTBAX2UvMvHIGql5Q4sfke2CXMgvo SGzb9pgdwpaX2LzmLTPIPRICS9gk3r+9yQjR7CIxqb0NapCwxKvjW9ghbBmJy5O7oV7uZ5R4 0u0L0TyDUeL0mR1sEAlrib7bFxkhNvBJTNo2nRkSqLwSHW1CECUeEltefYSa6Sgxc913aJhO Z5J4sPAf8wRGhVlIDp+F5PBZSA5fwMi8ilEktbQ4Nz212EivODG3uDQvXS85P3cTIzARnP53 /OMOxvcnrA4xCnAwKvHw7pi0NVKINbGsuDL3EKMEB7OSCO8Gn22RQrwpiZVVqUX58UWlOanF hxilOViUxHlto9oihQTSE0tSs1NTC1KLYLJMHJxSDYyF5pHzP52pXZ11v3xKacicyqfvDk1s 2pt0NVztmaPGL3szqf1a+becivg5m88LBTGu/ewoeCTHcPcJRs6l9XuCt/DtvTnrOreEy7FW CYedzjfY35bmBdvm9fvabVvlukL2kMeJ2D+1XZM3NAtJrlqfWGf5O8+VYTMHp94W5sCHKU1O r506ryqxFGckGmoxFxUnAgB4FUFFAAMAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrALMWRmVeSWpSXmKPExsVy+t/xy7peAdsiDY7PMrY42PyQyYHRY9XB D0wBjFFcNimpOZllqUX6dglcGbMOPWUsaEiqmLztK3MD4xWPLkZODgkBE4mbd+8zQdhiEhfu rWfrYuTiEBJYwiixp20PO4Qzg0li59GtrBDOOUaJsz+fMEE4ZxklTt6bzg7SzyKgKnH+TD+Y zSZgKDF102zGLkYODhEBbYn2j2IgYWEBX4nVdz8yg9i8AvYSW2c1gK3mFHCQ+PxzDzPEzOlM En3fX7KCJPgF9CWu/v0EdZ+9xMwrZxghmgUlfky+xwJiMwtoSWze1sQKYctLbF7zFmyBkIC6 xI27u9knMArPQtIyC0nLLCQtCxiZVzGKpJYW56bnFhvpFSfmFpfmpesl5+duYgSG87ZjP7fs YOx6F3yIUYCDUYmHd8ekrZFCrIllxZW5hxglOJiVRHg3+GyLFOJNSaysSi3Kjy8qzUktPsQo zcGiJM7bu2d1pJBAemJJanZqakFqEUyWiYNTqoFxVssV0Y4tc/2T/t/t2bP4dXv+45x7jbve f33s5HVd+8ymrQez5jT2bz2QfmOnlqcmh3mk3OnHB2TW6Fibhm/dvHC3cULrk9ueW6q+OvK6 zdu6z4FDO1aipHNuyEeLsF8S/X6bV7M1up43ixaWmqjnXNnnWp++/nfPwvigy53W86f9PmFT WzlbiaU4I9FQi7moOBEAs59ygGMCAAA= X-CMS-MailID: 20170911085850eucas1p11de108e2666b0011d65ba4ae0592bec0 X-Msg-Generator: CA X-Sender-IP: 182.198.249.180 X-Local-Sender: =?UTF-8?B?UGV0ZXIgU3RlcGhlbnNvbhtTQ1NDLURhdGEgUGxhbmUb?= =?UTF-8?B?7IK87ISx7KCE7J6QG1ByaW5jaXBhbCBFbmdpbmVlciwgU29mdHdhcmU=?= X-Global-Sender: =?UTF-8?B?UGV0ZXIgU3RlcGhlbnNvbhtTQ1NDLURhdGEgUGxhbmUbU2Ft?= =?UTF-8?B?c3VuZyBFbGVjdHJvbmljcxtQcmluY2lwYWwgRW5naW5lZXIsIFNvZnR3YXJl?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDA1Q0QwNTAwNTg=?= CMS-TYPE: 201P X-CMS-RootMailID: 20170908113052epcas5p482d9743d118953c431bef7f194126f0b X-RootMTR: 20170908113052epcas5p482d9743d118953c431bef7f194126f0b References: <20170908082917.v5j4vczoq75vs5lk@sinister.lan.codevat.com> <20170908171703.4b4918ae@pwslap01u.europe.root.pri> On Fri, 8 Sep 2017 17:17:03 +0100 Peter Stephenson wrote: > All this is entirely correct. I wonder if it would be helpful for us to > make it easier to set an emulation at invocation, i.e. "zsh --emulate sh > ..."? I've slightly reordered to try to ensure the maximum compatibility with the previous code, and also added an extra sentence about the usefulness of --emulate compared with the emulate builtin. I'll commit this. pws diff --git a/Doc/Zsh/invoke.yo b/Doc/Zsh/invoke.yo index e03c1e2..a184bc8 100644 --- a/Doc/Zsh/invoke.yo +++ b/Doc/Zsh/invoke.yo @@ -46,6 +46,20 @@ ifzman(zmanref(zshoptions))\ ifnzman(noderef(Options))\ . +The long option `tt(--emulate)' followed (in a separate word) by an +emulation mode may be passed to the shell. +The emulation modes are those described for the tt(emulate) builtin, +see +ifzman(zmanref(zshbuiltins))\ +ifnzman(noderef(Shell Builtin Commands)). +The `tt(--emulate)' option must precede any other options (which might +otherwise be overridden), but following options are honoured, so +may be used to modify the requested emulation mode. Note that certain +extra steps are taken to ensure a smooth emulation when this option +is used compared with the tt(emulate) command within the shell: for +example, variables that conflict with POSIX usage such as tt(path) are +not defined within the shell. + Options may be specified by name using the tt(-o) option. tt(-o) acts like a single-letter option, but takes a following string as the option name. For example, diff --git a/Src/builtin.c b/Src/builtin.c index 2e72ba2..0c2a62a 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -5905,7 +5905,7 @@ bin_emulate(char *nam, char **argv, Options ops, UNUSED(int func)) savehackchar = keyboardhackchar; emulate(shname, opt_R, &new_emulation, new_opts); optlist = newlinklist(); - if (parseopts(nam, &argv, new_opts, &cmd, optlist)) { + if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0)) { ret = 1; goto restore; } diff --git a/Src/init.c b/Src/init.c index 87dd2e2..c537266 100644 --- a/Src/init.c +++ b/Src/init.c @@ -244,33 +244,24 @@ static int restricted; /**/ static void -parseargs(char **argv, char **runscript, char **cmdptr) +parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr) { char **x; LinkList paramlist; + int flags = PARSEARGS_TOPLEVEL; + if (**argv == '-') + flags |= PARSEARGS_LOGIN; argzero = posixzero = *argv++; SHIN = 0; - /* There's a bit of trickery with opts[INTERACTIVE] here. It starts * - * at a value of 2 (instead of 1) or 0. If it is explicitly set on * - * the command line, it goes to 1 or 0. If input is coming from * - * somewhere that normally makes the shell non-interactive, we do * - * "opts[INTERACTIVE] &= 1", so that only a *default* on state will * - * be changed. At the end of the function, a value of 2 gets * - * changed to 1. */ - opts[INTERACTIVE] = isatty(0) ? 2 : 0; /* - * MONITOR is similar: we initialise it to 2, and if it's - * still 2 at the end, we set it to the value of INTERACTIVE. + * parseopts sets up some options after we deal with emulation in + * order to be consistent --- the code in parseopts_setemulate() is + * matched by code at the end of the present function. */ - opts[MONITOR] = 2; /* may be unset in init_io() */ - opts[HASHDIRS] = 2; /* same relationship to INTERACTIVE */ - opts[USEZLE] = 1; /* see below, related to SHINSTDIN */ - opts[SHINSTDIN] = 0; - opts[SINGLECOMMAND] = 0; - if (parseopts(NULL, &argv, opts, cmdptr, NULL)) + if (parseopts(zsh_name, &argv, opts, cmdptr, NULL, flags)) exit(1); /* @@ -334,9 +325,45 @@ parseopts_insert(LinkList optlist, char *base, int optno) } /* + * This sets the global emulation plus the options we traditionally + * set immediately after that. This is just for historical consistency + * --- I don't think those options actually need to be set here. + */ +static void parseopts_setemulate(char *nam, int flags) +{ + emulate(nam, 1, &emulation, opts); /* initialises most options */ + opts[LOGINSHELL] = ((flags & PARSEARGS_LOGIN) != 0); + opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid()); + + /* There's a bit of trickery with opts[INTERACTIVE] here. It starts * + * at a value of 2 (instead of 1) or 0. If it is explicitly set on * + * the command line, it goes to 1 or 0. If input is coming from * + * somewhere that normally makes the shell non-interactive, we do * + * "opts[INTERACTIVE] &= 1", so that only a *default* on state will * + * be changed. At the end of the function, a value of 2 gets * + * changed to 1. */ + opts[INTERACTIVE] = isatty(0) ? 2 : 0; + /* + * MONITOR is similar: we initialise it to 2, and if it's + * still 2 at the end, we set it to the value of INTERACTIVE. + */ + opts[MONITOR] = 2; /* may be unset in init_io() */ + opts[HASHDIRS] = 2; /* same relationship to INTERACTIVE */ + opts[USEZLE] = 1; /* see below, related to SHINSTDIN */ + opts[SHINSTDIN] = 0; + opts[SINGLECOMMAND] = 0; +} + +/* * Parse shell options. - * If nam is not NULL, this is called from a command; don't - * exit on failure. + * + * If (flags & PARSEARGS_TOPLEVEL): + * - we are doing shell initilisation + * - nam is the name under which the shell was started + * - set up emulation and standard options based on that. + * Otherwise: + * - nam is a command name + * - don't exit on failure. * * If optlist is not NULL, it used to form a list of pointers * into new_opts indicating which options have been changed. @@ -345,23 +372,26 @@ parseopts_insert(LinkList optlist, char *base, int optno) /**/ mod_export int parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, - LinkList optlist) + LinkList optlist, int flags) { int optionbreak = 0; int action, optno; char **argv = *argvp; + int toplevel = ((flags & PARSEARGS_TOPLEVEL) != 0u); + int emulate_required = toplevel; + char *top_emulation = nam; *cmdp = 0; #define WARN_OPTION(F, S) \ do { \ - if (nam) \ + if (!toplevel) \ zwarnnam(nam, F, S); \ else \ zerr(F, S); \ } while (0) #define LAST_OPTION(N) \ do { \ - if (nam) { \ + if (!toplevel) { \ if (*argv) \ argv++; \ goto doneargv; \ @@ -381,7 +411,7 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, argv++; goto doneoptions; } - if (nam || *argv != args+1 || **argv != '-') + if (!toplevel || *argv != args+1 || **argv != '-') goto badoptionstring; /* GNU-style long options */ ++*argv; @@ -394,6 +424,19 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, printhelp(); LAST_OPTION(0); } + if (!strcmp(*argv, "emulate")) { + ++argv; + if (!*argv) { + zerr("--emulate: argument required"); + exit(1); + } + if (!emulate_required) { + zerr("--emulate: must precede other options"); + exit(1); + } + top_emulation = *argv; + break; + } /* `-' characters are allowed in long options */ for(args = *argv; *args; args++) if(*args == '-') @@ -402,9 +445,17 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, } if (unset(SHOPTIONLETTERS) && **argv == 'b') { + if (emulate_required) { + parseopts_setemulate(top_emulation, flags); + emulate_required = 0; + } /* -b ends options at the end of this argument */ optionbreak = 1; } else if (**argv == 'c') { + if (emulate_required) { + parseopts_setemulate(top_emulation, flags); + emulate_required = 0; + } /* -c command */ *cmdp = *argv; new_opts[INTERACTIVE] &= 1; @@ -417,15 +468,20 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, return 1; } longoptions: + if (emulate_required) { + parseopts_setemulate(top_emulation, flags); + emulate_required = 0; + } if (!(optno = optlookup(*argv))) { WARN_OPTION("no such option: %s", *argv); return 1; - } else if (optno == RESTRICTED && !nam) { + } else if (optno == RESTRICTED && toplevel) { restricted = action; - } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { + } else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) { WARN_OPTION("can't change option: %s", *argv); } else { - if (dosetopt(optno, action, !nam, new_opts) && nam) { + if (dosetopt(optno, action, toplevel, new_opts) && + !toplevel) { WARN_OPTION("can't change option: %s", *argv); } else if (optlist) { parseopts_insert(optlist, new_opts, optno); @@ -442,15 +498,21 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, } break; } else { + if (emulate_required) { + parseopts_setemulate(top_emulation, flags); + emulate_required = 0; + } if (!(optno = optlookupc(**argv))) { WARN_OPTION("bad option: -%c", **argv); return 1; - } else if (optno == RESTRICTED && !nam) { + } else if (optno == RESTRICTED && toplevel) { restricted = action; - } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { + } else if ((optno == EMACSMODE || optno == VIMODE) && + !toplevel) { WARN_OPTION("can't change option: %s", *argv); } else { - if (dosetopt(optno, action, !nam, new_opts) && nam) { + if (dosetopt(optno, action, toplevel, new_opts) && + !toplevel) { WARN_OPTION("can't change option: -%c", **argv); } else if (optlist) { parseopts_insert(optlist, new_opts, optno); @@ -470,6 +532,10 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp, } doneargv: *argvp = argv; + if (emulate_required) { + parseopts_setemulate(top_emulation, flags); + emulate_required = 0; + } return 0; } @@ -1660,11 +1726,9 @@ zsh_main(UNUSED(int argc), char **argv) fdtable[0] = fdtable[1] = fdtable[2] = FDT_EXTERNAL; createoptiontable(); - emulate(zsh_name, 1, &emulation, opts); /* initialises most options */ - opts[LOGINSHELL] = (**argv == '-'); - opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid()); - /* sets ZLE, INTERACTIVE, SHINSTDIN and SINGLECOMMAND */ - parseargs(argv, &runscript, &cmd); + /* sets emulation, LOGINSHELL, PRIVILEGED, ZLE, INTERACTIVE, + * SHINSTDIN and SINGLECOMMAND */ + parseargs(zsh_name, argv, &runscript, &cmd); SHTTY = -1; init_io(cmd); diff --git a/Src/zsh.h b/Src/zsh.h index abe9a9c..1e982a6 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1361,6 +1361,14 @@ struct options { int argscount, argsalloc; }; +/* Flags to parseargs() */ + +enum { + PARSEARGS_TOPLEVEL = 0x1, /* Call to initialise shell */ + PARSEARGS_LOGIN = 0x2 /* Shell is login shell */ +}; + + /* * Handler arguments are: builtin name, null-terminated argument * list excluding command name, option structure, the funcid element from the diff --git a/Test/B07emulate.ztst b/Test/B07emulate.ztst index 2de097e..7b1592f 100644 --- a/Test/B07emulate.ztst +++ b/Test/B07emulate.ztst @@ -251,3 +251,28 @@ emulate sh -c '[[ a == a ]]' 0:regression test for POSIX_ALIASES reserved words F:Some reserved tokens are handled in alias expansion + + for mode in ksh bash zsh; do + $ZTST_testdir/../Src/zsh --emulate $mode -f -c 'emulate' + done +0:--emulate option +>ksh +>sh +>zsh + + $ZTST_testdir/../Src/zsh -f --emulate sh +1:--emulate must be first +*?*: --emulate: must precede other options + + $ZTST_testdir/../Src/zsh --emulate +1:--emulate needs an argument +*?*: --emulate: argument required + + for opt in shwordsplit noshwordsplit; do + $ZTST_testdir/../Src/zsh --emulate sh -f -o $opt -c ' + [[ -o shwordsplit ]] && echo yes || echo no + ' + done +0:--emulate followed by other options +>yes +>no