process_escape_sequence.c 2.3 KB

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