summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom@tomsmeding.com>2024-07-14 10:25:56 +0200
committerTom Smeding <tom@tomsmeding.com>2024-07-14 10:25:56 +0200
commit1168c8ab426105bcd1b65aaf1f62c7a6144b0ae8 (patch)
treedd7d13be9988d234d9b3284b4bc88a9dd7f74d46
parent723828d1d473b70f77fa7878f855c2956ddcacc4 (diff)
file_lines module, herschrijf omd ermee
-rw-r--r--Maakbestand4
-rw-r--r--src/io/lines.c92
-rw-r--r--src/io/lines.h25
-rw-r--r--src/omd.c82
-rw-r--r--src/util/string_view.h10
5 files changed, 140 insertions, 73 deletions
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 <stdlib.h>
+#include <string.h>
+
+#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 <stdio.h>
+#include <stdbool.h>
+
+#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 <stdlib.h>
#include <string.h>
#include <unistd.h>
+#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 <stddef.h>
+
+
+// A non-owned view on a (sub)string.
+struct string_view {
+ char *s;
+ size_t len;
+};