summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Src/Zle/compcore.c55
-rw-r--r--Src/lex.c22
-rw-r--r--Src/utils.c24
-rw-r--r--Src/zsh.h4
5 files changed, 77 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog
index d8c091eab..3e5c5d4d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2007-01-08  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 23097: Src/lex.c, Src/utils.c, Src/zsh.h, Src/Zle/compcore.c:
+	splitting of $'...' strings in completion.
+
 2007-01-05  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
 	* 23091: Doc/Zsh/compctl.yo, Doc/Zsh/contrib.yo: fixes
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index a21b83569..2259db01a 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -1432,10 +1432,8 @@ set_comp_sep(void)
      *     set, which isn't necessarily correct if the quotes were typed by
      *     the user).
      * osq: c.f. odq, taking account of Snull's and embeded "'"'s.
-     * issq: flag that current quoting is single quotes; I assume that
-     *       civilization would end if we used a consistent way of
-     *       flagging the different types of quotes, or something.
-     * lsq: when quoting is single quotes (issq), counts the offset
+     * qttype: type of quotes using standard QT_* definitions.
+     * lsq: when quoting is single quotes (QT_SINGLE), counts the offset
      *      adjustment needed in the word being examined in the lexer loop.
      * sqq: the value of lsq for the current completion word.
      * qa:  not, unfortunately, a question and answer session with the
@@ -1443,7 +1441,7 @@ set_comp_sep(void)
      *      when stripping single quotes: 1 for RCQUOTES, 3 otherwise
      *      (because we leave a "'" in the final string).
      */
-    int dq = 0, odq, sq = 0, osq, issq = 0, sqq = 0, lsq = 0, qa = 0;
+    int dq = 0, odq, sq = 0, osq, qttype, sqq = 0, lsq = 0, qa = 0;
     /* dolq: like sq and dq but for dollars quoting. */
     int dolq = 0;
     /* remember some global variable values (except lp is local) */
@@ -1479,26 +1477,25 @@ set_comp_sep(void)
     addedx = 1;
     noerrs = 1;
     lexsave();
-    tmp = (char *) zhalloc(tl = 3 + strlen(s));
+    /*
+     * tl is the length of the temporary string including
+     * the space at the start and the x at the cursor position,
+     * but not the NULL byte.
+     */
+    tl = strlen(s) + 2;
+    tmp = (char *) zhalloc(tl + 1);
     tmp[0] = ' ';
     memcpy(tmp + 1, s, noffs);
     tmp[(scs = zlemetacs = 1 + noffs)] = 'x';
     strcpy(tmp + 2 + noffs, s + noffs);
 
-    switch (*compqstack) {
-    case QT_NONE:
-#ifdef DEBUG
-	dputs("BUG: head of compqstack is NULL");
-#endif
-	break;
-
+    switch ((qttype = *compqstack)) {
     case QT_BACKSLASH:
         remq = 1;
 	tmp = rembslash(tmp);
         break;
 
     case QT_SINGLE:
-        issq = 1;
         if (isset(RCQUOTES))
             qa = 1;
         else
@@ -1531,22 +1528,32 @@ set_comp_sep(void)
 	break;
 
     case QT_DOLLARS:
-	sl = strlen(tmp);
 	j = zlemetacs;
-	tmp = getkeystring(tmp, &tl,
+	tmp = getkeystring(tmp, &sl,
 			   GETKEY_DOLLAR_QUOTE|GETKEY_UPDATE_OFFSET,
 			   &zlemetacs);
-	/* The number of characters we removed because of $' quoting */
-	dolq = sl - tl;
+	/* The number of bytes we removed because of $' quoting */
+	dolq = tl - sl;
 	/* Offset into the word is modified, too... */
 	css += zlemetacs - j;
 	break;
+
+    case QT_NONE:
+    default: /* to silence compiler warnings */
+#ifdef DEBUG
+	dputs("BUG: head of compqstack is NULL");
+#endif
+	break;
+
     }
     odq = dq;
     osq = sq;
     inpush(dupstrspace(tmp), 0, NULL);
     zlemetaline = tmp;
-    zlemetall = tl - 1;
+    /*
+     * Length of temporary string, calculated above.
+     */
+    zlemetall = tl;
     strinbeg(0);
     noaliases = 1;
     do {
@@ -1582,7 +1589,7 @@ set_comp_sep(void)
                         dq--;
                 }
             }
-            if (issq) {
+            if (qttype == QT_SINGLE) {
                 for (p = tokstr, lsq = 0; *p; p++) {
                     if (sq && *p == Snull)
                         sq -= qa;
@@ -1606,6 +1613,8 @@ set_comp_sep(void)
 	    swe = we - 1 - dq - sq - dolq;
             sqq = lsq;
 	    soffs = zlemetacs - swb - css;
+	    DPUTS2(p[soffs] != 'x', "expecting 'x' at offset %d of \"%s\"",
+		   soffs, p);
 	    chuck(p + soffs);
 	    ns = dupstring(p);
 	}
@@ -1736,7 +1745,7 @@ set_comp_sep(void)
      */
     sav = s[(i = swb - 1 - sqq + dq)];
     s[i] = '\0';
-    qp = (issq ? dupstring(s) : rembslash(s));
+    qp = (qttype == QT_SINGLE) ? dupstring(s) : rembslash(s);
     s[i] = sav;
     if (swe < swb)
 	swe = swb;
@@ -1747,11 +1756,11 @@ set_comp_sep(void)
 	if ((int)strlen(ns) > swe - swb + 1)
 	    ns[swe - swb + 1] = '\0';
     }
-    qs = (issq ? dupstring(s + swe) : rembslash(s + swe));
+    qs = (qttype == QT_SINGLE) ? dupstring(s + swe) : rembslash(s + swe);
     sl = strlen(ns);
     if (soffs > sl)
 	soffs = sl;
-    if (issq) {
+    if (qttype == QT_SINGLE) {
         remsquote(qp);
         remsquote(qs);
     }
diff --git a/Src/lex.c b/Src/lex.c
index a568e25c4..7a0bf2b1c 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -96,18 +96,18 @@ mod_export int addedx;
 mod_export int wb, we;
 
 /* 1 if aliases should not be expanded */
- 
+
 /**/
 mod_export int noaliases;
 
 /* we are parsing a line sent to use by the editor */
- 
+
 /**/
 mod_export int zleparse;
- 
+
 /**/
 mod_export int wordbeg;
- 
+
 /**/
 mod_export int parbegin;
 
@@ -115,7 +115,7 @@ mod_export int parbegin;
 mod_export int parend;
 
 /* don't recognize comments */
- 
+
 /**/
 mod_export int nocomments;
 
@@ -1181,10 +1181,20 @@ gettokstr(int c, int sub)
 		STOPHIST
 		while ((c = hgetc()) != '\'' && !lexstop) {
 		    if (strquote && c == '\\') {
-			add(c);
 			c = hgetc();
 			if (lexstop)
 			    break;
+			/*
+			 * Mostly we don't need to do anything special
+			 * with escape backslashes or closing quotes
+			 * inside $'...'; however in completion we
+			 * need to be able to strip multiple backslashes
+			 * neatly.
+			 */
+			if (c == '\\' || c == '\'')
+			    add(Bnull);
+			else
+			    add('\\');
 		    } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
 			if (bptr[-1] == '\\')
 			    bptr--, len--;
diff --git a/Src/utils.c b/Src/utils.c
index d4bf6c2eb..6faf196a9 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3925,7 +3925,6 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int heap)
     ptr = unmetafy(ums, &umlen);
 
     memset(&mbs, 0, sizeof mbs);
-    mb_metacharinit();
     while (umlen > 0) {
 	size_t cnt = eol ? MB_INVALID : mbrtowc(&c, ptr, umlen, &mbs);
 
@@ -4577,10 +4576,27 @@ ucs4toutf8(char *dest, unsigned int wval)
 /*
  * Decode a key string, turning it into the literal characters.
  * The value returned is a newly allocated string from the heap.
- * The length is (usually) returned in *len.
+ *
+ * The length is returned in *len.  This is usually the length of
+ * the final unmetafied string.  The exception is the case of
+ * a complete GETKEY_DOLLAR_QUOTE conversion where *len is the
+ * length of the input string which has been used (up to and including
+ * the terminating single quote); as the final string is metafied and
+ * NULL-terminated its length is not required.  If both GETKEY_DOLLAR_QUOTE
+ * and GETKEY_UPDATE_OFFSET are present in "how", the string is not
+ * expected to be terminated (this is used in completion to parse
+ * a partial $'...'-quoted string) and the length passed back is
+ * that of the converted string.  Note in both cases that this is a length
+ * in bytes (i.e. the same as given by a raw pointer difference), not
+ * characters, which may occupy multiple bytes.
+ *
  * how is a set of bits from the GETKEY_ values defined in zsh.h;
  * not all combinations of bits are useful.  Callers will typically
  * use one of the GETKEYS_ values which define sets of bits.
+ * Note, for example that:
+ * - GETKEY_SINGLE_CHAR must not be combined with GETKEY_DOLLAR_QUOTE.
+ * - GETKEY_UPDATE_OFFSET is only allowed if GETKEY_DOLLAR_QUOTE is
+ *   also present.
  *
  * The return value is unmetafied unless GETKEY_DOLLAR_QUOTE is
  * in use.
@@ -4946,9 +4962,9 @@ getkeystring(char *s, int *len, int how, int *misc)
     if (how & GETKEY_DOLLAR_QUOTE)
 	*tdest = '\0';
     if (how & GETKEY_SINGLE_CHAR)
-      *misc = 0;
+	*misc = 0;
     else
-      *len = t - buf;
+	*len = ((how & GETKEY_DOLLAR_QUOTE) ? tdest : t) - buf;
     return buf;
 }
 
diff --git a/Src/zsh.h b/Src/zsh.h
index 752587c57..2f627a37f 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1914,8 +1914,12 @@ struct heap {
 #define STRINGIFY(x)		STRINGIFY_LITERAL(x)
 #define ERRMSG(x)		(__FILE__ ":" STRINGIFY(__LINE__) ": " x)
 # define DPUTS(X,Y) if (!(X)) {;} else dputs(ERRMSG(Y))
+# define DPUTS1(X,Y,Z1) if (!(X)) {;} else dputs(ERRMSG(Y), Z1)
+# define DPUTS2(X,Y,Z1,Z2) if (!(X)) {;} else dputs(ERRMSG(Y), Z1, Z2)
 #else
 # define DPUTS(X,Y)
+# define DPUTS1(X,Y,Z1)
+# define DPUTS2(X,Y,Z1,Z2)
 #endif
 
 /**************************/