zsh-workers
 help / color / mirror / code / Atom feed
* bug in parameter expansion
@ 2012-11-07 19:13 Scott Moser
  2012-11-07 20:45 ` Peter Stephenson
  0 siblings, 1 reply; 4+ messages in thread
From: Scott Moser @ 2012-11-07 19:13 UTC (permalink / raw)
  To: zsh-workers

This issue was initially reported against shell code delivered in
cloud-init at [1], but it seems to me to be a bug in zsh's posix shell
behavior.

$ for shell in /bin/dash /bin/bash /bin/ksh /bin/zsh; do \
  echo "=== $shell ==="; $shell -c 'echo "${1%%=*}"' \
  -- A=B; done
=== /bin/dash ===
A
=== /bin/bash ===
A
=== /bin/ksh ===
A
=== /bin/zsh ===
zsh:1: * not found

It also has the issue when matching prefix (#):
$ zsh -c 'echo ${1#=?}' -- =AB
zsh:1: ? not found
$ bash -c 'echo ${1#=?}' -- =AB
B

It is seemingly easily worked around by escaping the '=' like:
  $ zsh -c 'echo "${1%%\=*}"' -- A=B
  A
or:
  zsh -c 'equal="="; echo "${1%%${equal}*}"' -- A=B
  A

Scott
--
[1] https://bugs.launchpad.net/ubuntu/+source/cloud-init/+bug/1073077


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

* Re: bug in parameter expansion
  2012-11-07 19:13 bug in parameter expansion Scott Moser
@ 2012-11-07 20:45 ` Peter Stephenson
  2012-11-08 14:53   ` Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Peter Stephenson @ 2012-11-07 20:45 UTC (permalink / raw)
  To: zsh-workers

On Wed, 7 Nov 2012 14:13:36 -0500 (EST)
Scott Moser <smoser@ubuntu.com> wrote:
> This issue was initially reported against shell code delivered in
> cloud-init at [1], but it seems to me to be a bug in zsh's posix shell
> behavior.

As it happens, that's not quite true, because zsh doesn't have POSIX
behaviour by default, and it will work as you expect if you invoke it as
sh or "setopt noequals".

It's still pretty funny, even in the native mode, though.  That's a very
strange place for =-expansion to happen.

It's happening because we look at the string "=*" and we tokenise that to
make patterns (such as the "*") active if it was in quotes.  We tokenise
the "=" the same as if it were a command line argument.  I can't think
of any occasion we'd want to do that if we know it's *not* a command
line argument: there's already a flag for this, so the fix is simple.
Maybe someone can think of a pathological case where we should do the
=-expansion (or =(...) expansion) even in a substituted string, but
I can't think of one.  This doesn't trigger any test failures.

Index: Src/lex.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/lex.c,v
retrieving revision 1.73
diff -p -u -r1.73 lex.c
--- Src/lex.c	5 Oct 2012 21:35:06 -0000	1.73
+++ Src/lex.c	7 Nov 2012 20:37:05 -0000
@@ -1265,51 +1265,53 @@ gettokstr(int c, int sub)
 		break;
 	    goto brk;
 	case LX2_EQUALS:
-	    if (intpos) {
-		e = hgetc();
-		if (e != '(') {
-		    hungetc(e);
-		    lexstop = 0;
-		    c = Equals;
-		} else {
-		    add(Equals);
-		    if (skipcomm()) {
-			peek = LEXERR;
-			goto brk;
-		    }
-		    c = Outpar;
-		}
-	    } else if (!sub && peek != ENVSTRING &&
-		       incmdpos && !bct && !brct) {
-		char *t = tokstr;
-		if (idigit(*t))
-		    while (++t < bptr && idigit(*t));
-		else {
-		    int sav = *bptr;
-		    *bptr = '\0';
-		    t = itype_end(t, IIDENT, 0);
-		    if (t < bptr) {
-			skipparens(Inbrack, Outbrack, &t);
+	    if (!sub) {
+		if (intpos) {
+		    e = hgetc();
+		    if (e != '(') {
+			hungetc(e);
+			lexstop = 0;
+			c = Equals;
 		    } else {
-			*bptr = sav;
+			add(Equals);
+			if (skipcomm()) {
+			    peek = LEXERR;
+			    goto brk;
+			}
+			c = Outpar;
 		    }
-		}
-		if (*t == '+')
-                    t++;
-		if (t == bptr) {
-		    e = hgetc();
-		    if (e == '(' && incmdpos) {
+		} else if (peek != ENVSTRING &&
+			   incmdpos && !bct && !brct) {
+		    char *t = tokstr;
+		    if (idigit(*t))
+			while (++t < bptr && idigit(*t));
+		    else {
+			int sav = *bptr;
 			*bptr = '\0';
-			return ENVARRAY;
+			t = itype_end(t, IIDENT, 0);
+			if (t < bptr) {
+			    skipparens(Inbrack, Outbrack, &t);
+			} else {
+			    *bptr = sav;
+			}
 		    }
-		    hungetc(e);
-		    lexstop = 0;
-		    peek = ENVSTRING;
-		    intpos = 2;
+		    if (*t == '+')
+			t++;
+		    if (t == bptr) {
+			e = hgetc();
+			if (e == '(' && incmdpos) {
+			    *bptr = '\0';
+			    return ENVARRAY;
+			}
+			hungetc(e);
+			lexstop = 0;
+			peek = ENVSTRING;
+			intpos = 2;
+		    } else
+			c = Equals;
 		} else
 		    c = Equals;
-	    } else
-		c = Equals;
+	    }
 	    break;
 	case LX2_BKSLASH:
 	    c = hgetc();

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


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

* Re: bug in parameter expansion
  2012-11-07 20:45 ` Peter Stephenson
@ 2012-11-08 14:53   ` Bart Schaefer
  2012-11-08 15:20     ` Peter Stephenson
  0 siblings, 1 reply; 4+ messages in thread
From: Bart Schaefer @ 2012-11-08 14:53 UTC (permalink / raw)
  To: zsh-workers

On Nov 7,  8:45pm, Peter Stephenson wrote:
}
} It's happening because we look at the string "=*" and we tokenise that to
} make patterns (such as the "*") active if it was in quotes.  We tokenise
} the "=" the same as if it were a command line argument.  I can't think
} of any occasion we'd want to do that if we know it's *not* a command
} line argument: there's already a flag for this, so the fix is simple.

This looks OK to me, but just to be sure I understand:  The flag you're
talking about in this context is "sub" rather than "incmdpos"?  For those
who may be attempting to learn the code, "incmdpos" really does mean "in
the command position", e.g., the first word in the buffer or the first
word after a separator such as ";" or "|", among other cases.

The "sub" flag doesn't directly mean "not a command line argument" here,
unless I'm mistaken?


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

* Re: bug in parameter expansion
  2012-11-08 14:53   ` Bart Schaefer
@ 2012-11-08 15:20     ` Peter Stephenson
  0 siblings, 0 replies; 4+ messages in thread
From: Peter Stephenson @ 2012-11-08 15:20 UTC (permalink / raw)
  To: zsh-workers

On Thu, 08 Nov 2012 06:53:31 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Nov 7,  8:45pm, Peter Stephenson wrote:
> } It's happening because we look at the string "=*" and we tokenise
> } that to make patterns (such as the "*") active if it was in
> } quotes.  We tokenise the "=" the same as if it were a command line
> } argument.  I can't think of any occasion we'd want to do that if
> } we know it's *not* a command line argument: there's already a flag
> } for this, so the fix is simple.
> 
> This looks OK to me, but just to be sure I understand:  The flag
> you're talking about in this context is "sub" rather than
> "incmdpos"?  For those who may be attempting to learn the code,
> "incmdpos" really does mean "in the command position", e.g., the
> first word in the buffer or the first word after a separator such as
> ";" or "|", among other cases.

Yes, the flag I'm talking about is "sub".

I think you probably mean intpos rather than incmdpos; it says we're at
the start of the word, which is the only place you want to do =cmd
expansion.  However, I don't think the code even relies on that --- it
tokenises the "=" and relies on the fact that expansion later only looks
for an active =cmd expansion by checking the first character in the
argument.  Later still tokens are turned back to normal characters.

> The "sub" flag doesn't directly mean "not a command line argument"
> here, unless I'm mistaken?

Umm, yes and no.  No, it's not explicitly saying that.  However, it is
only used in a context where we're doing some substitution to a string
that isn't by itself a command line argument, though it may form part of
a command line argument later.

I think that's OK because at all such points the command line
tokenisation has taken place and it's the normal zsh behaviour that
substitution and globbing doesn't take place on substituted strings.  If
GLOB_SUBST is set, the (re)tokenisation takes place later, because we
don't expect to get tokens out of the early stages of expansion.

pws


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

end of thread, other threads:[~2012-11-08 15:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-07 19:13 bug in parameter expansion Scott Moser
2012-11-07 20:45 ` Peter Stephenson
2012-11-08 14:53   ` Bart Schaefer
2012-11-08 15:20     ` Peter Stephenson

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