about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2000-07-27 17:48:47 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2000-07-27 17:48:47 +0000
commit0aee5e1bb490617b1d84d5ad8e20571d26fc9986 (patch)
tree54f2adfe54ef20a76b24ae8e25c5bdb203d14a02
parent31862868fa7979e4b58cb71c42ac1c63acb8c7fc (diff)
downloadzsh-0aee5e1bb490617b1d84d5ad8e20571d26fc9986.tar.gz
zsh-0aee5e1bb490617b1d84d5ad8e20571d26fc9986.tar.xz
zsh-0aee5e1bb490617b1d84d5ad8e20571d26fc9986.zip
12414: vared quotes separators when editing arrays
-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);