Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Is this a bug? Why not?



On Sat, 17 Apr 2010 15:06:53 +0200
Mikael Magnusson <mikachu@xxxxxxxxx> wrote:
> This patch

(resetting globsubst for the argument of a variable substitution when
the pattern matching is already done)

> breaks at least cd ~-/<tab>

    realpath=${~:-\~$linepath}/

doesn't expand the second "~" despite the first "~" because the second
tilde is quoted.  Strictly this new behaviour is probably correct
because the quote should indeed stop the second tilde being active, but
actually the hack below fixes this so I've left it (even though removing
the backslash seemed to work in this case, too).

> and anything using _pids for me.

That's because given

  desc='  PID TTY          TIME CMD' 
  out=( ' 2591 pts/1    00:00:02 zsh'
        ' 2600 pts/1    00:00:01 dropbox'
        ' 3271 pts/1    00:00:00 zsh'
        ' 3272 pts/1    00:00:00 ps' ) 

this expression:

  pids=( "${(@)${(@M)out#${(l.${#desc[1,(r)(#i)[[:blank:]]pid]}..?.)~:-}[^[:blank:]]#}##*[[:blank:]]}" )

sets

  pids=( '' '' '' '' ) 

Er... obviously.  What's happening is

${(l.${#desc[1,(r)(#i)[[:blank:]]pid]}..?.)~:-}

should turn into ????? which are activated for use in patterns, because
of the "~", but it isn't because globsubst is now turned off when we get
to padding because we already handled the value as the right hand side
of ":-" (i.e. the empty string) so there was no value to activate.

One fix is to leave globsubst on when it's forced by the "~" flag.  That
doesn't screw up sh compatibility, which knows nothing about the flag,
but it's not really the right thing to do, which would be to track
through to see where the text came from and conditionally tokenize it,
yeugh.  The difference is in the case where GLOB_SUBST is set but you're
using zsh substitution syntax, which is not typical (and is the sort of
complicated hybrid I'd dearly love to forbid but will never be able to).
As I'm definitely not doing any major surgery on paramsubst() to
preserve different notions of globsubst at different points in the
function myself (feel free to volunteer) it may be all you will get in
any case.  See the test file for a simpler indication of implications.

Ultimately, I think this hack may actually be the right thing to do
because it preserves traditional zsh behaviour in typical cases (where
the option isn't set and ~ is used to force it) as well as any script
adhering to sh syntax.

I'll think about some documentation.

  "Ceterum censeo functio de substitutione parametrum esse rescribenda"
  ("Furthermore, I am of the opinion that paramsubst() ought to be
   rewritten")  ---  Marcus Porcius Cato the Elder

Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.103
diff -p -u -r1.103 subst.c
--- Src/subst.c	9 Apr 2010 15:40:14 -0000	1.103
+++ Src/subst.c	18 Apr 2010 19:03:01 -0000
@@ -1386,7 +1386,8 @@ paramsubst(LinkList l, LinkNode n, char 
     int plan9 = isset(RCEXPANDPARAM);
     /*
      * Likwise, but with ~ and ~~.  Also, we turn it off later
-     * on if qt is passed down.
+     * on if qt is passed down. The value can go to 2 if we
+     * use ~ to force this on.
      */
     int globsubst = isset(GLOBSUBST);
     /*
@@ -1899,12 +1900,12 @@ paramsubst(LinkList l, LinkNode n, char 
 	     * spsep, NULL means $IFS.
 	     */
 	} else if (c == '~' || c == Tilde) {
-	    /* GLOB_SUBST on or off (doubled) */
+	    /* GLOB_SUBST (forced) on or off (doubled) */
 	    if ((c = *++s) == '~' || c == Tilde) {
 		globsubst = 0;
 		s++;
 	    } else
-		globsubst = 1;
+		globsubst = 2;
 	} else if (c == '+') {
 	    /*
 	     * Return whether indicated parameter is set. 
@@ -1935,7 +1936,8 @@ paramsubst(LinkList l, LinkNode n, char 
 	    break;
     }
     /* Don't activate special pattern characters if inside quotes */
-    globsubst = globsubst && !qt;
+    if (qt)
+	globsubst = 0;
 
     /*
      * At this point, we usually expect a parameter name.
@@ -2417,7 +2419,10 @@ paramsubst(LinkList l, LinkNode n, char 
 		multsub(&val, spbreak && !aspar, (aspar ? NULL : &aval), &isarr, NULL);
 		opts[SHWORDSPLIT] = ws;
 		copied = 1;
-		spbreak = globsubst = 0;
+		spbreak = 0;
+		/* Leave globsubst on if forced */
+		if (globsubst != 2)
+		    globsubst = 0;
 	    }
 	    break;
 	case ':':
Index: Test/D04parameter.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/D04parameter.ztst,v
retrieving revision 1.41
diff -p -u -r1.41 D04parameter.ztst
--- Test/D04parameter.ztst	9 Apr 2010 15:40:14 -0000	1.41
+++ Test/D04parameter.ztst	18 Apr 2010 19:03:01 -0000
@@ -226,10 +226,12 @@
     foo="boring*"
     print ${foo+$foo}
     print ${foo+"$foo"}
+    print ${~foo+"$foo"}
   )
 0:globsubst together with nested quoted expansion
 >boringfile
 >boring*
+>boringfile
 
   print -l "${$(print one word)}" "${=$(print two words)}"
 0:splitting of $(...) inside ${...}

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



Messages sorted by: Reverse Date, Date, Thread, Author