Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/coreutils/echo.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/coreutils/echo.c
r1765 r2725 6 6 * The Regents of the University of California. All rights reserved. 7 7 * 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 9 * 10 10 * Original copyright notice is retained at the end of this file. … … 26 26 #include "libbb.h" 27 27 28 int bb_echo(char **argv) 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) 29 33 { 30 34 const char *arg; … … 34 38 nflag = 1, /* 1 -- print '\n' */ 35 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 36 55 arg = *++argv; 37 56 if (!arg) … … 41 60 char nflag = 1; 42 61 char eflag = 0; 62 63 /* We must check that stdout is not closed. */ 64 if (fcntl(1, F_GETFL) == -1) 65 return 1; 43 66 44 67 while (1) { … … 89 112 #if !ENABLE_FEATURE_FANCY_ECHO 90 113 /* SUSv3 specifies that octal escapes must begin with '0'. */ 91 if ( (( (unsigned char)*arg) - '1') >= 7)114 if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */ 92 115 #endif 93 116 { 94 117 /* Since SUSv3 mandates a first digit of 0, 4-digit octals 95 118 * of the form \0### are accepted. */ 96 if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) { 97 arg++; 119 if (*arg == '0') { 120 /* NB: don't turn "...\0" into "...\" */ 121 if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) { 122 arg++; 123 } 98 124 } 99 /* bb_process_escape_sequence can handle nul correctly */ 125 /* bb_process_escape_sequence handles NUL correctly 126 * ("...\" case). */ 100 127 c = bb_process_escape_sequence(&arg); 101 128 } 102 129 } 103 putchar(c);130 bb_putchar(c); 104 131 } 105 132 … … 107 134 if (!arg) 108 135 break; 109 putchar(' ');136 bb_putchar(' '); 110 137 } 111 138 112 139 newline_ret: 113 140 if (nflag) { 114 putchar('\n');141 bb_putchar('\n'); 115 142 } 116 143 ret: 117 return fflush(stdout); 118 } 119 120 /* This is a NOFORK applet. Be very careful! */ 121 122 int echo_main(int argc, char** argv); 123 int echo_main(int argc, char** argv) 124 { 125 return bb_echo(argv); 144 return fflush_all(); 126 145 } 127 146 … … 164 183 * @(#)echo.c 8.1 (Berkeley) 5/31/93 165 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
Note:
See TracChangeset
for help on using the changeset viewer.