busybox/libbb/process_escape_sequence.c
<<
>>
Prefs
   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 FAST_FUNC bb_process_escape_sequence(const char **ptr)
  20{
  21        /* bash builtin "echo -e '\ec'" interprets \e as ESC,
  22         * but coreutils "/bin/echo -e '\ec'" does not.
  23         * manpages tend to support coreutils way.
  24         * Update: coreutils added support for \e on 28 Oct 2009. */
  25        static const char charmap[] ALIGN1 = {
  26                'a',  'b', 'e', 'f',  'n',  'r',  't',  'v',  '\\', 0,
  27                '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
  28
  29        const char *p;
  30        const char *q;
  31        unsigned num_digits;
  32        unsigned r;
  33        unsigned n;
  34        unsigned d;
  35        unsigned base;
  36
  37        num_digits = n = 0;
  38        base = 8;
  39        q = *ptr;
  40
  41#ifdef WANT_HEX_ESCAPES
  42        if (*q == 'x') {
  43                ++q;
  44                base = 16;
  45                ++num_digits;
  46        }
  47#endif
  48
  49        /* 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. */
  52        do {
  53                d = (unsigned char)(*q) - '0';
  54#ifdef WANT_HEX_ESCAPES
  55                if (d >= 10) {
  56                        d = (unsigned char)(_tolower(*q)) - 'a' + 10;
  57                }
  58#endif
  59
  60                if (d >= base) {
  61#ifdef WANT_HEX_ESCAPES
  62                        if ((base == 16) && (!--num_digits)) {
  63/*                              return '\\'; */
  64                                --q;
  65                        }
  66#endif
  67                        break;
  68                }
  69
  70                r = n * base + d;
  71                if (r > UCHAR_MAX) {
  72                        break;
  73                }
  74
  75                n = r;
  76                ++q;
  77        } while (++num_digits < 3);
  78
  79        if (num_digits == 0) {  /* mnemonic escape sequence? */
  80                p = charmap;
  81                do {
  82                        if (*p == *q) {
  83                                q++;
  84                                break;
  85                        }
  86                } while (*++p);
  87                /* 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;
  91        }
  92
  93        *ptr = q;
  94
  95        return (char) n;
  96}
  97