Bump to version 1.22.1
[platform/upstream/busybox.git] / coreutils / tee.c
index 25c1087..48cc050 100644 (file)
@@ -4,96 +4,97 @@
  *
  * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
  *
- * 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 source tree.
  */
 
 /* BB_AUDIT SUSv3 compliant */
 /* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include "busybox.h"
-
+//usage:#define tee_trivial_usage
+//usage:       "[-ai] [FILE]..."
+//usage:#define tee_full_usage "\n\n"
+//usage:       "Copy stdin to each FILE, and also to stdout\n"
+//usage:     "\n       -a      Append to the given FILEs, don't overwrite"
+//usage:     "\n       -i      Ignore interrupt signals (SIGINT)"
+//usage:
+//usage:#define tee_example_usage
+//usage:       "$ echo \"Hello\" | tee /tmp/foo\n"
+//usage:       "$ cat /tmp/foo\n"
+//usage:       "Hello\n"
+
+#include "libbb.h"
+
+int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int tee_main(int argc, char **argv)
 {
        const char *mode = "w\0a";
        FILE **files;
-       FILE **p;
-       char **filenames;
-       int flags;
-       int retval = EXIT_SUCCESS;
-#ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO
-       size_t c;
-       RESERVE_CONFIG_BUFFER(buf, BUFSIZ);
+       FILE **fp;
+       char **names;
+       char **np;
+       char retval;
+//TODO: make unconditional
+#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
+       ssize_t c;
+# define buf bb_common_bufsiz1
 #else
        int c;
 #endif
+       retval = getopt32(argv, "ia");  /* 'a' must be 2nd */
+       argc -= optind;
+       argv += optind;
 
-       flags = bb_getopt_ulflags(argc, argv, "ia");    /* 'a' must be 2nd */
-
-       mode += (flags & 2);    /* Since 'a' is the 2nd option... */
+       mode += (retval & 2);   /* Since 'a' is the 2nd option... */
 
-       if (flags & 1) {
-               signal(SIGINT, SIG_IGN);        /* TODO - switch to sigaction.*/
+       if (retval & 1) {
+               signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. (why?) */
        }
-
+       retval = EXIT_SUCCESS;
        /* gnu tee ignores SIGPIPE in case one of the output files is a pipe
         * that doesn't consume all its input.  Good idea... */
-       signal(SIGPIPE, SIG_IGN);               /* TODO - switch to sigaction.*/
+       signal(SIGPIPE, SIG_IGN);
 
-       /* Allocate an array of FILE *'s, with one extra for a sentinal. */
-       p = files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 2));
-       *p = stdout;
-       argv += optind - 1;
-       filenames = argv - 1;
-       *filenames = (char *) bb_msg_standard_input;    /* for later */
-       goto GOT_NEW_FILE;
+       /* Allocate an array of FILE *'s, with one extra for a sentinel. */
+       fp = files = xzalloc(sizeof(FILE *) * (argc + 2));
+       np = names = argv - 1;
 
+       files[0] = stdout;
+       goto GOT_NEW_FILE;
        do {
-               if ((*p = bb_wfopen(*argv, mode)) == NULL) {
-                       retval = EXIT_FAILURE;
-                       continue;
-               }
-               filenames[(int)(p - files)] = *argv;
-       GOT_NEW_FILE:
-               setbuf(*p, NULL);       /* tee must not buffer output. */
-               ++p;
-       } while (*++argv);
-
-       *p = NULL;                              /* Store the sentinal value. */
-
-#ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO
-       while ((c = read(0, buf, BUFSIZ)) != 0) {
-               for (p=files ; *p ; p++) {
-                       fwrite(buf, 1, c, *p);
+               *fp = stdout;
+               if (NOT_LONE_DASH(*argv)) {
+                       *fp = fopen_or_warn(*argv, mode);
+                       if (*fp == NULL) {
+                               retval = EXIT_FAILURE;
+                               argv++;
+                               continue;
+                       }
                }
+               *np = *argv++;
+ GOT_NEW_FILE:
+               setbuf(*fp, NULL);      /* tee must not buffer output. */
+               fp++;
+               np++;
+       } while (*argv);
+       /* names[0] will be filled later */
+
+#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
+       while ((c = safe_read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+               fp = files;
+               do
+                       fwrite(buf, 1, c, *fp);
+               while (*++fp);
+       }
+       if (c < 0) {            /* Make sure read errors are signaled. */
+               retval = EXIT_FAILURE;
        }
-
-#ifdef CONFIG_FEATURE_CLEAN_UP
-       RELEASE_CONFIG_BUFFER(buf);
-#endif
-
 #else
        setvbuf(stdout, NULL, _IONBF, 0);
        while ((c = getchar()) != EOF) {
-               for (p=files ; *p ; p++) {
-                       putc(c, *p);
-               }
+               fp = files;
+               do
+                       putc(c, *fp);
+               while (*++fp);
        }
 #endif
 
@@ -101,16 +102,17 @@ int tee_main(int argc, char **argv)
         * output files.  Since we know that the first entry in the output
         * file table is stdout, we can save one "if ferror" test by
         * setting the first entry to stdin and checking stdout error
-        * status with bb_fflush_stdout_and_exit()... although fflush()ing
+        * status with fflush_stdout_and_exit()... although fflush()ing
         * is unnecessary here. */
-
-       p = files;
-       *p = stdin;
-       do {            /* Now check for (input and) output errors. */
+       np = names;
+       fp = files;
+       names[0] = (char *) bb_msg_standard_input;
+       files[0] = stdin;
+       do {    /* Now check for input and output errors. */
                /* Checking ferror should be sufficient, but we may want to fclose.
                 * If we do, remember not to close stdin! */
-               bb_xferror(*p, filenames[(int)(p - files)]);
-       } while (*++p);
+               die_if_ferror(*fp++, *np++);
+       } while (*fp);
 
-       bb_fflush_stdout_and_exit(retval);
+       fflush_stdout_and_exit(retval);
 }