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 source tree.
   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        const char *q;
  22        unsigned num_digits;
  23        unsigned n;
  24        unsigned base;
  25
  26        num_digits = n = 0;
  27        base = 8;
  28        q = *ptr;
  29
  30        if (WANT_HEX_ESCAPES && *q == 'x') {
  31                ++q;
  32                base = 16;
  33                ++num_digits;
  34        }
  35
  36        /* bash requires leading 0 in octal escapes:
  37         * \02 works, \2 does not (prints \ and 2).
  38         * We treat \2 as a valid octal escape sequence. */
  39        do {
  40                unsigned r;
  41#if !WANT_HEX_ESCAPES
  42                unsigned d = (unsigned char)(*q) - '0';
  43#else
  44                unsigned d = (unsigned char)_tolower(*q) - '0';
  45                if (d >= 10)
  46                        d += ('0' - 'a' + 10);
  47#endif
  48                if (d >= base) {
  49                        if (WANT_HEX_ESCAPES && base == 16) {
  50                                --num_digits;
  51                                if (num_digits == 0) {
  52                                        /* \x<bad_char>: return '\',
  53                                         * leave ptr pointing to x */
  54                                        return '\\';
  55                                }
  56                        }
  57                        break;
  58                }
  59
  60                r = n * base + d;
  61                if (r > UCHAR_MAX) {
  62                        break;
  63                }
  64
  65                n = r;
  66                ++q;
  67        } while (++num_digits < 3);
  68
  69        if (num_digits == 0) {
  70                /* Not octal or hex escape sequence.
  71                 * Is it one-letter one? */
  72
  73                /* bash builtin "echo -e '\ec'" interprets \e as ESC,
  74                 * but coreutils "/bin/echo -e '\ec'" does not.
  75                 * Manpages tend to support coreutils way.
  76                 * Update: coreutils added support for \e on 28 Oct 2009. */
  77                static const char charmap[] ALIGN1 = {
  78                        'a',  'b', 'e', 'f',  'n',  'r',  't',  'v',  '\\', '\0',
  79                        '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\',
  80                };
  81                const char *p = charmap;
  82                do {
  83                        if (*p == *q) {
  84                                q++;
  85                                break;
  86                        }
  87                } while (*++p != '\0');
  88                /* p points to found escape char or NUL,
  89                 * advance it and find what it translates to.
  90                 * Note that \NUL and unrecognized sequence \z return '\'
  91                 * and leave ptr pointing to NUL or z. */
  92                n = p[sizeof(charmap) / 2];
  93        }
  94
  95        *ptr = q;
  96
  97        return (char) n;
  98}
  99
 100char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src)
 101{
 102        while (1) {
 103                char c, c1;
 104                c = c1 = *src++;
 105                if (c1 == '\\')
 106                        c1 = bb_process_escape_sequence(&src);
 107                *dst = c1;
 108                if (c == '\0')
 109                        return dst;
 110                dst++;
 111        }
 112}
 113