diff options
-rw-r--r-- | src/toilet.c | 105 |
1 files changed, 38 insertions, 67 deletions
diff --git a/src/toilet.c b/src/toilet.c index ff51ba8..de32003 100644 --- a/src/toilet.c +++ b/src/toilet.c @@ -1,11 +1,9 @@ #include <assert.h> #include <ctype.h> -#include <errno.h> #include <getopt.h> #include <limits.h> #include <pwd.h> #include <stdbool.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> @@ -13,7 +11,7 @@ #include "util/debug.h" #include "util/error.h" -#include "util/loop_args.h" +#include "util/loop_files.h" #include "util/map.h" #include "util/versie.h" @@ -21,8 +19,6 @@ static int modeMap; -#define BUF_SIZE 4096 - static void usage(FILE *f) { fprintf(f, "Gebruik: toilet [-nchV] [BESTAND]...\n" @@ -77,91 +73,66 @@ static char** parse_options(int argc, char **argv, int *modeMap) { return argv + optind; } -static size_t count_lines(char *fname, FILE *f) { - size_t nlines = 0; - bool last_was_nl = false; - - while (!feof(f)) { - static char buf[BUF_SIZE]; - const size_t n = fread(buf, 1, BUF_SIZE, f); - - for (size_t i = 0; i < n; i++) { - last_was_nl = false; - if (buf[i] == '\n') { - nlines++; - last_was_nl = true; - } - } - } +static size_t get_count(enum MODE mode, struct filebuf *fb) { + switch (mode) { + case M_BYTES: + return fb->sz; - if (!last_was_nl) nlines++; + case M_WORDS: { +#define IN(i) (i < fb->sz) - if (errno != 0) { - printf("toilet: fout bij lezen uit bestand '%s'\n", fname); - exit(1); - } + size_t words = 0; - rewind(f); - return nlines; -} - -static size_t count_words(FILE *f) { - size_t nwords = 0; + // (c) Tom Forging + for (size_t i = 0; IN(i);) { + size_t previ = i; + while (IN(i) && !isspace(fb->buf[i])) i++; + words += i != previ; + while (IN(i) && isspace(fb->buf[i])) i++; + } - while (!feof(f)) { - static char buf[BUF_SIZE]; - const size_t n = fread(buf, 1, BUF_SIZE, f); + return words; - // (c) Tom Forging - for (size_t i = 0; i<n;) { - size_t previ = i; - while (i<n && !isspace(buf[i])) i++; - nwords += i != previ; - while (i<n && isspace(buf[i])) i++; +#undef IN } - } - rewind(f); - return nwords; -} + case M_LINES: { + size_t lines = 0; + size_t i = 0; -static size_t get_count(enum MODE mode, char *fname, FILE *f) { - switch (mode) { - case M_BYTES: { - fseek(f, 0, SEEK_END); - long offset = ftell(f); - rewind(f); - return offset; - } + while (i != fb->sz) { + if (fb->buf[i] == '\n') lines++; + i++; + } - case M_WORDS: - return count_words(f); + // handle case if file does not have trailing newline + if (fb->buf[i - 1] != '\n') { + lines++; + } - case M_LINES: - return count_lines(fname, f); + return lines; + } default: assert(false); } } -static int process(char *fname, bool isstdin) { - FILE *f = isstdin ? stdin : fopen(fname, "rb"); - +static int process(struct filebuf *fb, char *fname, bool) { for (enum MODE mode = 1; mode <= M_BYTES; mode <<= 1) { if (mode & modeMap) { - const size_t count = get_count(mode, fname, f); + const size_t count = get_count(mode, fb); printf("%li ", count); } } - - if (fname != NULL) printf("%s", fname); - putchar('\n'); - - if (!isstdin) fclose(f); + printf("%s\n", fname); + free_filebuf(fb); return 0; } +// TODO: be smarter, toilet doesn't have to read the whole file in memory (for +// unmappable files) + int entry_toilet(int argc, char **argv) { modeMap = 0; char **args = parse_options(argc, argv, &modeMap); @@ -169,5 +140,5 @@ int entry_toilet(int argc, char **argv) { modeMap = INT_MAX; } - return loop_args(args, process); + return loop_files(args, process); } |