summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <t.j.smeding@uu.nl>2024-07-13 22:16:10 +0200
committerTom Smeding <t.j.smeding@uu.nl>2024-07-13 22:16:14 +0200
commit8ebc1e27f7a19091515b8de742d486698dae4d6e (patch)
tree18051f4744d689f8f98587af661cfd39fd87c226
parent712530e52091520f8f2bf347dc9ecb4030d9c4ed (diff)
omd
-rw-r--r--Maakbestand4
-rw-r--r--src/omd.c145
-rw-r--r--src/util/debug.h11
-rw-r--r--src/util/error.c9
-rw-r--r--src/util/error.h5
-rw-r--r--src/util/versie.c7
-rw-r--r--src/util/versie.h6
-rwxr-xr-xversie.sh4
8 files changed, 190 insertions, 1 deletions
diff --git a/Maakbestand b/Maakbestand
index 98e0798..177df33 100644
--- a/Maakbestand
+++ b/Maakbestand
@@ -1,5 +1,7 @@
+VERSION := $(shell ./versie.sh)
+
CC := gcc
-CFLAGS := -Wall -Wextra -std=c2x -O2
+CFLAGS := -Wall -Wextra -std=c2x -O2 -D_GNU_SOURCE -DDRUKKEDOOS_VERSIE=\"$(VERSION)\"
LDFLAGS :=
OBJDIR := obj
diff --git a/src/omd.c b/src/omd.c
new file mode 100644
index 0000000..5568d27
--- /dev/null
+++ b/src/omd.c
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "util/versie.h"
+#include "util/error.h"
+#include "util/debug.h"
+
+static void usage(FILE *f) {
+ fprintf(f,
+ "Gebruik: omd [-hV] <bestand...>\n"
+ "\n"
+ " -h Toon deze hulptekst\n"
+ " -V Toon versienummer\n");
+}
+
+// Returns pointer to argument array containing the file names
+static char** parse_options(int argc, char **argv) {
+ int opt;
+ while ((opt = getopt(argc, argv, "hV")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage(stdout);
+ exit(0);
+
+ case 'V':
+ drukkedoos_print_versie(stdout, "omd");
+ exit(0);
+
+ case '?':
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ return argv + optind;
+}
+
+static void reverse_in_place(char *buf, size_t len) {
+ for (size_t i = 0, j = len - 1; i < len / 2; i++, j--) {
+ char c = buf[i];
+ buf[i] = buf[j];
+ buf[j] = c;
+ }
+}
+
+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;
+
+ 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");
+ }
+
+ 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);
+ }
+ }
+
+cleanup:
+ free(buffer);
+}
+
+int entry_omd(int argc, char **argv) {
+ char **args = parse_options(argc, argv);
+ if (*args == NULL) {
+ process(NULL, stdin);
+ } else {
+ while (*args != NULL) {
+ FILE *f = fopen(*args, "r");
+ if (!f) {
+ fprintf(stderr, "omd: Kon bestand '%s' niet openen\n", *args);
+ return 1;
+ }
+ process(*args, f);
+ fclose(f);
+ args++;
+ }
+ }
+ return 0;
+}
diff --git a/src/util/debug.h b/src/util/debug.h
new file mode 100644
index 0000000..9ee7c5f
--- /dev/null
+++ b/src/util/debug.h
@@ -0,0 +1,11 @@
+#pragma once
+
+
+// Uncomment this to enable DEBUG() statements.
+// #define ENABLE_DEBUG
+
+#ifdef ENABLE_DEBUG
+#define DEBUG(...) fprintf(stderr, ">> " __VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
diff --git a/src/util/error.c b/src/util/error.c
new file mode 100644
index 0000000..e7f1f02
--- /dev/null
+++ b/src/util/error.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "error.h"
+
+
+void print_error_nomem(const char *progname) {
+ fprintf(stderr, "%s: Kon geen geheugen reserveren!\n", progname);
+ exit(1);
+}
diff --git a/src/util/error.h b/src/util/error.h
new file mode 100644
index 0000000..99a9c77
--- /dev/null
+++ b/src/util/error.h
@@ -0,0 +1,5 @@
+#pragma once
+
+
+__attribute__((noreturn))
+void print_error_nomem(const char *progname);
diff --git a/src/util/versie.c b/src/util/versie.c
new file mode 100644
index 0000000..880823a
--- /dev/null
+++ b/src/util/versie.c
@@ -0,0 +1,7 @@
+#include "versie.h"
+
+void drukkedoos_print_versie(FILE *f, const char *progname) {
+ fprintf(f,
+ "%s, deel van drukkedoos versie %s\n",
+ progname, DRUKKEDOOS_VERSIE);
+}
diff --git a/src/util/versie.h b/src/util/versie.h
new file mode 100644
index 0000000..0f1dafb
--- /dev/null
+++ b/src/util/versie.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <stdio.h>
+
+
+void drukkedoos_print_versie(FILE *f, const char *progname);
diff --git a/versie.sh b/versie.sh
new file mode 100755
index 0000000..85aecf1
--- /dev/null
+++ b/versie.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+tag=$(git describe --tags 2>/dev/null)
+if [[ $? -eq 0 ]]; then echo "$tag"; exit; fi
+echo "vgit-$(git rev-parse --short HEAD)"