/* See LICENSE file for copyright and license details. */
#include <string.h>

#include "../util.h"

size_t
unescape(char *s)
{
	size_t len, i, off, m, factor, q;

	len = strlen(s);

	for (i = 0; i < len; i++) {
		if (s[i] != '\\')
			continue;
		off = 0;

		switch (s[i + 1]) {
		case '\\': s[i] = '\\'; off++; break;
		case '\'': s[i] = '\'', off++; break;
		case '"':  s[i] =  '"', off++; break;
		case 'a':  s[i] = '\a'; off++; break;
		case 'b':  s[i] = '\b'; off++; break;
		case 'e':  s[i] =  033; off++; break;
		case 'f':  s[i] = '\f'; off++; break;
		case 'n':  s[i] = '\n'; off++; break;
		case 'r':  s[i] = '\r'; off++; break;
		case 't':  s[i] = '\t'; off++; break;
		case 'v':  s[i] = '\v'; off++; break;
		case 'x':
			/* "\xH[H]" hexadecimal escape */
			for (m = i + 2; m < i + 1 + 3 && m < len; m++)
				if ((s[m] < '0' && s[m] > '9') &&
				    (s[m] < 'A' && s[m] > 'F') &&
				    (s[m] < 'a' && s[m] > 'f'))
					break;
			if (m == i + 2)
				eprintf("%s: invalid escape sequence '\\%c'\n", argv0, s[i + 1]);
			off += m - i - 1;
			for (--m, q = 0, factor = 1; m > i + 1; m--) {
				if (s[m] >= '0' && s[m] <= '9')
					q += (s[m] - '0') * factor;
				else if (s[m] >= 'A' && s[m] <= 'F')
					q += ((s[m] - 'A') + 10) * factor;
				else if (s[m] >= 'a' && s[m] <= 'f')
					q += ((s[m] - 'a') + 10) * factor;
				factor *= 16;
			}
			s[i] = q;
			break;
		case '\0':
			eprintf("%s: null escape sequence\n", argv0);
		default:
			/* "\O[OO]" octal escape */
			for (m = i + 1; m < i + 1 + 3 && m < len; m++)
				if (s[m] < '0' || s[m] > '7')
					break;
			if (m == i + 1)
				eprintf("%s: invalid escape sequence '\\%c'\n", argv0, s[i + 1]);
			off += m - i - 1;
			for (--m, q = 0, factor = 1; m > i; m--) {
				q += (s[m] - '0') * factor;
				factor *= 8;
			}
			s[i] = q;
		}

		for (m = i + 1; m <= len - off; m++)
			s[m] = s[m + off];
		len -= off;
	}

	return len;
}