From 03f8544691a8de9f77a803fd8cd2eeadb919ec03 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Sun, 10 Dec 2023 00:39:16 +0100 Subject: Genesis commit --- c/cat/.gitignore | 1 + c/cat/Makefile | 8 +++++ c/cat/cat.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 c/cat/.gitignore create mode 100644 c/cat/Makefile create mode 100644 c/cat/cat.c (limited to 'c/cat') diff --git a/c/cat/.gitignore b/c/cat/.gitignore new file mode 100644 index 0000000..ef07ddc --- /dev/null +++ b/c/cat/.gitignore @@ -0,0 +1 @@ +cat diff --git a/c/cat/Makefile b/c/cat/Makefile new file mode 100644 index 0000000..081ffd4 --- /dev/null +++ b/c/cat/Makefile @@ -0,0 +1,8 @@ +include ../base.mk + +all: cat +cat: cat.c + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -f cat diff --git a/c/cat/cat.c b/c/cat/cat.c new file mode 100644 index 0000000..7aaaa6b --- /dev/null +++ b/c/cat/cat.c @@ -0,0 +1,102 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define warn(...) \ + do { \ + warn(__VA_ARGS__); \ + rv = EXIT_FAILURE; \ + } while (0) + +static int rv = EXIT_SUCCESS; +static bool out_is_reg; +static char buf[BUFSIZ]; + +static void cat(const char *); +static void cat_sendfile(const char *, int, size_t); +static void cat_readwrite(const char *, int); + +int +main(int argc, char **argv) +{ + struct stat sb; + + if (fstat(STDOUT_FILENO, &sb) == -1) + warn("fstat: /dev/stdout"); + else + out_is_reg = S_ISREG(sb.st_mode); + + if (argc == 1) + cat("-"); + for (int i = 1; i < argc; i++) + cat(argv[i]); + return rv; +} + +void +cat(const char *file) +{ + int fd; + struct stat sb; + + if (strcmp(file, "-") == 0) + fd = STDIN_FILENO; + else if ((fd = open(file, O_RDONLY)) == -1) { + warn("open: %s", file); + return; + } + + if (fstat(fd, &sb) == -1) { + warn("fstat: %s", file); + goto out; + } + + if (S_ISREG(sb.st_mode) && out_is_reg) + cat_sendfile(file, fd, sb.st_size); + else + cat_readwrite(file, fd); + +out: + close(fd); +} + +void +cat_sendfile(const char *file, int fd, size_t n) +{ + off_t off = 0; + ssize_t nw; + + do { + nw = sendfile(STDOUT_FILENO, fd, &off, n); + off += nw; + } while (nw != -1 && (size_t)off < n); + + if (nw == -1) + warn("sendfile: %s", file); +} + +void +cat_readwrite(const char *file, int fd) +{ + ssize_t nr, nw; + + while ((nr = read(fd, buf, BUFSIZ)) > 0) { + for (ssize_t off = 0; nr > 0; nr -= nw, off += nw) { + if ((nw = write(STDOUT_FILENO, buf + off, nr)) == -1) { + warn("write: %s", file); + return; + } + } + } + if (nr == -1) + warn("read: %s", file); +} -- cgit v1.2.3