summaryrefslogtreecommitdiff
path: root/Src/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/utils.c')
-rw-r--r--Src/utils.c140
1 files changed, 121 insertions, 19 deletions
diff --git a/Src/utils.c b/Src/utils.c
index 5b6998950..de1a219f7 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4563,10 +4563,14 @@ 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.
* 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.
+ *
+ * The return value is unmetafied unless GETKEY_DOLLAR_QUOTE is
+ * in use.
*/
/**/
@@ -4574,7 +4578,7 @@ mod_export char *
getkeystring(char *s, int *len, int how, int *misc)
{
char *buf, tmp[1];
- char *t, *u = NULL;
+ char *t, *tdest = NULL, *u = NULL, *sstart = s;
char svchar = '\0';
int meta = 0, control = 0;
int i;
@@ -4591,16 +4595,42 @@ getkeystring(char *s, int *len, int how, int *misc)
# endif
#endif
+ DPUTS((how & GETKEY_UPDATE_OFFSET) &&
+ (how & ~(GETKEY_DOLLAR_QUOTE|GETKEY_UPDATE_OFFSET)),
+ "BUG: offset updating in getkeystring only supported with $'.");
+
if (how & GETKEY_SINGLE_CHAR)
t = buf = tmp;
- else if (!(how & GETKEY_DOLLAR_QUOTE))
+ else
t = buf = zhalloc(strlen(s) + 1);
- else {
- t = buf = s;
- s += 2;
+ if (how & GETKEY_DOLLAR_QUOTE) {
+ /*
+ * TODO: we're not necessarily guaranteed the output string will
+ * be no longer than the input with \u and \U when output
+ * characters need to be metafied: should check the maximum
+ * length.
+ *
+ * We're going to unmetafy into the original string, but
+ * to get a proper metafied input we're going to metafy
+ * into an allocated buffer. This is necessary if we have
+ * \u and \U's with multiple metafied bytes. We can't
+ * simply remetafy the entire string because there may
+ * be tokens (indeed, we know there are lexical nulls floating
+ * around), so we have to be aware character by character
+ * what we are converting.
+ */
+ tdest = t;
+ t = s;
}
for (; *s; s++) {
+ char *torig = t;
if (*s == '\\' && s[1]) {
+ int miscadded;
+ if ((how & GETKEY_UPDATE_OFFSET) && s - sstart > *misc) {
+ (*misc)++;
+ miscadded = 1;
+ } else
+ miscadded = 0;
switch (*++s) {
case 'a':
#ifdef __STDC__
@@ -4630,6 +4660,8 @@ getkeystring(char *s, int *len, int how, int *misc)
case 'E':
if (!(how & GETKEY_EMACS)) {
*t++ = '\\', s--;
+ if (miscadded)
+ (*misc)--;
continue;
}
/* FALL THROUGH */
@@ -4641,18 +4673,26 @@ getkeystring(char *s, int *len, int how, int *misc)
if (s[1] == '-')
s++;
meta = 1 + control; /* preserve the order of ^ and meta */
- } else
+ } else {
+ if (miscadded)
+ (*misc)--;
*t++ = '\\', s--;
+ }
continue;
case 'C':
if (how & GETKEY_EMACS) {
if (s[1] == '-')
s++;
control = 1;
- } else
+ } else {
+ if (miscadded)
+ (*misc)--;
*t++ = '\\', s--;
+ }
continue;
case Meta:
+ if (miscadded)
+ (*misc)--;
*t++ = '\\', s--;
break;
case '-':
@@ -4670,7 +4710,17 @@ getkeystring(char *s, int *len, int how, int *misc)
}
goto def;
case 'u':
+ if ((how & GETKEY_UPDATE_OFFSET) && s - sstart > *misc)
+ (*misc) += 4;
case 'U':
+ if ((how & GETKEY_UPDATE_OFFSET) && s - sstart > *misc) {
+ (*misc) += 6;
+ /*
+ * We've now adjusted the offset for all the input
+ * characters, so we need to subtract for each
+ * byte of output below.
+ */
+ }
wval = 0;
for (i=(*s == 'u' ? 4 : 8); i>0; i--) {
if (*++s && idigit(*s))
@@ -4692,19 +4742,29 @@ getkeystring(char *s, int *len, int how, int *misc)
if (count == -1) {
zerr("character not in range");
if (how & GETKEY_DOLLAR_QUOTE) {
- for (u = t; (*u++ = *++s););
+ /* HERE new convention */
+ for (u = t; (*u++ = *++s);) {
+ if ((how & GETKEY_UPDATE_OFFSET) &&
+ s - sstart > *misc)
+ (*misc)++;
+ }
return t;
}
*t = '\0';
*len = t - buf;
return buf;
}
+ if ((how & GETKEY_UPDATE_OFFSET) && s - sstart > *misc)
+ (*misc) += count;
t += count;
continue;
# else
# if defined(HAVE_NL_LANGINFO) && defined(CODESET)
if (!strcmp(nl_langinfo(CODESET), "UTF-8")) {
- t += ucs4toutf8(t, wval);
+ count = ucs4toutf8(t, wval);
+ t += count;
+ if ((how & GETKEY_UPDATE_OFFSET) && s - sstart > *misc)
+ (*misc) += count;
continue;
} else {
# ifdef HAVE_ICONV
@@ -4721,7 +4781,12 @@ getkeystring(char *s, int *len, int how, int *misc)
if (cd == (iconv_t)-1) {
zerr("cannot do charset conversion");
if (how & GETKEY_DOLLAR_QUOTE) {
- for (u = t; (*u++ = *++s););
+ /* HERE: new convention */
+ for (u = t; (*u++ = *++s);) {
+ if ((how & GETKEY_UPDATE_OFFSET) &&
+ s - sstart > *misc)
+ (*misc)++;
+ }
return t;
}
*t = '\0';
@@ -4736,6 +4801,8 @@ getkeystring(char *s, int *len, int how, int *misc)
*len = t - buf;
return buf;
}
+ if ((how & GETKEY_UPDATE_OFFSET) && s - sstart > *misc)
+ (*misc) += count;
continue;
# else
zerr("cannot do charset conversion");
@@ -4775,15 +4842,20 @@ getkeystring(char *s, int *len, int how, int *misc)
}
s--;
} else {
- if (!(how & GETKEY_EMACS) && *s != '\\')
+ if (!(how & GETKEY_EMACS) && *s != '\\') {
+ if (miscadded)
+ (*misc)--;
*t++ = '\\';
+ }
*t++ = *s;
}
break;
}
} else if ((how & GETKEY_DOLLAR_QUOTE) && *s == Snull) {
- for (u = t; (*u++ = *s++););
- return t + 1;
+ /* return length to following character */
+ *len = (s - sstart) + 1;
+ *tdest = '\0';
+ return buf;
} else if (*s == '^' && !control && (how & GETKEY_CTRL) && s[1]) {
control = 1;
continue;
@@ -4801,8 +4873,25 @@ getkeystring(char *s, int *len, int how, int *misc)
} else if (*s == Meta)
*t++ = *++s ^ 32;
- else
+ else {
*t++ = *s;
+ if (itok(*s)) {
+ if (meta || control) {
+ /*
+ * Presumably we should be using meta or control
+ * on the character representing the token.
+ */
+ *s = ztokens[*s - Pound];
+ } else if (how & GETKEY_DOLLAR_QUOTE) {
+ /*
+ * We don't want to metafy this, it's a real
+ * token.
+ */
+ *tdest++ = *s;
+ continue;
+ }
+ }
+ }
if (meta == 2) {
t[-1] |= 0x80;
meta = 0;
@@ -4818,18 +4907,31 @@ getkeystring(char *s, int *len, int how, int *misc)
t[-1] |= 0x80;
meta = 0;
}
- if ((how & GETKEY_DOLLAR_QUOTE) && imeta(t[-1])) {
- *t = t[-1] ^ 32;
- t[-1] = Meta;
- t++;
+ if (how & GETKEY_DOLLAR_QUOTE) {
+ char *t2;
+ for (t2 = torig; t2 < t; t2++) {
+ if (imeta(*t2)) {
+ *tdest++ = Meta;
+ *tdest++ = *t2 ^ 32;
+ } else
+ *tdest++ = *t2;
+ }
}
if ((how & GETKEY_SINGLE_CHAR) && t != tmp) {
*misc = STOUC(tmp[0]);
return s + 1;
}
}
- DPUTS(how & GETKEY_DOLLAR_QUOTE, "BUG: unterminated $' substitution");
+ /*
+ * When called from completion, where we use GETKEY_UPDATE_OFFSET to
+ * update the index into the metafied editor line, we don't necessarily
+ * have the end of a $'...' quotation, else we should do.
+ */
+ DPUTS((how & (GETKEY_DOLLAR_QUOTE|GETKEY_UPDATE_OFFSET)) ==
+ GETKEY_DOLLAR_QUOTE, "BUG: unterminated $' substitution");
*t = '\0';
+ if (how & GETKEY_DOLLAR_QUOTE)
+ *tdest = '\0';
if (how & GETKEY_SINGLE_CHAR)
*misc = 0;
else