Annotation of /trunk/mkinitrd-magellan/busybox/coreutils/echo.c
Parent Directory | Revision Log
Revision 984 -
(hide annotations)
(download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 8499 byte(s)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 8499 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 | niro | 532 | /* 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 | niro | 816 | * The previous version did not allow 4-digit octals. |
24 | niro | 532 | */ |
25 | |||
26 | niro | 816 | #include "libbb.h" |
27 | niro | 532 | |
28 | niro | 816 | /* This is a NOFORK applet. Be very careful! */ |
29 | niro | 532 | |
30 | niro | 816 | /* NB: can be used by shell even if not enabled as applet */ |
31 | |||
32 | int echo_main(int argc UNUSED_PARAM, char **argv) | ||
33 | niro | 532 | { |
34 | niro | 816 | 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 | niro | 532 | #else |
59 | const char *p; | ||
60 | niro | 816 | char nflag = 1; |
61 | char eflag = 0; | ||
62 | niro | 532 | |
63 | niro | 816 | /* 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 | niro | 532 | /* 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 | niro | 816 | p = arg + 1; |
79 | if (!*p) /* A single '-', so echo it. */ | ||
80 | niro | 532 | goto just_echo; |
81 | |||
82 | do { | ||
83 | niro | 816 | if (!strrchr("neE", *p)) |
84 | niro | 532 | goto just_echo; |
85 | } while (*++p); | ||
86 | |||
87 | /* All of the options in this arg are valid, so handle them. */ | ||
88 | niro | 816 | p = arg + 1; |
89 | niro | 532 | do { |
90 | niro | 816 | if (*p == 'n') |
91 | niro | 532 | nflag = 0; |
92 | niro | 816 | if (*p == 'e') |
93 | niro | 532 | eflag = '\\'; |
94 | } while (*++p); | ||
95 | } | ||
96 | niro | 816 | just_echo: |
97 | niro | 532 | #endif |
98 | niro | 816 | while (1) { |
99 | /* arg is already == *argv and isn't NULL */ | ||
100 | niro | 532 | int c; |
101 | |||
102 | niro | 816 | if (!eflag) { |
103 | /* optimization for very common case */ | ||
104 | fputs(arg, stdout); | ||
105 | } else while ((c = *arg++)) { | ||
106 | niro | 532 | if (c == eflag) { /* Check for escape seq. */ |
107 | niro | 816 | if (*arg == 'c') { |
108 | niro | 532 | /* '\c' means cancel newline and |
109 | * ignore all subsequent chars. */ | ||
110 | niro | 816 | goto ret; |
111 | niro | 532 | } |
112 | niro | 816 | #if !ENABLE_FEATURE_FANCY_ECHO |
113 | niro | 532 | /* SUSv3 specifies that octal escapes must begin with '0'. */ |
114 | niro | 816 | if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */ |
115 | niro | 532 | #endif |
116 | { | ||
117 | /* Since SUSv3 mandates a first digit of 0, 4-digit octals | ||
118 | * of the form \0### are accepted. */ | ||
119 | niro | 816 | if (*arg == '0') { |
120 | /* NB: don't turn "...\0" into "...\" */ | ||
121 | if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) { | ||
122 | arg++; | ||
123 | } | ||
124 | niro | 532 | } |
125 | niro | 816 | /* bb_process_escape_sequence handles NUL correctly |
126 | * ("...\" case). */ | ||
127 | c = bb_process_escape_sequence(&arg); | ||
128 | niro | 532 | } |
129 | } | ||
130 | niro | 816 | bb_putchar(c); |
131 | niro | 532 | } |
132 | |||
133 | niro | 816 | arg = *++argv; |
134 | if (!arg) | ||
135 | break; | ||
136 | bb_putchar(' '); | ||
137 | niro | 532 | } |
138 | |||
139 | niro | 816 | newline_ret: |
140 | niro | 532 | if (nflag) { |
141 | niro | 816 | bb_putchar('\n'); |
142 | niro | 532 | } |
143 | niro | 816 | ret: |
144 | niro | 984 | return fflush_all(); |
145 | niro | 532 | } |
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 | niro | 816 | |
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 |