aboutsummaryrefslogtreecommitdiff
path: root/ed.xmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'ed.xmap.c')
-rw-r--r--ed.xmap.c145
1 files changed, 129 insertions, 16 deletions
diff --git a/ed.xmap.c b/ed.xmap.c
index cc7d7054a229..f293825a4654 100644
--- a/ed.xmap.c
+++ b/ed.xmap.c
@@ -543,7 +543,7 @@ printOne(const Char *key, const XmapVal *val, int ntype)
struct KeyFuncs *fp;
static const char *fmt = "%s\n";
- xprintf("%-15S-> ", key);
+ xprintf("%-15" TCSH_S "-> ", key);
if (val != NULL)
switch (ntype) {
case XK_STR:
@@ -604,8 +604,60 @@ unparsech(struct Strbuf *buf, Char ch)
}
}
+static Char
+parse_hex_range(const Char **cp, size_t l)
+{
+ size_t ui = 0;
+ Char r = 0, c;
+
+ if (l > 8)
+ abort();
+
+ for (; (c = (**cp & CHAR)) != '\0' && ui < l && Isxdigit(c); (*cp)++, ui++) {
+ Char x = Isdigit(c) ? '0' : ((Isupper(c) ? 'A' : 'a') - 10);
+#ifndef IS_ASCII
+ c = _toascii(c);
+#endif
+ r <<= 4;
+ r |= c - x;
+ }
+ (*cp)--;
+#ifndef IS_ASCII
+ return _toebcdic[r & 0xff];
+#else
+ return r;
+#endif
+}
+
+static int
+okcontrol(Char c)
+{
+ return c && (isalpha(c & CHAR) || strchr("@^_?\\|[{]}", c));
+}
+
+static Char
+handlecontrol(Char c)
+{
+ Char o;
+#ifdef IS_ASCII
+ o = (c == '?') ? CTL_ESC('\177') : (c & 0237);
+#else
+ o = (c == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[c] & 0237];
+ if (adrof(STRwarnebcdic))
+ xprintf(/*CGETS(9, 9, no NLS-String yet!*/
+ "Warning: Control character %s%c may be interpreted differently in EBCDIC.\n", "\\c", c /*)*/);
+#endif
+ return o;
+}
+
+/*
+ * The e parameter is false when we are doing echo and true when we are
+ * using it to parse other escaped strings. For echo, we don't print errors
+ * and we don't unescape backslashes that we don't understand. Perhaps we
+ * always not unescape backslashes we don't understand...
+ */
eChar
-parseescape(const Char **ptr)
+parseescape(const Char **ptr, int e)
{
const Char *p;
Char c;
@@ -613,7 +665,8 @@ parseescape(const Char **ptr)
p = *ptr;
if ((p[1] & CHAR) == 0) {
- xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p);
+ if (e)
+ xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p);
return CHAR_ERR;
}
if ((*p & CHAR) == '\\') {
@@ -625,6 +678,34 @@ parseescape(const Char **ptr)
case 'b':
c = CTL_ESC('\010'); /* Backspace */
break;
+ case 'c':
+ p++;
+ if ((*p & CHAR) == '\\') {
+ p++;
+ if ((*p & CHAR) != '\\') {
+out:
+ *ptr = p;
+ if (e)
+ xprintf(/*CGETS(9, 9, */
+ "Invalid escape sequence: %s%c\n"/*)*/, "\\c\\", (char)*p);
+ return CHAR_ERR;
+ }
+ c = (*p & CHAR) & 0237;
+ } else if (okcontrol(*p & CHAR)) {
+ c = handlecontrol(*p & CHAR);
+ } else { /* backward compat */
+ /*
+ * we allow a plain \c to mean no more output for echo,
+ * (e is FALSE) and return CHAR_EOF, but we require a
+ * control character for the rest of the cases.
+ */
+ if (e)
+ goto out;
+ /* point to the last character */
+ *ptr = p - 1;
+ return CHAR_EOF;
+ }
+ break;
case 'e':
c = CTL_ESC('\033'); /* Escape */
break;
@@ -646,6 +727,41 @@ parseescape(const Char **ptr)
case '\\':
c = '\\';
break;
+ case 'x':
+ p++;
+ if ((*p & CHAR) == '{' && Isxdigit(*(p + 1) & CHAR)) { /* \x{20ac} */
+ const Char *q = p - 2;
+ p++;
+ c = parse_hex_range(&p, 8);
+ if ((p[1] & CHAR) != '}') {
+ if (e)
+ xprintf("%s", /* CGETS(9, 9, */
+ "Missing closing brace");
+ p = q;
+ c = '\\';
+ break;
+ }
+ p++;
+ } else if (Isxdigit(*p & CHAR)) { /* \x9f */
+ c = parse_hex_range(&p, 2);
+ } else { /* backward compat */
+ c = '\\';
+ p -= 2;
+ }
+ break;
+ case 'u':
+ case 'U':
+ {
+ size_t limit = (*p & CHAR) == 'u' ? 4 : 8;
+ p++;
+ if (Isxdigit(*p & CHAR)) { /* \u20ac or \U000020ac */
+ c = parse_hex_range(&p, limit);
+ } else { /* backward compat */
+ c = '\\';
+ p -= 2;
+ }
+ }
+ break;
case '0':
case '1':
case '2':
@@ -667,35 +783,32 @@ parseescape(const Char **ptr)
val = (val << 3) | (ch - '0');
}
if ((val & ~0xff) != 0) {
- xprintf("%s", CGETS(9, 9,
+ if (e)
+ xprintf("%s", CGETS(9, 9,
"Octal constant does not fit in a char.\n"));
- return 0;
+ *ptr = p;
+ return CHAR_ERR;
}
#ifndef IS_ASCII
if (CTL_ESC(val) != val && adrof(STRwarnebcdic))
xprintf(/*CGETS(9, 9, no NLS-String yet!*/
- "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/);
+ "Warning: Octal constant \\%3.3o is interpreted as "
+ "EBCDIC value.\n", val/*)*/);
#endif
c = (Char) val;
--p;
}
break;
default:
+ if (!e)
+ --p;
c = *p;
break;
}
}
- else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) ||
- strchr("@^_?\\|[{]}", p[1] & CHAR))) {
+ else if ((*p & CHAR) == '^' && okcontrol(p[1] & CHAR)) {
p++;
-#ifdef IS_ASCII
- c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
-#else
- c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
- if (adrof(STRwarnebcdic))
- xprintf(/*CGETS(9, 9, no NLS-String yet!*/
- "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/);
-#endif
+ c = handlecontrol(*p & CHAR);
}
else
c = *p & CHAR;