summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/toilet.c105
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);
}