tee.c (3637B)
1 // tee.c - pipe fitting 2 // 3 // Copyright (c) 1996, Paul Slootman 4 // 5 // Author: Paul Slootman 6 // (paul@wurtel.hobby.nl, paul@murphy.nl, paulS@toecompst.nl) 7 // Modifications for MSVC: Yasuhiro Matsumoto 8 // Modifications for Neovim: https://github.com/neovim/neovim/pull/36363 9 // 10 // This source code is released into the public domain. It is provided on an 11 // as-is basis and no responsibility is accepted for its failure to perform 12 // as expected. It is worth at least as much as you paid for it! 13 // 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 #ifndef _MSC_VER 30 # include <unistd.h> 31 #endif 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 #ifdef _WIN32 38 # define sysconf(x) - 1 39 #endif 40 41 void usage(void) 42 { 43 fprintf(stderr, 44 "Neotee: a web-scale fork of tee\n" 45 "Usage:\n" 46 "\ttee [-a] file ... file_n\n" 47 "\n" 48 "\t-a\tappend to files instead of truncating\n" 49 "\n" 50 "Tee reads its input, and writes to each of the specified files,\n" 51 "as well as to the standard output.\n" 52 "\n" 53 "Shipped with Nvim 0.12+ for use with :make, :grep, :!, etc.\n"); 54 } 55 56 int main(int argc, char *argv[]) 57 { 58 int append = 0; 59 size_t numfiles; 60 int maxfiles; 61 FILE **filepointers; 62 int i; 63 char buf[65536]; 64 int n; 65 int optnr = 1; 66 67 for (i = 1; i < argc; i++) { 68 if (argv[i][0] != '-') { 69 break; 70 } 71 if (!strcmp(argv[i], "-a")) { 72 append++; 73 } else { 74 usage(); 75 exit(2); 76 } 77 optnr++; 78 } 79 80 numfiles = argc - optnr; 81 82 if (numfiles == 0) { 83 usage(); 84 exit(2); 85 } 86 87 maxfiles = sysconf(_SC_OPEN_MAX); // or fill in 10 or so 88 if (maxfiles < 0) { 89 maxfiles = 10; 90 } 91 if (numfiles + 3 > maxfiles) { // +3 accounts for stdin, out, err 92 fprintf(stderr, "There is a limit of max %d files.\n", maxfiles - 3); 93 exit(1); 94 } 95 filepointers = calloc(numfiles, sizeof(FILE *)); // NOLINT 96 if (filepointers == NULL) { 97 fprintf(stderr, "Error allocating memory for %ld files\n", (long)numfiles); 98 exit(1); 99 } 100 for (i = 0; i < numfiles; i++) { 101 filepointers[i] = fopen(argv[i + optnr], append ? "ab" : "wb"); 102 if (filepointers[i] == NULL) { 103 fprintf(stderr, "Can't open \"%s\"\n", argv[i + optnr]); 104 exit(1); 105 } 106 } 107 #ifdef _WIN32 108 setmode(fileno(stdin), O_BINARY); 109 fflush(stdout); // needed for _fsetmode(stdout) 110 setmode(fileno(stdout), O_BINARY); 111 setvbuf(stdout, NULL, _IONBF, 0); // unbuffered for immediate output 112 #endif 113 114 while ((n = fread(buf, 1, sizeof(buf), stdin)) > 0) { 115 fwrite(buf, 1, n, stdout); 116 for (i = 0; i < numfiles; i++) { 117 if (filepointers[i]) { 118 fwrite(buf, 1, n, filepointers[i]); 119 } 120 } 121 fflush(stdout); 122 } 123 for (i = 0; i < numfiles; i++) { 124 if (filepointers[i]) { 125 fclose(filepointers[i]); 126 } 127 } 128 129 exit(0); 130 }