File nethack-escapes-revamp.patch of Package nethack
From 612755bfb5c412079795c68ba392df5d93874ed8 Mon Sep 17 00:00:00 2001
From: "nethack.rankin" <nethack.rankin>
Date: Thu, 4 Aug 2011 02:41:44 +0000
Subject: [PATCH] escapes() revamp
Partial rewrite of escapes(), mostly changing its if-then-else
logic so that end-of-string can be checked once instead for each case.
The previous version had a bug if the input string ended with backslash
and one decimal digit (due to being lumped together with the handling
for trailing \X or \O).
---
src/options.c | 82 ++++++++++++++++++++++++++++++---------------------
1 file changed, 48 insertions(+), 34 deletions(-)
Index: src/options.c
===================================================================
--- src/options.c.orig
+++ src/options.c
@@ -633,32 +633,45 @@ escapes(cp, tp)
const char *cp;
char *tp;
{
+ static NEARDATA const char
+ oct[] = "01234567", dec[] = "0123456789",
+ hex[] = "00112233445566778899aAbBcCdDeEfF";
+ const char *dp;
+ int cval, meta, dcount;
+
while (*cp)
{
- int cval = 0, meta = 0;
-
- if (*cp == '\\' && index("mM", cp[1])) {
- meta = 1;
- cp += 2;
- }
- if (*cp == '\\' && index("0123456789xXoO", cp[1]))
- {
- const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
- int dcount = 0;
+ /* \M has to be followed by something to do meta conversion,
+ otherwise it will just be \M which ultimately yields 'M' */
+ meta = (*cp == '\\' && (cp[1] == 'm' || cp[1] == 'M') && cp[2]);
+ if (meta) cp += 2;
- cp++;
- if (*cp == 'x' || *cp == 'X')
- for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
- cval = (cval * 16) + (dp - hex) / 2;
- else if (*cp == 'o' || *cp == 'O')
- for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
- cval = (cval * 8) + (*cp - '0');
- else
- for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
- cval = (cval * 10) + (*cp - '0');
- }
- else if (*cp == '\\') /* C-style character escapes */
- {
+ cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
+ if ((*cp != '\\' && *cp != '^') || !cp[1]) {
+ /* simple character, or nothing left for \ or ^ to escape */
+ cval = *cp++;
+ } else if (*cp == '^') { /* expand control-character syntax */
+ cval = (*++cp & 0x1f);
+ ++cp;
+ /* remaining cases are all for backslash and we know cp[1] is not \0 */
+ } else if (index(dec, cp[1])) {
+ ++cp; /* move past backslash to first digit */
+ do {
+ cval = (cval * 10) + (*cp - '0');
+ } while (*++cp && index(dec, *cp) && ++dcount < 3);
+ } else if ((cp[1] == 'o' || cp[1] == 'O') &&
+ cp[2] && index(oct, cp[2])) {
+ cp += 2; /* move past backslash and 'O' */
+ do {
+ cval = (cval * 8) + (*cp - '0');
+ } while (*++cp && index(oct, *cp) && ++dcount < 3);
+ } else if ((cp[1] == 'x' || cp[1] == 'X') &&
+ cp[2] && (dp = index(hex, cp[2])) != 0) {
+ cp += 2; /* move past backslash and 'X' */
+ do {
+ cval = (cval * 16) + ((int)(dp - hex) / 2);
+ } while (*++cp && (dp = index(hex, *cp)) != 0 && ++dcount < 2);
+ } else { /* C-style character escapes */
switch (*++cp)
{
case '\\': cval = '\\'; break;
@@ -668,18 +681,12 @@ char *tp;
case 'r': cval = '\r'; break;
default: cval = *cp;
}
- cp++;
- }
- else if (*cp == '^') /* expand control-character syntax */
- {
- cval = (*++cp & 0x1f);
- cp++;
+ ++cp;
}
- else
- cval = *cp++;
+
if (meta)
cval |= 0x80;
- *tp++ = cval;
+ *tp++ = (char)cval;
}
*tp = '\0';
}