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