summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/mod_zle.yo6
-rw-r--r--Src/Zle/zle_main.c49
-rw-r--r--Src/exec.c2
-rw-r--r--Src/utils.c43
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);