From 59b45432c3e804aac60987a8e841888b5132e5dd Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Thu, 12 Feb 2026 21:30:26 +0100 Subject: [PATCH 1/4] also help on flags --- cli.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli.c b/cli.c index ecc7355..c5a33a0 100644 --- a/cli.c +++ b/cli.c @@ -26,6 +26,11 @@ bool cli_command(args_t *args, const char *command_name) { } bool cli_bool(args_t args, const char *flag_name) { + if (args.help) { + cli_print_indentation(args); + printf("[ flg ] %s\n", flag_name); + return false; + } for ( int i = 0; i < args.count; i++ ) { if (strcmp(args.values[i], flag_name) == 0) { return true; From d2b9b4d607c307bdfa2d99b5d4ec672adf143a94 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Thu, 12 Feb 2026 21:38:23 +0100 Subject: [PATCH 2/4] remove cringe capitalization --- cig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cig.h b/cig.h index 8673b39..e1a157d 100644 --- a/cig.h +++ b/cig.h @@ -130,7 +130,7 @@ allocator_t allocator_from_arena(arena_allocator_t *this); // - Use borrow_allocator as backing for testing/debugging // - Use forever_allocator as backing for if the lifetime of the allocated // items is the entire program duration. -// - DO NOT use another arena_allocator as backing +// - do not use another arena_allocator as backing #define arena_allocator_create(BACKING_ALLOCATOR, INITIAL_CAPACITY) \ allocator_from_arena(&arena_allocator_value(BACKING_ALLOCATOR, INITIAL_CAPACITY)) From 3ae94863fac8880b4ef50d16c1b892d3c5bacd25 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Tue, 19 May 2026 20:55:26 +0200 Subject: [PATCH 3/4] update readme --- README.md | 153 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 122 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 6d212b7..19ca98e 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,129 @@ -# ISSUES -When a memory bug is detected in one of the treads it won't report a non-zero -exit code while running the tests. +# what is the goal? +- A standard library inspired by languages like zig, odin and rust. +- Single header, multiple source files, and no build step. -# A collection of libraries inspired by zig, and other stuff. +# current and coming features -I like zig, but I really like writing C. I am starting with implementing -different allocator types. I don't know how the other parts of the library will -fit in, but they will certainly use the allocators. +- [x] allocators +- [x] dynamic arrays +- [x] simple cli arg parsing +- [-] functions to build parsers +- [-] string builder +- [ ] hashmap +- [ ] easing functions +- [ ] simple gui engine -I want a series of standard collection types with nice interfaces. ArrayLists, -LinkedLists, value-based HashMaps, reference-based HashMaps. +# example -I also want to provide template header files that use the X-macro pattern so -that users can easily make tagged unions, option types, automatic bit-flags, -and maybe even an ECS inspierd struct filled with optional fields. +## allocators and dynamic arrays +```c +#include +#include -I probably want a ui library. It will rely on a graphical drawing interface. It -will be a little different though. It is inspired from my experience with using -raygui. instead of making some sort of layout engine, I will provide a set of -useful functions to manipulate rectangles. I think this produces programs that -are easier to reason about, while still reducing needless duplication of code. -The workflow relies heavily on function-static variables, which are a c -superpower in this scenario. You will essentially start with some 'fixed' -rectangle (probably derived from the window size) and then perform splitting -operations on that rectangle. Even a dynamic split that creates a draggable -border, updating the local function-static variable (which is a normalized -float) to let you resize sections. Also, the interface will be like immediate -mode guis, with one exception from the way raygui works. The drawing operations -are deferred, and called in the reverse order. This way the first gui function -that captrues input can signal to the other function that input is captured, -and the drawing of the gui elements can reflect the priority of the gui -functions. Overlapping gui elements in raygui is the main painpoint imo. +#define CIG_IMPL +#include "cig/cig.h" -# TODO +int main(void) { + + with_borrow(allocator) { + // initial capacity is optional + int *ns = make_arr(int, allocator, .initial_capacity=10); + + for (int i = 0; i < 100; i++) { + // the array grows as the capacity is reached + arr_append(ns, i); + } + + for (int i = 0; i < 10; i++) { + int last = arr_pop(ns); + printf("last value was %d\n", last); + } + + for (int i = 0; i < arr_len(ns); i++) { + printf("value of ns[%d] is %d\n", i, ns[i]); + } + + // you can break out of a with_borrow scope + break; + + printf("this is never printed\n"); + + // WARNING: returning from within a with_borrow + // scope will cause a memory leak + return; + } + // everything allocated by the borrow allocator is + // freed here, and the borrow allocator is also out of + // scope. + + + // you can also make the borrow allocator like this: + allocator_t backing = borrow_allocator_create(); + + // this arena allocator is slightly clever. You assign + // an initial size of the memory block, but uses a + // backing arena to allow you to allocate more than + // that. Whenever allocator_reset is called it figures + // out how much was allocated outside the big chunk of + // memory, frees everything and allocates a bigger + // block. So it's size will move towards what you + // happen to use in the game loop. It assumes that it + // is the owner of the given backing allocator, and it + // should probably be a borrow_allocator. + allocator_t arena_allocator = arena_allocator_create(backing, 100 * MB); + + // Imagine a game loop + while (true) { + // every time this resets, assuming the backing + // memory chunk doesn't need to grow, this + // operation is very fast. + allocator_reset(arena_allocator); + + float *fs = make_arr(float, arena_allocator); + arr_append(fs, 1.1); + arr_append(fs, 1.2); + arr_append(fs, 1.3); + + break; + } + + allocator_reset(backing); + return 0; +} +``` + +## cli +```c +#include +#include +#include + +#define CIG_IMPL +#include "cig/cig.h" + +int main(int argc, const char **argv) { + args_t args = cli_make_args(argc, argv); + + if (cli_command(&args, "say-foo")) { + printf("foo\n"); + } else + if (cli_command(&args, "say-bar")) { + printf("bar\n"); + } else + if (cli_command(&args), "greet") { + bool do_nothing = cli_bool(args, "--do-nothing"); + const char *name = cli_req_str(args, "--name"); + if (args.help) exit(0); + + if (do_nothing) { + return; + } + + printf("Hello %s!\n", name); + } else { + printf("use the -h or --help flag to see available commands\n"); + } +} + +``` -If there is an allocation error it does not actually cause a crash... -FIX!!! From e998334d698f3dc38c12c8d7fd6daed007bb20dc Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Wed, 20 May 2026 19:05:41 +0200 Subject: [PATCH 4/4] copy justfile over from feature/hashmap --- justfile | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 justfile diff --git a/justfile b/justfile new file mode 100644 index 0000000..28be195 --- /dev/null +++ b/justfile @@ -0,0 +1,60 @@ +CC := "zig cc" +CFLAGS := "-pedantic -Wall -Wextra -Wno-override-init -O0 -g -fno-omit-frame-pointer -fno-inline" +LDFLAGS := if os() == "macos" { + "$(pkg-config --libs --cflags criterion)" +} else { + "-lcriterion" +} + +TMP := "/tmp" + +TESTBIN := TMP/"all_tests" + +set shell := ["bash", "-cu"] + + +FOOBAR := "foobar" +FOOBAR_SOURCE := FOOBAR+".c" +FOOBAR_BIN := TMP/FOOBAR +FOOBAR_EXPANDED := TMP/FOOBAR+"-expanded.c" + +build_foobar2: + {{CC}} {{FOOBAR_SOURCE}} {{CFLAGS}} -o foobar2 + +run_foobar: build_foobar + {{FOOBAR_BIN}} + +build_foobar: foobar_expanded + {{CC}} {{FOOBAR_EXPANDED}} {{CFLAGS}} -o {{FOOBAR_BIN}} + echo "{{FOOBAR_BIN}}" + +foobar_expanded: + {{CC}} -P -E {{FOOBAR_SOURCE}} -o {{FOOBAR_EXPANDED}} + clang-format -i {{FOOBAR_EXPANDED}} + +clean_foobar: + rm {{FOOBAR_BIN}} + +[default] +test: build + {{TESTBIN}} + +test_memcheck: build + valgrind --leak-check=full \ + --show-leak-kinds=all \ + --trace-children=yes \ + --error-exitcode=1 \ + {{TESTBIN}} + +build: + find . -type f -name 'test*.c' | xargs -r {{CC}} {{CFLAGS}} {{LDFLAGS}} _allocator_impl.c -o {{TESTBIN}} + +DEPENDENCY_HEADERS := if os() == "macos" { + "$(pkg-config --cflags-only-I criterion | sed 's/-I//g')" +} else { + "TODO" +} + +tag: + echo "Making tags from project and headers in {{DEPENDENCY_HEADERS}}" + ctags --languages=c --langmap=c:.c.h -R {{DEPENDENCY_HEADERS}} .