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

Re: Bug in banghist-like expansions?



On Fri, 26 Feb 2010 20:58:39 +0100
Frank Terbeck <ft@xxxxxxxxxxxxxxxxxxx> wrote:
> zsh% baz=/foo/bar
> zsh% print ${baz:s/\//l/}
> zsh: unrecognized modifier
>> 
> I couldn't find a limitation in the manual about escaping the delimiter
> in such expansions in `zshexpn(1)'. Is this a bug or am I missing
> something?

Yes, it is documented that this should work, if you can find it.  The :s
documentation is a bit wayward (and just confused me, too): the full
explanation is further down the page at the end of the list of
modifiers.

There are actually four distinct cases to fix.

Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.109
diff -p -u -r1.109 expn.yo
--- Doc/Zsh/expn.yo	9 Feb 2010 20:37:26 -0000	1.109
+++ Doc/Zsh/expn.yo	26 Feb 2010 23:18:29 -0000
@@ -273,6 +273,8 @@ The forms `tt(gs/)var(l)tt(/)var(r)' and
 perform global substitution, i.e. substitute every occurrence of var(r)
 for var(l).  Note that the tt(g) or tt(:G) must appear in exactly the
 position shown.
+
+See further notes on this form of substitution below.
 )
 item(tt(&))(
 Repeat the previous tt(s) substitution.  Like tt(s), may be preceded
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.100
diff -p -u -r1.100 subst.c
--- Src/subst.c	8 Feb 2010 11:53:56 -0000	1.100
+++ Src/subst.c	26 Feb 2010 23:18:30 -0000
@@ -3282,6 +3282,13 @@ modify(char **str, char **ptr)
 		ptr1 += charlen;
 		for (ptr2 = ptr1, charlen = 0; *ptr2; ptr2 += charlen) {
 		    convchar_t del2;
+		    if ((*ptr2 == Bnull || *ptr2 == '\\') && ptr2[1]) {
+			/* in double quotes, the backslash isn't tokenized */
+			if (*ptr2 == '\\')
+			    *ptr2 = Bnull;
+			charlen = 2;
+			continue;
+		    }
 		    charlen = MB_METACHARLENCONV(ptr2, &del2);
 #ifdef MULTIBYTE_SUPPORT
 		    if (del2 == WEOF)
@@ -3301,6 +3308,13 @@ modify(char **str, char **ptr)
 		*ptr1end = '\0';
 		for (ptr3 = ptr2, charlen = 0; *ptr3; ptr3 += charlen) {
 		    convchar_t del3;
+		    if ((*ptr3 == Bnull || *ptr3 == '\\') && ptr3[1]) {
+			/* in double quotes, the backslash isn't tokenized */
+			if (*ptr3 == '\\')
+			    *ptr3 = Bnull;
+			charlen = 2;
+			continue;
+		    }
 		    charlen = MB_METACHARLENCONV(ptr3, &del3);
 #ifdef MULTIBYTE_SUPPORT
 		    if (del3 == WEOF)
Index: Test/D04parameter.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/D04parameter.ztst,v
retrieving revision 1.38
diff -p -u -r1.38 D04parameter.ztst
--- Test/D04parameter.ztst	5 Sep 2009 19:49:20 -0000	1.38
+++ Test/D04parameter.ztst	26 Feb 2010 23:18:30 -0000
@@ -947,6 +947,18 @@
 >/
 >/
 
+  baz=foo/bar
+  zab=oof+rab
+  print ${baz:s/\//+/}
+  print "${baz:s/\//+/}"
+  print ${zab:s/+/\//}
+  print "${zab:s/+/\//}"
+0:Quoting of separator in substitution modifier
+>foo+bar
+>foo+bar
+>oof/rab
+>oof/rab
+
   nully=($'a\0c' $'a\0b\0b' $'a\0b\0a' $'a\0b\0' $'a\0b' $'a\0' $'a')
   for string in ${(o)nully}; do
     for (( i = 1; i <= ${#string}; i++ )); do

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