From 6230e82d44da25773437c5438c83a5d5fe275420 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 27 Sep 2017 09:41:50 +0100 Subject: 41764 (test tweaked): allow [key]+=value when modifying arrays --- Src/params.c | 39 ++++++++++++++++++++++++++++++++------- Src/subst.c | 17 +++++++++++++---- Src/zsh.h | 4 +++- 3 files changed, 48 insertions(+), 12 deletions(-) (limited to 'Src') diff --git a/Src/params.c b/Src/params.c index 4d4d08085..3236f7165 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 55b5444c6..eef0dc75b 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 b6e2001fb..c1138bfab 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. */ -- cgit 1.4.1