about summary refs log tree commit diff
path: root/Src/lex.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-08-23 22:04:25 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-08-23 22:04:25 +0000
commitdb3ba137b34582a2810b0fb01b6ba451acbc1c9b (patch)
tree6d2f321cc78d9794a139221463bee6d3f89bde9e /Src/lex.c
parent437f67718cd03f1d2eff2331827c2e225dee4aaf (diff)
downloadzsh-db3ba137b34582a2810b0fb01b6ba451acbc1c9b.tar.gz
zsh-db3ba137b34582a2810b0fb01b6ba451acbc1c9b.tar.xz
zsh-db3ba137b34582a2810b0fb01b6ba451acbc1c9b.zip
23795: improve ${(Q)...} with $'..'
Diffstat (limited to 'Src/lex.c')
-rw-r--r--Src/lex.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/Src/lex.c b/Src/lex.c
index 8bf90847a..a334dc722 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1556,6 +1556,7 @@ mod_export int
 parse_subst_string(char *s)
 {
     int c, l = strlen(s), err, olen, lexstop_ret;
+    char *ptr;
 
     if (!*s || !strcmp(s, nulstring))
 	return 0;
@@ -1593,6 +1594,43 @@ parse_subst_string(char *s)
 	return 1;
     }
 #endif
+    /* Check for $'...' quoting.  This needs special handling. */
+    for (ptr = s; *ptr; )
+    {
+	if (*ptr == String && ptr[1] == Snull)
+	{
+	    char *t;
+	    int len, tlen, diff;
+	    t = getkeystring(ptr + 2, &len, GETKEYS_DOLLARS_QUOTE, NULL);
+	    len += 2;
+	    tlen = strlen(t);
+	    diff = len - tlen;
+	    /*
+	     * Yuk.
+	     * parse_subst_string() currently handles strings in-place.
+	     * That's not so easy to fix without knowing whether
+	     * additional memory should come off the heap or
+	     * otherwise.  So we cheat by copying the unquoted string
+	     * into place, unless it's too long.  That's not the
+	     * normal case, but I'm worried there are are pathological
+	     * cases with converting metafied multibyte strings.
+	     * If someone can prove there aren't I will be very happy.
+	     */
+	    if (diff < 0) {
+		DPUTS(1, "$'...' subst too long: fix get_parse_string()");
+		return 1;
+	    }
+	    memcpy(ptr, t, tlen);
+	    ptr += tlen;
+	    if (diff > 0) {
+		char *dptr = ptr;
+		char *sptr = ptr + diff;
+		while ((*dptr++ = *sptr++))
+		    ;
+	    }
+	} else
+	    ptr++;
+    }
     return 0;
 }