master xplshn/aruu / shared / libutil / unescape.c
 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}