* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*
* Original copyright notice is retained at the end of this file.
*/
#include "libbb.h"
-/* argc is unused, but removing it precludes compiler from
- * using call -> jump optimization */
-int bb_echo(int argc, char **argv)
+/* This is a NOFORK applet. Be very careful! */
+
+/* NB: can be used by shell even if not enabled as applet */
+
+int echo_main(int argc UNUSED_PARAM, char **argv)
{
const char *arg;
#if !ENABLE_FEATURE_FANCY_ECHO
/* We must check that stdout is not closed.
* The reason for this is highly non-obvious.
- * bb_echo is used from shell. Shell must correctly handle "echo foo"
+ * echo_main is used from shell. Shell must correctly handle "echo foo"
* if stdout is closed. With stdio, output gets shoveled into
* stdout buffer, and even fflush cannot clear it out. It seems that
* even if libc receives EBADF on write attempts, it feels determined
* to output data no matter what. So it will try later,
* and possibly will clobber future output. Not good. */
- if (dup2(1, 1) != 1)
- return -1;
+// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
+ if (fcntl(1, F_GETFL) == -1)
+ return 1; /* match coreutils 6.10 (sans error msg to stderr) */
+ //if (dup2(1, 1) != 1) - old way
+ // return 1;
arg = *++argv;
if (!arg)
char eflag = 0;
/* We must check that stdout is not closed. */
- if (dup2(1, 1) != 1)
- return -1;
+ if (fcntl(1, F_GETFL) == -1)
+ return 1;
while (1) {
arg = *++argv;
}
#if !ENABLE_FEATURE_FANCY_ECHO
/* SUSv3 specifies that octal escapes must begin with '0'. */
- if ( (((unsigned char)*arg) - '1') >= 7)
+ if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */
#endif
{
/* Since SUSv3 mandates a first digit of 0, 4-digit octals
* of the form \0### are accepted. */
- if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) {
- arg++;
+ if (*arg == '0') {
+ /* NB: don't turn "...\0" into "...\" */
+ if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
+ arg++;
+ }
}
- /* bb_process_escape_sequence can handle nul correctly */
+ /* bb_process_escape_sequence handles NUL correctly
+ * ("...\" case). */
c = bb_process_escape_sequence(&arg);
}
}
bb_putchar('\n');
}
ret:
- return fflush(stdout);
-}
-
-/* This is a NOFORK applet. Be very careful! */
-
-int echo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int echo_main(int argc, char **argv)
-{
- return bb_echo(argc, argv);
+ return fflush_all();
}
/*-
#ifdef VERSION_WITH_WRITEV
/* We can't use stdio.
* The reason for this is highly non-obvious.
- * bb_echo is used from shell. Shell must correctly handle "echo foo"
+ * echo_main is used from shell. Shell must correctly handle "echo foo"
* if stdout is closed. With stdio, output gets shoveled into
* stdout buffer, and even fflush cannot clear it out. It seems that
* even if libc receives EBADF on write attempts, it feels determined
* Using writev instead, with 'direct' conversion of argv vector.
*/
-int bb_echo(int argc, char **argv)
+int echo_main(int argc, char **argv)
{
struct iovec io[argc];
struct iovec *cur_io = io;
}
ret:
/* TODO: implement and use full_writev? */
- return writev(1, io, (cur_io - io)) >= 0;
+ return writev(1, io, (cur_io - io)) >= 0;
}
#endif