diff options
Diffstat (limited to 'Src/params.c')
-rw-r--r-- | Src/params.c | 192 |
1 files changed, 127 insertions, 65 deletions
diff --git a/Src/params.c b/Src/params.c index d628ddf37..c7514de8a 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2704,7 +2704,7 @@ setarrvalue(Value v, char **val) v->pm->gsu.a->setfn(v->pm, val); } else if (v->start == -1 && v->end == 0 && PM_TYPE(v->pm->node.flags) == PM_HASHED) { - arrhashsetfn(v->pm, val, 1); + arrhashsetfn(v->pm, val, ASSPM_AUGMENT); } else if ((PM_TYPE(v->pm->node.flags) == PM_HASHED)) { freearray(val); zerr("%s: attempt to set slice of associative array", @@ -3186,69 +3186,124 @@ 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)) { - /* - * This is an ordinary array with key / value pairs. - */ - int maxlen, origlen; - char **aptr, **fullval; - 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 = mathevali(*aptr); - if (*iptr < 0 || - (!isset(KSHARRAYS) && *iptr == 0)) { - unqueue_signals(); - zerr("bad subscript for direct array assignment: %s", *aptr); + /* + * At this point, we may have array entries consisting of + * - a Marker element --- normally allocated array entry but + * with just Marker char and null + * - an array index element --- as normal for associative array, + * but non-standard for normal array which we handle now. + * - a value for the indexed element. + * This only applies if the flag ASSPM_KEY_VALUE is passed in, + * indicating prefork() detected this syntax. + * + * For associative arrays we just junk the Makrer elements. + */ + if (flags & ASSPM_KEY_VALUE) { + char **aptr; + if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) { + /* + * This is an ordinary array with key / value pairs. + */ + int maxlen, origlen, nextind; + char **fullval; + 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; + } + nextind = 0; + for (aptr = val; *aptr; ) { + if (**aptr == Marker) { + *iptr = mathevali(*++aptr); + if (*iptr < 0 || + (!isset(KSHARRAYS) && *iptr == 0)) { + unqueue_signals(); + zerr("bad subscript for direct array assignment: %s", *aptr); + return NULL; + } + if (!isset(KSHARRAYS)) + --*iptr; + nextind = *iptr + 1; + ++iptr; + aptr += 2; + } else { + ++nextind; + ++aptr; + } + if (nextind > maxlen) + maxlen = nextind; + } + fullval = zshcalloc((maxlen+1) * sizeof(char *)); + if (!fullval) { + zerr("array too large"); return NULL; } - if (!isset(KSHARRAYS)) - --*iptr; - if (*iptr + 1 > maxlen) - maxlen = *iptr + 1; - ++iptr; - } - fullval = zshcalloc((maxlen+1) * sizeof(char *)); - if (!fullval) { - zerr("array too large"); - return NULL; - } - fullval[maxlen] = NULL; - if (flags & ASSPM_AUGMENT) { - char **srcptr = v->pm->gsu.a->getfn(v->pm); - for (aptr = fullval; aptr <= fullval + origlen; aptr++) { - *aptr = ztrdup(*srcptr); - srcptr++; + fullval[maxlen] = NULL; + if (flags & ASSPM_AUGMENT) { + char **srcptr = v->pm->gsu.a->getfn(v->pm); + for (aptr = fullval; aptr <= fullval + origlen; 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++) { + iptr = subscripts; + nextind = 0; + for (aptr = val; *aptr; ++aptr) { + if (**aptr == Marker) { + zsfree(*aptr); + zsfree(*++aptr); /* Index, no longer needed */ + fullval[*iptr] = *++aptr; + nextind = *iptr + 1; + ++iptr; + } else { + fullval[nextind] = *aptr; + ++nextind; + } + /* aptr now on value in both cases */ + } + 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; + } else if (PM_TYPE(v->pm->node.flags & PM_HASHED)) { /* - * 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. + * We strictly enforce [key]=value syntax for associative + * arrays. Marker can only indicate a Marker / key / value + * triad; it cannot be there by accident. + * + * It's too inefficient to strip Markers here, and they + * can't be there in the other form --- so just ignore + * them willy nilly lower down. */ - if (!*aptr) - *aptr = ztrdup(""); + for (aptr = val; *aptr; aptr += 3) { + if (**aptr != Marker) { + unqueue_signals(); + freearray(val); + zerr("bad [key]=value syntax for associative array"); + return NULL; + } + } + } else { + unqueue_signals(); + freearray(val); + zerr("invalid use of [key]=value assignment syntax"); + return NULL; } - setarrvalue(v, fullval); - unqueue_signals(); - return v->pm; } if (flags & ASSPM_AUGMENT) { @@ -3741,30 +3796,37 @@ nullsethashfn(UNUSED(Param pm), HashTable x) /* Function to set value of an association parameter using key/value pairs */ /**/ -mod_export void -arrhashsetfn(Param pm, char **val, int augment) +static void +arrhashsetfn(Param pm, char **val, int flags) { /* Best not to shortcut this by using the existing hash table, * * since that could cause trouble for special hashes. This way, * * it's up to pm->gsu.h->setfn() what to do. */ - int alen = arrlen(val); + int alen = 0; HashTable opmtab = paramtab, ht = 0; - char **aptr = val; + char **aptr; Value v = (Value) hcalloc(sizeof *v); v->end = -1; + for (aptr = val; *aptr; ++aptr) { + if (**aptr != Marker) + ++alen; + } + if (alen % 2) { freearray(val); zerr("bad set of key/value pairs for associative array"); return; } - if (augment) { + if (flags & ASSPM_AUGMENT) { ht = paramtab = pm->gsu.h->getfn(pm); } - if (alen && (!augment || !paramtab)) { + if (alen && (!(flags & ASSPM_AUGMENT) || !paramtab)) { ht = paramtab = newparamtable(17, pm->node.nam); } - while (*aptr) { + for (aptr = val; *aptr; ) { + if (**aptr == Marker) + zsfree(*aptr++); /* The parameter name is ztrdup'd... */ v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET); /* |