zsh-workers
 help / color / mirror / code / Atom feed
* [key]+=val
       [not found] <CGME20170925103513eucas1p2b7d91180ccc6defe455daca9248ae222@eucas1p2.samsung.com>
@ 2017-09-25 10:35 ` Peter Stephenson
  2017-09-25 17:53   ` [key]+=val Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2017-09-25 10:35 UTC (permalink / raw)
  To: Zsh Hackers' List

I'm intending to make it so that

foo+=([key]+=val)

does something useful (appending to foo[key]) but

foo=([key]+=val)

doesn't (just creates the value), because you're starting with an empty
set of values in foo so there's nothing to append to.  Does this sound
reasonable?  It's a messy layering violation otherwise so it would need
a good reason to do it differently.

pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [key]+=val
  2017-09-25 10:35 ` [key]+=val Peter Stephenson
@ 2017-09-25 17:53   ` Bart Schaefer
  2017-09-26  9:32     ` [key]+=val Peter Stephenson
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2017-09-25 17:53 UTC (permalink / raw)
  To: Zsh Hackers' List

On Mon, Sep 25, 2017 at 3:35 AM, Peter Stephenson
<p.stephenson@samsung.com> wrote:
>
> foo=([key]+=val)
>
> doesn't (just creates the value), because you're starting with an empty
> set of values in foo so there's nothing to append to.  Does this sound
> reasonable?  It's a messy layering violation otherwise so it would need
> a good reason to do it differently.

Ksh says:

$ typeset -A foo
$ foo=([samekey]+=val [samekey]+=ue [samekey]+=grows)
$ typeset -p foo
typeset -A foo=([samekey]=valuegrows)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [key]+=val
  2017-09-25 17:53   ` [key]+=val Bart Schaefer
@ 2017-09-26  9:32     ` Peter Stephenson
  2017-09-26 17:28       ` [key]+=val Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2017-09-26  9:32 UTC (permalink / raw)
  To: Zsh Hackers' List

On Mon, 25 Sep 2017 10:53:25 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Mon, Sep 25, 2017 at 3:35 AM, Peter Stephenson
> <p.stephenson@samsung.com> wrote:
> >
> > foo=([key]+=val)
> >
> > doesn't (just creates the value), because you're starting with an empty
> > set of values in foo so there's nothing to append to.  Does this sound
> > reasonable?  It's a messy layering violation otherwise so it would need
> > a good reason to do it differently.
> 
> Ksh says:
> 
> $ typeset -A foo
> $ foo=([samekey]+=val [samekey]+=ue [samekey]+=grows)
> $ typeset -p foo
> typeset -A foo=([samekey]=valuegrows)

That's actually not too hard, and in fact it helped me think through a
slightly neater (and less leak-prone) way of updating normal arrays.

What I was worried about was starting off in a context where we're
creating a new array except we're not really creating a new array
because we're digging into an old one...  in this case, we're always
referring to elements in the array we're creating, which I can live
with.

Here's what I've got.  I haven't complicated the documentation by noting
the edge case you mentioned.

pws

diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 430f097..a71dc66 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -145,7 +145,8 @@ indent(var(name)tt(+=LPAR())tt([)var(key)tt(]=)var(value) ...tt(RPAR()))
 
 In the second form var(key) may specify an existing index as well as an
 index off the end of the old array; any existing value is overwritten by
-var(value).
+var(value).  Also, it is possible to use tt([)var(key)tt(]+=)var(value)
+to append to the existing value at that key.
 
 Within the parentheses on the right hand side of either form of the
 assignment, newlines and semicolons are treated the same as white space,
@@ -180,7 +181,9 @@ indent(var(name)tt(+=LPAR())var(key) var(value) ...tt(RPAR()))
 indent(var(name)tt(+=LPAR())tt([)var(key)tt(]=)var(value) ...tt(RPAR()))
 
 This adds a new key/value pair if the key is not already present, and
-replaces the value for the existing key if it is.
+replaces the value for the existing key if it is.  In the second
+form it is also possible to use tt([)var(key)tt(]+=)var(value) to
+append to the existing value at that key.
 
 To create an empty array (including associative arrays), use one of:
 ifzman()
diff --git a/Src/params.c b/Src/params.c
index 4d4d080..3236f71 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3208,13 +3208,15 @@ assignaparam(char *s, char **val, int flags)
 	     * This is an ordinary array with key / value pairs.
 	     */
 	    int maxlen, origlen, nextind;
-	    char **fullval;
+	    char **fullval, **origptr;
 	    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));
+		origptr = v->pm->gsu.a->getfn(v->pm);
+		maxlen = origlen = arrlen(origptr);
 	    } else {
 		maxlen = origlen = 0;
+		origptr = NULL;
 	    }
 	    nextind = 0;
 	    for (aptr = val; *aptr; ) {
@@ -3245,25 +3247,36 @@ assignaparam(char *s, char **val, int flags)
 	    }
 	    fullval[maxlen] = NULL;
 	    if (flags & ASSPM_AUGMENT) {
-		char **srcptr = v->pm->gsu.a->getfn(v->pm);
+		char **srcptr = origptr;
 		for (aptr = fullval; aptr <= fullval + origlen; aptr++) {
-		    *aptr = ztrdup(*srcptr); 
+		    *aptr = ztrdup(*srcptr);
 		    srcptr++;
 		}
 	    }
 	    iptr = subscripts;
 	    nextind = 0;
 	    for (aptr = val; *aptr; ++aptr) {
+		char *old;
 		if (**aptr == Marker) {
+		    int augment = ((*aptr)[1] == '+');
 		    zsfree(*aptr);
 		    zsfree(*++aptr); /* Index, no longer needed */
-		    fullval[*iptr] = *++aptr;
+		    old = fullval[*iptr];
+		    if (augment && old) {
+			fullval[*iptr] = bicat(old, *++aptr);
+			zsfree(*aptr);
+		    } else {
+			fullval[*iptr] = *++aptr;
+		    }
 		    nextind = *iptr + 1;
 		    ++iptr;
 		} else {
+		    old = fullval[nextind];
 		    fullval[nextind] = *aptr;
 		    ++nextind;
 		}
+		if (old)
+		    zsfree(old);
 		/* aptr now on value in both cases */
 	    }
 	    if (*aptr) {		/* Shouldn't be possible */
@@ -3828,8 +3841,20 @@ arrhashsetfn(Param pm, char **val, int flags)
 	ht = paramtab = newparamtable(17, pm->node.nam);
     }
     for (aptr = val; *aptr; ) {
-	if (**aptr == Marker)
+	int eltflags = 0;
+	if (**aptr == Marker) {
+	    /* Either all elements have Marker or none. Checked in caller. */
+	    if ((*aptr)[1] == '+') {
+		/* Actually, assignstrvalue currently doesn't handle this... */
+		eltflags = ASSPM_AUGMENT;
+		/* ...so we'll use the trick from setsparam(). */
+		v->start = INT_MAX;
+	    } else {
+		v->start = 0;
+	    }
+	    v->end = -1;
 	    zsfree(*aptr++);
+	}
 	/* The parameter name is ztrdup'd... */
 	v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
 	/*
@@ -3840,7 +3865,7 @@ arrhashsetfn(Param pm, char **val, int flags)
 	    v->pm = (Param) paramtab->getnode(paramtab, *aptr);
 	zsfree(*aptr++);
 	/* ...but we can use the value without copying. */
-	setstrvalue(v, *aptr++);
+	assignstrvalue(v, *aptr++, eltflags);
     }
     paramtab = opmtab;
     pm->gsu.h->setfn(pm, ht);
diff --git a/Src/subst.c b/Src/subst.c
index 55b5444..eef0dc7 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -53,16 +53,25 @@ keyvalpairelement(LinkList list, LinkNode node)
     if ((start = (char *)getdata(node)) &&
 	start[0] == Inbrack &&
 	(end = strchr(start+1, Outbrack)) &&
-	end[1] == Equals) {
+	/* ..]=value or ]+=Value */
+	(end[1] == Equals ||
+	 (end[1] == '+' && end[2] == Equals))) {
 	static char marker[2] = { Marker, '\0' };
+	static char marker_plus[3] = { Marker, '+', '\0' };
 	*end = '\0';
 
 	dat = start + 1;
 	singsub(&dat);
 	untokenize(dat);
-	setdata(node, marker);
-	node = insertlinknode(list, node, dat);
-	dat = end + 2;
+	if (end[1] == '+') {
+	    setdata(node, marker_plus);
+	    node = insertlinknode(list, node, dat);
+	    dat = end + 3;
+	} else {
+	    setdata(node, marker);
+	    node = insertlinknode(list, node, dat);
+	    dat = end + 2;
+	}
 	singsub(&dat);
 	untokenize(dat);
 	return insertlinknode(list, node, dat);
diff --git a/Src/zsh.h b/Src/zsh.h
index b6e2001..c1138bf 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -228,7 +228,9 @@ struct mathfunc {
  * - In pattern character arrays as guaranteed not to mark a character in
  *   a string.
  * - In assignments with the ASSPM_KEY_VALUE flag set in order to
- *   mark that there is a key / value pair following.
+ *   mark that there is a key / value pair following.  If this
+ *   comes from [key]=value the Marker is followed by a null;
+ *   if from [key]+=value the Marker is followed by a '+' then a null.
  * All the above are local uses --- any case where the Marker has
  * escaped beyond the context in question is an error.
  */
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index abac8f7..4f8e76a 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -2302,3 +2302,39 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 >KVA2two
 >KVA3three
 >*
+
+  local -a keyvalarray
+  keyvalarray=(1 2 3)
+  keyvalarray+=([1]+=a [2]=b)
+  print $keyvalarray
+0:Append to element(s) of array
+>1a b 3
+
+  local -A keyvalhash
+  keyvalhash=([a]=a [b]=b [c]=c)
+  keyvalhash+=([a]+=yee [b]=ee)
+  local key val
+  for key in "${(ok)keyvalhash[@]}"; do
+    val=${keyvalhash[$key]}
+    print -r -- $key $val
+  done
+0:Append to element(s) of associative array
+>a ayee
+>b ee
+>c c
+
+  local -A keyvalarray
+  keyvalarray=([1]=who [2]=anyway [1]+=is [1]+=that [1]+=mysterious [1]+=man)
+  print -rl -- ${(kv)keyvalarray}
+0:Append to element of associative array on creation
+>1
+>whoisthatmysteriousman
+>2
+>anyway
+
+  local -A keyvalhash
+  keyvalhash=([one]=hows [one]+=your [one]+=father [one]+=today)
+  print -rl -- ${(kv)keyvalhash}
+0:Append to element of associative array on creation
+>one
+>howsyourfathertoday


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [key]+=val
  2017-09-26  9:32     ` [key]+=val Peter Stephenson
@ 2017-09-26 17:28       ` Bart Schaefer
  2017-09-27  8:42         ` [key]+=val Peter Stephenson
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2017-09-26 17:28 UTC (permalink / raw)
  To: Zsh Hackers' List

On Sep 26, 10:32am, Peter Stephenson wrote:
}
} +  local -A keyvalarray
} +  keyvalarray=([1]=who [2]=anyway [1]+=is [1]+=that [1]+=mysterious [1]+=man)
} +  print -rl -- ${(kv)keyvalarray}
} +0:Append to element of associative array on creation
} +>1
} +>whoisthatmysteriousman
} +>2
} +>anyway
} +
} +  local -A keyvalhash
} +  keyvalhash=([one]=hows [one]+=your [one]+=father [one]+=today)
} +  print -rl -- ${(kv)keyvalhash}
} +0:Append to element of associative array on creation
} +>one
} +>howsyourfathertoday

Did you intend for both of those tests to use associative arrays?


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [key]+=val
  2017-09-26 17:28       ` [key]+=val Bart Schaefer
@ 2017-09-27  8:42         ` Peter Stephenson
  2017-09-27  8:59           ` [key]+=val Peter Stephenson
  2017-09-27 16:22           ` [key]+=val Peter Stephenson
  0 siblings, 2 replies; 7+ messages in thread
From: Peter Stephenson @ 2017-09-27  8:42 UTC (permalink / raw)
  To: Zsh Hackers' List

On Tue, 26 Sep 2017 10:28:52 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> Did you intend for both of those tests to use associative arrays?

No, I've fixed the first test and submitted this.

Thanks
pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [key]+=val
  2017-09-27  8:42         ` [key]+=val Peter Stephenson
@ 2017-09-27  8:59           ` Peter Stephenson
  2017-09-27 16:22           ` [key]+=val Peter Stephenson
  1 sibling, 0 replies; 7+ messages in thread
From: Peter Stephenson @ 2017-09-27  8:59 UTC (permalink / raw)
  To: Zsh Hackers' List

I think I'm basically done with the [key]=val syntax.

One further possible change might be to enforce the use of that syntax
for associative (but not normal) arrays when KSH_ARRAYS is set.  That
might cause problems with some half-converted scripts.  It doesn't seem
worth a separate option just for that.

pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [key]+=val
  2017-09-27  8:42         ` [key]+=val Peter Stephenson
  2017-09-27  8:59           ` [key]+=val Peter Stephenson
@ 2017-09-27 16:22           ` Peter Stephenson
  1 sibling, 0 replies; 7+ messages in thread
From: Peter Stephenson @ 2017-09-27 16:22 UTC (permalink / raw)
  To: Zsh Hackers' List

Some tests for normal arrays with KSH_ARRAYS set.

diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index d6ed648..5ffaaa1 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -2231,6 +2231,20 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 >two
 >three
 
+  (setopt KSH_ARRAYS
+  local keyvalarray
+  keyvalarray=([0]=one [2]=three)
+  print -l "${keyvalarray[@]}"
+  keyvalarray+=([1]=two)
+  print -l "${keyvalarray[@]}")
+0:[key]=val for normal arrays with KSH_ARRAYS
+>one
+>
+>three
+>one
+>two
+>three
+
  typeset -A keyvalhash
  touch foo Xnot_globbedX
  key="another key" val="another value"
@@ -2258,6 +2272,17 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 >7
 >1 2 3 4 5 6 7
 
+ (setopt KSH_ARRAYS
+ local keyvalarray
+ keyvalarray=(1 2 3)
+ keyvalarray+=([4]=5 [6]=7)
+ keyvalarray+=([3]=4 [5]=6)
+ print ${#keyvalarray[*]}
+ print ${keyvalarray[*]})
+0:append to normal array using [key]=val with KSH_ARRAYS
+>7
+>1 2 3 4 5 6 7
+
  local -A keyvalhash
  keyvalhash=(['1first element!']=first' 'value
 	     ["2second element?"]=second" "value
@@ -2288,6 +2313,19 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 >new_sixth
 >seventh
 
+  (setopt KSH_ARRAYS
+  local keyvalarray
+  keyvalarray=(first [1]=second third [5]=sixth seventh [4]=fifth new_sixth)
+  print -l "${keyvalarray[@]}")
+0:mixed syntax [key]=val with normal arrays with KSH_ARRAYS
+>first
+>second
+>third
+>
+>fifth
+>new_sixth
+>seventh
+
   local -A keyvalhash
   keyvalhash=(1 one [2]=two 3 three)
 1:Mixed syntax with [key]=val not allowed for hash.
@@ -2303,6 +2341,17 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 >KVA3three
 >*
 
+  (setopt KSH_ARRAYS
+  touch KVA1one KVA2two KVA3three
+  local keyvalarray
+  keyvalarray=(KVA* [3]=*)
+  print -l "${keyvalarray[@]}")
+0:Globbing in non-[key]=val parts of mixed syntax with KSH_ARRAYS
+>KVA1one
+>KVA2two
+>KVA3three
+>*
+
   local -a keyvalarray
   keyvalarray=(1 2 3)
   keyvalarray+=([1]+=a [2]=b)
@@ -2310,6 +2359,14 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
 0:Append to element(s) of array
 >1a b 3
 
+  (setopt KSH_ARRAYS
+  local -a keyvalarray
+  keyvalarray=(1 2 3)
+  keyvalarray+=([0]+=a [1]=b)
+  print ${keyvalarray[*]})
+0:Append to element(s) of array with KSH_ARRAYS
+>1a b 3
+
   local -A keyvalhash
   keyvalhash=([a]=a [b]=b [c]=c)
   keyvalhash+=([a]+=yee [b]=ee)
@@ -2326,7 +2383,15 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
   local -a keyvalarray
   keyvalarray=([1]=who [2]=anyway [1]+=is [1]+=that [1]+=mysterious [1]+=man)
   print -rl -- "${keyvalarray[@]}"
-0:Append to element of associative array on creation
+0:Append to element of array on creation
+>whoisthatmysteriousman
+>anyway
+
+  (setopt KSH_ARRAYS
+  local -a keyvalarray
+  keyvalarray=([0]=who [1]=anyway [0]+=is [0]+=that [0]+=mysterious [0]+=man)
+  print -rl -- "${keyvalarray[@]}")
+0:Append to element of array on creation with KSH_ARRAYS
 >whoisthatmysteriousman
 >anyway
 


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-09-27 16:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20170925103513eucas1p2b7d91180ccc6defe455daca9248ae222@eucas1p2.samsung.com>
2017-09-25 10:35 ` [key]+=val Peter Stephenson
2017-09-25 17:53   ` [key]+=val Bart Schaefer
2017-09-26  9:32     ` [key]+=val Peter Stephenson
2017-09-26 17:28       ` [key]+=val Bart Schaefer
2017-09-27  8:42         ` [key]+=val Peter Stephenson
2017-09-27  8:59           ` [key]+=val Peter Stephenson
2017-09-27 16:22           ` [key]+=val Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).