diff options
-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 |