sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | 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 = 4; 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 }