summaryrefslogtreecommitdiff
path: root/src/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/io')
-rw-r--r--src/io/read_file.c94
-rw-r--r--src/io/read_file.h19
2 files changed, 113 insertions, 0 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);