tee.c (1962B)
- // Collection of Unix tools, comparable to coreutils
- // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
- #define _POSIX_C_SOURCE 200809L
- #include <assert.h> /* assert() */
- #include <errno.h> /* errno */
- #include <stdio.h> /* fprintf(), fgetc(), fputc(), fclose(), fopen() */
- #include <stdlib.h> /* malloc(), free(), abort() */
- #include <string.h> /* strerror() */
- #include <unistd.h> /* getopt(), opt… */
- void
- cleanup(FILE **fds)
- {
- if(fds != NULL)
- {
- free(fds);
- }
- }
- int
- main(int argc, char *argv[])
- {
- const char *mode = "w";
- FILE **fds = {NULL}; // Shut up GCC
- int c;
- while((c = getopt(argc, argv, ":ai")) != -1)
- {
- switch(c)
- {
- case 'a':
- mode = "a";
- break;
- case 'i': /* ignore SIGINT */;
- break;
- }
- }
- argc -= optind;
- argv += optind;
- if(argc > 0)
- {
- fds = malloc(sizeof(FILE *) * (size_t)argc);
- if(!fds)
- {
- fprintf(stderr, "Cannot allocate fd array: %s\n", strerror(errno));
- return 1;
- }
- }
- for(int argi = 0; argi < argc; argi++)
- {
- assert(argv[argi]);
- // POSIX: implementations shouldn't treat '-' as stdin
- fds[argi] = fopen(argv[argi], mode);
- if(fds[argi] == NULL)
- {
- fprintf(stderr, "Error opening ‘%s’: %s\n", argv[argi], strerror(errno));
- cleanup(fds);
- return 1;
- }
- }
- // main loop, note that failed writes shouldn't make tee exit
- int err = 0;
- while((c = fgetc(stdin)) != EOF)
- {
- if(fputc(c, stdout) == EOF)
- {
- fprintf(stderr, "Error writing ‘<stdout>’: %s\n", strerror(errno));
- err = 1;
- errno = 0;
- }
- for(int argi = 0; argi < argc; argi++)
- {
- if(fputc(c, fds[argi]) == EOF)
- {
- fprintf(stderr, "Error writing to argument %d: %s\n", argi, strerror(errno));
- err = 1;
- errno = 0;
- }
- }
- }
- // cleanup
- for(int argi = 0; argi < argc; argi++)
- {
- if(fclose(fds[argi]) != 0)
- {
- abort();
- }
- }
- cleanup(fds);
- return err;
- }