From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3697 invoked by alias); 11 Sep 2017 20:51:26 -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: 41676 Received: (qmail 13911 invoked by uid 1010); 11 Sep 2017 20:51:26 -0000 X-Qmail-Scanner-Diagnostics: from know-smtprelay-omc-9.server.virginmedia.net 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(80.0.253.73):SA:0(-4.7/5.0):. Processed in 2.724622 secs); 11 Sep 2017 20:51:26 -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=-4.7 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_PASS,T_DKIM_INVALID autolearn=ham autolearn_force=no version=3.4.1 X-Envelope-From: p.w.stephenson@ntlworld.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | X-Originating-IP: [86.21.219.59] X-Authenticated-User: p.w.stephenson@ntlworld.com X-Spam: 0 X-Authority: v=2.1 cv=aJkN0uJm c=1 sm=1 tr=0 a=utowdAHh8RITBM/6U1BPxA==:117 a=utowdAHh8RITBM/6U1BPxA==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=kj9zAlcOel0A:10 a=x7bEGLp0ZPQA:10 a=npldXguGAAAA:8 a=illeUefYFC9RSV667tEA:9 a=6GQSABZqPOQsdixR:21 a=iYtfTeF9SsOHMV6r:21 a=CjuIK1q_8ugA:10 a=1Z6EAcxPEhoA:10 a=1MEZn5qd6kv58cYvHi58:22 Date: Mon, 11 Sep 2017 21:51:15 +0100 From: Peter Stephenson To: Zsh hackers list Subject: PATCH: [key]=value syntax, work in progress Message-ID: <20170911215115.6aa27dec@ntlworld.com> X-Mailer: Claws Mail 3.11.1 (GTK+ 2.24.28; x86_64-redhat-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ntlworld.com; s=meg.feb2017; t=1505163076; bh=7zEy+l3CRxs0s5ndg1FbESDM+DaiTjaTdsv/kpIw7fQ=; h=Date:From:To:Subject; b=r+5T/8IV9ZRo2A8Y9fU9rEk0LmVijoRMa4uBiiwVgjcljv84oKL7Fe5w1mIGo7vrm mrjMoDApd7ZJBSyYvnRVGaWEb9UwgVlMeRqLSvCYHo6OYX2rLsac/TKDt9b5jKgwg/ wqDhggcLJVCOXz6SWFMtF4NnSBIRxfKOq/NUPswxoEHdQYVuMSjG7cVeDRiHHaX2r0 cN46xRbyXx8rGBUwH31TUm9f0W9PjaxZ2lh8uf+ovz882OgaGf8wWI184l3ASiz1PT nWhwuk3QA+t0v5VXPq1ZaQ9CjvN7I+3dtSVevLe07q5fSKqPUd3Q2aPsw8/vfoUAjX yReJVtEZawaQA== 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