diff --git a/libpoke/pkl-trans.c b/libpoke/pkl-trans.c index 18366ca0..f3195820 100644 --- a/libpoke/pkl-trans.c +++ b/libpoke/pkl-trans.c @@ -20,6 +20,7 @@ #include #define _(str) gettext (str) +#include #include #include #include @@ -304,6 +305,8 @@ PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_string) size_t string_length, i; bool found_backslash = false; +#define isodigit(c) ((unsigned)c - '0' < 8) // is octal digit + /* Please keep this code in sync with the string printer in pvm-val.c:pvm_print_val. */ @@ -311,27 +314,46 @@ PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_string) \-expansion, and report errors in the contents of the string. */ for (p = string_pointer, string_length = 0; *p != '\0'; ++p) { - if (p[0] == '\\') + string_length++; + if (*p != '\\') + continue; + + found_backslash = true; + ++p; + + if (isodigit (p[0])) + { + if (isodigit (p[1])) + p += isodigit (p[2]) && p[0] <= '3' ? 2 // reason: 0377 == 0xff + : 1; + continue; + } + + switch (*p) { - switch (p[1]) + case '\\': + case 'n': + case 't': + case '"': + break; + case 'x': + ++p; + if (!isxdigit (p[0])) { - case '\\': - case 'n': - case 't': - case '"': - string_length++; - break; - default: PKL_ERROR (PKL_AST_LOC (string), - "invalid \\%c sequence in string", p[1]); + _ ("\\x used with no following hex digits")); PKL_TRANS_PAYLOAD->errors++; PKL_PASS_ERROR; } - p++; - found_backslash = true; + if (isxdigit (p[1])) + ++p; + break; + default: + PKL_ERROR (PKL_AST_LOC (string), "invalid \\%c sequence in string", + *p); + PKL_TRANS_PAYLOAD->errors++; + PKL_PASS_ERROR; } - else - string_length++; } if (!found_backslash) @@ -342,24 +364,57 @@ PKL_PHASE_BEGIN_HANDLER (pkl_trans1_ps_string) for (p = string_pointer, i = 0; *p != '\0'; ++p, ++i) { - if (p[0] == '\\') + if (*p != '\\') { - switch (p[1]) + new_string_pointer[i] = *p; + continue; + } + ++p; + + // octal escape sequence + if (isodigit (p[0])) + { + new_string_pointer[i] = p[0] - '0'; + if (isodigit (p[1])) { - case '\\': new_string_pointer[i] = '\\'; break; - case 'n': new_string_pointer[i] = '\n'; break; - case 't': new_string_pointer[i] = '\t'; break; - case '"': new_string_pointer[i] = '"'; break; - default: - assert (0); + new_string_pointer[i] + = (new_string_pointer[i] << 3) | (p[1] - '0'); + ++p; + if (isodigit (p[1]) && p[-1] <= '3') + { + new_string_pointer[i] + = (new_string_pointer[i] << 3) | (p[1] - '0'); + ++p; + } } - p++; + continue; + } + + switch (*p) + { + case '\\': new_string_pointer[i] = '\\'; break; + case 'n': new_string_pointer[i] = '\n'; break; + case 't': new_string_pointer[i] = '\t'; break; + case '"': new_string_pointer[i] = '"'; break; + case 'x': +#define xd(x) ((unsigned)(x) - '0' < 10 ? (x) - '0' : ((x) | 0x20) - 'a' + 10) + ++p; + new_string_pointer[i] = xd (p[0]); + if (isxdigit (p[1])) + { + new_string_pointer[i] = (xd (p[0]) << 4) | xd (p[1]); + ++p; + } + break; +#undef xd + default: + assert (0); } - else - new_string_pointer[i] = p[0]; } new_string_pointer[i] = '\0'; +#undef isodigit + free (string_pointer); PKL_AST_STRING_POINTER (string) = new_string_pointer; }