Contents of /tags/mkinitrd-6_1_12/busybox/coreutils/echo.c
Parent Directory | Revision Log
Revision 939 -
(show annotations)
(download)
Tue Nov 17 21:24:51 2009 UTC (14 years, 10 months ago) by niro
File MIME type: text/plain
File size: 8501 byte(s)
Tue Nov 17 21:24:51 2009 UTC (14 years, 10 months ago) by niro
File MIME type: text/plain
File size: 8501 byte(s)
tagged 'mkinitrd-6_1_12'
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 tarball for details. |
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 | #include "libbb.h" |
27 | |
28 | /* This is a NOFORK applet. Be very careful! */ |
29 | |
30 | /* NB: can be used by shell even if not enabled as applet */ |
31 | |
32 | int echo_main(int argc UNUSED_PARAM, char **argv) |
33 | { |
34 | const char *arg; |
35 | #if !ENABLE_FEATURE_FANCY_ECHO |
36 | enum { |
37 | eflag = '\\', |
38 | nflag = 1, /* 1 -- print '\n' */ |
39 | }; |
40 | |
41 | /* We must check that stdout is not closed. |
42 | * The reason for this is highly non-obvious. |
43 | * echo_main is used from shell. Shell must correctly handle "echo foo" |
44 | * if stdout is closed. With stdio, output gets shoveled into |
45 | * stdout buffer, and even fflush cannot clear it out. It seems that |
46 | * even if libc receives EBADF on write attempts, it feels determined |
47 | * to output data no matter what. So it will try later, |
48 | * and possibly will clobber future output. Not good. */ |
49 | // TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? |
50 | if (fcntl(1, F_GETFL) == -1) |
51 | return 1; /* match coreutils 6.10 (sans error msg to stderr) */ |
52 | //if (dup2(1, 1) != 1) - old way |
53 | // return 1; |
54 | |
55 | arg = *++argv; |
56 | if (!arg) |
57 | goto newline_ret; |
58 | #else |
59 | const char *p; |
60 | char nflag = 1; |
61 | char eflag = 0; |
62 | |
63 | /* We must check that stdout is not closed. */ |
64 | if (fcntl(1, F_GETFL) == -1) |
65 | return 1; |
66 | |
67 | while (1) { |
68 | arg = *++argv; |
69 | if (!arg) |
70 | goto newline_ret; |
71 | if (*arg != '-') |
72 | break; |
73 | |
74 | /* If it appears that we are handling options, then make sure |
75 | * that all of the options specified are actually valid. |
76 | * Otherwise, the string should just be echoed. |
77 | */ |
78 | p = arg + 1; |
79 | if (!*p) /* A single '-', so echo it. */ |
80 | goto just_echo; |
81 | |
82 | do { |
83 | if (!strrchr("neE", *p)) |
84 | goto just_echo; |
85 | } while (*++p); |
86 | |
87 | /* All of the options in this arg are valid, so handle them. */ |
88 | p = arg + 1; |
89 | do { |
90 | if (*p == 'n') |
91 | nflag = 0; |
92 | if (*p == 'e') |
93 | eflag = '\\'; |
94 | } while (*++p); |
95 | } |
96 | just_echo: |
97 | #endif |
98 | while (1) { |
99 | /* arg is already == *argv and isn't NULL */ |
100 | int c; |
101 | |
102 | if (!eflag) { |
103 | /* optimization for very common case */ |
104 | fputs(arg, stdout); |
105 | } else while ((c = *arg++)) { |
106 | if (c == eflag) { /* Check for escape seq. */ |
107 | if (*arg == 'c') { |
108 | /* '\c' means cancel newline and |
109 | * ignore all subsequent chars. */ |
110 | goto ret; |
111 | } |
112 | #if !ENABLE_FEATURE_FANCY_ECHO |
113 | /* SUSv3 specifies that octal escapes must begin with '0'. */ |
114 | if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */ |
115 | #endif |
116 | { |
117 | /* Since SUSv3 mandates a first digit of 0, 4-digit octals |
118 | * of the form \0### are accepted. */ |
119 | if (*arg == '0') { |
120 | /* NB: don't turn "...\0" into "...\" */ |
121 | if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) { |
122 | arg++; |
123 | } |
124 | } |
125 | /* bb_process_escape_sequence handles NUL correctly |
126 | * ("...\" case). */ |
127 | c = bb_process_escape_sequence(&arg); |
128 | } |
129 | } |
130 | bb_putchar(c); |
131 | } |
132 | |
133 | arg = *++argv; |
134 | if (!arg) |
135 | break; |
136 | bb_putchar(' '); |
137 | } |
138 | |
139 | newline_ret: |
140 | if (nflag) { |
141 | bb_putchar('\n'); |
142 | } |
143 | ret: |
144 | return fflush(stdout); |
145 | } |
146 | |
147 | /*- |
148 | * Copyright (c) 1991, 1993 |
149 | * The Regents of the University of California. All rights reserved. |
150 | * |
151 | * This code is derived from software contributed to Berkeley by |
152 | * Kenneth Almquist. |
153 | * |
154 | * Redistribution and use in source and binary forms, with or without |
155 | * modification, are permitted provided that the following conditions |
156 | * are met: |
157 | * 1. Redistributions of source code must retain the above copyright |
158 | * notice, this list of conditions and the following disclaimer. |
159 | * 2. Redistributions in binary form must reproduce the above copyright |
160 | * notice, this list of conditions and the following disclaimer in the |
161 | * documentation and/or other materials provided with the distribution. |
162 | * |
163 | * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change |
164 | * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> |
165 | * |
166 | * California, Berkeley and its contributors. |
167 | * 4. Neither the name of the University nor the names of its contributors |
168 | * may be used to endorse or promote products derived from this software |
169 | * without specific prior written permission. |
170 | * |
171 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
172 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
173 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
174 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
175 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
176 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
177 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
178 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
179 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
180 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
181 | * SUCH DAMAGE. |
182 | * |
183 | * @(#)echo.c 8.1 (Berkeley) 5/31/93 |
184 | */ |
185 | |
186 | #ifdef VERSION_WITH_WRITEV |
187 | /* We can't use stdio. |
188 | * The reason for this is highly non-obvious. |
189 | * echo_main is used from shell. Shell must correctly handle "echo foo" |
190 | * if stdout is closed. With stdio, output gets shoveled into |
191 | * stdout buffer, and even fflush cannot clear it out. It seems that |
192 | * even if libc receives EBADF on write attempts, it feels determined |
193 | * to output data no matter what. So it will try later, |
194 | * and possibly will clobber future output. Not good. |
195 | * |
196 | * Using writev instead, with 'direct' conversion of argv vector. |
197 | */ |
198 | |
199 | int echo_main(int argc, char **argv) |
200 | { |
201 | struct iovec io[argc]; |
202 | struct iovec *cur_io = io; |
203 | char *arg; |
204 | char *p; |
205 | #if !ENABLE_FEATURE_FANCY_ECHO |
206 | enum { |
207 | eflag = '\\', |
208 | nflag = 1, /* 1 -- print '\n' */ |
209 | }; |
210 | arg = *++argv; |
211 | if (!arg) |
212 | goto newline_ret; |
213 | #else |
214 | char nflag = 1; |
215 | char eflag = 0; |
216 | |
217 | while (1) { |
218 | arg = *++argv; |
219 | if (!arg) |
220 | goto newline_ret; |
221 | if (*arg != '-') |
222 | break; |
223 | |
224 | /* If it appears that we are handling options, then make sure |
225 | * that all of the options specified are actually valid. |
226 | * Otherwise, the string should just be echoed. |
227 | */ |
228 | p = arg + 1; |
229 | if (!*p) /* A single '-', so echo it. */ |
230 | goto just_echo; |
231 | |
232 | do { |
233 | if (!strrchr("neE", *p)) |
234 | goto just_echo; |
235 | } while (*++p); |
236 | |
237 | /* All of the options in this arg are valid, so handle them. */ |
238 | p = arg + 1; |
239 | do { |
240 | if (*p == 'n') |
241 | nflag = 0; |
242 | if (*p == 'e') |
243 | eflag = '\\'; |
244 | } while (*++p); |
245 | } |
246 | just_echo: |
247 | #endif |
248 | |
249 | while (1) { |
250 | /* arg is already == *argv and isn't NULL */ |
251 | int c; |
252 | |
253 | cur_io->iov_base = p = arg; |
254 | |
255 | if (!eflag) { |
256 | /* optimization for very common case */ |
257 | p += strlen(arg); |
258 | } else while ((c = *arg++)) { |
259 | if (c == eflag) { /* Check for escape seq. */ |
260 | if (*arg == 'c') { |
261 | /* '\c' means cancel newline and |
262 | * ignore all subsequent chars. */ |
263 | cur_io->iov_len = p - (char*)cur_io->iov_base; |
264 | cur_io++; |
265 | goto ret; |
266 | } |
267 | #if !ENABLE_FEATURE_FANCY_ECHO |
268 | /* SUSv3 specifies that octal escapes must begin with '0'. */ |
269 | if ( (((unsigned char)*arg) - '1') >= 7) |
270 | #endif |
271 | { |
272 | /* Since SUSv3 mandates a first digit of 0, 4-digit octals |
273 | * of the form \0### are accepted. */ |
274 | if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) { |
275 | arg++; |
276 | } |
277 | /* bb_process_escape_sequence can handle nul correctly */ |
278 | c = bb_process_escape_sequence( (void*) &arg); |
279 | } |
280 | } |
281 | *p++ = c; |
282 | } |
283 | |
284 | arg = *++argv; |
285 | if (arg) |
286 | *p++ = ' '; |
287 | cur_io->iov_len = p - (char*)cur_io->iov_base; |
288 | cur_io++; |
289 | if (!arg) |
290 | break; |
291 | } |
292 | |
293 | newline_ret: |
294 | if (nflag) { |
295 | cur_io->iov_base = (char*)"\n"; |
296 | cur_io->iov_len = 1; |
297 | cur_io++; |
298 | } |
299 | ret: |
300 | /* TODO: implement and use full_writev? */ |
301 | return writev(1, io, (cur_io - io)) >= 0; |
302 | } |
303 | #endif |