From 1168c8ab426105bcd1b65aaf1f62c7a6144b0ae8 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sun, 14 Jul 2024 10:25:56 +0200 Subject: file_lines module, herschrijf omd ermee --- Maakbestand | 4 ++- src/io/lines.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/io/lines.h | 25 ++++++++++++++ src/omd.c | 82 ++++++-------------------------------------- src/util/string_view.h | 10 ++++++ 5 files changed, 140 insertions(+), 73 deletions(-) create mode 100644 src/io/lines.c create mode 100644 src/io/lines.h create mode 100644 src/util/string_view.h diff --git a/Maakbestand b/Maakbestand index 7b20ca7..70df156 100644 --- a/Maakbestand +++ b/Maakbestand @@ -3,7 +3,9 @@ VERSION := $(shell ./versie.sh) PREFIX ?= /usr CC := gcc -CFLAGS := -Wall -Wextra -std=c2x -O2 -D_GNU_SOURCE -DDRUKKEDOOS_VERSIE=\"$(VERSION)\" +CFLAGS := -Wall -Wextra -std=c2x -O2 +CFLAGS += -D_GNU_SOURCE -DDRUKKEDOOS_VERSIE=\"$(VERSION)\" +CFLAGS += -Isrc LDFLAGS := OBJDIR := obj diff --git a/src/io/lines.c b/src/io/lines.c new file mode 100644 index 0000000..6367c1d --- /dev/null +++ b/src/io/lines.c @@ -0,0 +1,92 @@ +#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(progname); + 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; + 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(fl->progname); + } + + 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; + 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 + 1; + return true; +} + +void file_lines_close(struct file_lines *fl) { + free(fl->buffer); +} diff --git a/src/io/lines.h b/src/io/lines.h new file mode 100644 index 0000000..b09b756 --- /dev/null +++ b/src/io/lines.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include "util/string_view.h" + + +struct file_lines { + const char *progname, *fname; + + FILE *f; + size_t cap; + char *buffer; + size_t cursor; + size_t readfrom; // if -1, no newline in buffer +}; + +// Returns false on EOF. FILE remains ownership of the caller. +bool file_lines_open(const char *progname, const char *fname, FILE *f, struct file_lines *dst); + +// Returns whether successful +bool file_lines_read(struct file_lines *fl, struct string_view *dst); + +void file_lines_close(struct file_lines *fl); diff --git a/src/omd.c b/src/omd.c index b43538a..aa48ee0 100644 --- a/src/omd.c +++ b/src/omd.c @@ -3,6 +3,7 @@ #include #include #include +#include "io/lines.h" #include "util/versie.h" #include "util/error.h" #include "util/debug.h" @@ -48,83 +49,20 @@ static void reverse_in_place(char *buf, size_t len) { } static void process(const char *fname, FILE *f) { - size_t cap = 4096; - char *buffer = malloc(cap); - if (!buffer) print_error_nomem("omd"); - - size_t cursor = 0; + struct file_lines fl; + if (!file_lines_open("omd", fname, f, &fl)) exit(1); while (true) { - DEBUG("cursor=%zu\n", cursor); - - // read a line - size_t linelen = 0; - while (true) { - // grow buffer when small - if (cap - cursor < 1024) { - cap *= 2; - if (cap == 0) { - fprintf(stderr, "omd: Regel te lang\n"); - exit(1); - } - DEBUG("realloc to cap %zu\n", cap); - buffer = realloc(buffer, cap); - if (!buffer) print_error_nomem("omd"); - } + struct string_view sv; + if (!file_lines_read(&fl, &sv)) break; - size_t nr = fread(buffer + cursor, 1, cap - cursor, f); - DEBUG("nr=%zu\n", nr); - if (nr == 0) { - if (feof(f)) { - if (cursor == 0) return; - linelen = cursor; - break; - } - if (fname) fprintf(stderr, "omd: Fout bij lezen van bestand '%s'\n", fname); - else fprintf(stderr, "omd: Fout bij lezen van standaardinvoer\n"); - exit(1); - } - char *p = memchr(buffer + cursor, '\n', nr); - cursor += nr; - if (p != NULL) { - linelen = p - buffer; - break; - } - } - - DEBUG("line with len %zu (cursor=%zu)\n", linelen, cursor); - - // we have a newline at cursor+linelen; print all lines that we already have in full - size_t linestart = 0; - while (true) { - reverse_in_place(buffer + linestart, linelen); - if (linestart + linelen < cap && buffer[linestart + linelen] == '\n') { - size_t nw = fwrite(buffer + linestart, 1, linelen + 1, stdout); - if (nw < linelen + 1) exit(1); - } else { - size_t nw = fwrite(buffer + linestart, 1, linelen, stdout); - if (nw < linelen) exit(1); - putchar('\n'); - // no newline in the buffer but nevertheless a completed line means that input is at EOF - goto cleanup; - } - - linestart += linelen + 1; - char *p = memchr(buffer + linestart, '\n', cursor - linestart); - if (p == NULL) { - DEBUG("no more newlines, moving back from %zu len %zu\n", linestart, cursor - linestart); - // move back whatever we have left - memmove(buffer, buffer + linestart, cursor - linestart); - cursor -= linestart; - break; - } - linelen = p - (buffer + linestart); - DEBUG("next line from %zu len %zu\n", linestart, linelen); - } + reverse_in_place(sv.s, sv.len); + size_t nw = fwrite(sv.s, 1, sv.len, stdout); + if (nw < sv.len) exit(1); + putchar('\n'); } -cleanup: - free(buffer); + file_lines_close(&fl); } int entry_omd(int argc, char **argv) { diff --git a/src/util/string_view.h b/src/util/string_view.h new file mode 100644 index 0000000..82f7b0c --- /dev/null +++ b/src/util/string_view.h @@ -0,0 +1,10 @@ +#pragma once + +#include + + +// A non-owned view on a (sub)string. +struct string_view { + char *s; + size_t len; +}; -- cgit v1.2.3-70-g09d2