echo.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * echo implementation for busybox - used as a helper for testsuite/*
  4. * on systems lacking "echo -en"
  5. *
  6. * Copyright (c) 1991, 1993
  7. * The Regents of the University of California. All rights reserved.
  8. *
  9. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10. *
  11. * Original copyright notice is retained at the end of this file.
  12. */
  13. /* BB_AUDIT SUSv3 compliant -- unless configured as fancy echo. */
  14. /* http://www.opengroup.org/onlinepubs/007904975/utilities/echo.html */
  15. /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
  16. *
  17. * Because of behavioral differences, implemented configurable SUSv3
  18. * or 'fancy' gnu-ish behaviors. Also, reduced size and fixed bugs.
  19. * 1) In handling '\c' escape, the previous version only suppressed the
  20. * trailing newline. SUSv3 specifies _no_ output after '\c'.
  21. * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
  22. * The previous version did not allow 4-digit octals.
  23. */
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <limits.h>
  27. #include <unistd.h>
  28. #define WANT_HEX_ESCAPES 1
  29. /* Usual "this only works for ascii compatible encodings" disclaimer. */
  30. #undef _tolower
  31. #define _tolower(X) ((X)|((char) 0x20))
  32. static char bb_process_escape_sequence(const char **ptr)
  33. {
  34. static const char charmap[] = {
  35. 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0,
  36. '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
  37. const char *p;
  38. const char *q;
  39. unsigned int num_digits;
  40. unsigned int r;
  41. unsigned int n;
  42. unsigned int d;
  43. unsigned int base;
  44. num_digits = n = 0;
  45. base = 8;
  46. q = *ptr;
  47. #ifdef WANT_HEX_ESCAPES
  48. if (*q == 'x') {
  49. ++q;
  50. base = 16;
  51. ++num_digits;
  52. }
  53. #endif
  54. do {
  55. d = (unsigned char)(*q) - '0';
  56. #ifdef WANT_HEX_ESCAPES
  57. if (d >= 10) {
  58. d = (unsigned char)(_tolower(*q)) - 'a' + 10;
  59. }
  60. #endif
  61. if (d >= base) {
  62. #ifdef WANT_HEX_ESCAPES
  63. if ((base == 16) && (!--num_digits)) {
  64. /* return '\\'; */
  65. --q;
  66. }
  67. #endif
  68. break;
  69. }
  70. r = n * base + d;
  71. if (r > UCHAR_MAX) {
  72. break;
  73. }
  74. n = r;
  75. ++q;
  76. } while (++num_digits < 3);
  77. if (num_digits == 0) { /* mnemonic escape sequence? */
  78. p = charmap;
  79. do {
  80. if (*p == *q) {
  81. q++;
  82. break;
  83. }
  84. } while (*++p);
  85. n = *(p + (sizeof(charmap)/2));
  86. }
  87. *ptr = q;
  88. return (char) n;
  89. }
  90. int main(int argc, char **argv)
  91. {
  92. const char *arg;
  93. const char *p;
  94. char nflag = 1;
  95. char eflag = 0;
  96. /* We must check that stdout is not closed. */
  97. if (dup2(1, 1) != 1)
  98. return -1;
  99. while (1) {
  100. arg = *++argv;
  101. if (!arg)
  102. goto newline_ret;
  103. if (*arg != '-')
  104. break;
  105. /* If it appears that we are handling options, then make sure
  106. * that all of the options specified are actually valid.
  107. * Otherwise, the string should just be echoed.
  108. */
  109. p = arg + 1;
  110. if (!*p) /* A single '-', so echo it. */
  111. goto just_echo;
  112. do {
  113. if (!strrchr("neE", *p))
  114. goto just_echo;
  115. } while (*++p);
  116. /* All of the options in this arg are valid, so handle them. */
  117. p = arg + 1;
  118. do {
  119. if (*p == 'n')
  120. nflag = 0;
  121. if (*p == 'e')
  122. eflag = '\\';
  123. } while (*++p);
  124. }
  125. just_echo:
  126. while (1) {
  127. /* arg is already == *argv and isn't NULL */
  128. int c;
  129. if (!eflag) {
  130. /* optimization for very common case */
  131. fputs(arg, stdout);
  132. } else while ((c = *arg++)) {
  133. if (c == eflag) { /* Check for escape seq. */
  134. if (*arg == 'c') {
  135. /* '\c' means cancel newline and
  136. * ignore all subsequent chars. */
  137. goto ret;
  138. }
  139. {
  140. /* Since SUSv3 mandates a first digit of 0, 4-digit octals
  141. * of the form \0### are accepted. */
  142. if (*arg == '0') {
  143. /* NB: don't turn "...\0" into "...\" */
  144. if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
  145. arg++;
  146. }
  147. }
  148. /* bb_process_escape_sequence handles NUL correctly
  149. * ("...\" case. */
  150. c = bb_process_escape_sequence(&arg);
  151. }
  152. }
  153. putchar(c);
  154. }
  155. arg = *++argv;
  156. if (!arg)
  157. break;
  158. putchar(' ');
  159. }
  160. newline_ret:
  161. if (nflag) {
  162. putchar('\n');
  163. }
  164. ret:
  165. return fflush(NULL);
  166. }
  167. /*-
  168. * Copyright (c) 1991, 1993
  169. * The Regents of the University of California. All rights reserved.
  170. *
  171. * This code is derived from software contributed to Berkeley by
  172. * Kenneth Almquist.
  173. *
  174. * Redistribution and use in source and binary forms, with or without
  175. * modification, are permitted provided that the following conditions
  176. * are met:
  177. * 1. Redistributions of source code must retain the above copyright
  178. * notice, this list of conditions and the following disclaimer.
  179. * 2. Redistributions in binary form must reproduce the above copyright
  180. * notice, this list of conditions and the following disclaimer in the
  181. * documentation and/or other materials provided with the distribution.
  182. *
  183. * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
  184. * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
  185. *
  186. * California, Berkeley and its contributors.
  187. * 4. Neither the name of the University nor the names of its contributors
  188. * may be used to endorse or promote products derived from this software
  189. * without specific prior written permission.
  190. *
  191. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
  192. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  193. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  194. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  195. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  196. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  197. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  198. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  199. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  200. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  201. * SUCH DAMAGE.
  202. *
  203. * @(#)echo.c 8.1 (Berkeley) 5/31/93
  204. */