source: MondoRescue/branches/3.3/mindi-busybox/coreutils/echo.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 9.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * echo implementation for busybox
4 *
5 * Copyright (c) 1991, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 *
10 * Original copyright notice is retained at the end of this file.
11 */
12
13/* BB_AUDIT SUSv3 compliant -- unless configured as fancy echo. */
14/* http://www.opengroup.org/onlinepubs/007904975/utilities/echo.html */
15
16/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
17 *
18 * Because of behavioral differences, implemented configurable SUSv3
19 * or 'fancy' gnu-ish behaviors. Also, reduced size and fixed bugs.
20 * 1) In handling '\c' escape, the previous version only suppressed the
21 * trailing newline. SUSv3 specifies _no_ output after '\c'.
22 * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
23 * The previous version did not allow 4-digit octals.
24 */
25
26//usage:#define echo_trivial_usage
27//usage: IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..."
28//usage:#define echo_full_usage "\n\n"
29//usage: "Print the specified ARGs to stdout"
30//usage: IF_FEATURE_FANCY_ECHO( "\n"
31//usage: "\n -n Suppress trailing newline"
32//usage: "\n -e Interpret backslash escapes (i.e., \\t=tab)"
33//usage: "\n -E Don't interpret backslash escapes (default)"
34//usage: )
35//usage:
36//usage:#define echo_example_usage
37//usage: "$ echo \"Erik is cool\"\n"
38//usage: "Erik is cool\n"
39//usage: IF_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n"
40//usage: "Erik\n"
41//usage: "is\n"
42//usage: "cool\n"
43//usage: "$ echo \"Erik\\nis\\ncool\"\n"
44//usage: "Erik\\nis\\ncool\n")
45
46#include "libbb.h"
47
48/* This is a NOFORK applet. Be very careful! */
49
50/* NB: can be used by shell even if not enabled as applet */
51
52/*
53 * NB2: we don't use stdio, we need better error handing.
54 * Examples include writing into non-opened stdout and error on write.
55 *
56 * With stdio, output gets shoveled into stdout buffer, and even
57 * fflush cannot clear it out. It seems that even if libc receives
58 * EBADF on write attempts, it feels determined to output data no matter what.
59 * If echo is called by shell, it will try writing again later, and possibly
60 * will clobber future output. Not good.
61 *
62 * Solaris has fpurge which discards buffered input. glibc has __fpurge.
63 * But this function is not standard.
64 */
65
66int echo_main(int argc UNUSED_PARAM, char **argv)
67{
68 char **pp;
69 const char *arg;
70 char *out;
71 char *buffer;
72 unsigned buflen;
73#if !ENABLE_FEATURE_FANCY_ECHO
74 enum {
75 eflag = 0, /* 0 -- disable escape sequences */
76 nflag = 1, /* 1 -- print '\n' */
77 };
78
79 argv++;
80#else
81 char nflag = 1;
82 char eflag = 0;
83
84 while ((arg = *++argv) != NULL) {
85 char n, e;
86
87 if (arg[0] != '-')
88 break; /* not an option arg, echo it */
89
90 /* If it appears that we are handling options, then make sure
91 * that all of the options specified are actually valid.
92 * Otherwise, the string should just be echoed.
93 */
94 arg++;
95 n = nflag;
96 e = eflag;
97 do {
98 if (*arg == 'n')
99 n = 0;
100 else if (*arg == 'e')
101 e = '\\';
102 else if (*arg != 'E') {
103 /* "-ccc" arg with one of c's invalid, echo it */
104 /* arg consisting from just "-" also handled here */
105 goto just_echo;
106 }
107 } while (*++arg);
108 nflag = n;
109 eflag = e;
110 }
111 just_echo:
112#endif
113
114 buflen = 0;
115 pp = argv;
116 while ((arg = *pp) != NULL) {
117 buflen += strlen(arg) + 1;
118 pp++;
119 }
120 out = buffer = xmalloc(buflen + 1); /* +1 is needed for "no args" case */
121
122 while ((arg = *argv) != NULL) {
123 int c;
124
125 if (!eflag) {
126 /* optimization for very common case */
127 out = stpcpy(out, arg);
128 } else
129 while ((c = *arg++) != '\0') {
130 if (c == eflag) {
131 /* This is an "\x" sequence */
132
133 if (*arg == 'c') {
134 /* "\c" means cancel newline and
135 * ignore all subsequent chars. */
136 goto do_write;
137 }
138 /* Since SUSv3 mandates a first digit of 0, 4-digit octals
139 * of the form \0### are accepted. */
140 if (*arg == '0') {
141 if ((unsigned char)(arg[1] - '0') < 8) {
142 /* 2nd char is 0..7: skip leading '0' */
143 arg++;
144 }
145 }
146 /* bb_process_escape_sequence handles NUL correctly
147 * ("...\" case). */
148 {
149 /* optimization: don't force arg to be on-stack,
150 * use another variable for that. ~30 bytes win */
151 const char *z = arg;
152 c = bb_process_escape_sequence(&z);
153 arg = z;
154 }
155 }
156 *out++ = c;
157 }
158
159 if (!*++argv)
160 break;
161 *out++ = ' ';
162 }
163
164 if (nflag) {
165 *out++ = '\n';
166 }
167
168 do_write:
169 /* Careful to error out on partial writes too (think ENOSPC!) */
170 errno = 0;
171 /*r =*/ full_write(STDOUT_FILENO, buffer, out - buffer);
172 free(buffer);
173 if (/*WRONG:r < 0*/ errno) {
174 bb_perror_msg(bb_msg_write_error);
175 return 1;
176 }
177 return 0;
178}
179
180/*
181 * Copyright (c) 1991, 1993
182 * The Regents of the University of California. All rights reserved.
183 *
184 * This code is derived from software contributed to Berkeley by
185 * Kenneth Almquist.
186 *
187 * Redistribution and use in source and binary forms, with or without
188 * modification, are permitted provided that the following conditions
189 * are met:
190 * 1. Redistributions of source code must retain the above copyright
191 * notice, this list of conditions and the following disclaimer.
192 * 2. Redistributions in binary form must reproduce the above copyright
193 * notice, this list of conditions and the following disclaimer in the
194 * documentation and/or other materials provided with the distribution.
195 *
196 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
197 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
198 *
199 * California, Berkeley and its contributors.
200 * 4. Neither the name of the University nor the names of its contributors
201 * may be used to endorse or promote products derived from this software
202 * without specific prior written permission.
203 *
204 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
205 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
206 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
208 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
209 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
210 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
212 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
213 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
214 * SUCH DAMAGE.
215 *
216 * @(#)echo.c 8.1 (Berkeley) 5/31/93
217 */
218
219#ifdef VERSION_WITH_WRITEV
220/* We can't use stdio.
221 * The reason for this is highly non-obvious.
222 * echo_main is used from shell. Shell must correctly handle "echo foo"
223 * if stdout is closed. With stdio, output gets shoveled into
224 * stdout buffer, and even fflush cannot clear it out. It seems that
225 * even if libc receives EBADF on write attempts, it feels determined
226 * to output data no matter what. So it will try later,
227 * and possibly will clobber future output. Not good.
228 *
229 * Using writev instead, with 'direct' conversion of argv vector.
230 */
231
232int echo_main(int argc, char **argv)
233{
234 struct iovec io[argc];
235 struct iovec *cur_io = io;
236 char *arg;
237 char *p;
238#if !ENABLE_FEATURE_FANCY_ECHO
239 enum {
240 eflag = '\\',
241 nflag = 1, /* 1 -- print '\n' */
242 };
243 arg = *++argv;
244 if (!arg)
245 goto newline_ret;
246#else
247 char nflag = 1;
248 char eflag = 0;
249
250 while (1) {
251 arg = *++argv;
252 if (!arg)
253 goto newline_ret;
254 if (*arg != '-')
255 break;
256
257 /* If it appears that we are handling options, then make sure
258 * that all of the options specified are actually valid.
259 * Otherwise, the string should just be echoed.
260 */
261 p = arg + 1;
262 if (!*p) /* A single '-', so echo it. */
263 goto just_echo;
264
265 do {
266 if (!strchr("neE", *p))
267 goto just_echo;
268 } while (*++p);
269
270 /* All of the options in this arg are valid, so handle them. */
271 p = arg + 1;
272 do {
273 if (*p == 'n')
274 nflag = 0;
275 if (*p == 'e')
276 eflag = '\\';
277 } while (*++p);
278 }
279 just_echo:
280#endif
281
282 while (1) {
283 /* arg is already == *argv and isn't NULL */
284 int c;
285
286 cur_io->iov_base = p = arg;
287
288 if (!eflag) {
289 /* optimization for very common case */
290 p += strlen(arg);
291 } else while ((c = *arg++)) {
292 if (c == eflag) {
293 /* This is an "\x" sequence */
294
295 if (*arg == 'c') {
296 /* "\c" means cancel newline and
297 * ignore all subsequent chars. */
298 cur_io->iov_len = p - (char*)cur_io->iov_base;
299 cur_io++;
300 goto ret;
301 }
302 /* Since SUSv3 mandates a first digit of 0, 4-digit octals
303 * of the form \0### are accepted. */
304 if (*arg == '0' && (unsigned char)(arg[1] - '0') < 8) {
305 arg++;
306 }
307 /* bb_process_escape_sequence can handle nul correctly */
308 c = bb_process_escape_sequence( (void*) &arg);
309 }
310 *p++ = c;
311 }
312
313 arg = *++argv;
314 if (arg)
315 *p++ = ' ';
316 cur_io->iov_len = p - (char*)cur_io->iov_base;
317 cur_io++;
318 if (!arg)
319 break;
320 }
321
322 newline_ret:
323 if (nflag) {
324 cur_io->iov_base = (char*)"\n";
325 cur_io->iov_len = 1;
326 cur_io++;
327 }
328 ret:
329 /* TODO: implement and use full_writev? */
330 return writev(1, io, (cur_io - io)) >= 0;
331}
332#endif
Note: See TracBrowser for help on using the repository browser.