Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / examples / loadables / tee.c
1 /* tee - duplicate standard input */
2
3 /* See Makefile for compilation details. */
4
5 #include "config.h"
6
7 #include "bashtypes.h"
8 #include "posixstat.h"
9 #include "filecntl.h"
10
11 #include <signal.h>
12
13 #if defined (HAVE_UNISTD_H)
14 #  include <unistd.h>
15 #endif
16
17 #include "bashansi.h"
18
19 #include <stdio.h>
20 #include <errno.h>
21
22 #include "builtins.h"
23 #include "shell.h"
24 #include "bashgetopt.h"
25
26 #if !defined (errno)
27 extern int errno;
28 #endif
29
30 typedef struct flist {
31   struct flist *next;
32   int fd;
33   char *fname;
34 } FLIST;
35
36 static FLIST *tee_flist;
37
38 #define TEE_BUFSIZE     8192
39
40 extern int interrupt_immediately;
41
42 extern char *strerror ();
43
44 tee_builtin (list)
45      WORD_LIST *list;
46 {
47   int opt, append, nointr, rval, fd, fflags;
48   int n, nr, nw;
49   FLIST *fl;
50   char *buf, *bp;
51
52   char *t;
53
54   reset_internal_getopt ();
55   append = nointr = 0;
56   tee_flist = (FLIST *)NULL;
57   while ((opt = internal_getopt (list, "ai")) != -1)
58     {
59       switch (opt)
60         {
61         case 'a':
62           append = 1;
63           break;
64         case 'i':
65           nointr = 1;
66           break;
67         default:
68           builtin_usage ();
69           return (EX_USAGE);
70         }
71     }
72   list = loptend;
73
74   if (nointr == 0)
75     interrupt_immediately++;
76
77   buf = xmalloc (TEE_BUFSIZE);
78
79   /* Initialize output file list. */
80   fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
81   tee_flist->fd = 1;
82   tee_flist->fname = "stdout";
83   tee_flist->next = (FLIST *)NULL;
84
85   /* Add file arguments to list of output files. */
86   fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
87   for (rval = EXECUTION_SUCCESS; list; list = list->next)
88     {
89       fd = open (list->word->word, fflags, 0666);
90       if (fd < 0)
91         {
92           builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
93           rval = EXECUTION_FAILURE;
94         }
95       else
96         {
97           fl->next = (FLIST *)xmalloc (sizeof(FLIST));
98           fl->next->fd = fd;
99           fl->next->fname = list->word->word;
100           fl = fl->next;
101           fl->next = (FLIST *)NULL;
102         }
103     }
104
105   while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
106     for (fl = tee_flist; fl; fl = fl->next)
107       {
108         n = nr;
109         bp = buf;
110         do
111           {
112             if ((nw = write (fl->fd, bp, n)) == -1)
113               {
114                 builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
115                 rval = EXECUTION_FAILURE;
116                 break;
117               }
118             bp += nw;
119           }
120         while (n -= nw);
121       }
122   if (nr < 0)
123     builtin_error ("read error: %s", strerror (errno));
124
125   /* Deallocate resources -- this is a builtin command. */
126   tee_flist = tee_flist->next;          /* skip bogus close of stdout */
127   while (tee_flist)
128     {
129       fl = tee_flist;
130       if (close (fl->fd) < 0)
131         {
132           builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
133           rval = EXECUTION_FAILURE;
134         }
135       tee_flist = tee_flist->next;
136       free (fl);
137     }
138   
139   return (rval);
140 }
141
142 char *tee_doc[] = {
143         "Copy standard input to standard output, making a copy in each",
144         "filename argument.  If the `-a' option is gived, the specified",
145         "files are appended to, otherwise they are overwritten.  If the",
146         "`-i' option is supplied, tee ignores interrupts.",
147         (char *)NULL
148 };
149
150 struct builtin tee_struct = {
151         "tee",                  /* builtin name */
152         tee_builtin,            /* function implementing the builtin */
153         BUILTIN_ENABLED,        /* initial flags for builtin */
154         tee_doc,                /* array of long documentation strings. */
155         "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
156         0                       /* reserved for internal use */
157 };