1 /* vim:set ts=4 sw=4:
2 *
3 * Copyright (c) 1996, Paul Slootman
4 *
5 * Author: Paul Slootman
6 * ([email protected], [email protected], [email protected])
7 * Modifications for MSVC: Yasuhiro Matsumoto
8 *
9 * This source code is released into the public domain. It is provided on an
10 * as-is basis and no responsibility is accepted for its failure to perform
11 * as expected. It is worth at least as much as you paid for it!
12 *
13 * tee.c - pipe fitting
14 *
15 * tee reads stdin, and writes what it reads to each of the specified
16 * files. The primary reason of existence for this version is a quick
17 * and dirty implementation to distribute with Vim, to make one of the
18 * most useful features of Vim possible on OS/2: quickfix.
19 *
20 * Of course, not using tee but instead redirecting make's output directly
21 * into a temp file and then processing that is possible, but if we have a
22 * system capable of correctly piping (unlike DOS, for example), why not
23 * use it as well as possible? This tee should also work on other systems,
24 * but it's not been tested there, only on OS/2.
25 *
26 * tee is also available in the GNU shellutils package, which is available
27 * precompiled for OS/2. That one probably works better.
28 */
29
30 #ifndef _MSC_VER
31 # include <unistd.h>
32 #endif
33 #include <malloc.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fcntl.h>
38
39 #ifdef _WIN32
40 # define sysconf(x) -1
41 #endif
42
usage(void)43 void usage(void)
44 {
45 fprintf(stderr,
46 "tee usage:\n\
47 \ttee [-a] file ... file_n\n\
48 \n\
49 \t-a\tappend to files instead of truncating\n\
50 \nTee reads its input, and writes to each of the specified files,\n\
51 as well as to the standard output.\n\
52 \n\
53 This version supplied with Vim 4.2 to make ':make' possible.\n\
54 For a more complete and stable version, consider getting\n\
55 [a port of] the GNU shellutils package.\n\
56 ");
57 }
58
59 /*
60 * fread only returns when count is read or at EOF.
61 * We could use fgets, but I want to be able to handle binary blubber.
62 */
63
64 int
myfread(char * buf,int elsize,int max,FILE * fp)65 myfread(char *buf, int elsize /*ignored*/, int max, FILE *fp)
66 {
67 int c;
68 int n = 0;
69
70 while ((n < max) && ((c = getchar()) != EOF))
71 {
72 *(buf++) = c;
73 n++;
74 if (c == '\n' || c == '\r')
75 break;
76 }
77 return n;
78 }
79
80
81 void
main(int argc,char * argv[])82 main(int argc, char *argv[])
83 {
84 int append = 0;
85 int numfiles;
86 int opt;
87 int maxfiles;
88 FILE **filepointers;
89 int i;
90 char buf[BUFSIZ];
91 int n;
92 int optind = 1;
93
94 for (i = 1; i < argc; i++)
95 {
96 if (argv[i][0] != '-')
97 break;
98 if (!strcmp(argv[i], "-a"))
99 append++;
100 else
101 usage();
102 optind++;
103 }
104
105 numfiles = argc - optind;
106
107 if (numfiles == 0)
108 {
109 fprintf(stderr, "doesn't make much sense using tee without any file name arguments...\n");
110 usage();
111 exit(2);
112 }
113
114 maxfiles = sysconf(_SC_OPEN_MAX); /* or fill in 10 or so */
115 if (maxfiles < 0)
116 maxfiles = 10;
117 if (numfiles + 3 > maxfiles) /* +3 accounts for stdin, out, err */
118 {
119 fprintf(stderr, "Sorry, there is a limit of max %d files.\n", maxfiles - 3);
120 exit(1);
121 }
122 filepointers = calloc(numfiles, sizeof(FILE *));
123 if (filepointers == NULL)
124 {
125 fprintf(stderr, "Error allocating memory for %d files\n", numfiles);
126 exit(1);
127 }
128 for (i = 0; i < numfiles; i++)
129 {
130 filepointers[i] = fopen(argv[i+optind], append ? "ab" : "wb");
131 if (filepointers[i] == NULL)
132 {
133 fprintf(stderr, "Can't open \"%s\"\n", argv[i+optind]);
134 exit(1);
135 }
136 }
137 #ifdef _WIN32
138 setmode(fileno(stdin), O_BINARY);
139 fflush(stdout); /* needed for _fsetmode(stdout) */
140 setmode(fileno(stdout), O_BINARY);
141 #endif
142
143 while ((n = myfread(buf, sizeof(char), sizeof(buf), stdin)) > 0)
144 {
145 fwrite(buf, sizeof(char), n, stdout);
146 fflush(stdout);
147 for (i = 0; i < numfiles; i++)
148 {
149 if (filepointers[i] &&
150 fwrite(buf, sizeof(char), n, filepointers[i]) != n)
151 {
152 fprintf(stderr, "Error writing to file \"%s\"\n", argv[i+optind]);
153 fclose(filepointers[i]);
154 filepointers[i] = NULL;
155 }
156 }
157 }
158 for (i = 0; i < numfiles; i++)
159 {
160 if (filepointers[i])
161 fclose(filepointers[i]);
162 }
163
164 exit(0);
165 }
166