summaryrefslogtreecommitdiff
path: root/util/sbase/libutil/unescape.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/sbase/libutil/unescape.c')
-rw-r--r--util/sbase/libutil/unescape.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/util/sbase/libutil/unescape.c b/util/sbase/libutil/unescape.c
new file mode 100644
index 00000000..b8f75ca9
--- /dev/null
+++ b/util/sbase/libutil/unescape.c
@@ -0,0 +1,58 @@
+/* See LICENSE file for copyright and license details. */
+#include <ctype.h>
+#include <string.h>
+
+#include "../util.h"
+
+#define is_odigit(c) ('0' <= c && c <= '7')
+
+size_t
+unescape(char *s)
+{
+ static const char escapes[256] = {
+ ['"'] = '"',
+ ['\''] = '\'',
+ ['\\'] = '\\',
+ ['a'] = '\a',
+ ['b'] = '\b',
+ ['E'] = 033,
+ ['e'] = 033,
+ ['f'] = '\f',
+ ['n'] = '\n',
+ ['r'] = '\r',
+ ['t'] = '\t',
+ ['v'] = '\v'
+ };
+ size_t m, q;
+ char *r, *w;
+
+ for (r = w = s; *r;) {
+ if (*r != '\\') {
+ *w++ = *r++;
+ continue;
+ }
+ r++;
+ if (!*r) {
+ eprintf("null escape sequence\n");
+ } else if (escapes[(unsigned char)*r]) {
+ *w++ = escapes[(unsigned char)*r++];
+ } else if (is_odigit(*r)) {
+ for (q = 0, m = 3; m && is_odigit(*r); m--, r++)
+ q = q * 8 + (*r - '0');
+ *w++ = MIN(q, 255);
+ } else if (*r == 'x' && isxdigit(r[1])) {
+ r++;
+ for (q = 0, m = 2; m && isxdigit(*r); m--, r++)
+ if (isdigit(*r))
+ q = q * 16 + (*r - '0');
+ else
+ q = q * 16 + (tolower(*r) - 'a' + 10);
+ *w++ = q;
+ } else {
+ eprintf("invalid escape sequence '\\%c'\n", *r);
+ }
+ }
+ *w = '\0';
+
+ return w - s;
+}