From 8ebc1e27f7a19091515b8de742d486698dae4d6e Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sat, 13 Jul 2024 22:16:10 +0200 Subject: omd --- Maakbestand | 4 +- src/omd.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util/debug.h | 11 +++++ src/util/error.c | 9 ++++ src/util/error.h | 5 ++ src/util/versie.c | 7 +++ src/util/versie.h | 6 +++ versie.sh | 4 ++ 8 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/omd.c create mode 100644 src/util/debug.h create mode 100644 src/util/error.c create mode 100644 src/util/error.h create mode 100644 src/util/versie.c create mode 100644 src/util/versie.h create mode 100755 versie.sh 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 +#include +#include +#include +#include +#include "util/versie.h" +#include "util/error.h" +#include "util/debug.h" + +static void usage(FILE *f) { + fprintf(f, + "Gebruik: omd [-hV] \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 +#include +#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 + + +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)" -- cgit v1.2.3-70-g09d2