unescape.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
unescape.c (1123B)
---
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
9 size_t
10 unescape(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, 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 }