zsh-workers
 help / color / mirror / code / Atom feed
* Aliasing assignment-ish words (aliases[x=y]=z)
@ 2016-01-01  0:37 Daniel Shahaf
  2016-01-10 19:19 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Shahaf @ 2016-01-01  0:37 UTC (permalink / raw)
  To: zsh-workers

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=us-ascii, Size: 438 bytes --]

    1	$ zsh -f
    2	% aliases[x=y]=z 
    3	% alias -L 
    4	alias run-help=man
    5	alias which-command=whence
    6	alias 'x=y'=z
    7	% which x=y 
    8	x=y: aliased to z
    9	% x=y
   10	% echo $+x
   11	1
   12	% 

Shouldn't line 9 have interpreted the word 'x=y' as an alias?  Or
perhaps line 2 should have signaled an error.

Also, the 'alias -L' output for that alias won't work as the code
producing the output intended.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Aliasing assignment-ish words (aliases[x=y]=z)
  2016-01-01  0:37 Aliasing assignment-ish words (aliases[x=y]=z) Daniel Shahaf
@ 2016-01-10 19:19 ` Bart Schaefer
  2016-01-10 19:50   ` Daniel Shahaf
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2016-01-10 19:19 UTC (permalink / raw)
  To: zsh-workers

On Jan 1, 12:37am, Daniel Shahaf wrote:
} Subject: Aliasing assignment-ish words (aliases[x=y]=z)
}
}     2	% aliases[x=y]=z 
}     9	% x=y
} 
} Shouldn't line 9 have interpreted the word 'x=y' as an alias?

No; alias expansion operates on shell words, and in that position
on the command line "x" "=" and "y" are separate words because of
assignment syntax rules.  The new treatment of "typeset" as keyword
extends this to global aliases and "typeset x=y".

There's more to it than this because "=" and "y" are not subject to
global alias expansion when they appear in "x=y" but that's the basic
premise.

} Or perhaps line 2 should have signaled an error.

It's long-standing practice that you can create alias table entries for
things that it's not actually possible to later interpret as aliases.
This is especially true when assigning to the parameter as you did.

Basically in this case the rule is that if you break it you get to keep
the pieces.

} Also, the 'alias -L' output for that alias won't work as the code
} producing the output intended.

There is no correct output possible in this instance, the alias command
provides no way to escape the equal sign.  I don't see any reasonable
alternative except to add a csh-style alias command where the word and
its expansion can be separate arguments.

That still doesn't help with the assignment-syntax conflict.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Aliasing assignment-ish words (aliases[x=y]=z)
  2016-01-10 19:19 ` Bart Schaefer
@ 2016-01-10 19:50   ` Daniel Shahaf
  2016-01-12  7:44     ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Shahaf @ 2016-01-10 19:50 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

Bart Schaefer wrote on Sun, Jan 10, 2016 at 11:19:43 -0800:
> On Jan 1, 12:37am, Daniel Shahaf wrote:
> } Subject: Aliasing assignment-ish words (aliases[x=y]=z)
> }
> }     2	% aliases[x=y]=z 
> }     9	% x=y
> } 
> } Shouldn't line 9 have interpreted the word 'x=y' as an alias?
> 
> No; alias expansion operates on shell words, and in that position
> on the command line "x" "=" and "y" are separate words because of
> assignment syntax rules.  The new treatment of "typeset" as keyword
> extends this to global aliases and "typeset x=y".
> 
> There's more to it than this because "=" and "y" are not subject to
> global alias expansion when they appear in "x=y" but that's the basic
> premise.
> 
> } Or perhaps line 2 should have signaled an error.
> 
> It's long-standing practice that you can create alias table entries for
> things that it's not actually possible to later interpret as aliases.
> This is especially true when assigning to the parameter as you did.
> 
> Basically in this case the rule is that if you break it you get to keep
> the pieces.
> 

Fair enough.

> } Also, the 'alias -L' output for that alias won't work as the code
> } producing the output intended.
> 
> There is no correct output possible in this instance, the alias command
> provides no way to escape the equal sign.  I don't see any reasonable
> alternative except to add a csh-style alias command where the word and
> its expansion can be separate arguments.
> 

I thought we might want to have 'alias -L' handle LHSes with '=' in them
specially: omit them from the output with a warning, or maybe fail hard
with no output at all.  It'd be slightly friendlier than emitting wrong
output (that may override other aliases) letting the user keep both
pieces.

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.)

Thanks,

Daniel

> That still doesn't help with the assignment-syntax conflict.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Aliasing assignment-ish words (aliases[x=y]=z)
  2016-01-10 19:50   ` Daniel Shahaf
@ 2016-01-12  7:44     ` Bart Schaefer
  2016-01-13  0:57       ` Daniel Shahaf
  2016-01-13  0:58       ` Daniel Shahaf
  0 siblings, 2 replies; 6+ messages in thread
From: Bart Schaefer @ 2016-01-12  7:44 UTC (permalink / raw)
  To: zsh-workers

On Jan 10,  7:50pm, Daniel Shahaf wrote:
}
} I thought we might want to have 'alias -L' handle LHSes with '=' in them
} specially: omit them from the output with a warning, or maybe fail hard

Yeah, that probably wouldn't be too difficult (I'd go with the warning).

} 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.)

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).

I find this interesting:

    torch% alias '==foo'
    zsh: bad assignment

"Bad assignment"?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Aliasing assignment-ish words (aliases[x=y]=z)
  2016-01-12  7:44     ` Bart Schaefer
@ 2016-01-13  0:57       ` Daniel Shahaf
  2016-01-13  0:58       ` Daniel Shahaf
  1 sibling, 0 replies; 6+ messages in thread
From: Daniel Shahaf @ 2016-01-13  0:57 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Mon, Jan 11, 2016 at 23:44:29 -0800:
> On Jan 10,  7:50pm, Daniel Shahaf wrote:
> } I thought we might want to have 'alias -L' handle LHSes with '=' in them
> } specially: omit them from the output with a warning, or maybe fail hard
> 
> Yeah, that probably wouldn't be too difficult (I'd go with the warning).
> 

Okay.

diff --git a/Src/hashtable.c b/Src/hashtable.c
index 2d1ff87..0664c36 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -1276,6 +1276,15 @@ printaliasnode(HashNode hn, int printflags)
     }
 
     if (printflags & PRINT_LIST) {
+	/* Fast fail on unrepresentable values. */
+	if (strchr(a->node.nam, '=')) {
+	    zwarn("invalid alias '%s' encountered while printing aliases", 
+		  a->node.nam);
+	    /* ### TODO: Return an error status to the C caller */
+	    return;
+	}
+
+	/* Normal path. */
 	printf("alias ");
 	if (a->node.flags & ALIAS_SUFFIX)
 	    printf("-s ");
diff --git a/Test/A02alias.ztst b/Test/A02alias.ztst
index 3896178..cfa9dae 100644
--- a/Test/A02alias.ztst
+++ b/Test/A02alias.ztst
@@ -96,3 +96,11 @@
 0:unalias -as
 >foo is a suffix alias for print
 >foo: suffix alias
+
+  aliases[x=y]=z
+  alias -L | grep x=y
+  echo $pipestatus[1]
+0:printing invalid aliases warns
+>0
+?(eval):2: invalid alias 'x=y' encountered while printing aliases
+# Currently, 'alias -L' returns 0 in this case.  Perhaps it should return 1.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Aliasing assignment-ish words (aliases[x=y]=z)
  2016-01-12  7:44     ` Bart Schaefer
  2016-01-13  0:57       ` Daniel Shahaf
@ 2016-01-13  0:58       ` Daniel Shahaf
  1 sibling, 0 replies; 6+ messages in thread
From: Daniel Shahaf @ 2016-01-13  0:58 UTC (permalink / raw)
  To: zsh-workers

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


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-01-13  0:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-01  0:37 Aliasing assignment-ish words (aliases[x=y]=z) Daniel Shahaf
2016-01-10 19:19 ` Bart Schaefer
2016-01-10 19:50   ` Daniel Shahaf
2016-01-12  7:44     ` Bart Schaefer
2016-01-13  0:57       ` Daniel Shahaf
2016-01-13  0:58       ` Daniel Shahaf

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).