test: correct confusing placement of "const"
[oweals/busybox.git] / coreutils / echo.c
index 8d25be7a5ccb4f211609fe2b1bf7ef850148a8f9..085e8516c487820b62e171599180f109c1f6975e 100644 (file)
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  *
  * Original copyright notice is retained at the end of this file.
  */
 
-#include "busybox.h"
-#include <stdio.h>
+/* BB_AUDIT SUSv3 compliant -- unless configured as fancy echo. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/echo.html */
 
-extern int 
-echo_main(int argc, char** argv)
-{
-       register char **ap;
-       char *p;
-       int c;
-       int nflag = 0;
-       int eflag = 0;
+/* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
+ *
+ * Because of behavioral differences, implemented configurable SUSv3
+ * or 'fancy' gnu-ish behaviors.  Also, reduced size and fixed bugs.
+ * 1) In handling '\c' escape, the previous version only suppressed the
+ *     trailing newline.  SUSv3 specifies _no_ output after '\c'.
+ * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
+ *    The previous version did not allow 4-digit octals.
+ */
 
+#include "libbb.h"
 
-       while ((c = getopt(argc, argv, "neE")) != EOF) {
-               switch (c) {
-               case 'n': 
-                       nflag = 1;
-                       break;
-               case 'e':
-                       eflag = 1;
-                       break;
-               case 'E':
-                       eflag = 0;
+int bb_echo(char **argv)
+{
+       const char *arg;
+#if !ENABLE_FEATURE_FANCY_ECHO
+       enum {
+               eflag = '\\',
+               nflag = 1,  /* 1 -- print '\n' */
+       };
+       arg = *++argv;
+       if (!arg)
+               goto newline_ret;
+#else
+       const char *p;
+       char nflag = 1;
+       char eflag = 0;
+
+       while (1) {
+               arg = *++argv;
+               if (!arg)
+                       goto newline_ret;
+               if (*arg != '-')
                        break;
-               default: 
-                       usage(echo_usage);
-               }
+
+               /* If it appears that we are handling options, then make sure
+                * that all of the options specified are actually valid.
+                * Otherwise, the string should just be echoed.
+                */
+               p = arg + 1;
+               if (!*p)        /* A single '-', so echo it. */
+                       goto just_echo;
+
+               do {
+                       if (!strrchr("neE", *p))
+                               goto just_echo;
+               } while (*++p);
+
+               /* All of the options in this arg are valid, so handle them. */
+               p = arg + 1;
+               do {
+                       if (*p == 'n')
+                               nflag = 0;
+                       if (*p == 'e')
+                               eflag = '\\';
+               } while (*++p);
        }
+ just_echo:
+#endif
+       while (1) {
+               /* arg is already == *argv and isn't NULL */
+               int c;
 
-       ap = &argv[optind];
-       while ((p = *ap++) != NULL) {
-               while ((c = *p++) != '\0') {
-                       if (c == '\\' && eflag) {
-                               if (*p == 'c')
-                                       exit(0);
-                               else
-                                       c = process_escape_sequence(&p);
+               if (!eflag) {
+                       /* optimization for very common case */
+                       fputs(arg, stdout);
+               } else while ((c = *arg++)) {
+                       if (c == eflag) {       /* Check for escape seq. */
+                               if (*arg == 'c') {
+                                       /* '\c' means cancel newline and
+                                        * ignore all subsequent chars. */
+                                       goto ret;
+                               }
+#if !ENABLE_FEATURE_FANCY_ECHO
+                               /* SUSv3 specifies that octal escapes must begin with '0'. */
+                               if ( (((unsigned char)*arg) - '1') >= 7)
+#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++;
+                                       }
+                                       /* bb_process_escape_sequence can handle nul correctly */
+                                       c = bb_process_escape_sequence(&arg);
+                               }
                        }
                        putchar(c);
                }
-               if (*ap)
-                       putchar(' ');
+
+               arg = *++argv;
+               if (!arg)
+                       break;
+               putchar(' ');
        }
-       if (! nflag)
+
+ newline_ret:
+       if (nflag) {
                putchar('\n');
-       fflush(stdout);
-       return( 0);
+       }
+ ret:
+       return fflush(stdout);
+}
+
+/* This is a NOFORK applet. Be very careful! */
+
+int echo_main(int argc, char** argv);
+int echo_main(int argc, char** argv)
+{
+       return bb_echo(argv);
 }
 
 /*-
@@ -87,9 +141,10 @@ echo_main(int argc, char** argv)
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
- *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ *             ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
  *
+ *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -108,5 +163,3 @@ echo_main(int argc, char** argv)
  *
  *     @(#)echo.c      8.1 (Berkeley) 5/31/93
  */
-
-