home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / sh-utils-1.12-src.tgz / tar.out / fsf / sh-utils / src / tee.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  5KB  |  229 lines

  1. /* tee - read from standard input and write to standard output and files.
  2.    Copyright (C) 85, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Mike Parker, Richard M. Stallman, and David MacKenzie */
  19.  
  20. #include <config.h>
  21. #include <stdio.h>
  22. #include <sys/types.h>
  23. #include <signal.h>
  24. #include <getopt.h>
  25.  
  26. #include "system.h"
  27. #include "version.h"
  28.  
  29. char *xmalloc ();
  30. void error ();
  31. int full_write ();
  32.  
  33. static int tee ();
  34.  
  35. /* If nonzero, append to output files rather than truncating them. */
  36. static int append;
  37.  
  38. /* If nonzero, ignore interrupts. */
  39. static int ignore_interrupts;
  40.  
  41. /* The name that this program was run with. */
  42. char *program_name;
  43.  
  44. /* If non-zero, display usage information and exit.  */
  45. static int show_help;
  46.  
  47. /* If non-zero, print the version on standard output and exit.  */
  48. static int show_version;
  49.  
  50. static struct option const long_options[] =
  51. {
  52.   {"append", no_argument, NULL, 'a'},
  53.   {"help", no_argument, &show_help, 1},
  54.   {"ignore-interrupts", no_argument, NULL, 'i'},
  55.   {"version", no_argument, &show_version, 1},
  56.   {NULL, 0, NULL, 0}
  57. };
  58.  
  59. static void
  60. usage (status)
  61.      int status;
  62. {
  63.   if (status != 0)
  64.     fprintf (stderr, "Try `%s --help' for more information.\n",
  65.          program_name);
  66.   else
  67.     {
  68.       printf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
  69.       printf ("\
  70. \n\
  71.   -a, --append              append to the given FILEs, do not overwrite\n\
  72.   -i, --ignore-interrupts   ignore interrupt signals\n\
  73.       --help                display this help and exit\n\
  74.       --version             output version information and exit\n\
  75. ");
  76.     }
  77.   exit (status);
  78. }
  79.  
  80. main (argc, argv)
  81.      int argc;
  82.      char **argv;
  83. {
  84.   int errs;
  85.   int optc;
  86.     
  87.   program_name = argv[0];
  88.   append = 0;
  89.   ignore_interrupts = 0;
  90.  
  91.   while ((optc = getopt_long (argc, argv, "ai", long_options, (int *) 0))
  92.      != EOF)
  93.     {
  94.       switch (optc)
  95.     {
  96.     case 0:
  97.       break;
  98.  
  99.     case 'a':
  100.       append = 1;
  101.       break;
  102.  
  103.     case 'i':
  104.       ignore_interrupts = 1;
  105.       break;
  106.  
  107.     default:
  108.       usage (1);
  109.     }
  110.     }
  111.  
  112.   if (show_version)
  113.     {
  114.       printf ("tee - %s\n", version_string);
  115.       exit (0);
  116.     }
  117.  
  118.   if (show_help)
  119.     usage (0);
  120.  
  121.   if (ignore_interrupts)
  122.     {
  123. #ifdef _POSIX_SOURCE
  124.       struct sigaction sigact;
  125.  
  126.       sigact.sa_handler = SIG_IGN;
  127.       sigemptyset (&sigact.sa_mask);
  128.       sigact.sa_flags = 0;
  129.       sigaction (SIGINT, &sigact, NULL);
  130. #else                /* !_POSIX_SOURCE */
  131.       signal (SIGINT, SIG_IGN);
  132. #endif                /* _POSIX_SOURCE */
  133.     }
  134.  
  135.   errs = tee (argc - optind, (const char **) &argv[optind]);
  136.   if (close (0) != 0)
  137.     error (1, errno, "standard input");
  138.   if (close (1) != 0)
  139.     error (1, errno, "standard output");
  140.   exit (errs);
  141. }
  142.  
  143. /* Copy the standard input into each of the NFILES files in FILES
  144.    and into the standard output.
  145.    Return 0 if successful, 1 if any errors occur. */
  146.  
  147. static int
  148. tee (nfiles, files)
  149.      int nfiles;
  150.      const char **files;
  151. {
  152.   int *descriptors;
  153.   char buffer[BUFSIZ];
  154.   register int bytes_read, i, ret = 0, mode;
  155.  
  156.   descriptors = (int *) xmalloc ((nfiles + 1) * sizeof (int));
  157.  
  158.   mode = O_WRONLY | O_CREAT;
  159.   if (append)
  160.     mode |= O_APPEND;
  161.   else
  162.     mode |= O_TRUNC;
  163.  
  164.   /* Move all the names `up' one in the argv array to make room for
  165.      the entry for standard output.  This writes into argv[argc].  */
  166.   for (i = nfiles; i >= 1; i--)
  167.     files[i] = files[i - 1];
  168.  
  169.   /* In the array of NFILES + 1 descriptors, make
  170.      the first one correspond to standard output.   */
  171.   descriptors[0] = 1;
  172.   files[0] = "standard output";
  173.  
  174.   for (i = 1; i <= nfiles; i++)
  175.     {
  176.       descriptors[i] = open (files[i], mode, 0666);
  177.       if (descriptors[i] == -1)
  178.     {
  179.       error (0, errno, "%s", files[i]);
  180.       ret = 1;
  181.     }
  182.     }
  183.  
  184.   while (1)
  185.     {
  186.       bytes_read = read (0, buffer, sizeof buffer);
  187. #ifdef EINTR
  188.       if (bytes_read < 0 && errno == EINTR)
  189.         continue;
  190. #endif
  191.       if (bytes_read <= 0)
  192.     break;
  193.  
  194.       /* Write to all NFILES + 1 descriptors.
  195.      Standard output is the first one.  */
  196.       for (i = 0; i <= nfiles; i++)
  197.     {
  198.       if (descriptors[i] != -1
  199.           && full_write (descriptors[i], buffer, bytes_read) < 0)
  200.         {
  201.           error (0, errno, "%s", files[i]);
  202.           /* Don't close stdout.  That's done in main.  */
  203.           if (descriptors[i] != 1)
  204.         close (descriptors[i]);
  205.           descriptors[i] = -1;
  206.           ret = 1;
  207.         }
  208.     }
  209.     }
  210.  
  211.   if (bytes_read == -1)
  212.     {
  213.       error (0, errno, "read error");
  214.       ret = 1;
  215.     }
  216.  
  217.   /* Close the files, but not standard output.  */
  218.   for (i = 1; i <= nfiles; i++)
  219.     if (descriptors[i] != -1 && close (descriptors[i]) != 0)
  220.       {
  221.     error (0, errno, "%s", files[i]);
  222.     ret = 1;
  223.       }
  224.  
  225.   free (descriptors);
  226.  
  227.   return ret;
  228. }
  229.