#include #include #include "lines.h" #include "util/debug.h" #include "util/error.h" bool file_lines_open(const char *progname, const char *fname, FILE *f, struct file_lines *dst) { dst->f = f; dst->cap = 4096; dst->buffer = malloc(dst->cap); if (!dst->buffer) { print_error_nomem(); return false; } dst->cursor = 0; dst->readfrom = (size_t)-1; dst->progname = progname; dst->fname = fname; return true; } bool file_lines_read(struct file_lines *fl, struct string_view *dst) { // Return already-read line if we have any if (fl->readfrom != (size_t)-1) { char *p = memchr(fl->buffer + fl->readfrom, '\n', fl->cursor - fl->readfrom); if (p != NULL) { dst->s = fl->buffer + fl->readfrom; dst->len = p - (fl->buffer + fl->readfrom); fl->readfrom = p - fl->buffer + 1; DEBUG("next line from %zu len %zu\n", fl->readfrom, dst->len); return true; } DEBUG("no more newlines, moving back from %zu len %zu\n", fl->readfrom, fl->cursor - fl->readfrom); // move back whatever we have left memmove(fl->buffer, fl->buffer + fl->readfrom, fl->cursor - fl->readfrom); fl->cursor -= fl->readfrom; } DEBUG("cursor=%zu\n", fl->cursor); // read a line size_t linelen = 0; bool havenewline = true; while (true) { // grow buffer when small if (fl->cap - fl->cursor < 1024) { fl->cap *= 2; if (fl->cap == 0) { fprintf(stderr, "%s: Regel te lang\n", fl->progname); exit(1); } DEBUG("realloc to cap %zu\n", fl->cap); fl->buffer = realloc(fl->buffer, fl->cap); if (!fl->buffer) print_error_nomem(); } size_t nr = fread(fl->buffer + fl->cursor, 1, fl->cap - fl->cursor, fl->f); DEBUG("nr=%zu\n", nr); if (nr == 0) { if (feof(fl->f)) { if (fl->cursor == 0) return false; linelen = fl->cursor; havenewline = false; break; } if (fl->fname) fprintf(stderr, "%s: Fout bij lezen van bestand '%s'\n", fl->progname, fl->fname); else fprintf(stderr, "%s: Fout bij lezen van standaardinvoer\n", fl->progname); exit(1); } char *p = memchr(fl->buffer + fl->cursor, '\n', nr); fl->cursor += nr; if (p != NULL) { linelen = p - fl->buffer; break; } } DEBUG("line with len %zu (cursor=%zu)\n", linelen, fl->cursor); // we have a newline at buffer + linelen; return lines in buffer dst->s = fl->buffer; dst->len = linelen; fl->readfrom = linelen + havenewline; return true; } void file_lines_close(struct file_lines *fl) { free(fl->buffer); }