diff options
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/read_file.c | 94 | ||||
-rw-r--r-- | src/io/read_file.h | 19 |
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); |