#include #include #include #include #include #include "util/error.h" #include "read_file.h" #include "global.h" #define CHECK_OOM(ptr) \ if (ptr == NULL) { \ print_error_nomem(); \ } struct filebuf *stream_to_filebuf(FILE *restrict stream, int openOptions) { if (openOptions & O_NOALLOWSPONGE) { return NULL; } 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, "%s: fout tijdens lezen van standaard invoer.\n", progname); 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_OWNED; 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, int openOptions, bool *isdir) { const int fd = open(fname, O_RDONLY); if (fd == -1) { return NULL; } struct stat sb; if (fstat(fd, &sb) == -1) { return NULL; } if (isdir != NULL) *isdir = S_ISDIR(sb.st_mode); if (openOptions & O_NOALLOWMAP) { goto sponge; } 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; } // braces are needed until we actually use c23 instead of c2x (only c23 allows // labels before declarations) sponge: { FILE *stream = fdopen(fd, "rb"); struct filebuf *res = stream_to_filebuf(stream, openOptions); 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); }