about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBarton E. Schaefer <schaefer@zsh.org>2014-02-15 13:49:26 -0800
committerBarton E. Schaefer <schaefer@zsh.org>2014-02-15 13:49:26 -0800
commit956d35ef12a061ec41396b1e0469bd166f6ef007 (patch)
treec0c11543b53c91aadd6fcd4ab854cb902251508e
parentae0b56cdda382732abc7c657e14f36a1e3d4d302 (diff)
downloadzsh-956d35ef12a061ec41396b1e0469bd166f6ef007.tar.gz
zsh-956d35ef12a061ec41396b1e0469bd166f6ef007.tar.xz
zsh-956d35ef12a061ec41396b1e0469bd166f6ef007.zip
32388: zparseopts -K preserves individual associative array elements
-rw-r--r--ChangeLog3
-rw-r--r--Doc/Zsh/mod_zutil.yo10
-rw-r--r--Src/Modules/zutil.c43
3 files changed, 50 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 14aac0671..cef2af0ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,9 @@
 	* 32389 (with Jun Takimoto): Test/X02zlevi.ztst, Test/comptest:
 	additional PTY and keybinding adjustments
 
+	* 32388: Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c: zparseopts -K
+	preserves individual associative array elements
+
 2014-02-14  Oliver Kiddle <opk@zsh.org>
 
 	* 32361: Src/Zle/zle_tricky.c: don't reset lastline before completion
diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo
index 726b0f055..ee9ec3adf 100644
--- a/Doc/Zsh/mod_zutil.yo
+++ b/Doc/Zsh/mod_zutil.yo
@@ -251,10 +251,12 @@ any not described by the var(specs).  This is similar to using the tt(shift)
 builtin.
 )
 item(tt(-K))(
-With this option, the arrays specified with the tt(-a) and tt(-A)
-options and with the `tt(=)var(array)' forms are kept unchanged when none
-of the var(specs) for them is used.  This allows assignment of default
-values to them before calling tt(zparseopts).
+With this option, the arrays specified with the tt(-a) option and with the
+`tt(=)var(array)' forms are kept unchanged when none of the var(specs) for
+them is used.  Otherwise the entire array is replaced when any of the
+var(specs) is used.  Individual elements of associative arrays specified
+with the tt(-A) option are preserved by tt(-K).  This allows assignment of
+default values to arrays before calling tt(zparseopts).
 )
 item(tt(-M))(
 This changes the assignment rules to implement a map among equivalent
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 399c45f46..46b29f237 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -1543,6 +1543,45 @@ add_opt_val(Zoptdesc d, char *arg)
     }
 }
 
+/*
+ * For "zparseopts -K -A assoc ..." this function copies the keys and
+ * values from the default and allocates the extra space for any parsed
+ * values having the same keys.  If there are no new values, creates an
+ * empty array.  Returns a pointer to the NULL element marking the end.
+ *
+ *  aval = pointer to the newly allocated array
+ *  assoc = name of the default hash param to copy
+ *  keep = whether we need to make the copy at all
+ *  num = count of new values to add space for
+ */
+static char **
+zalloc_default_array(char ***aval, char *assoc, int keep, int num)
+{
+    char **ap = 0;
+
+    *aval = 0;
+    if (keep && num) {
+	struct value vbuf;
+	Value v = fetchvalue(&vbuf, &assoc, 0,
+			     SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY);
+	if (v && v->isarr) {
+	    char **dp, **dval = getarrvalue(v);
+	    int dnum = (dval ? arrlen(dval) : 0) + 1;
+	    *aval = (char **) zalloc(((num * 2) + dnum) * sizeof(char *));
+	    for (ap = *aval, dp = dval; dp && *dp; dp++) {
+		*ap = (char *) zalloc(strlen(*dp) + 1);
+		strcpy(*ap++, *dp);
+	    }
+	    *ap = NULL;
+	}
+    }
+    if (!ap) {
+	ap = *aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *));
+	*ap = NULL;
+    }
+    return ap;
+}
+
 static int
 bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 {
@@ -1825,8 +1864,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 		num++;
 
 	if (!keep || num) {
-	    aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *));
-	    for (ap = aval, d = opt_descs; d; d = d->next) {
+	    ap = zalloc_default_array(&aval, assoc, keep, num);
+	    for (d = opt_descs; d; d = d->next) {
 		if (d->vals) {
 		    *ap++ = n = (char *) zalloc(strlen(d->name) + 2);
 		    *n = '-';