summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/io/read_file.c94
-rw-r--r--src/io/read_file.h19
-rw-r--r--src/tak.c105
3 files changed, 135 insertions, 83 deletions
diff --git a/src/io/read_file.c b/src/io/read_file.c
new file mode 100644
index 0000000..b2f4604
--- /dev/null
+++ b/src/io/read_file.c
@@ -0,0 +1,94 @@
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "read_file.h"
+
+#define CHECK_OOM(ptr) \
+ if (ptr == NULL) { \
+ fprintf(stderr, "geheugen is op"); \
+ /* I think I should free the original memory here, but whatever */ \
+ return NULL; \
+ }
+
+struct filebuf *stream_to_filebuf(FILE *restrict stream) {
+ size_t sz = 0;
+ size_t cap = 4096;
+ char *buf = malloc(cap);
+ CHECK_OOM(buf);
+
+ while (!feof(stream)) {
+ if (cap-sz == 0) {
+ cap *= 2;
+ buf = realloc(buf, cap);
+ CHECK_OOM(buf);
+ }
+
+ const size_t amount = cap-sz;
+ const size_t n = fread(buf+sz, 1, amount, stream);
+ sz += n;
+
+ if (n != amount && !feof(stream)) {
+ fprintf(stderr, "fout tijdens lezen van standaard invoer.\n");
+ free(buf);
+ return NULL;
+ }
+ }
+
+ buf = realloc(buf, sz);
+
+ struct filebuf *res = calloc(1, sizeof(struct filebuf));
+ res->buf = buf;
+ res->sz = sz;
+ res->mapping_type = MT_MMAP;
+ return res;
+}
+
+static void *fd_to_mmap(const int fd, struct stat sb) {
+ void *addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ return NULL;
+ }
+
+ close(fd);
+ return addr;
+}
+
+struct filebuf *file_to_filebuf(char *fname) {
+ const int fd = open(fname, O_RDONLY);
+
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ goto stream;
+ }
+
+ void *addr;
+ if ((addr = fd_to_mmap(fd, sb)) != NULL) {
+ struct filebuf *res = calloc(1, sizeof(struct filebuf));
+ res->buf = addr;
+ res->sz = sb.st_size;
+ res->mapping_type = MT_MMAP;
+ return res;
+ }
+
+stream: {
+ FILE *stream = fdopen(fd, "rb");
+ struct filebuf *res = stream_to_filebuf(stream);
+ fclose(stream);
+ return res;
+}
+}
+
+void free_filebuf(struct filebuf *fb) {
+ switch (fb->mapping_type) {
+ case MT_MMAP:
+ munmap(fb->buf, fb->sz);
+ break;
+ case MT_OWNED:
+ free(fb->buf);
+ break;
+ }
+ free(fb);
+}
diff --git a/src/io/read_file.h b/src/io/read_file.h
new file mode 100644
index 0000000..201ae5b
--- /dev/null
+++ b/src/io/read_file.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdio.h>
+
+enum mapping_type {
+ MT_MMAP,
+ MT_OWNED,
+};
+
+struct filebuf {
+ char *buf;
+ size_t sz;
+ enum mapping_type mapping_type;
+};
+
+struct filebuf *stream_to_filebuf(FILE *restrict stream);
+struct filebuf *file_to_filebuf(char *fname);
+void free_filebuf(struct filebuf *filebuf);
diff --git a/src/tak.c b/src/tak.c
index e970ae1..e8fb817 100644
--- a/src/tak.c
+++ b/src/tak.c
@@ -6,6 +6,7 @@
#include "util/map.h"
#include "util/versie.h"
+#include "io/read_file.h"
static void usage(FILE *f) {
fprintf(f,
@@ -39,25 +40,20 @@ static char** parse_options(int argc, char **argv) {
return argv + optind;
}
-struct state {
- char *buf;
- size_t sz;
-};
-
-static void process(struct state state) {
+static void process(struct filebuf *fb) {
char *lstart, *lend;
- lend = &state.buf[state.sz - 1];
+ lend = &fb->buf[fb->sz - 1];
- while (lend > state.buf) {
+ while (lend > fb->buf) {
if (*lend == '\n') {
lend--;
}
lstart = lend;
- while (*lstart != '\n' && lstart != state.buf) {
+ while (*lstart != '\n' && lstart != fb->buf) {
lstart--;
}
- if (lstart != state.buf) {
+ if (lstart != fb->buf) {
lstart++;
}
@@ -65,96 +61,39 @@ static void process(struct state state) {
lend = lstart-1;
}
-}
-
-#define CHECK_OOM(ptr) \
- if (ptr == NULL) { \
- fprintf(stderr, "tak: geheugen is op"); \
- /* I think I should free the original memory here, but whatever */ \
- return NULL; \
- }
-static char *read_stream(FILE *stream, size_t *sz) {
- *sz = 0;
- size_t cap = 4096;
- char *res = malloc(cap);
- CHECK_OOM(res);
-
- while (!feof(stream)) {
- if (cap-*sz == 0) {
- cap *= 2;
- res = realloc(res, cap);
- CHECK_OOM(res);
- }
-
- const size_t amount = cap-*sz;
- const size_t n = fread(res+*sz, 1, amount, stream);
- *sz += n;
-
- if (n != amount && !feof(stream)) {
- fprintf(stderr, "tak: fout tijdens lezen van standaard invoer.\n");
- free(res);
- return NULL;
- }
- }
-
- res = realloc(res, *sz);
- return res;
-}
-
-int handleStream(FILE *stream) {
- size_t sz = 0;
- char *data = read_stream(stream, &sz);
- if (data == NULL) {
- return 1;
- }
-
- struct state state = { .buf = data, .sz = sz };
- process(state);
-
- free(data);
- return 0;
-}
-
-int handleFile(char *fname) {
- struct map *map = open_map(fname);
- if (map == NULL) {
- return 1;
- }
-
- struct state state = { .buf = map->addr, .sz = map->sb.st_size };
- process(state);
-
- close_map(map);
-
- return 0;
+ free_filebuf(fb);
}
int entry_tak(int argc, char **argv) {
char **args = parse_options(argc, argv);
if (*args == NULL) {
- handleStream(stdin);
+ struct filebuf *fb = stream_to_filebuf(stdin);
+ if (fb == NULL) {
+ return 1;
+ }
+
+ process(fb);
return 0;
}
while (*args != NULL) {
+ struct filebuf *fb = NULL;
+
if (!strcmp(*args, "-")) {
- handleStream(stdin);
- goto next;
+ fb = stream_to_filebuf(stdin);
+ if (fb == NULL) {
+ return 1;
+ }
}
- if (!handleFile(*args)) {
- goto next;
+ if (fb == NULL) {
+ fb = file_to_filebuf(*args);
}
- FILE *stream = fopen(*args, "rb");
- if (handleStream(stream)) {
- return 1;
- }
- fclose(stream);
+ process(fb);
-next:
args++;
}