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