| /* See LICENSE file for copyright and license details. */ |
| #include <string.h> |
| |
| #include "../util.h" |
| |
| size_t |
| unescape(char *s) |
| { |
| size_t len, i, off, m, factor, q; |
| |
| len = strlen(s); |
| |
| for (i = 0; i < len; i++) { |
| if (s[i] != '\\') |
| continue; |
| off = 0; |
| |
| switch (s[i + 1]) { |
| case '\\': s[i] = '\\'; off++; break; |
| case '\'': s[i] = '\'', off++; break; |
| case '"': s[i] = '"', off++; break; |
| case 'a': s[i] = '\a'; off++; break; |
| case 'b': s[i] = '\b'; off++; break; |
| case 'e': s[i] = 033; off++; break; |
| case 'f': s[i] = '\f'; off++; break; |
| case 'n': s[i] = '\n'; off++; break; |
| case 'r': s[i] = '\r'; off++; break; |
| case 't': s[i] = '\t'; off++; break; |
| case 'v': s[i] = '\v'; off++; break; |
| case 'x': |
| /* "\xH[H]" hexadecimal escape */ |
| for (m = i + 2; m < i + 1 + 3 && m < len; m++) |
| if ((s[m] < '0' && s[m] > '9') && |
| (s[m] < 'A' && s[m] > 'F') && |
| (s[m] < 'a' && s[m] > 'f')) |
| break; |
| if (m == i + 2) |
| eprintf("%s: invalid escape sequence '\\%c'\n", argv0, s[i + 1]); |
| off += m - i - 1; |
| for (--m, q = 0, factor = 1; m > i + 1; m--) { |
| if (s[m] >= '0' && s[m] <= '9') |
| q += (s[m] - '0') * factor; |
| else if (s[m] >= 'A' && s[m] <= 'F') |
| q += ((s[m] - 'A') + 10) * factor; |
| else if (s[m] >= 'a' && s[m] <= 'f') |
| q += ((s[m] - 'a') + 10) * factor; |
| factor *= 16; |
| } |
| s[i] = q; |
| break; |
| case '\0': |
| eprintf("%s: null escape sequence\n", argv0); |
| default: |
| /* "\O[OO]" octal escape */ |
| for (m = i + 1; m < i + 1 + 3 && m < len; m++) |
| if (s[m] < '0' || s[m] > '7') |
| break; |
| if (m == i + 1) |
| eprintf("%s: invalid escape sequence '\\%c'\n", argv0, s[i + 1]); |
| off += m - i - 1; |
| for (--m, q = 0, factor = 1; m > i; m--) { |
| q += (s[m] - '0') * factor; |
| factor *= 8; |
| } |
| s[i] = q; |
| } |
| |
| for (m = i + 1; m <= len - off; m++) |
| s[m] = s[m + off]; |
| len -= off; |
| } |
| |
| return len; |
| } |