blob: 3ad908b57e07b14eb878b672a2eb7c1d4c378bb1 [file] [log] [blame]
Eric Andersenaad1a882001-03-16 22:47:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
Manuel Novoa III cad53642003-03-19 09:13:01 +00005 * Copyright (C) Manuel Novoa III <mjn3@codepoet.org>
Glenn L McGrathb4a1baa2003-01-13 22:09:50 +00006 * and Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenaad1a882001-03-16 22:47:14 +00007 *
Bernhard Reutner-Fischerb1629b12006-05-19 19:29:19 +00008 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenaad1a882001-03-16 22:47:14 +00009 */
10
Eric Andersenaad1a882001-03-16 22:47:14 +000011#include "libbb.h"
12
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000013#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
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000019char FAST_FUNC bb_process_escape_sequence(const char **ptr)
Eric Andersenaad1a882001-03-16 22:47:14 +000020{
Denis Vlasenko248b4a72008-09-19 23:43:59 +000021 /* bash builtin "echo -e '\ec'" interprets \e as ESC,
22 * but coreutils "/bin/echo -e '\ec'" does not.
Denys Vlasenko00f0ef42009-10-29 03:39:55 +010023 * manpages tend to support coreutils way.
24 * Update: coreutils added support for \e on 28 Oct 2009. */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000025 static const char charmap[] ALIGN1 = {
Denys Vlasenko00f0ef42009-10-29 03:39:55 +010026 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', 0,
27 '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
Eric Andersenaad1a882001-03-16 22:47:14 +000028
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000029 const char *p;
30 const char *q;
Denis Vlasenko248b4a72008-09-19 23:43:59 +000031 unsigned num_digits;
32 unsigned r;
33 unsigned n;
34 unsigned d;
35 unsigned base;
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000036
37 num_digits = n = 0;
38 base = 8;
Eric Andersene5dfced2001-04-09 22:48:12 +000039 q = *ptr;
Eric Andersenaad1a882001-03-16 22:47:14 +000040
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000041#ifdef WANT_HEX_ESCAPES
Eric Andersenb2a30052004-07-26 12:11:32 +000042 if (*q == 'x') {
Eric Andersenb2a30052004-07-26 12:11:32 +000043 ++q;
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000044 base = 16;
45 ++num_digits;
Eric Andersenb2a30052004-07-26 12:11:32 +000046 }
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000047#endif
Eric Andersenb2a30052004-07-26 12:11:32 +000048
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020049 /* bash requires leading 0 in octal escapes:
50 * \02 works, \2 does not (prints \ and 2).
51 * We treat \2 as a valid octal escape sequence. */
Manuel Novoa III cad53642003-03-19 09:13:01 +000052 do {
Denis Vlasenko7e754f12007-04-09 13:04:50 +000053 d = (unsigned char)(*q) - '0';
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000054#ifdef WANT_HEX_ESCAPES
55 if (d >= 10) {
Denis Vlasenko7e754f12007-04-09 13:04:50 +000056 d = (unsigned char)(_tolower(*q)) - 'a' + 10;
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000057 }
58#endif
59
60 if (d >= base) {
61#ifdef WANT_HEX_ESCAPES
62 if ((base == 16) && (!--num_digits)) {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000063/* return '\\'; */
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000064 --q;
65 }
66#endif
Eric Andersenccfc4482004-07-27 16:45:46 +000067 break;
Eric Andersenb2a30052004-07-26 12:11:32 +000068 }
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000069
70 r = n * base + d;
71 if (r > UCHAR_MAX) {
72 break;
Eric Andersene5dfced2001-04-09 22:48:12 +000073 }
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000074
75 n = r;
76 ++q;
77 } while (++num_digits < 3);
Eric Andersenaad1a882001-03-16 22:47:14 +000078
Eric Andersene5dfced2001-04-09 22:48:12 +000079 if (num_digits == 0) { /* mnemonic escape sequence? */
Manuel Novoa III cad53642003-03-19 09:13:01 +000080 p = charmap;
81 do {
Eric Andersene5dfced2001-04-09 22:48:12 +000082 if (*p == *q) {
83 q++;
84 break;
85 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000086 } while (*++p);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020087 /* p points to found escape char or NUL,
88 * advance it and find what it translates to */
89 p += sizeof(charmap) / 2;
90 n = *p;
Eric Andersene5dfced2001-04-09 22:48:12 +000091 }
Eric Andersenaad1a882001-03-16 22:47:14 +000092
Eric Andersene5dfced2001-04-09 22:48:12 +000093 *ptr = q;
Manuel Novoa III 413db4d2004-07-29 23:15:16 +000094
Eric Andersene5dfced2001-04-09 22:48:12 +000095 return (char) n;
Eric Andersenaad1a882001-03-16 22:47:14 +000096}