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