about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Doc/Zsh/expn.yo3
-rw-r--r--Doc/Zsh/options.yo3
-rw-r--r--Src/params.c10
-rw-r--r--Src/zsh.h29
-rw-r--r--Test/D04parameter.ztst34
6 files changed, 70 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 756ef0bdd..16e9150ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-10-09  Peter Stephenson  <pws@csr.com>
+
+	* 25831: Doc/Zsh/expn.yo, Doc/Zsh/options.yo, Src/params.c,
+	Src/zsh.h, Test/D04parameter.ztst: ensure failed subscript matches
+	of a type that are documented as strings rather than arrays
+	return an empty string rather than an empty array to avoid
+	strange RC_EXPAND_PARAM behaviour.
+
 2008-10-08  Peter Stephenson  <pws@csr.com>
 
 	* Nikolai Weibull: 25828: Completion/Unix/Command/_rm,
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index e2434431a..02b95d4f0 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -611,7 +611,8 @@ var(foo)tt(${)var(xx)tt(})var(bar),
 where the parameter var(xx)
 is set to tt(LPAR())var(a b c)tt(RPAR()), are substituted with
 `var(fooabar foobbar foocbar)' instead of the default
-`var(fooa b cbar)'.
+`var(fooa b cbar)'.  Note that an empty array will therefore cause
+all arguments to be removed.
 
 Internally, each such expansion is converted into the
 equivalent list for brace expansion.  E.g., tt(${^var}) becomes
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 5c7b29cfd..e3bc27127 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -485,7 +485,8 @@ Array expansions of the form
 `var(foo)tt(${)var(xx)tt(})var(bar)', where the parameter
 var(xx) is set to tt(LPAR())var(a b c)tt(RPAR()), are substituted with
 `var(fooabar foobbar foocbar)' instead of the default
-`var(fooa b cbar)'.
+`var(fooa b cbar)'.  Note that an empty array will therefore cause
+all arguments to be removed.
 )
 pindex(REMATCH_PCRE)
 cindex(regexp, PCRE)
diff --git a/Src/params.c b/Src/params.c
index 65b3ecff8..71cb2a907 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -1810,11 +1810,10 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
 	    /* Overload v->isarr as the flag bits for hashed arrays. */
 	    v->isarr = flags | (isvarat ? SCANPM_ISVAR_AT : 0);
 	    /* If no flags were passed, we need something to represent *
-	     * `true' yet differ from an explicit WANTVALS.  This is a *
-	     * bit of a hack, but makes some sense:  When no subscript *
-	     * is provided, all values are substituted.                */
+	     * `true' yet differ from an explicit WANTVALS.  Use a     *
+	     * special flag for this case.                             */
 	    if (!v->isarr)
-		v->isarr = SCANPM_MATCHMANY;
+		v->isarr = SCANPM_ARRONLY;
 	}
 	v->pm = pm;
 	v->flags = 0;
@@ -2188,7 +2187,8 @@ setstrvalue(Value v, char *val)
 	zsfree(val);
 	return;
     }
-    if ((v->pm->node.flags & PM_HASHED) && (v->isarr & SCANPM_MATCHMANY)) {
+    if ((v->pm->node.flags & PM_HASHED) &&
+	(v->isarr & (SCANPM_MATCHMANY|SCANPM_ARRONLY))) {
 	zerr("%s: attempt to set slice of associative array", v->pm->node.nam);
 	zsfree(val);
 	return;
diff --git a/Src/zsh.h b/Src/zsh.h
index 2ceab1dca..94d4503e4 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1532,16 +1532,25 @@ struct tieddata {
 #define TYPESET_OPTNUM "LRZiEF"
 
 /* Flags for extracting elements of arrays and associative arrays */
-#define SCANPM_WANTVALS   (1<<0)
-#define SCANPM_WANTKEYS   (1<<1)
-#define SCANPM_WANTINDEX  (1<<2)
-#define SCANPM_MATCHKEY   (1<<3)
-#define SCANPM_MATCHVAL   (1<<4)
-#define SCANPM_MATCHMANY  (1<<5)
-#define SCANPM_ASSIGNING  (1<<6)
-#define SCANPM_KEYMATCH   (1<<7)
-#define SCANPM_DQUOTED    (1<<8)
-#define SCANPM_ISVAR_AT   ((-1)<<15)	/* Only sign bit is significant */
+#define SCANPM_WANTVALS   (1<<0) /* Return value includes hash values */
+#define SCANPM_WANTKEYS   (1<<1) /* Return value includes hash keys */
+#define SCANPM_WANTINDEX  (1<<2) /* Return value includes array index */
+#define SCANPM_MATCHKEY   (1<<3) /* Subscript matched against key */
+#define SCANPM_MATCHVAL   (1<<4) /* Subscript matched against value */
+#define SCANPM_MATCHMANY  (1<<5) /* Subscript matched repeatedly, return all */
+#define SCANPM_ASSIGNING  (1<<6) /* Assigning whole array/hash */
+#define SCANPM_KEYMATCH   (1<<7) /* keys of hash treated as patterns */
+#define SCANPM_DQUOTED    (1<<8) /* substitution was double-quoted
+				  * (only used for testing early end of
+				  * subscript)
+				  */
+#define SCANPM_ARRONLY    (1<<9) /* value is array but we don't
+				  * necessarily want to match multiple
+				  * elements
+				  */
+#define SCANPM_ISVAR_AT   ((-1)<<15)	/* "$foo[@]"-style substitution
+					 * Only sign bit is significant
+					 */
 
 /*
  * Flags for doing matches inside parameter substitutions, i.e.
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 376932b34..4cd137bbd 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1086,3 +1086,37 @@
 >no
 >no
 >no
+
+  rcexbug() {
+    emulate -L zsh
+    setopt rcexpandparam
+    local -A hash
+    local -a full empty
+    full=(X x)
+    hash=(X x)
+    print ORDINARY ARRAYS
+    : The following behaves as documented in zshoptions
+    print FULL expand=$full
+    : Empty arrays remove the adjacent argument
+    print EMPTY expand=$empty
+    print ASSOCIATIVE ARRAY
+    print Subscript flags returning many values
+    print FOUND key=$hash[(I)X] val=$hash[(R)x]
+    : This should behave like $empty, and does
+    print LOST key=$hash[(I)y] val=$hash[(R)Y]
+    print Subscript flags returning single values
+    : Doc says "substitutes ... empty string"
+    : so must not behave like an empty array
+    print STRING key=$hash[(i)y] val=$hash[(r)Y]
+  }
+  rcexbug
+0:Lookup failures on elements of arrays with RC_EXPAND_PARAM
+>ORDINARY ARRAYS
+>FULL expand=X expand=x
+>EMPTY
+>ASSOCIATIVE ARRAY
+>Subscript flags returning many values
+>FOUND key=X val=x
+>LOST
+>Subscript flags returning single values
+>STRING key= val=