about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-10-30 14:01:32 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-10-30 14:01:32 +0000
commita232ab562423eccb9523c190c5e03242320cc3fd (patch)
tree78161b5cbd651fd5174689950c226b301addd653
parent12a38ba4f725e423e9f5ab4c87af7fc03663b90e (diff)
downloadzsh-a232ab562423eccb9523c190c5e03242320cc3fd.tar.gz
zsh-a232ab562423eccb9523c190c5e03242320cc3fd.tar.xz
zsh-a232ab562423eccb9523c190c5e03242320cc3fd.zip
users/12149: "@" with splitting in double quotes retains empty fields
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/expn.yo11
-rw-r--r--Src/subst.c23
-rw-r--r--Test/D04parameter.ztst32
4 files changed, 62 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index cf9096faa..757821aff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2007-10-30  Peter Stephenson  <pws@csr.com>
 
+	* users/12149: Doc/Zsh/expn.yo, Src/subst.c,
+	Test/D04parameter.ztst:  "${(@s.:.)...}" retains empty
+	fields, although "${(s.:.)...}" remains backward compatible.
+
+2007-10-30  Peter Stephenson  <pws@csr.com>
+
 	* 24030, adapted: Src/Modules/curses.c: turning off a key timeout
 	on Solaris 8 seemed to need leaving and re-entering cbreak mode.
 	This can't be done per-window, so make this specific to Solaris
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index cc87ebe6f..f48616580 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -960,6 +960,17 @@ separator var(string).  Note that a var(string) of two or more
 characters means that all of them must match in sequence; this differs from
 the treatment of two or more characters in the tt(IFS) parameter.
 See also the tt(=) flag and the tt(SH_WORD_SPLIT) option.
+
+For historical reasons, the usual behaviour that empty array elements
+are retained inside double quotes is disabled for arrays generated
+by splitting; hence the following:
+
+example(line="one::three"
+print -l "${(s.:.)line}")
+
+produces two lines of output for tt(one) and tt(three) and elides the
+empty field.  To override this behaviour, supply the "(@)" flag as well,
+i.e.  tt("${(@s.:.)line}").
 )
 enditem()
 
diff --git a/Src/subst.c b/Src/subst.c
index 6ce723acd..e586ede9a 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1260,13 +1260,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
      * parameter (the value v) to storing them in val and aval.
      * However, sometimes you find v reappearing temporarily.
      *
-     * The values -1 and 2 are special to isarr.  It looks like 2 is
-     * some kind of an internal flag to do with whether the array's been
-     * copied, in which case I don't know why we don't use the copied
-     * flag, but they do both occur close together so they presumably
-     * have different effects.  The value -1 is used to force us to
-     * keep an empty array.  It's tested in the YUK chunk (I mean the
-     * one explicitly marked as such).
+     * The values -1 and 2 are special to isarr.  The value -1 is used
+     * to force us to keep an empty array.  It's tested in the YUK chunk
+     * (I mean the one explicitly marked as such).  The value 2
+     * indicates an array has come from splitting a scalar.  We use
+     * that to override the usual rule that in double quotes we don't
+     * remove empty elements (so "${(s.:):-foo::bar}" produces two
+     * words).  This seems to me to be quite the wrong thing to do,
+     * but it looks like code may be relying on it.  So we require (@)
+     * as well before we keep the empty fields (look for assignments
+     * like "isarr = nojoin ? 1 : 2").
      */
     int isarr = 0;
     /*
@@ -2453,7 +2456,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		    char *arr[2], **t, **a, **p;
 		    if (spsep || spbreak) {
 			aval = sepsplit(val, spsep, 0, 1);
-			isarr = 2;
+			isarr = nojoin ? 1 : 2;
 			l = arrlen(aval);
 			if (l && !*(aval[l-1]))
 			    l--;
@@ -2772,7 +2775,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	    else if (!aval[1])
 		val = aval[0];
 	    else
-		isarr = 2;
+		isarr = nojoin ? 1 : 2;
 	}
 	if (isarr)
 	    l->list.flags |= LF_ARRAY;
@@ -2974,7 +2977,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	    val = getdata(firstnode(list));
 	else {
 	    aval = hlinklist2array(list, 0);
-	    isarr = 2;
+	    isarr = nojoin ? 1 : 2;
 	    l->list.flags |= LF_ARRAY;
 	}
 	copied = 1;
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 1910e60be..e8718a691 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -942,3 +942,35 @@
 >some
 >sunny
 >day
+
+  foo="line:with::missing::fields:in:it"
+  print -l ${(s.:.)foo}
+0:Removal of empty fields in unquoted splitting
+>line
+>with
+>missing
+>fields
+>in
+>it
+
+  foo="line:with::missing::fields:in:it"
+  print -l "${(s.:.)foo}"
+0:Hacky removal of empty fields in quoted splitting with no "@"
+>line
+>with
+>missing
+>fields
+>in
+>it
+
+  foo="line:with::missing::fields:in:it"
+  print -l "${(@s.:.)foo}"
+0:Retention of empty fields in quoted splitting with "@"
+>line
+>with
+>
+>missing
+>
+>fields
+>in
+>it