blob: 415d45dda5202864973ea36215258e0f2c755d26 [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 Moolenaar40043152020-07-10 20:45:31 +020035#include <stdlib.h>
36#include <string.h>
Bram Moolenaar24db7292016-01-03 16:56:10 +010037#include <fcntl.h>
38
39#ifdef _WIN32
40# define sysconf(x) -1
41#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000042
43void 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\
51as well as to the standard output.\n\
52\n\
53This version supplied with Vim 4.2 to make ':make' possible.\n\
54For 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
64int
65myfread(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
Bram Moolenaar739f7992022-06-06 22:16:09 +010081int
Bram Moolenaar071d4272004-06-13 20:20:40 +000082main(int argc, char *argv[])
83{
84 int append = 0;
Bram Moolenaar68093d32022-06-08 13:11:45 +010085 size_t numfiles;
Bram Moolenaar071d4272004-06-13 20:20:40 +000086 int maxfiles;
87 FILE **filepointers;
88 int i;
89 char buf[BUFSIZ];
90 int n;
Bram Moolenaar24db7292016-01-03 16:56:10 +010091 int optind = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
Bram Moolenaar24db7292016-01-03 16:56:10 +010093 for (i = 1; i < argc; i++)
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 {
Bram Moolenaar24db7292016-01-03 16:56:10 +010095 if (argv[i][0] != '-')
96 break;
97 if (!strcmp(argv[i], "-a"))
98 append++;
99 else
100 usage();
101 optind++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102 }
103
104 numfiles = argc - optind;
105
106 if (numfiles == 0)
107 {
108 fprintf(stderr, "doesn't make much sense using tee without any file name arguments...\n");
109 usage();
110 exit(2);
111 }
112
113 maxfiles = sysconf(_SC_OPEN_MAX); /* or fill in 10 or so */
114 if (maxfiles < 0)
115 maxfiles = 10;
116 if (numfiles + 3 > maxfiles) /* +3 accounts for stdin, out, err */
117 {
118 fprintf(stderr, "Sorry, there is a limit of max %d files.\n", maxfiles - 3);
119 exit(1);
120 }
121 filepointers = calloc(numfiles, sizeof(FILE *));
122 if (filepointers == NULL)
123 {
Bram Moolenaar68093d32022-06-08 13:11:45 +0100124 fprintf(stderr, "Error allocating memory for %ld files\n",
125 (long)numfiles);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126 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 }
Bram Moolenaar40043152020-07-10 20:45:31 +0200137#ifdef _WIN32
Bram Moolenaar24db7292016-01-03 16:56:10 +0100138 setmode(fileno(stdin), O_BINARY);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 fflush(stdout); /* needed for _fsetmode(stdout) */
Bram Moolenaar24db7292016-01-03 16:56:10 +0100140 setmode(fileno(stdout), O_BINARY);
Bram Moolenaar40043152020-07-10 20:45:31 +0200141#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142
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}