From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13810 invoked by alias); 13 Jan 2016 00:58:17 -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: 37592 Received: (qmail 7207 invoked from network); 13 Jan 2016 00:58:16 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.0 Date: Wed, 13 Jan 2016 00:58:14 +0000 From: Daniel Shahaf To: zsh-workers@zsh.org Subject: Re: Aliasing assignment-ish words (aliases[x=y]=z) Message-ID: <20160113005814.GB7091@tarsus.local2> References: <20160110003757.GA18461@tarsus.local2> <160110111943.ZM864@torch.brasslantern.com> <20160110195030.GB1997@tarsus.local2> <160111234429.ZM6760@torch.brasslantern.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <160111234429.ZM6760@torch.brasslantern.com> User-Agent: Mutt/1.5.23 (2014-03-12) Bart Schaefer wrote on Mon, Jan 11, 2016 at 23:44:29 -0800: > On Jan 10, 7:50pm, Daniel Shahaf wrote: > } For what it's worth, the real-world use-case behind this thread is > } a z-sy-h user whose zshrc has an alias "aliases[=]='noglob ='" and > } a function literally named '='. (That alias works as expected, as > } does "aliases[=ls]='...'" even if EQUALS is set.) > > I find this interesting: > > torch% alias '==foo' > zsh: bad assignment > > "Bad assignment"? Comes from getasg() which is shared core of 'alias' 'hash' 'typeset'. > Hm, it also ought to be possible to special case a word starting with > '=' (since it's not possible to alias the empty string to anything). The enclosed patch implements that. However, I have no opinion as to whether it should be committed. To be applied on top of the patch I just sent. diff --git a/Src/builtin.c b/Src/builtin.c index b06bc6d..d8974eb 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1855,11 +1855,13 @@ fcedit(char *ename, char *fn) /* Separate an argument into name=value parts, returning them in an * * asgment structure. Because the asgment structure used is global, * * only one of these can be active at a time. The string s gets placed * - * in this global structure, so it needs to be in permanent memory. */ + * in this global structure, so it needs to be in permanent memory. * + * * + * If allow_equals is set, the 'name' part may start with a '='. */ /**/ static Asgment -getasg(char ***argvp, LinkList assigns) +getasg(char ***argvp, LinkList assigns, int allow_equals) { char *s = **argvp; static struct asgment asg; @@ -1877,7 +1879,7 @@ getasg(char ***argvp, LinkList assigns) } /* check if name is empty */ - if (*s == '=') { + if (*s == '=' && !allow_equals) { zerr("bad assignment"); return NULL; } @@ -1885,6 +1887,8 @@ getasg(char ***argvp, LinkList assigns) asg.is_array = 0; /* search for `=' */ + if (*s == '=' && allow_equals) + ++s; for (; *s && *s != '='; s++); /* found `=', so return with a value */ @@ -2622,7 +2626,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) return 1; } - if (!(asg = getasg(&argv, assigns))) { + if (!(asg = getasg(&argv, assigns, 0))) { unqueue_signals(); return 1; } @@ -2634,7 +2638,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) return 1; } - if (!(asg = getasg(&argv, assigns))) { + if (!(asg = getasg(&argv, assigns, 0))) { unqueue_signals(); return 1; } @@ -2794,7 +2798,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) printflags |= PRINT_NAMEONLY; } - while ((asg = getasg(&argv, assigns))) { + while ((asg = getasg(&argv, assigns, 0))) { LinkList pmlist = newlinklist(); LinkNode pmnode; @@ -2840,7 +2844,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) } /* Take arguments literally. Don't glob */ - while ((asg = getasg(&argv, assigns))) { + while ((asg = getasg(&argv, assigns, 0))) { HashNode hn = (paramtab == realparamtab ? /* getnode2() to avoid autoloading */ paramtab->getnode2(paramtab, asg->name) : @@ -3715,7 +3719,7 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func)) argv++; continue; } - if (!(asg = getasg(&argv, NULL))) { + if (!(asg = getasg(&argv, NULL, 0))) { zwarnnam(name, "bad assignment"); returnval = 1; } else if (ASG_VALUEP(asg)) { @@ -3947,7 +3951,7 @@ bin_alias(char *name, char **argv, Options ops, UNUSED(int func)) /* Take arguments literally. Don't glob */ queue_signals(); - while ((asg = getasg(&argv, NULL))) { + while ((asg = getasg(&argv, NULL, 1))) { if (asg->value.scalar && !OPT_ISSET(ops,'L')) { /* The argument is of the form foo=bar and we are not * * forcing a listing with -L, so define an alias */ diff --git a/Src/hashtable.c b/Src/hashtable.c index 0664c36..51155cf 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -1277,7 +1277,7 @@ printaliasnode(HashNode hn, int printflags) if (printflags & PRINT_LIST) { /* Fast fail on unrepresentable values. */ - if (strchr(a->node.nam, '=')) { + if (strchr(a->node.nam + 1, '=')) { zwarn("invalid alias '%s' encountered while printing aliases", a->node.nam); /* ### TODO: Return an error status to the C caller */ diff --git a/Test/A02alias.ztst b/Test/A02alias.ztst index cfa9dae..24dbbd7 100644 --- a/Test/A02alias.ztst +++ b/Test/A02alias.ztst @@ -104,3 +104,16 @@ >0 ?(eval):2: invalid alias 'x=y' encountered while printing aliases # Currently, 'alias -L' returns 0 in this case. Perhaps it should return 1. + + alias \=="echo hello world" + alias \=foo="echo hello foo" + eval "=" + eval "=foo" + eval "=bar" + # Test the EQUALS option + eval "=pwd" +0:alias whose LHS starts with '=' +>hello world +>hello foo +*>*Test* +?(eval):1: bar not found