From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8657 invoked from network); 31 May 2000 05:45:51 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 31 May 2000 05:45:51 -0000 Received: (qmail 6004 invoked by alias); 31 May 2000 05:45:40 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 11677 Received: (qmail 5997 invoked from network); 31 May 2000 05:45:39 -0000 Date: Tue, 30 May 2000 22:45:36 -0700 (PDT) From: Wayne Davison To: Zsh Workers Subject: PATCH: fix for $var[1,0] expansion Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Long ago when the subject came up that $var[1,0] was handled the same way as $var[1,1], I suggested a potential fix -- change the way that arrays are handled internally so that the zsh syntax can properly generate an empty array at the first element (even though KSH array indexing can't be fixed). I finally got around to coding this up today. The following patch changes the "value" structure to have a "start" and a "len" instead of "a" and "b". "Start" is still a 0-relative index (just like "a"), but "len" is now the length of the array (with negative numbers being treated specially, just like they used to be) instead of being a 0-relative last element index (which is what "b" was). This allows zsh to internally represent an empty array at any position. The external syntax is not changed in any way. The only user-visible change is that $var[1,0] now properly results in an empty array. I poured over the code quite a bit to try to ensure that I didn't make any off-by-one errors in the translation. The resulting shell passes all the "make test" checking, and I'm currently using it as my main shell on my Linux box. However, there could still be some lurking bugs, so if anyone has some scripts that make extensive use of arrays, please give this a go and see how it works. ..wayne.. ---8<------8<------8<------8<---cut here--->8------>8------>8------>8--- Index: Src/glob.c @@ -921,8 +921,8 @@ Complist q; /* pattern after parsing */ char *ostr = (char *)getdata(np); /* the pattern before the parser */ /* chops it up */ - int first = 0, last = -1; /* index of first/last match to */ - /* return */ + int first = 0, count = -1; /* index of first match to return */ + /* plus number of items */ struct globdata saved; /* saved glob state */ if (unset(GLOBOPT) || !haswilds(ostr)) { @@ -1334,15 +1334,15 @@ v.isarr = SCANPM_WANTVALS; v.pm = NULL; - v.b = -1; + v.len = -1; v.inv = 0; if (getindex(&s, &v) || s == os) { zerr("invalid subscript", NULL, 0); restore_globstate(saved); return; } - first = v.a; - last = v.b; + first = v.start; + count = v.len; break; } default: @@ -1428,16 +1428,15 @@ if (first < 0) first += matchct; - if (last < 0) - last += matchct; + if (count < 0) + count += matchct + 1; if (first < 0) first = 0; - if (last >= matchct) - last = matchct - 1; - if (first <= last) { - matchptr = matchbuf + matchct - 1 - last; - last -= first; - while (last-- >= 0) { /* insert matches in the arg list */ + if (count > matchct - first) + count = matchct - first; + if (count > 0) { + matchptr = matchbuf + matchct - first - count; + while (count-- > 0) { /* insert matches in the arg list */ insertlinknode(list, node, matchptr->name); matchptr++; } Index: Src/params.c @@ -394,8 +394,8 @@ } v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED)); v.inv = 0; - v.a = 0; - v.b = -1; + v.start = 0; + v.len = -1; paramvals[numparamvals] = getstrvalue(&v); if (flags & SCANPM_MATCHVAL) { if (pattry(scanprog, paramvals[numparamvals])) { @@ -437,8 +437,8 @@ else if (PM_TYPE(v->pm->flags) == PM_HASHED) { v->arr = paramvalarr(v->pm->gets.hfn(v->pm), v->isarr); /* Can't take numeric slices of associative arrays */ - v->a = 0; - v->b = numparamvals; + v->start = 0; + v->len = numparamvals + 1; return v->arr; } else return NULL; @@ -932,13 +932,15 @@ paramtab = tht; } v->isarr = (*inv ? SCANPM_WANTINDEX : 0); - v->a = 0; + v->start = 0; *inv = 0; /* We've already obtained the "index" (key) */ - *w = v->b = -1; + *w = v->len = -1; r = isset(KSHARRAYS) ? 1 : 0; - } else - if (!(r = mathevalarg(s, &s)) || (isset(KSHARRAYS) && r >= 0)) - r++; + } else { + r = mathevalarg(s, &s); + if ((!r && !a2) || (isset(KSHARRAYS) && r >= 0)) + r++; + } if (word && !v->isarr) { s = t = getstrvalue(v); i = wordcount(s, sep, 0); @@ -955,7 +957,7 @@ return 0; if (!a2 && *tt != ',') - *w = (zlong)(s - t) - 1; + *w = (zlong)(s - d) - 1; return (a2 ? s : d + 1) - t; } else if (!v->isarr && !word) { @@ -1014,7 +1016,7 @@ (v->isarr & (SCANPM_MATCHKEY | SCANPM_MATCHVAL | SCANPM_KEYMATCH))))) { *inv = v->inv; - *w = v->b; + *w = v->len; return 1; } } else @@ -1065,7 +1067,7 @@ if (!--r) { r = (zlong)(t - s + (a2 ? -1 : 1)); if (!a2 && *tt != ',') - *w = r + strlen(ta[i]) - 2; + *w = strlen(ta[i]) - 1; return r; } return a2 ? -1 : 0; @@ -1129,7 +1131,7 @@ int getindex(char **pptr, Value v) { - int a, b, inv = 0; + int start, len, inv = 0; char *s = *pptr, *tbrack; *s++ = '['; @@ -1141,31 +1143,32 @@ if ((s[0] == '*' || s[0] == '@') && s[1] == ']') { if ((v->isarr || IS_UNSET_VALUE(v)) && s[0] == '@') v->isarr |= SCANPM_ISVAR_AT; - v->a = 0; - v->b = -1; + v->start = 0; + v->len = -1; s += 2; } else { - zlong we = 0, dummy; + zlong wlen = 0, dummy; - a = getarg(&s, &inv, v, 0, &we); + start = getarg(&s, &inv, v, 0, &wlen); if (inv) { - if (!v->isarr && a != 0) { + if (!v->isarr && start != 0) { char *t, *p; t = getstrvalue(v); - if (a > 0) { - for (p = t + a - 1; p-- > t; ) + if (start > 0) { + for (p = t + start - 1; p-- > t; ) if (*p == Meta) - a--; + start--; } else - a = -ztrlen(t + a + strlen(t)); + start = -ztrlen(t + start + strlen(t)); } - if (a > 0 && (isset(KSHARRAYS) || (v->pm->flags & PM_HASHED))) - a--; + if (start > 0 && (isset(KSHARRAYS) || (v->pm->flags & PM_HASHED))) + start--; if (v->isarr != SCANPM_WANTINDEX) { v->inv = 1; v->isarr = 0; - v->a = v->b = a; + v->start = start; + v->len = 1; } if (*s == ',') { zerr("invalid subscript", NULL, 0); @@ -1179,25 +1182,28 @@ } else { int com; - if (a > 0) - a--; + if (start > 0) + start--; if ((com = (*s == ','))) { s++; - b = getarg(&s, &inv, v, 1, &dummy); - if (b > 0) - b--; + len = getarg(&s, &inv, v, 1, &dummy); + if (len > 0) { + len -= start; + if (len < 0) + len = 0; + } } else { - b = we ? we : a; + len = wlen ? wlen : 1; } if (*s == ']' || *s == Outbrack) { s++; - if (v->isarr && a == b && !com && + if (v->isarr && len == 1 && !com && (!(v->isarr & SCANPM_MATCHMANY) || !(v->isarr & (SCANPM_MATCHKEY | SCANPM_MATCHVAL | SCANPM_KEYMATCH)))) v->isarr = 0; - v->a = a; - v->b = b; + v->start = start; + v->len = len; } else s = *pptr; } @@ -1258,7 +1264,8 @@ v = (Value) hcalloc(sizeof *v); v->pm = argvparam; v->inv = 0; - v->a = v->b = ppar - 1; + v->start = ppar - 1; + v->len = 1; if (sav) *s = sav; } else { @@ -1288,8 +1295,8 @@ } v->pm = pm; v->inv = 0; - v->a = 0; - v->b = -1; + v->start = 0; + v->len = -1; if (bracks > 0 && (*s == '[' || *s == Inbrack)) { if (getindex(&s, v)) { *pptr = s; @@ -1297,19 +1304,21 @@ } } else if (!(flags & SCANPM_ASSIGNING) && v->isarr && iident(*t) && isset(KSHARRAYS)) - v->b = 0, v->isarr = 0; + v->len = 1, v->isarr = 0; } if (!bracks && *s) return NULL; *pptr = s; - if (v->a > MAX_ARRLEN || - v->a < -MAX_ARRLEN) { - zerr("subscript too %s: %d", (v->a < 0) ? "small" : "big", v->a); + if (v->start > MAX_ARRLEN || + v->start < -MAX_ARRLEN) { + zerr("subscript too %s: %d", (v->start < 0) ? "small" : "big", + v->start); return NULL; } - if (v->b > MAX_ARRLEN || - v->b < -MAX_ARRLEN) { - zerr("subscript too %s: %d", (v->b < 0) ? "small" : "big", v->b); + if (v->start + v->len > MAX_ARRLEN || + v->start + v->len < -MAX_ARRLEN) { + zerr("subscript too %s: %d", (v->len < 0) ? "small" : "big", + v->start + v->len); return NULL; } return v; @@ -1326,7 +1335,7 @@ return hcalloc(1); if (v->inv && !(v->pm->flags & PM_HASHED)) { - sprintf(buf, "%d", v->a); + sprintf(buf, "%d", v->start); s = dupstring(buf); return s; } @@ -1345,9 +1354,10 @@ if (v->isarr) s = sepjoin(ss, NULL, 1); else { - if (v->a < 0) - v->a += arrlen(ss); - s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a]; + if (v->start < 0) + v->start += arrlen(ss); + s = (v->start >= arrlen(ss) || v->start < 0) ? + (char *) hcalloc(1) : ss[v->start]; } return s; case PM_INTEGER: @@ -1367,18 +1377,18 @@ break; } - if (v->a == 0 && v->b == -1) + if (v->start == 0 && v->len == -1) return s; - if (v->a < 0) - v->a += strlen(s); - if (v->b < 0) - v->b += strlen(s); - s = (v->a > (int)strlen(s)) ? dupstring("") : dupstring(s + v->a); - if (v->b < v->a) + if (v->start < 0) + v->start += strlen(s); + if (v->len < 0) + v->len += strlen(s) - v->start + 1; + s = (v->start > (int)strlen(s)) ? dupstring("") : dupstring(s + v->start); + if (v->len <= 0) s[0] = '\0'; - else if (v->b - v->a < (int)strlen(s)) - s[v->b - v->a + 1 + (s[v->b - v->a] == Meta)] = '\0'; + else if (v->len <= (int)strlen(s)) + s[v->len + (s[v->len - 1] == Meta)] = '\0'; return s; } @@ -1399,25 +1409,25 @@ char buf[DIGBUFSIZE]; s = arrdup(nular); - sprintf(buf, "%d", v->a); + sprintf(buf, "%d", v->start); s[0] = dupstring(buf); return s; } s = getvaluearr(v); - if (v->a == 0 && v->b == -1) + if (v->start == 0 && v->len == -1) return s; - if (v->a < 0) - v->a += arrlen(s); - if (v->b < 0) - v->b += arrlen(s); - if (v->a > arrlen(s) || v->a < 0) + if (v->start < 0) + v->start += arrlen(s); + if (v->len < 0) + v->len += arrlen(s) - v->start + 1; + if (v->start > arrlen(s) || v->start < 0) s = arrdup(nular); else - s = arrdup(s + v->a); - if (v->b < v->a) + s = arrdup(s + v->start); + if (v->len <= 0) s[0] = NULL; - else if (v->b - v->a < arrlen(s)) - s[v->b - v->a + 1] = NULL; + else if (v->len <= arrlen(s)) + s[v->len] = NULL; return s; } @@ -1428,7 +1438,7 @@ if (!v || v->isarr) return 0; if (v->inv) - return v->a; + return v->start; if (PM_TYPE(v->pm->flags) == PM_INTEGER) return v->pm->gets.ifn(v->pm); if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) @@ -1446,7 +1456,7 @@ if (!v || v->isarr) { mn.u.l = 0; } else if (v->inv) { - mn.u.l = v->a; + mn.u.l = v->start; } else if (PM_TYPE(v->pm->flags) == PM_INTEGER) { mn.u.l = v->pm->gets.ifn(v->pm); } else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) { @@ -1495,7 +1505,7 @@ v->pm->flags &= ~PM_UNSET; switch (PM_TYPE(v->pm->flags)) { case PM_SCALAR: - if (v->a == 0 && v->b == -1) { + if (v->start == 0 && v->len == -1) { (v->pm->sets.cfn) (v->pm, val); if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct) v->pm->ct = strlen(val); @@ -1506,22 +1516,22 @@ z = dupstring((v->pm->gets.cfn) (v->pm)); zlen = strlen(z); if (v->inv && unset(KSHARRAYS)) - v->a--, v->b--; - if (v->a < 0) { - v->a += zlen; - if (v->a < 0) - v->a = 0; + v->start--; + if (v->start < 0) { + v->start += zlen; + if (v->start < 0) + v->start = 0; } - if (v->a > zlen) - v->a = zlen; - if (v->b < 0) - v->b += zlen; - if (v->b > zlen - 1) - v->b = zlen - 1; - x = (char *) zalloc(v->a + strlen(val) + zlen - v->b); - strncpy(x, z, v->a); - strcpy(x + v->a, val); - strcat(x + v->a, z + v->b + 1); + if (v->start > zlen) + v->start = zlen; + if (v->len < 0) + v->len += zlen - v->start + 1; + if (v->len > zlen - v->start) + v->len = zlen - v->start; + x = (char *) zalloc(strlen(val) + zlen - v->len + 1); + strncpy(x, z, v->start); + strcpy(x + v->start, val); + strcat(x + v->start, z + v->start + v->len); (v->pm->sets.cfn) (v->pm, x); zsfree(val); } @@ -1618,7 +1628,7 @@ zerr("attempt to assign array value to non-array", NULL, 0); return; } - if (v->a == 0 && v->b == -1) { + if (v->start == 0 && v->len == -1) { if (PM_TYPE(v->pm->flags) == PM_HASHED) arrhashsetfn(v->pm, val); else @@ -1633,30 +1643,30 @@ return; } if (v->inv && unset(KSHARRAYS)) - v->a--, v->b--; + v->start--; // v->len--;?? q = old = v->pm->gets.afn(v->pm); n = arrlen(old); - if (v->a < 0) - v->a += n; - if (v->b < 0) - v->b += n; - if (v->a < 0) - v->a = 0; - if (v->b < 0) - v->b = 0; - - ll = v->a + arrlen(val); - if (v->b < n) - ll += n - v->b; + if (v->start < 0) + v->start += n; + if (v->len < 0) + v->len += n - v->start + 1; + if (v->start < 0) + v->start = 0; + if (v->len < 0) + v->len = 0; + + ll = v->start + arrlen(val); + if (v->start + v->len - 1 < n) + ll += n - (v->start + v->len - 1); p = new = (char **) zcalloc(sizeof(char *) * (ll + 1)); - for (i = 0; i < v->a; i++) + for (i = 0; i < v->start; i++) *p++ = i < n ? ztrdup(*q++) : ztrdup(""); for (r = val; *r;) *p++ = ztrdup(*r++); - if (v->b + 1 < n) - for (q = old + v->b + 1; *q;) + if (v->start + v->len < n) + for (q = old + v->start + v->len; *q;) *p++ = ztrdup(*q++); *p = NULL; @@ -2151,7 +2161,7 @@ HashTable opmtab = paramtab, ht = 0; char **aptr = val; Value v = (Value) hcalloc(sizeof *v); - v->b = -1; + v->len = -1; if (alen % 2) { freearray(val); Index: Src/subst.c @@ -1138,7 +1138,7 @@ v = (Value) hcalloc(sizeof *v); v->isarr = isarr; v->pm = pm; - v->b = -1; + v->len = -1; if (getindex(&s, v) || s == os) break; } @@ -1154,9 +1154,9 @@ if (v->pm->flags & PM_ARRAY) { int tmplen = arrlen(v->pm->gets.afn(v->pm)); - if (v->a < 0) - v->a += tmplen + v->inv; - if (!v->inv && (v->a >= tmplen || v->a < 0)) + if (v->start < 0) + v->start += tmplen + v->inv; + if (!v->inv && (v->start >= tmplen || v->start < 0)) vunset = 1; } if (!vunset) { Index: Src/zsh.h @@ -467,8 +467,8 @@ int isarr; Param pm; /* parameter node */ int inv; /* should we return the index ? */ - int a; /* first element of array slice, or -1 */ - int b; /* last element of array slice, or -1 */ + int start; /* first element of array slice, or -1 */ + int len; /* length of array slice, or -1 */ char **arr; /* cache for hash turned into array */ }; Index: Src/Modules/mapfile.c @@ -202,8 +202,8 @@ for (hn = ht->nodes[i]; hn; hn = hn->next) { struct value v; - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; Index: Src/Modules/parameter.c @@ -229,8 +229,8 @@ Cmdnam cn = zcalloc(sizeof(*cn)); struct value v; - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; @@ -400,8 +400,8 @@ for (hn = ht->nodes[i]; hn; hn = hn->next) { struct value v; - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; @@ -754,8 +754,8 @@ struct value v; char *val; - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; @@ -1433,8 +1433,8 @@ struct value v; char *val; - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; @@ -1659,8 +1659,8 @@ struct value v; char *val; - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; Index: Src/Zle/complete.c @@ -1033,8 +1033,8 @@ for (cp = compkparams, pp = compkpms; cp->name; cp++, pp++) if (!strcmp(hn->nam, cp->name)) { - v.isarr = v.inv = v.a = 0; - v.b = -1; + v.isarr = v.inv = v.start = 0; + v.len = -1; v.arr = NULL; v.pm = (Param) hn; if (cp->type == PM_INTEGER) ---8<------8<------8<------8<---cut here--->8------>8------>8------>8---