From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10993 invoked by alias); 29 Sep 2016 08:55:38 -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: 39493 Received: (qmail 11679 invoked from network); 29 Sep 2016 08:55:38 -0000 X-Qmail-Scanner-Diagnostics: from mailout1.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.11):SA:0(-3.0/5.0):. Processed in 0.642769 secs); 29 Sep 2016 08:55:38 -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=-3.0 required=5.0 tests=RP_MATCHES_RCVD autolearn=unavailable autolearn_force=no version=3.4.1 X-Envelope-From: p.stephenson@samsung.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: none (ns1.primenet.com.au: domain at samsung.com does not designate permitted sender hosts) X-AuditID: cbfec7ef-f79e76d000005b57-33-57ecd700f5c7 Date: Thu, 29 Sep 2016 09:55:24 +0100 From: Peter Stephenson To: Zsh hackers list Subject: Re: Is "command" working right, yet? Message-id: <20160929095524.48a716e1@pwslap01u.europe.root.pri> In-reply-to: <1c0f3af3-068e-32f5-ee52-5122d519a4b8@inlv.org> 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+NgFnrDIsWRmVeSWpSXmKPExsWy7djP87oM19+EG3z6Z2ZxsPkhkwOjx6qD H5gCGKO4bFJSczLLUov07RK4MjafO8pUsNyhYsb6JvYGxl79LkZODgkBE4l7D36zQNhiEhfu rWfrYuTiEBJYxijx6GIDI4TTyyQxecUsRpiOBa9fIVTNe/ufCcKZxiTx6eg+KOcMo8SsBU+Z IZyzjBIXX81gA+lnEVCVWNO/EGwWm4ChxNRNs8FsEQEtiR0nTwJ1c3AIC+hK/FxZCBLmFbCX uNU6F6yEU8BG4mbLISYQm19AX+Lq309MECfZS8y8coYRol5Q4sfke2APMQvoSGzb9pgdwpaX 2LzmLdg9EgLN7BJPzjQzguySEJCV2HSAGWKOi8STvQ/ZIWxhiVfHt0DZMhKXJ3dDA6mfUeJJ ty/EnBmMEqfP7GCDSFhL9N2+yAixjE9i0rbpzBDzeSU62oQgTA+JY21BENWOEmcObmSZwKg4 C8nVs5BcPQvJ1QsYmVcxiqSWFuempxYb6hUn5haX5qXrJefnbmIEpoHT/46/38H4tDnkEKMA B6MSD2/HqdfhQqyJZcWVuYcYJTiYlUR4F1x9Ey7Em5JYWZValB9fVJqTWnyIUZqDRUmcd++C K+FCAumJJanZqakFqUUwWSYOTqkGxiCvm3Ozf7fOP/Luv+Py2gNiDbo3rhR9ev01ZDF/w6xm ng2yG9waqky/Zj35GXp2Qcq39xGhW999etC82fQmQy/XBYG6GX3eTC621Re6EhZwf55j88Hs 9u51YhdLdq2ZMqfNZblNewzTaxfZ+w9FJ+tc3vP/5Qa5TKel1w2MmS+K5q58LDJv8nIlluKM REMt5qLiRABBvBtB/wIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrGIsWRmVeSWpSXmKPExsVy+t/xa7pXrr0JN5hxxtjiYPNDJgdGj1UH PzAFMEa52WSkJqakFimk5iXnp2TmpdsqhYa46VooKeQl5qbaKkXo+oYEKSmUJeaUAnlGBmjA wTnAPVhJ3y7BLWPzuaNMBcsdKmasb2JvYOzV72Lk5JAQMJFY8PoVG4QtJnHh3nogm4tDSGAJ o0T/6+mMEM4MJokpd89AZc4xSnxfMh8qc5ZRomPlRRaQfhYBVYk1/QsZQWw2AUOJqZtmg9ki AloSO06eZOpi5OAQFtCV+LmyECTMK2Avcat1LlgJp4CNxM2WQ0wQM28xSxz83swOkuAX0Je4 +vcTE8R99hIzr5xhhGgWlPgx+R7YXmag+Zu3NbFC2PISm9e8ZQaxhQTUJW7c3c0+gVF4FpKW WUhaZiFpWcDIvIpRJLW0ODc9t9hIrzgxt7g0L10vOT93EyMwjrYd+7llB2PXu+BDjAIcjEo8 vB2nXocLsSaWFVfmHmKU4GBWEuFdcPVNuBBvSmJlVWpRfnxRaU5q8SFGU2DATGSWEk3OB8Z4 Xkm8oYmhuaWhkbGFhbmRkZI479QPV8KFBNITS1KzU1MLUotg+pg4OKUaGPdwNZ8XCeOPe7Oo TMnxp82/OQmrX8ksMph//pBipPnaCb8usnTcEzuzM0noJqfDrdiOkvi1olfnnuxYUb7+R3NN HPejtfVOGypZBbkXr5i6I0PvxRSZ66esbkr3/lgffrl/561fxtrKokG70o4by66qf7M1e/Kf ywLrVig85Dd533Aq73iBtYsSS3FGoqEWc1FxIgAbYORRuQIAAA== X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20160929085527eucas1p1aa27a90aadf84dcae4fcdf4ba8e363e0 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-HopCount: 7 X-CMS-RootMailID: 20160926031819epcas3p1f38ba621e9a4d500877e2f8f5d1c28c8 X-RootMTR: 20160926031819epcas3p1f38ba621e9a4d500877e2f8f5d1c28c8 References: <160202163744.ZM2066@torch.brasslantern.com> <56B761B8.6000507@inlv.org> <160925201328.ZM24563@torch.brasslantern.com> <20160927110820.7661e8ad@pwslap01u.europe.root.pri> <564b0585-4286-a6c6-d64e-b190af5ace57@inlv.org> <20160928113028.42512c91@pwslap01u.europe.root.pri> <1c0f3af3-068e-32f5-ee52-5122d519a4b8@inlv.org> On Wed, 28 Sep 2016 19:37:46 +0100 Martijn Dekker wrote: > The options combine now, but builtins don't take precedence. As > explained above, I'd expect "command -pv echo" to output simply "echo" > and not "/bin/echo", because it's a builtin. Also 'command -pv :' should > output ':'. OK, I've simply added that as a special case otherwise bin_whence() is going to get too tortuous, plus some tests. pws diff --git a/Src/builtin.c b/Src/builtin.c index 248f929..c78fd9b 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3643,7 +3643,15 @@ bin_whence(char *nam, char **argv, Options ops, int func) returnval = 1; } popheap(); - } else if ((cnam = findcmd(*argv, 1))) { + } else if (func == BIN_COMMAND && + (hn = builtintab->getnode(builtintab, *argv))) { + /* + * Special case for "command -p[vV]" which needs to + * show a builtin in preference to an external command. + */ + builtintab->printnode(hn, printflags); + informed = 1; + } else if ((cnam = findcmd(*argv, 1, func == BIN_COMMAND))) { /* Found external command. */ if (wd) { printf("%s: command\n", *argv); diff --git a/Src/exec.c b/Src/exec.c index c27c41c..c79a278 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -207,7 +207,7 @@ static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = { /* structure for command builtin for when it is used with -v or -V */ static struct builtin commandbn = - BUILTIN(0, 0, bin_whence, 0, -1, BIN_COMMAND, "vV", NULL); + BUILTIN("command", 0, bin_whence, 0, -1, BIN_COMMAND, "pvV", NULL); /* parse string into a list */ @@ -575,6 +575,41 @@ commandnotfound(char *arg0, LinkList args) return doshfunc(shf, args, 1); } +/* + * Search the default path for cmd. + * pbuf of length plen is the buffer to use. + * Return NULL if not found. + */ + +static char * +search_defpath(char *cmd, char *pbuf, int plen) +{ + char *ps = DEFAULT_PATH, *pe = NULL, *s; + + for (ps = DEFAULT_PATH; ps; ps = pe ? pe+1 : NULL) { + pe = strchr(ps, ':'); + if (*ps == '/') { + s = pbuf; + if (pe) { + if (pe - ps >= plen) + continue; + struncpy(&s, ps, pe-ps); + } else { + if (strlen(ps) >= plen) + continue; + strucpy(&s, ps); + } + *s++ = '/'; + if ((s - pbuf) + strlen(cmd) >= plen) + continue; + strucpy(&s, cmd); + if (iscom(pbuf)) + return pbuf; + } + } + return NULL; +} + /* execute an external command */ /**/ @@ -663,27 +698,10 @@ execute(LinkList args, int flags, int defpath) /* for command -p, search the default path */ if (defpath) { - char *s, pbuf[PATH_MAX]; - char *dptr, *pe, *ps = DEFAULT_PATH; - - for(;ps;ps = pe ? pe+1 : NULL) { - pe = strchr(ps, ':'); - if (*ps == '/') { - s = pbuf; - if (pe) - struncpy(&s, ps, pe-ps); - else - strucpy(&s, ps); - *s++ = '/'; - if ((s - pbuf) + strlen(arg0) >= PATH_MAX) - continue; - strucpy(&s, arg0); - if (iscom(pbuf)) - break; - } - } + char pbuf[PATH_MAX]; + char *dptr; - if (!ps) { + if (!search_defpath(arg0, pbuf, PATH_MAX)) { if (commandnotfound(arg0, args) == 0) _exit(0); zerr("command not found: %s", arg0); @@ -760,17 +778,26 @@ execute(LinkList args, int flags, int defpath) /* * Get the full pathname of an external command. * If the second argument is zero, return the first argument if found; - * if non-zero, return the path using heap memory. (RET_IF_COM(X), above). + * if non-zero, return the path using heap memory. (RET_IF_COM(X), + * above). + * If the third argument is non-zero, use the system default path + * instead of the current path. */ /**/ mod_export char * -findcmd(char *arg0, int docopy) +findcmd(char *arg0, int docopy, int default_path) { char **pp; char *z, *s, buf[MAXCMDLEN]; Cmdnam cn; + if (default_path) + { + if (search_defpath(arg0, buf, MAXCMDLEN)) + return docopy ? dupstring(buf) : arg0; + return NULL; + } cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0); if (!cn && isset(HASHCMDS) && !isrelative(arg0)) cn = hashcmd(arg0, path); @@ -2662,24 +2689,76 @@ execcmd(Estate state, int input, int output, int how, int last1) } checked = 0; if ((cflags & BINF_COMMAND) && nextnode(firstnode(args))) { - /* check for options to command builtin */ - char *next = (char *) getdata(nextnode(firstnode(args))); + /* + * Check for options to "command". + * If just -p, this is handled here: use the default + * path to execute. + * If -v or -V, possibly with -p, dispatch to bin_whence + * but with flag to indicate special handling of -p. + * Otherwise, just leave marked as BINF_COMMAND + * modifier with no additional action. + */ + LinkNode argnode = nextnode(firstnode(args)); + char *argdata = (char *) getdata(argnode); char *cmdopt; - if (next && *next == '-' && strlen(next) == 2 && - (cmdopt = strchr("pvV", next[1]))) - { - if (*cmdopt == 'p') { - uremnode(args, firstnode(args)); - use_defpath = 1; - if (nextnode(firstnode(args))) - next = (char *) getdata(nextnode(firstnode(args))); - } else { - hn = &commandbn.node; - is_builtin = 1; + int has_p = 0, has_vV = 0, has_other = 0; + while (*argdata == '-') { + /* Just to be definite, stop on single "-", too, */ + if (!argdata[1] || (argdata[1] == '-' && !argdata[2])) + break; + for (cmdopt = argdata+1; *cmdopt; cmdopt++) { + switch (*cmdopt) { + case 'p': + /* + * If we've got this multiple times (command + * -p -p) we'll treat the second -p as a + * command because we only remove one below. + * Don't think that's a big issue, and it's + * also traditional behaviour. + */ + has_p = 1; + break; + case 'v': + case 'V': + has_vV = 1; + break; + default: + has_other = 1; + break; + } + } + if (has_other) { + /* Don't know how to handle this, so don't */ + has_p = has_vV = 0; break; } + + argnode = nextnode(argnode); + if (!argnode) + break; + argdata = (char *) getdata(argnode); } - if (!strcmp(next, "--")) + if (has_vV) { + /* Leave everything alone, dispatch to whence */ + hn = &commandbn.node; + is_builtin = 1; + break; + } else if (has_p) { + /* Use default path; absorb command and option. */ + uremnode(args, firstnode(args)); + use_defpath = 1; + if ((argnode = nextnode(firstnode(args)))) + argdata = (char *) getdata(argnode); + } + /* + * Else just absorb command and any trailing + * end-of-options marker. This can only occur + * if we just had -p or something including more + * than just -p, -v and -V, in which case we behave + * as if this is command [non-option-stuff]. This + * isn't a good place for standard option handling. + */ + if (!strcmp(argdata, "--")) uremnode(args, firstnode(args)); } if ((cflags & BINF_EXEC) && nextnode(firstnode(args))) { diff --git a/Src/subst.c b/Src/subst.c index 92fde45..ecd7487 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -627,7 +627,7 @@ equalsubstr(char *str, int assign, int nomatch) cmdstr = dupstrpfx(str, pp-str); untokenize(cmdstr); remnulargs(cmdstr); - if (!(cnam = findcmd(cmdstr, 1))) { + if (!(cnam = findcmd(cmdstr, 1, 0))) { if (nomatch) zerr("%s not found", cmdstr); return NULL; diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index 394480c..46a58e9 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -113,6 +113,16 @@ External command cat executed + command -pv cat + command -pv echo + command -p -V cat + command -p -V -- echo +0:command -p in combination +*>*/cat +>echo +>cat is /*/cat +>echo is a shell builtin + cd() { echo Not cd at all; } builtin cd . && unfunction cd 0:`builtin' precommand modifier