diff options
author | Linnnus <[email protected]> | 2024-02-17 00:26:40 +0100 |
---|---|---|
committer | Linnnus <[email protected]> | 2024-02-17 00:47:08 +0100 |
commit | ad937750d754676f8e9e01ce2c1021ad1a80ee04 (patch) | |
tree | 470920cffe3d30f466ba837b68ac885a1a9f0aef | |
parent | dd4f820139f81ae5013824f24c5392b567562c41 (diff) |
feat: Add creole utility
This patch a) gives the different binaries' main() files more meaning
full names and b) adds the creole binary, which works like smu except
for my dialect of Creole (which should hopefully approach proper Creole
as this repo matures).
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | flake.nix | 10 | ||||
-rw-r--r-- | src/creole_test_main.c (renamed from src/creole-test.c) | 0 | ||||
-rw-r--r-- | src/creole_util_main.c | 108 | ||||
-rw-r--r-- | src/simplewiki_main.c (renamed from src/main.c) | 0 |
5 files changed, 126 insertions, 10 deletions
@@ -11,30 +11,36 @@ PREFIX ?= /usr/local all: build/simplewiki -install: build/simplewiki +install: build/simplewiki build/creole mkdir -p $(PREFIX)/bin mkdir -p $(PREFIX)/share/man/man1 cp -f build/simplewiki $(PREFIX)/bin + cp -f build/creole $(PREFIX)/bin gzip <doc/simplewiki.1 >$(PREFIX)/share/man/man1/simplewiki.1.gz uninstall: rm -f $(PREFIX)/bin/simplewiki + rm -f $(PREFIX)/bin/creole rm -f $(PREFIX)/share/man/man1/simplewiki.1.gz rmdir $(PREFIX)/bin >/dev/null 2>&1 || true rmdir $(PREFIX)/share/man/man1 >/dev/null 2>&1 || true -build/simplewiki: build/main.o build/die.o build/arena.o build/strutil.o build/creole.o - $(CC) $(CFLAGS) $(LDFLAGS) -o build/simplewiki $^ $(LDLIBS) +build/simplewiki: build/simplewiki_main.o build/die.o build/arena.o build/strutil.o build/creole.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) -build/creole-test: build/creole-test.o build/creole.o +build/creole_test: build/creole_test_main.o build/creole.o $(CC) $(CFLAGS) -o $@ $^ -build/creole-test.o: src/creole-test.c -build/main.o: src/main.c src/arena.h src/die.h src/strutil.h src/creole.h +build/creole: build/creole_util_main.o build/creole.o + $(CC) $(CFLAGS) -o $@ $^ + +build/creole_test_main.o: src/creole_test_main.c +build/simplewiki_main.o: src/simplewiki_main.c src/arena.h src/die.h src/strutil.h src/creole.h build/arena.o: src/arena.c src/arena.h build/die.o: src/die.c src/die.h build/strutil.o: src/strutil.c src/strutil.h src/arena.h build/creole.o: src/creole.c +build/creole_util_main.o: src/creole_util_main.c src/creole.h build/%.o: src/%.c | build/ $(CC) $(CFLAGS) -c -o $@ $< @@ -39,14 +39,16 @@ src = ./.; - nativeBuildInputs = with pkgs; [ pkg-config ]; - buildInputs = with pkgs; [ libgit2 ]; + buildPhase = '' + make build/creole_test + ''; installPhase = '' mkdir -p $out/bin - make build/creole-test - mv build/creole-test $out/bin + mv build/creole_test $out/bin ''; + + meta.mainProgram = "creole_test"; }; devShell = (pkgs.mkShell.override { inherit stdenv; }) { diff --git a/src/creole-test.c b/src/creole_test_main.c index 1157721..1157721 100644 --- a/src/creole-test.c +++ b/src/creole_test_main.c diff --git a/src/creole_util_main.c b/src/creole_util_main.c new file mode 100644 index 0000000..7d29c68 --- /dev/null +++ b/src/creole_util_main.c @@ -0,0 +1,108 @@ +#include "creole.h" + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#define CHUNK_SIZE 128 + +int read_file(const char *file_path, char **out_buffer, size_t *out_length) { + assert(out_buffer != NULL && *out_buffer == NULL); + assert(file_path != NULL); + + FILE *fp = fopen(file_path, "r"); + if (fp == NULL) { + return -1; + } + + char *buffer = NULL; + size_t allocated = 0; + size_t used = 0; + while (true) { + // Grow buffer, if needed. + if (used + CHUNK_SIZE > allocated) { + // Grow exponentially to guarantee O(log(n)) performance. + allocated = (allocated == 0) ? CHUNK_SIZE : allocated * 2; + + // Overflow check. Some ANSI C compilers may optimize this away, though. + if (allocated <= used) { + free(buffer); + fclose(fp); + errno = EOVERFLOW; + return -1; + } + + char *temp = realloc(buffer, allocated); + if (temp == NULL) { + int old_errno = errno; + free(buffer); // free() may not set errno + fclose(fp); // fclose() may set errno + errno = old_errno; + return -1; + } + buffer = temp; + } + + size_t nread = fread(buffer + used, 1, CHUNK_SIZE, fp); + if (nread == 0) { + // End-of-file or errnor has occured. + // FIXME: Should we be checking (nread < CHUNK_SIZE)? + // https://stackoverflow.com/a/39322170 + break; + } + used += nread; + } + + if (ferror(fp)) { + int old_errno = errno; + free(buffer); // free() may not set errno + fclose(fp); // fclose() may set errno + errno = old_errno; + return -1; + } + + // Reallocate to optimal size. + char *temp = realloc(buffer, used + 1); + if (temp == NULL) { + int old_errno = errno; + free(buffer); // free() may not set errno + fclose(fp); // fclose() may set errno + errno = old_errno; + return -1; + } + buffer = temp; + + // Null-terminate the buffer. Note that buffers may still contain \0, + // so strlen(buffer) == length may not be true. + buffer[used] = '\0'; + + // Return buffer. + *out_buffer = buffer; + if (out_length != NULL) { + *out_length = used; + } + fclose(fp); + return 0; +} + +int main(void) { + size_t buffer_length = 0; + char *buffer = NULL; + if (read_file("/dev/stdin", &buffer, &buffer_length) < 0) { + perror("Failed to read stdin"); + return EXIT_FAILURE; + } + + render_creole(stdout, buffer, buffer_length); + + // The lack of return value makes it painfully obvious that we aren't + // handling errors at all. This represents my half-hearted attempt to fix that. + if (ferror(stdout)) { + perror("Failed to write to stdout"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/main.c b/src/simplewiki_main.c index 5c04467..5c04467 100644 --- a/src/main.c +++ b/src/simplewiki_main.c |