From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21855 invoked by alias); 26 Sep 2017 09:33:10 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 41764 Received: (qmail 6153 invoked by uid 1010); 26 Sep 2017 09:33:10 -0000 X-Qmail-Scanner-Diagnostics: from mailout2.w1.samsung.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.99.2/21882. spamassassin: 3.4.1. Clear:RC:0(210.118.77.12):SA:0(-6.9/5.0):. Processed in 2.288528 secs); 26 Sep 2017 09:33:10 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.1 X-Envelope-From: p.stephenson@samsung.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | X-AuditID: cbfec7f1-f793a6d00000326b-d5-59ca1ecac766 Date: Tue, 26 Sep 2017 10:32:54 +0100 From: Peter Stephenson To: Zsh Hackers' List Subject: Re: [key]+=val Message-id: <20170926103254.1670a650@pwslap01u.europe.root.pri> In-reply-to: Organization: Samsung Cambridge Solution Centre X-Mailer: Claws Mail 3.7.9 (GTK+ 2.22.0; i386-redhat-linux-gnu) MIME-version: 1.0 Content-type: text/plain; charset="US-ASCII" Content-transfer-encoding: 7bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrNIsWRmVeSWpSXmKPExsWy7djP87qn5E5FGjxaoWJxsPkhkwOjx6qD H5gCGKO4bFJSczLLUov07RK4Mm7+5S/4a1/x6dZL1gbGqYZdjJwcEgImEpfuzGSDsMUkLtxb D2RzcQgJLGWUODfvCCOE08skseLzNXaYjs8P1kMlljFKLLm1gRnCmcYkMed+B1TmDKPEpf7X 7BDOWUaJXT3LWbsYOThYBFQl7n01AhnFJmAoMXXTbEaQsIiAtkT7RzGQsLCAuERL22pGEJtX wF7i37ROsBJOgWCJNXPBSvgF9CWu/v3EBHGQvcTMK2egygUlfky+xwJiMwvoSGzb9pgdwpaX 2LzmLdidEgIL2CT+/9kK1ewi0fftACuELSzx6vgWqC9lJC5P7maBsPsZJZ50+0I0z2CUOH1m BzTArCX6bl9khNjAJzFp23RmkEMlBHglOtqEIEo8JD7cWcEIEXaUuPwtEhIitxgljsx5xjSB UWEWkrtnIbl7FpK7FzAyr2IUSS0tzk1PLTbSK07MLS7NS9dLzs/dxAhMAqf/Hf+4g/H9CatD jAIcjEo8vA1MJyOFWBPLiitzDzFKcDArifDOlToVKcSbklhZlVqUH19UmpNafIhRmoNFSZzX NqotUkggPbEkNTs1tSC1CCbLxMEp1cBokXVdPSjg4xVfn6yVMn1iLiGB05bZKAlffLbj64WH q9avn7z4X9ICj/6stkKpBQJ3GzykAlYnSH3bY9F0IyTPKERUvivNZIpi8eyoN9FqRx6cuTRD d+vLv3rbFbN/zDM97Fzp8fCqjn7mEoXM7TztvLtzAwSPsx5+c+/6aYuNp+/8tbuoJz9PiaU4 I9FQi7moOBEAEX2Kqf4CAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrLLMWRmVeSWpSXmKPExsVy+t/xy7qn5E5FGuzpYLY42PyQyYHRY9XB D0wBjFFcNimpOZllqUX6dglcGTf/8hf8ta/4dOslawPjVMMuRk4OCQETic8P1jNC2GISF+6t Z+ti5OIQEljCKLHs2VJGCGcGk8SXdT9YQKqEBM4xSky8VQ6ROMsoceveHKAWDg4WAVWJe1+N QGrYBAwlpm6azQgSFhHQlmj/KAYSFhYQl2hpWw22jFfAXuLftE4wm1MgWOLOrEvsECPvMEos 6FvEDpLgF9CXuPr3ExPEdfYSM6+cgWoWlPgx+R7YPcwCWhKbtzWxQtjyEpvXvGWGuFNd4sbd 3ewTGIVnIWmZhaRlFpKWBYzMqxhFUkuLc9Nzi430ihNzi0vz0vWS83M3MQIDeduxn1t2MHa9 Cz7EKMDBqMTD28B0MlKINbGsuDL3EKMEB7OSCO9cqVORQrwpiZVVqUX58UWlOanFhxilOViU xHl796yOFBJITyxJzU5NLUgtgskycXBKNTCmzNz2PPlQxSne2ufb53k8TXzGsukY49RnMwsi uOpW7T9ztXOKfVU677eeqnVZX/gTT9k/vPvTYOvc2hn7lr15Ev44WWz/vT2HXb2OLXpuO2d2 SOzf2dtnSu+6dkXOL0/mqO05nZtNjG/bruwIf/v/z+2QDUsjWvbui99dPJ3/GdfEkK/szz19 pJVYijMSDbWYi4oTAfZymM1gAgAA X-CMS-MailID: 20170926093258eucas1p2559e9da7c7765f7d3800b9e31f0707c1 X-Msg-Generator: CA X-Sender-IP: 182.198.249.180 X-Local-Sender: =?UTF-8?B?UGV0ZXIgU3RlcGhlbnNvbhtTQ1NDLURhdGEgUGxhbmUb?= =?UTF-8?B?7IK87ISx7KCE7J6QG1ByaW5jaXBhbCBFbmdpbmVlciwgU29mdHdhcmU=?= X-Global-Sender: =?UTF-8?B?UGV0ZXIgU3RlcGhlbnNvbhtTQ1NDLURhdGEgUGxhbmUbU2Ft?= =?UTF-8?B?c3VuZyBFbGVjdHJvbmljcxtQcmluY2lwYWwgRW5naW5lZXIsIFNvZnR3YXJl?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDA1Q0QwNTAwNTg=?= CMS-TYPE: 201P X-CMS-RootMailID: 20170925103513eucas1p2b7d91180ccc6defe455daca9248ae222 X-RootMTR: 20170925103513eucas1p2b7d91180ccc6defe455daca9248ae222 References: <20170925113509.25c2703e@pwslap01u.europe.root.pri> On Mon, 25 Sep 2017 10:53:25 -0700 Bart Schaefer wrote: > On Mon, Sep 25, 2017 at 3:35 AM, Peter Stephenson > 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