cat.c (2222B)
- // Collection of Unix tools, comparable to coreutils
- // SPDX-FileCopyrightText: 2017-2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #include <errno.h> /* errno */
- #include <fcntl.h> /* open(), O_RDONLY */
- #include <stdio.h> /* fprintf(), BUFSIZ */
- #include <string.h> /* strerror(), strncmp() */
- #include <unistd.h> /* read(), write(), close() */
- int
- concat(int fd, const char *fdname)
- {
- ssize_t c;
- char buf[BUFSIZ];
- while((c = read(fd, buf, sizeof(buf))) > 0)
- {
- if(write(1, buf, (size_t)c) < 0)
- {
- fprintf(stderr, "cat: Error writing: %s\n", strerror(errno));
- return 1;
- }
- }
- if(c < 0)
- {
- fprintf(stderr, "cat: Error reading ‘%s’: %s\n", fdname, strerror(errno));
- return 1;
- }
- return 0;
- }
- // FreeBSD also has sendfile(2) but it's only for sockets
- #ifdef __linux__
- #include <sys/sendfile.h>
- // Grabbed from /usr/src/hare/stdlib/io/+linux/platform_file.ha
- #ifndef SENDFILE_MAX
- #define SENDFILE_MAX 2147479552
- #endif // SENDFILE_MAX
- int
- fd_copy(int fd, const char *fdname)
- {
- ssize_t c = 0;
- off_t off = 0;
- while((c = sendfile(1, fd, &off, SENDFILE_MAX)) > 0)
- ;
- if(c < 0)
- {
- if(errno == EINVAL && off == 0)
- {
- return concat(fd, fdname);
- }
- fprintf(stderr, "cat: Error copying ‘%s’: %s\n", fdname, strerror(errno));
- return 1;
- }
- return 0;
- }
- #else // __linux__
- #define fd_copy concat
- #endif // __linux__
- int
- main(int argc, char *argv[])
- {
- if(argc <= 1)
- {
- return concat(0, "<stdin>");
- }
- // For POSIX compatibility
- if(strncmp(argv[1], "-u", 3) == 0)
- {
- argc--;
- argv++;
- }
- for(int argi = 1; argi < argc; argi++)
- {
- if(strncmp(argv[argi], "-", 2) == 0)
- {
- if(concat(0, "<stdin>") != 0)
- {
- return 1;
- }
- }
- else if(strncmp(argv[argi], "--", 3) == 0)
- {
- continue;
- }
- else
- {
- int fd = open(argv[argi], O_RDONLY);
- if(fd < 0)
- {
- fprintf(stderr, "cat: Error opening ‘%s’: %s\n", argv[argi], strerror(errno));
- return 1;
- }
- if(fd_copy(fd, argv[argi]) != 0)
- {
- return 1;
- }
- if(close(fd) < 0)
- {
- fprintf(stderr, "cat: Error closing ‘%s’: %s\n", argv[argi], strerror(errno));
- return 1;
- }
- }
- }
- return 0;
- }