1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) Manuel Novoa III <mjn3@codepoet.org>
6 * and Vladimir Oleynik <dzo@simtreas.ru>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "libbb.h"
12
13#define WANT_HEX_ESCAPES 1
14
15/* Usual "this only works for ascii compatible encodings" disclaimer. */
16#undef _tolower
17#define _tolower(X) ((X)|((char) 0x20))
18
19char bb_process_escape_sequence(const char **ptr)
20{
21	static const char charmap[] ALIGN1 = {
22		'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
23		'\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
24
25	const char *p;
26	const char *q;
27	unsigned int num_digits;
28	unsigned int r;
29	unsigned int n;
30	unsigned int d;
31	unsigned int base;
32
33	num_digits = n = 0;
34	base = 8;
35	q = *ptr;
36
37#ifdef WANT_HEX_ESCAPES
38	if (*q == 'x') {
39		++q;
40		base = 16;
41		++num_digits;
42	}
43#endif
44
45	do {
46		d = (unsigned char)(*q) - '0';
47#ifdef WANT_HEX_ESCAPES
48		if (d >= 10) {
49			d = (unsigned char)(_tolower(*q)) - 'a' + 10;
50		}
51#endif
52
53		if (d >= base) {
54#ifdef WANT_HEX_ESCAPES
55			if ((base == 16) && (!--num_digits)) {
56/*				return '\\'; */
57				--q;
58			}
59#endif
60			break;
61		}
62
63		r = n * base + d;
64		if (r > UCHAR_MAX) {
65			break;
66		}
67
68		n = r;
69		++q;
70	} while (++num_digits < 3);
71
72	if (num_digits == 0) {	/* mnemonic escape sequence? */
73		p = charmap;
74		do {
75			if (*p == *q) {
76				q++;
77				break;
78			}
79		} while (*++p);
80		n = *(p + (sizeof(charmap)/2));
81	}
82
83	*ptr = q;
84
85	return (char) n;
86}
87