1/* See LICENSE file for copyright and license details. */
2#include <ctype.h>
3#include <string.h>
4
5#include "../util.h"
6
7#define is_odigit(c) ('0' <= c && c <= '7')
8
9size_t
10unescape(char *s)
11{
12 static const char escapes[256] = {
13 ['"'] = '"',
14 ['\''] = '\'',
15 ['\\'] = '\\',
16 ['a'] = '\a',
17 ['b'] = '\b',
18 ['E'] = 033,
19 ['e'] = 033,
20 ['f'] = '\f',
21 ['n'] = '\n',
22 ['r'] = '\r',
23 ['t'] = '\t',
24 ['v'] = '\v'
25 };
26 size_t m, q;
27 char *r, *w;
28
29 for (r = w = s; *r;) {
30 if (*r != '\\') {
31 *w++ = *r++;
32 continue;
33 }
34 r++;
35 if (!*r) {
36 eprintf("null escape sequence\n");
37 } else if (escapes[(unsigned char)*r]) {
38 *w++ = escapes[(unsigned char)*r++];
39 } else if (is_odigit(*r)) {
40 for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
41 q = q * 8 + (*r - '0');
42 *w++ = MIN(q, (size_t)255);
43 } else if (*r == 'x' && isxdigit(r[1])) {
44 r++;
45 for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
46 if (isdigit(*r))
47 q = q * 16 + (*r - '0');
48 else
49 q = q * 16 + (tolower(*r) - 'a' + 10);
50 *w++ = q;
51 } else {
52 eprintf("invalid escape sequence '\\%c'\n", *r);
53 }
54 }
55 *w = '\0';
56
57 return w - s;
58}