/*- * Copyright (c) 2024 Kyle Evans * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include static void usage(void) { fprintf(stderr, "usage: %s [-b bytes | -c lines | -e] [-s buffer-size]\n", getprogname()); exit(1); } int main(int argc, char *argv[]) { char *buf; const char *errstr; size_t bufsz = 0, reps; ssize_t ret; enum { MODE_BYTES, MODE_COUNT, MODE_EOF } mode; int ch; /* * -b specifies number of bytes. * -c specifies number of read() calls. * -e specifies eof (default) * -s to pass a buffer size * * Reading N lines is the same as -c with a high buffer size. */ mode = MODE_EOF; while ((ch = getopt(argc, argv, "b:c:es:")) != -1) { switch (ch) { case 'b': mode = MODE_BYTES; reps = strtonum(optarg, 0, SSIZE_MAX, &errstr); if (errstr != NULL) errx(1, "strtonum: %s", errstr); break; case 'c': mode = MODE_COUNT; reps = strtonum(optarg, 1, SSIZE_MAX, &errstr); if (errstr != NULL) errx(1, "strtonum: %s", errstr); break; case 'e': mode = MODE_EOF; break; case 's': bufsz = strtonum(optarg, 1, SSIZE_MAX, &errstr); if (errstr != NULL) errx(1, "strtonum: %s", errstr); break; default: usage(); } } if (bufsz == 0) { if (mode == MODE_BYTES) bufsz = reps; else bufsz = LINE_MAX; } buf = malloc(bufsz); if (buf == NULL) err(1, "malloc"); for (;;) { size_t readsz; /* * Be careful not to over-read if we're in byte-mode. In every other * mode, we'll read as much as we can. */ if (mode == MODE_BYTES) readsz = MIN(bufsz, reps); else readsz = bufsz; ret = read(STDIN_FILENO, buf, readsz); if (ret == -1 && errno == EINTR) continue; if (ret == -1) err(1, "read"); if (ret == 0) { if (mode == MODE_EOF) return (0); errx(1, "premature EOF"); } /* Write out what we've got */ write(STDOUT_FILENO, buf, ret); /* * Bail out if we've hit our metric (byte mode / count mode). */ switch (mode) { case MODE_BYTES: reps -= ret; if (reps == 0) return (0); break; case MODE_COUNT: reps--; if (reps == 0) return (0); break; default: break; } } return (0); }