blob: c668d2d1e3ac409bee6f2081d28654ea7b791353 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vim:set ts=4 sw=4:
2 *
3 * Copyright (c) 1996, Paul Slootman
4 *
5 * Author: Paul Slootman
6 * (paul@wurtel.hobby.nl, paul@murphy.nl, paulS@toecompst.nl)
Bram Moolenaar24db7292016-01-03 16:56:10 +01007 * Modifications for MSVC: Yasuhiro Matsumoto
Bram Moolenaar071d4272004-06-13 20:20:40 +00008 *
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
Bram Moolenaar24db7292016-01-03 16:56:10 +010030#ifndef _MSC_VER
31# include <unistd.h>
32#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000033#include <malloc.h>
34#include <stdio.h>
Bram Moolenaar24db7292016-01-03 16:56:10 +010035#include <fcntl.h>
36
37#ifdef _WIN32
38# define sysconf(x) -1
39#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000040
41void usage(void)
42{
43 fprintf(stderr,
44"tee usage:\n\
45\ttee [-a] file ... file_n\n\
46\n\
47\t-a\tappend to files instead of truncating\n\
48\nTee reads its input, and writes to each of the specified files,\n\
49as well as to the standard output.\n\
50\n\
51This version supplied with Vim 4.2 to make ':make' possible.\n\
52For a more complete and stable version, consider getting\n\
53[a port of] the GNU shellutils package.\n\
54");
55}
56
57/*
58 * fread only returns when count is read or at EOF.
59 * We could use fgets, but I want to be able to handle binary blubber.
60 */
61
62int
63myfread(char *buf, int elsize /*ignored*/, int max, FILE *fp)
64{
65 int c;
66 int n = 0;
67
68 while ((n < max) && ((c = getchar()) != EOF))
69 {
70 *(buf++) = c;
71 n++;
72 if (c == '\n' || c == '\r')
73 break;
74 }
75 return n;
76}
77
78
79void
80main(int argc, char *argv[])
81{
82 int append = 0;
83 int numfiles;
84 int opt;
85 int maxfiles;
86 FILE **filepointers;
87 int i;
88 char buf[BUFSIZ];
89 int n;
Bram Moolenaar24db7292016-01-03 16:56:10 +010090 int optind = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +000091
Bram Moolenaar24db7292016-01-03 16:56:10 +010092 for (i = 1; i < argc; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 {
Bram Moolenaar24db7292016-01-03 16:56:10 +010094 if (argv[i][0] != '-')
95 break;
96 if (!strcmp(argv[i], "-a"))
97 append++;
98 else
99 usage();
100 optind++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101 }
102
103 numfiles = argc - optind;
104
105 if (numfiles == 0)
106 {
107 fprintf(stderr, "doesn't make much sense using tee without any file name arguments...\n");
108 usage();
109 exit(2);
110 }
111
112 maxfiles = sysconf(_SC_OPEN_MAX); /* or fill in 10 or so */
113 if (maxfiles < 0)
114 maxfiles = 10;
115 if (numfiles + 3 > maxfiles) /* +3 accounts for stdin, out, err */
116 {
117 fprintf(stderr, "Sorry, there is a limit of max %d files.\n", maxfiles - 3);
118 exit(1);
119 }
120 filepointers = calloc(numfiles, sizeof(FILE *));
121 if (filepointers == NULL)
122 {
123 fprintf(stderr, "Error allocating memory for %d files\n", numfiles);
124 exit(1);
125 }
126 for (i = 0; i < numfiles; i++)
127 {
128 filepointers[i] = fopen(argv[i+optind], append ? "ab" : "wb");
129 if (filepointers[i] == NULL)
130 {
131 fprintf(stderr, "Can't open \"%s\"\n", argv[i+optind]);
132 exit(1);
133 }
134 }
Bram Moolenaar24db7292016-01-03 16:56:10 +0100135 setmode(fileno(stdin), O_BINARY);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136 fflush(stdout); /* needed for _fsetmode(stdout) */
Bram Moolenaar24db7292016-01-03 16:56:10 +0100137 setmode(fileno(stdout), O_BINARY);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138
139 while ((n = myfread(buf, sizeof(char), sizeof(buf), stdin)) > 0)
140 {
141 fwrite(buf, sizeof(char), n, stdout);
142 fflush(stdout);
143 for (i = 0; i < numfiles; i++)
144 {
145 if (filepointers[i] &&
146 fwrite(buf, sizeof(char), n, filepointers[i]) != n)
147 {
148 fprintf(stderr, "Error writing to file \"%s\"\n", argv[i+optind]);
149 fclose(filepointers[i]);
150 filepointers[i] = NULL;
151 }
152 }
153 }
154 for (i = 0; i < numfiles; i++)
155 {
156 if (filepointers[i])
157 fclose(filepointers[i]);
158 }
159
160 exit(0);
161}