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).
This commit is contained in:
+47
-33
@@ -753,40 +753,58 @@ nmcpy(dest, src, maxlen)
|
|||||||
* has the effect of 'meta'-ing the value which follows (so that the
|
* has the effect of 'meta'-ing the value which follows (so that the
|
||||||
* alternate character set will be enabled).
|
* alternate character set will be enabled).
|
||||||
*
|
*
|
||||||
* For 3.4.3 and earlier, ending with "\M", backslash, or caret prior
|
* For 3.4.3 and earlier, input ending with "\M", backslash, or caret
|
||||||
* to terminating '\0' would pull that '\0' into the output and then
|
* prior to terminating '\0' would pull that '\0' into the output and then
|
||||||
* keep processing past it. Now, a trailing escape will be handled
|
* keep processing past it, potentially overflowing the output buffer.
|
||||||
* as if it was preceded with its own backslash and be kept as is,
|
* Now, trailing \ or ^ will act like \\ or \^ and add '\\' or '^' to the
|
||||||
* with end of string terminator always honored as end of input.
|
* output and stop there; trailing \M will fall through to \<other> and
|
||||||
|
* yield 'M', then stop. Any \X or \O followed by something other than
|
||||||
|
* an appropriate digit will also fall through to \<other> and yield 'X'
|
||||||
|
* or 'O', plus stop if the non-digit is end-of-string.
|
||||||
*/
|
*/
|
||||||
STATIC_OVL void
|
STATIC_OVL void
|
||||||
escapes(cp, tp)
|
escapes(cp, tp)
|
||||||
const char *cp;
|
const char *cp;
|
||||||
char *tp;
|
char *tp;
|
||||||
{
|
{
|
||||||
|
static NEARDATA const char
|
||||||
|
oct[] = "01234567", dec[] = "0123456789",
|
||||||
|
hex[] = "00112233445566778899aAbBcCdDeEfF";
|
||||||
|
const char *dp;
|
||||||
|
int cval, meta, dcount;
|
||||||
|
|
||||||
while (*cp) {
|
while (*cp) {
|
||||||
int cval = 0, meta = 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;
|
||||||
|
|
||||||
if (*cp == '\\' && cp[1] && index("mM", cp[1]) && cp[2]) {
|
cval = dcount = 0; /* for decimal, octal, hexadecimal cases */
|
||||||
meta = 1;
|
if ((*cp != '\\' && *cp != '^') || !cp[1]) {
|
||||||
cp += 2;
|
/* simple character, or nothing left for \ or ^ to escape */
|
||||||
}
|
cval = *cp++;
|
||||||
if (*cp == '\\' && cp[1] && index("0123456789xXoO", cp[1]) && cp[2]) {
|
} else if (*cp == '^') { /* expand control-character syntax */
|
||||||
NEARDATA const char hex[] = "00112233445566778899aAbBcCdDeEfF";
|
cval = (*++cp & 0x1f);
|
||||||
const char *dp;
|
++cp;
|
||||||
int dcount = 0;
|
/* remaining cases are all for backslash and we know cp[1] is not \0 */
|
||||||
|
} else if (index(dec, cp[1])) {
|
||||||
cp++;
|
++cp; /* move past backslash to first digit */
|
||||||
if (*cp == 'x' || *cp == 'X')
|
do {
|
||||||
for (++cp; *cp && (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
|
cval = (cval * 10) + (*cp - '0');
|
||||||
cval = (cval * 16) + ((int)(dp - hex) / 2);
|
} while (*++cp && index(dec, *cp) && ++dcount < 3);
|
||||||
else if (*cp == 'o' || *cp == 'O')
|
} else if ((cp[1] == 'o' || cp[1] == 'O') &&
|
||||||
for (++cp; *cp && (index("01234567",*cp)) && (dcount++ < 3); cp++)
|
cp[2] && index(oct, cp[2])) {
|
||||||
cval = (cval * 8) + (*cp - '0');
|
cp += 2; /* move past backslash and 'O' */
|
||||||
else
|
do {
|
||||||
for (; *cp && (index("0123456789",*cp)) && (dcount++ < 3); cp++)
|
cval = (cval * 8) + (*cp - '0');
|
||||||
cval = (cval * 10) + (*cp - '0');
|
} while (*++cp && index(oct, *cp) && ++dcount < 3);
|
||||||
} else if (*cp == '\\' && cp[1]) { /* C-style character escapes */
|
} 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) {
|
switch (*++cp) {
|
||||||
case '\\': cval = '\\'; break;
|
case '\\': cval = '\\'; break;
|
||||||
case 'n': cval = '\n'; break;
|
case 'n': cval = '\n'; break;
|
||||||
@@ -795,16 +813,12 @@ char *tp;
|
|||||||
case 'r': cval = '\r'; break;
|
case 'r': cval = '\r'; break;
|
||||||
default: cval = *cp;
|
default: cval = *cp;
|
||||||
}
|
}
|
||||||
cp++;
|
++cp;
|
||||||
} else if (*cp == '^' && cp[1]) { /* expand control-character syntax */
|
}
|
||||||
cval = (*++cp & 0x1f);
|
|
||||||
cp++;
|
|
||||||
} else
|
|
||||||
cval = *cp++;
|
|
||||||
|
|
||||||
if (meta)
|
if (meta)
|
||||||
cval |= 0x80;
|
cval |= 0x80;
|
||||||
*tp++ = cval;
|
*tp++ = (char)cval;
|
||||||
}
|
}
|
||||||
*tp = '\0';
|
*tp = '\0';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user