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

PATCH: [key]=value syntax, work in progress



Very early days in an attempt to support the [key]=value syntax in array
assignment.  See tests at end for what I have done so far.

typeset does not yet support this syntax.

Note that the index does not determine the type of the array / hash
being created --- this is how bash works, and it would be a guess at
best as we allow math evaluation for numeric subscripts.

Please let me know now of anything that is going in the wrong direction
or based on a misunderstanding or just plain wrong.  The clumsiest bit
is the addition to do key / value assignment for normal arrays, but I
don't think it's actually broken.

Note globbing is suppressed for this form of array assignment.  That
seems pretty much inevitable --- turning a value into multiple values
isn't useful here.

Feel free to come up with corner cases, but I'm likely to test for
them as errors rather than add gratuitous extra support.

pws

diff --git a/Src/exec.c b/Src/exec.c
index e2432fd..73506a1 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2394,7 +2394,7 @@ static void
 addvars(Estate state, Wordcode pc, int addflags)
 {
     LinkList vl;
-    int xtr, isstr, htok = 0;
+    int xtr, isstr, htok = 0, dontglob = 0;
     char **arr, **ptr, *name;
     int flags;
 
@@ -2428,8 +2428,38 @@ addvars(Estate state, Wordcode pc, int addflags)
 	if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) {
 	    init_list1(svl, ecgetstr(state, EC_DUPTOK, &htok));
 	    vl = &svl;
-	} else
+	} else {
+	    char *start, *end;
+	    LinkNode ve, next;
 	    vl = ecgetlist(state, WC_ASSIGN_NUM(ac), EC_DUPTOK, &htok);
+	    if (vl &&
+		(ve = firstnode(vl)) &&
+		(start = (char *)getdata(ve)) &&
+		start[0] == Inbrack &&
+		(end = strchr(start+1, Outbrack)) &&
+		end[1] == Equals) {
+		dontglob = 1;
+		myflags |= ASSPM_KEY_VALUE;
+		for (;;) {
+		    *end = '\0';
+		    next = nextnode(ve);
+		    setdata(ve, start+1);
+		    insertlinknode(vl, ve, end+2);
+		    ve = next;
+		    if (!ve)
+			break;
+		    if (!(start = (char *)getdata(ve)) ||
+			start[0] != Inbrack ||
+			!(end = strchr(start+1, Outbrack)) ||
+			end[1] != Equals) {
+			zerr("bad array element, expected [key]=value: %s",
+			     start);
+			state->pc = opc;
+			return;
+		    }
+		}
+	    }
+	}
 
 	if (vl && htok) {
 	    prefork(vl, (isstr ? (PREFORK_SINGLE|PREFORK_ASSIGN) :
@@ -2438,8 +2468,9 @@ addvars(Estate state, Wordcode pc, int addflags)
 		state->pc = opc;
 		return;
 	    }
-	    if (!isstr || (isset(GLOBASSIGN) && isstr &&
-			   haswilds((char *)getdata(firstnode(vl))))) {
+	    if (!dontglob &&
+		(!isstr || (isset(GLOBASSIGN) && isstr &&
+			   haswilds((char *)getdata(firstnode(vl)))))) {
 		globlist(vl, 0);
 		/* Unset the parameter to force it to be recreated
 		 * as either scalar or array depending on how many
diff --git a/Src/params.c b/Src/params.c
index 6fbee88..8201fa5 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3185,6 +3185,64 @@ 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)) {
+	int maxlen, origlen;
+	char **aptr, **fullval, *dummy;
+	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 = mathevalarg(*aptr, &dummy);
+	    if (*iptr < 0 ||
+		(!isset(KSHARRAYS) && *iptr == 0)) {
+		zerr("bad subscript for direct array assignment: %s", *aptr);
+		return NULL;
+	    }
+	    if (!isset(KSHARRAYS))
+		--*iptr;
+	    if (*iptr + 1 > maxlen)
+		maxlen = *iptr + 1;
+	    ++iptr;
+	}
+	fullval = zshcalloc((maxlen+1) * sizeof(char *));
+	fullval[maxlen] = NULL;
+	if (flags & ASSPM_AUGMENT) {
+	    char **srcptr = v->pm->gsu.a->getfn(v->pm);
+	    for (aptr = fullval; aptr <= fullval + maxlen; 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++) {
+	    /*
+	     * 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;
+    }
+
     if (flags & ASSPM_AUGMENT) {
     	if (v->start == 0 && v->end == -1) {
 	    if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
diff --git a/Src/zsh.h b/Src/zsh.h
index 1e982a6..13fb1e1 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2060,6 +2060,11 @@ enum {
     ASSPM_WARN = (ASSPM_WARN_CREATE|ASSPM_WARN_NESTED),
     /* Import from environment, so exercise care evaluating value */
     ASSPM_ENV_IMPORT = 1 << 3,
+    /* Array is key / value pairs.
+     * This is normal for associative arrays but variant behaviour for
+     * normal arrays.
+     */
+    ASSPM_KEY_VALUE = 1 << 4
 };
 
 /* node for named directory hash table (nameddirtab) */
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 8dbc1e8..fd098d5 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -2207,3 +2207,25 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 0:(z) splitting with remaining tokens
 >foo-bar*thingy?
  
+ typeset -A keyvalhash
+ keyvalhash=([one]=eins [two]=zwei)
+ keyvalhash+=([three]=drei)
+ for key in ${(ok)keyvalhash}; do
+   print $key $keyvalhash[$key]
+ done
+0:[key]=val for hashes
+>one eins
+>three drei
+>two zwei
+
+  keyvalarray=([1]=one [3]=three)
+  print -l "${keyvalarray[@]}"
+  keyvalarray+=([2]=two)
+  print -l "${keyvalarray[@]}"
+0:[key]=val for normal arrays
+>one
+>
+>three
+>one
+>two
+>three



Messages sorted by: Reverse Date, Date, Thread, Author