summary refs log tree commit diff
path: root/Src/params.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/params.c')
-rw-r--r--Src/params.c192
1 files changed, 127 insertions, 65 deletions
diff --git a/Src/params.c b/Src/params.c
index d628ddf37..c7514de8a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2704,7 +2704,7 @@ setarrvalue(Value v, char **val)
 	    v->pm->gsu.a->setfn(v->pm, val);
     } else if (v->start == -1 && v->end == 0 &&
     	    PM_TYPE(v->pm->node.flags) == PM_HASHED) {
-    	arrhashsetfn(v->pm, val, 1);
+    	arrhashsetfn(v->pm, val, ASSPM_AUGMENT);
     } else if ((PM_TYPE(v->pm->node.flags) == PM_HASHED)) {
 	freearray(val);
 	zerr("%s: attempt to set slice of associative array",
@@ -3186,69 +3186,124 @@ assignaparam(char *s, char **val, int flags)
     if (flags & ASSPM_WARN)
 	check_warn_pm(v->pm, "array", created, may_warn_about_nested_vars);
 
-    if ((flags & ASSPM_KEY_VALUE) && (PM_TYPE(v->pm->node.flags) & PM_ARRAY)) {
-	/*
-	 * This is an ordinary array with key / value pairs.
-	 */
-	int maxlen, origlen;
-	char **aptr, **fullval;
-	zlong *subscripts = (zlong *)zhalloc(arrlen(val) * sizeof(zlong));
-	zlong *iptr = subscripts;
-	if (flags & ASSPM_AUGMENT) {
-	    maxlen = origlen = arrlen(v->pm->gsu.a->getfn(v->pm));
-	} else {
-	    maxlen = origlen = 0;
-	}
-	for (aptr = val; *aptr && aptr[1]; aptr += 2) {
-	    *iptr = mathevali(*aptr);
-	    if (*iptr < 0 ||
-		(!isset(KSHARRAYS) && *iptr == 0)) {
-		unqueue_signals();
-		zerr("bad subscript for direct array assignment: %s", *aptr);
+    /*
+     * At this point, we may have array entries consisting of
+     * - a Marker element --- normally allocated array entry but
+     *   with just Marker char and null
+     * - an array index element --- as normal for associative array,
+     *   but non-standard for normal array which we handle now.
+     * - a value for the indexed element.
+     * This only applies if the flag ASSPM_KEY_VALUE is passed in,
+     * indicating prefork() detected this syntax.
+     *
+     * For associative arrays we just junk the Makrer elements.
+     */
+    if (flags & ASSPM_KEY_VALUE) {
+	char **aptr;
+	if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
+	    /*
+	     * This is an ordinary array with key / value pairs.
+	     */
+	    int maxlen, origlen, nextind;
+	    char **fullval;
+	    zlong *subscripts = (zlong *)zhalloc(arrlen(val) * sizeof(zlong));
+	    zlong *iptr = subscripts;
+	    if (flags & ASSPM_AUGMENT) {
+		maxlen = origlen = arrlen(v->pm->gsu.a->getfn(v->pm));
+	    } else {
+		maxlen = origlen = 0;
+	    }
+	    nextind = 0;
+	    for (aptr = val; *aptr; ) {
+		if (**aptr == Marker) {
+		    *iptr = mathevali(*++aptr);
+		    if (*iptr < 0 ||
+			(!isset(KSHARRAYS) && *iptr == 0)) {
+			unqueue_signals();
+			zerr("bad subscript for direct array assignment: %s", *aptr);
+			return NULL;
+		    }
+		    if (!isset(KSHARRAYS))
+			--*iptr;
+		    nextind = *iptr + 1;
+		    ++iptr;
+		    aptr += 2;
+		} else {
+		    ++nextind;
+		    ++aptr;
+		}
+		if (nextind > maxlen)
+		    maxlen = nextind;
+	    }
+	    fullval = zshcalloc((maxlen+1) * sizeof(char *));
+	    if (!fullval) {
+		zerr("array too large");
 		return NULL;
 	    }
-	    if (!isset(KSHARRAYS))
-		--*iptr;
-	    if (*iptr + 1 > maxlen)
-		maxlen = *iptr + 1;
-	    ++iptr;
-	}
-	fullval = zshcalloc((maxlen+1) * sizeof(char *));
-	if (!fullval) {
-	    zerr("array too large");
-	    return NULL;
-	}
-	fullval[maxlen] = NULL;
-	if (flags & ASSPM_AUGMENT) {
-	    char **srcptr = v->pm->gsu.a->getfn(v->pm);
-	    for (aptr = fullval; aptr <= fullval + origlen; aptr++) {
-		*aptr = ztrdup(*srcptr); 
-		srcptr++;
+	    fullval[maxlen] = NULL;
+	    if (flags & ASSPM_AUGMENT) {
+		char **srcptr = v->pm->gsu.a->getfn(v->pm);
+		for (aptr = fullval; aptr <= fullval + origlen; aptr++) {
+		    *aptr = ztrdup(*srcptr); 
+		    srcptr++;
+		}
 	    }
-	}
-	iptr = subscripts;
-	for (aptr = val; *aptr && aptr[1]; aptr += 2) {
-	    zsfree(*aptr);
-	    fullval[*iptr] = aptr[1];
-	    ++iptr;
-	}
-	if (*aptr) {		/* Shouldn't be possible */
-	    DPUTS(1, "Extra element in key / value array");
-	    zsfree(*aptr);
-	}
-	free(val);
-	for (aptr = fullval; aptr < fullval + maxlen; aptr++) {
+	    iptr = subscripts;
+	    nextind = 0;
+	    for (aptr = val; *aptr; ++aptr) {
+		if (**aptr == Marker) {
+		    zsfree(*aptr);
+		    zsfree(*++aptr); /* Index, no longer needed */
+		    fullval[*iptr] = *++aptr;
+		    nextind = *iptr + 1;
+		    ++iptr;
+		} else {
+		    fullval[nextind] = *aptr;
+		    ++nextind;
+		}
+		/* aptr now on value in both cases */
+	    }
+	    if (*aptr) {		/* Shouldn't be possible */
+		DPUTS(1, "Extra element in key / value array");
+		zsfree(*aptr);
+	    }
+	    free(val);
+	    for (aptr = fullval; aptr < fullval + maxlen; aptr++) {
+		/*
+		 * Remember we don't have sparse arrays but and they're null
+		 * terminated --- so any value we don't set has to be an
+		 * empty string.
+		 */
+		if (!*aptr)
+		    *aptr = ztrdup("");
+	    }
+	    setarrvalue(v, fullval);
+	    unqueue_signals();
+	    return v->pm;
+	} else if (PM_TYPE(v->pm->node.flags & PM_HASHED)) {
 	    /*
-	     * Remember we don't have sparse arrays but and they're null
-	     * terminated --- so any value we don't set has to be an
-	     * empty string.
+	     * We strictly enforce [key]=value syntax for associative
+	     * arrays.  Marker can only indicate a Marker / key / value
+	     * triad; it cannot be there by accident.
+	     *
+	     * It's too inefficient to strip Markers here, and they
+	     * can't be there in the other form --- so just ignore
+	     * them willy nilly lower down.
 	     */
-	    if (!*aptr)
-		*aptr = ztrdup("");
+	    for (aptr = val; *aptr; aptr += 3) {
+		if (**aptr != Marker) {
+		    unqueue_signals();
+		    freearray(val);
+		    zerr("bad [key]=value syntax for associative array");
+		    return NULL;
+		}
+	    }
+	} else {
+	    unqueue_signals();
+	    freearray(val);
+	    zerr("invalid use of [key]=value assignment syntax");
+	    return NULL;
 	}
-	setarrvalue(v, fullval);
-	unqueue_signals();
-	return v->pm;
     }
 
     if (flags & ASSPM_AUGMENT) {
@@ -3741,30 +3796,37 @@ nullsethashfn(UNUSED(Param pm), HashTable x)
 /* Function to set value of an association parameter using key/value pairs */
 
 /**/
-mod_export void
-arrhashsetfn(Param pm, char **val, int augment)
+static void
+arrhashsetfn(Param pm, char **val, int flags)
 {
     /* Best not to shortcut this by using the existing hash table,   *
      * since that could cause trouble for special hashes.  This way, *
      * it's up to pm->gsu.h->setfn() what to do.                     */
-    int alen = arrlen(val);
+    int alen = 0;
     HashTable opmtab = paramtab, ht = 0;
-    char **aptr = val;
+    char **aptr;
     Value v = (Value) hcalloc(sizeof *v);
     v->end = -1;
 
+    for (aptr = val; *aptr; ++aptr) {
+	if (**aptr != Marker)
+	    ++alen;
+    }
+
     if (alen % 2) {
 	freearray(val);
 	zerr("bad set of key/value pairs for associative array");
 	return;
     }
-    if (augment) {
+    if (flags & ASSPM_AUGMENT) {
 	ht = paramtab = pm->gsu.h->getfn(pm);
     }
-    if (alen && (!augment || !paramtab)) {
+    if (alen && (!(flags & ASSPM_AUGMENT) || !paramtab)) {
 	ht = paramtab = newparamtable(17, pm->node.nam);
     }
-    while (*aptr) {
+    for (aptr = val; *aptr; ) {
+	if (**aptr == Marker)
+	    zsfree(*aptr++);
 	/* The parameter name is ztrdup'd... */
 	v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
 	/*