neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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 }