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