summaryrefslogtreecommitdiff
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
/**************************/