• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* echo.c - echo supporting -n and -e.
2  *
3  * Copyright 2007 Rob Landley <rob@landley.net>
4  *
5  * See http://opengroup.org/onlinepubs/9699919799/utilities/echo.html
6  *
7  * Deviations from posix: we parse command line options, as Linux has
8  * consistently done since 1992. Posix defaults -e to on, we require -e.
9  * We also honor -- to _stop_ option parsing (bash doesn't, we go with
10  * consistency over compatibility here).
11 
12 USE_ECHO(NEWTOY(echo, "^?Een[-eE]", TOYFLAG_BIN|TOYFLAG_MAYFORK))
13 
14 config ECHO
15   bool "echo"
16   default y
17   help
18     usage: echo [-neE] [args...]
19 
20     Write each argument to stdout, with one space between each, followed
21     by a newline.
22 
23     -n	No trailing newline
24     -E	Print escape sequences literally (default)
25     -e	Process the following escape sequences:
26     	\\	Backslash
27     	\0NNN	Octal values (1 to 3 digits)
28     	\a	Alert (beep/flash)
29     	\b	Backspace
30     	\c	Stop output here (avoids trailing newline)
31     	\f	Form feed
32     	\n	Newline
33     	\r	Carriage return
34     	\t	Horizontal tab
35     	\v	Vertical tab
36     	\xHH	Hexadecimal values (1 to 2 digits)
37 */
38 
39 #define FOR_echo
40 #include "toys.h"
41 
echo_main(void)42 void echo_main(void)
43 {
44   int i = 0, out;
45   char *arg, *c;
46 
47   for (;;) {
48     arg = toys.optargs[i];
49     if (!arg) break;
50     if (i++) putchar(' ');
51 
52     // Should we output arg verbatim?
53 
54     if (!FLAG(e)) {
55       xprintf("%s", arg);
56       continue;
57     }
58 
59     // Handle -e
60 
61     for (c = arg;;) {
62       if (!(out = *(c++))) break;
63 
64       // handle \escapes
65       if (out == '\\' && *c) {
66         int slash = *(c++), n = unescape(slash);
67 
68         if (n) out = n;
69         else if (slash=='c') return;
70         else if (slash=='0') {
71           out = 0;
72           while (*c>='0' && *c<='7' && n++<3) out = (out*8)+*(c++)-'0';
73         } else if (slash=='x') {
74           out = 0;
75           while (n++<2) {
76             if (*c>='0' && *c<='9') out = (out*16)+*(c++)-'0';
77             else {
78               int temp = tolower(*c);
79               if (temp>='a' && temp<='f') {
80                 out = (out*16)+temp-'a'+10;
81                 c++;
82               } else {
83                 if (n==1) {
84                   --c;
85                   out = '\\';
86                 }
87                 break;
88               }
89             }
90           }
91         // Slash in front of unknown character, print literal.
92         } else c--;
93       }
94       putchar(out);
95     }
96   }
97 
98   // Output "\n" if no -n
99   if (!FLAG(n)) putchar('\n');
100 }
101