diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | Doc/Zsh/mod_zle.yo | 6 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 49 | ||||
-rw-r--r-- | Src/exec.c | 2 | ||||
-rw-r--r-- | Src/utils.c | 43 |
5 files changed, 92 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog index 4cf7bea69..c1925dd74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2000-07-27 Peter Stephenson <pws@cambridgesiliconradio.com> + + * 12414: Doc/Zsh/mod_zle.yo, Src/exec.c, Src/utils.c, + Src/Zle/zle_main.c: vared quotes separators when editing arrays. + 2000-07-27 Sven Wischnowsky <wischnow@zsh.org> * 12408: Test/55arguments.ztst: fix completion test (55*) because diff --git a/Doc/Zsh/mod_zle.yo b/Doc/Zsh/mod_zle.yo index d0423f65e..f858b35d7 100644 --- a/Doc/Zsh/mod_zle.yo +++ b/Doc/Zsh/mod_zle.yo @@ -161,6 +161,12 @@ an array parameter, or the tt(-A) flag to create an associative array. If the type of an existing parameter does not match the type to be created, the parameter is unset and recreated. +If an array or array slice is being edited, separator characters as defined +in tt($IFS) will be shown quoted with a backslash. Conversely, when the +edited text is split into an array, a backslash quotes an immediately +following separator character; no other special handling of backslashes, or +any handling of quotes, is performed. + Individual elements of existing array or associative array parameters may be edited by using subscript syntax on var(name). New elements are created automatically, even without tt(-c). diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index d6f0b6c8e..e25f11f1e 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -823,7 +823,46 @@ bin_vared(char *name, char **args, char *ops, int func) zwarnnam(name, "no such variable: %s", args[0], 0); return 1; } else if (v) { - s = getstrvalue(v); + if (v->isarr) { + /* Array: check for separators and quote them. */ + char **arr = getarrvalue(v), **aptr, **tmparr, **tptr; + tptr = tmparr = (char **)zhalloc(sizeof(char *)*(arrlen(arr)+1)); + for (aptr = arr; *aptr; aptr++) { + int sepcount = 0; + /* See if this word contains a separator character */ + for (t = *aptr; *t; t++) { + if (*t == Meta) { + if (isep(t[1] ^ 32)) + sepcount++; + t++; + } else if (isep(*t)) + sepcount++; + } + if (sepcount) { + /* Yes, so allocate enough space to quote it. */ + char *newstr, *nptr; + newstr = zhalloc(strlen(*aptr)+sepcount+1); + /* Go through string quoting separators */ + for (t = *aptr, nptr = newstr; *t; ) { + if (*t == Meta) { + if (isep(t[1] ^ 32)) + *nptr++ = '\\'; + *nptr++ = *t++; + } else if (isep(*t)) + *nptr++ = '\\'; + *nptr++ = *t++; + } + *nptr = '\0'; + /* Stick this into the array of words to join up */ + *tptr++ = newstr; + } else + *tptr++ = *aptr; /* No, keep original array element */ + } + *tptr = NULL; + s = sepjoin(tmparr, NULL, 0); + } else { + s = ztrdup(getstrvalue(v)); + } pm = v->pm; } else if (*s) { zwarnnam(name, "invalid parameter name: %s", args[0], 0); @@ -842,7 +881,7 @@ bin_vared(char *name, char **args, char *ops, int func) haso = 1; } /* edit the parameter value */ - zpushnode(bufstack, ztrdup(s)); + zpushnode(bufstack, s); varedarg = *args; ifl = isfirstln; @@ -881,7 +920,11 @@ bin_vared(char *name, char **args, char *ops, int func) if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) { char **a; - a = spacesplit(t, 1, 0); + /* + * Use spacesplit with fourth argument 1: identify quoted separators, + * unquote but don't split. + */ + a = spacesplit(t, 1, 0, 1); if (PM_TYPE(pm->flags) == PM_ARRAY) setaparam(args[0], a); else diff --git a/Src/exec.c b/Src/exec.c index 027c11ca2..a3e28d45d 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2744,7 +2744,7 @@ readoutput(int in, int qt) } addlinknode(ret, buf); } else { - char **words = spacesplit(buf, 0, 1); + char **words = spacesplit(buf, 0, 1, 0); while (*words) { if (isset(GLOBSUBST)) diff --git a/Src/utils.c b/Src/utils.c index 33fed62dd..48218326b 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1831,7 +1831,7 @@ skipwsep(char **s) /**/ mod_export char ** -spacesplit(char *s, int allownull, int heap) +spacesplit(char *s, int allownull, int heap, int quote) { char *t, **ret, **ptr; int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1); @@ -1839,6 +1839,14 @@ spacesplit(char *s, int allownull, int heap) ptr = ret = (heap ? (char **) hcalloc(l) : (char **) zcalloc(l)); + if (quote) { + /* + * we will be stripping quoted separators by hacking string, + * so make sure it's hackable. + */ + s = dupstring(s); + } + t = s; skipwsep(&s); if (*s && isep(*s == Meta ? s[1] ^ 32 : *s)) @@ -1853,7 +1861,7 @@ spacesplit(char *s, int allownull, int heap) skipwsep(&s); } t = s; - findsep(&s, NULL); + findsep(&s, NULL, quote); if (s > t || allownull) { *ptr = (heap ? (char *) hcalloc((s - t) + 1) : (char *) zcalloc((s - t) + 1)); @@ -1871,13 +1879,30 @@ spacesplit(char *s, int allownull, int heap) /**/ static int -findsep(char **s, char *sep) +findsep(char **s, char *sep, int quote) { + /* + * *s is the string we are looking along, which will be updated + * to the point we have got to. + * + * sep is a possibly multicharacter separator to look for. If NULL, + * use normal separator characters. + * + * quote is a flag that '\<sep>' should not be treated as a separator. + * in this case we need to be able to strip the backslash directly + * in the string, so the calling function must have sent us something + * modifiable. currently this only works for sep == NULL. + */ int i; char *t, *tt; if (!sep) { for (t = *s; *t; t++) { + if (quote && *t == '\\' && + isep(t[1] == Meta ? (t[2] ^ 32) : t[1])) { + chuck(t); + continue; + } if (*t == Meta) { if (isep(t[1] ^ 32)) break; @@ -1928,7 +1953,7 @@ findword(char **s, char *sep) if (sep) { sl = strlen(sep); r = *s; - while (! findsep(s, sep)) { + while (! findsep(s, sep, 0)) { r = *s += sl; } return r; @@ -1942,7 +1967,7 @@ findword(char **s, char *sep) break; } *s = t; - findsep(s, sep); + findsep(s, sep, 0); return t; } @@ -1955,7 +1980,7 @@ wordcount(char *s, char *sep, int mul) if (sep) { r = 1; sl = strlen(sep); - for (; (c = findsep(&s, sep)) >= 0; s += sl) + for (; (c = findsep(&s, sep, 0)) >= 0; s += sl) if ((c && *(s + sl)) || mul) r++; } else { @@ -1975,7 +2000,7 @@ wordcount(char *s, char *sep, int mul) if (mul <= 0) skipwsep(&s); } - findsep(&s, NULL); + findsep(&s, NULL, 0); t = s; if (mul <= 0) skipwsep(&s); @@ -2023,7 +2048,7 @@ sepsplit(char *s, char *sep, int allownull, int heap) char *t, *tt, **r, **p; if (!sep) - return spacesplit(s, allownull, heap); + return spacesplit(s, allownull, heap, 0); sl = strlen(sep); n = wordcount(s, sep, 1); @@ -2032,7 +2057,7 @@ sepsplit(char *s, char *sep, int allownull, int heap) for (t = s; n--;) { tt = t; - findsep(&t, sep); + findsep(&t, sep, 0); *p = (heap ? (char *) hcalloc(t - tt + 1) : (char *) zcalloc(t - tt + 1)); strncpy(*p, tt, t - tt); |