diff options
-rw-r--r-- | src/io/read_file.c | 94 | ||||
-rw-r--r-- | src/io/read_file.h | 19 | ||||
-rw-r--r-- | src/tak.c | 105 |
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); @@ -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++; } |