jrk

my own c stdlib to keep myself sane
git clone git://git.jakekoroman.com/jrk
Log | Files | Refs

commit 8bb0a76de071706c0425755add0d05031ad7ce38
parent 2d3c87ffc63950c59fc2353898c30d0940e15894
Author: Jake Koroman <jake@jakekoroman.com>
Date:   Mon,  6 Oct 2025 14:54:48 -0400

add JRK_NO_EXIT_ON_DIE for better control of error handling.

Most failing functions now return bool and log their errors if
JRK_NO_EXIT_ON_DIE is defined. This will make integration with codebases
much easier. No longer will the program hard crash because of an
internal jrk.h error.

Also, you can now overwrite all die and log macros.

Diffstat:
Mjrk.h | 145++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 110 insertions(+), 35 deletions(-)

diff --git a/jrk.h b/jrk.h @@ -1,9 +1,16 @@ /* * TODO: - * - application shouldn't be dying on all failures, have a way - * to configure that ... just die without calling exit() * - look at at the jrk_sv_chop_delim_loop stuff. there must * must be a better way of handling things. + * + * NOTES: + * To avoid the application from crashing when calling the die macros + * you can define JRK_NO_EXIT_ON_DIE. This will convert all die macros + * to log calls. It is now up to the caller to handle the errors properly. + * Most functions that can fail will return a bool and will log themselves, + * which should make error handling easy. Be aware that some will return a + * negative int to indicate failure. These are normally functions that call + * into POSIX and return sizes as to be conformant to those POSIX syscalls. */ #include <stdbool.h> @@ -28,7 +35,7 @@ typedef float f32; typedef double f64; #define JRK_UNUSED(x) (void)x -#define JRK_ARRSIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#define JRK_ARRLENGTH(arr) (sizeof(arr) / sizeof(arr[0])) #define jrk_return_defer(value) \ do { result = value; goto defer; } while(0) @@ -81,10 +88,10 @@ u64 jrk_fd_size(i32); void jrk_fd_close(i32); i32 jrk_sb_appendf(jrk_StringBuilder*, const char*, ...); -void jrk_sb_fd_read_all(jrk_StringBuilder*, i32); -u64 jrk_sb_fd_write_all(jrk_StringBuilder*, i32); -void jrk_sb_write_file(jrk_StringBuilder*, char*); -void jrk_sb_read_entire_file(jrk_StringBuilder*, char*); +bool jrk_sb_fd_read_all(jrk_StringBuilder*, i32); +i64 jrk_sb_fd_write_all(jrk_StringBuilder*, i32); +bool jrk_sb_write_file(jrk_StringBuilder*, char*); +bool jrk_sb_read_entire_file(jrk_StringBuilder*, char*); void jrk_sb_append_buf_at(jrk_StringBuilder*, char*, u64, u64); jrk_StringView jrk_sv_from_parts(char*, u64); @@ -101,21 +108,71 @@ char *jrk_tmpstrings_pushf(char*, ...); #define jrk_sv_chop_delim_loop(sv, it, delim) \ for (jrk_StringView it = jrk_sv_chop_delim(sv, delim); it.count != 0; it = jrk_sv_chop_delim(sv, delim)) -#define jrk_die(x) \ - do { \ - fprintf(stderr, "%s:%d: error: "x" \n", __FILE__, __LINE__); \ - exit(69); \ - } while(0) +#ifndef jrk_die + #define jrk_die(x) \ + do { \ + fprintf(stderr, "%s:%d: error: "x" \n", __FILE__, __LINE__); \ + exit(69); \ + } while (0) +#endif -#define jrk_diev(x, ...) \ - do { \ - fprintf(stderr, "%s:%d: error: "x"\n", __FILE__, __LINE__, __VA_ARGS__); \ - exit(69); \ - } while(0) +#ifndef jrk_diev + #define jrk_diev(x, ...) \ + do { \ + fprintf(stderr, "%s:%d: error: "x"\n", __FILE__, __LINE__, __VA_ARGS__); \ + exit(69); \ + } while (0) +#endif #define jrk_edie(x) jrk_diev(x": %s", strerror(errno)) #define jrk_ediev(x, ...) jrk_diev(x": %s", __VA_ARGS__, strerror(errno)) +#ifndef jrk_log + #define jrk_log(x) \ + do { \ + fprintf(stderr, "info: "x"\n"); \ + } while (0) +#endif + +#ifndef jrk_logv + #define jrk_logv(x, ...) \ + do { \ + fprintf(stderr, "info: "x"\n", __VA_ARGS__); \ + } while (0) +#endif + +#ifndef jrk_elog + #define jrk_elog(x) \ + do { \ + fprintf(stderr, "error: "x"\n"); \ + } while (0) +#endif + +#ifndef jrk_elogv + #define jrk_elogv(x, ...) \ + do { \ + fprintf(stderr, "error: "x"\n", __VA_ARGS__); \ + } while (0) +#endif + +#define jrk_eelog(x) jrk_elog(x": %s", strerror(errno)) +#define jrk_eelogv(x, ...) jrk_elogv(x": %s", __VA_ARGS__, strerror(errno)) + +#define JRK_NO_EXIT_ON_DIE +#ifdef JRK_NO_EXIT_ON_DIE + #undef jrk_edie + #define jrk_edie jrk_eelog + + #undef jrk_ediev + #define jrk_ediev jrk_eelogv + + #undef jrk_die + #define jrk_die jrk_elog + + #undef jrk_diev + #define jrk_diev jrk_elogv +#endif + /* NOTE: no shortname as 'assert' is just too generic */ #define jrk_assert(c, msg) do { if (!(c)) jrk_die("jrk_assert: "msg); } while(0) #define jrk_assertv(c, msg, ...) do { if (!(c)) jrk_diev("jrk_assert: "msg, __VA_ARGS__); } while(0) @@ -206,11 +263,11 @@ char *jrk_tmpstrings_pushf(char*, ...); #define jrk_arena_sb_append_null(arena, sb) jrk_arena_da_append((arena), (sb), '\0') -#define jrk_arena_sb_append_cstr(arena, sb, cstr) \ - do { \ - const char *s = (cstr); \ - i64 n = strlen((cstr)); \ - jrk_arena_da_append_many((arena), (sb), s, n); \ +#define jrk_arena_sb_append_cstr(arena, sb, cstr) \ + do { \ + const char *s = (cstr); \ + i64 n = strlen((cstr)); \ + jrk_arena_da_append_many((arena), (sb), s, n); \ } while (0) #define jrk_sb_append_cstr(sb, cstr) \ @@ -227,7 +284,7 @@ char *jrk_tmpstrings_pushf(char*, ...); #ifdef JRK_SHORTNAMES #define UNUSED JRK_UNUSED - #define ARRSIZE JRK_ARRSIZE + #define ARRLENGTH JRK_ARRLENGTH #define KILOBYTES JRK_KILOBYTES #define MEGABYTES JRK_MEGABYTES #define GIGABYTES JRK_GIGABYTES @@ -238,6 +295,8 @@ char *jrk_tmpstrings_pushf(char*, ...); #define diev jrk_diev #define edie jrk_edie #define ediev jrk_ediev + #define log jrk_log + #define logv jrk_logv #define Arena jrk_Arena #define StringBuilder jrk_StringBuilder @@ -380,6 +439,7 @@ jrk_arena_push(jrk_Arena *arena, u64 n) jrk_assertv(arena->offset + n <= arena->capacity, "jrk_arena_push(%p, %ld): arena push requires %ld bytes but has a capacity of %ld bytes", (void *) arena, n, arena->offset + n, arena->capacity); + void *result = &arena->data[arena->offset]; arena->prev_offset = arena->offset; arena->offset += n; @@ -491,7 +551,6 @@ jrk_sb_appendf(jrk_StringBuilder *sb, const char *fmt, ...) return result; } - void jrk_arena_sb_append_buf_at(jrk_Arena *arena, jrk_StringBuilder *sb, char *buf, u64 size, u64 idx) { @@ -555,24 +614,29 @@ jrk_fd_size(i32 fd) return statbuf.st_size; } -void +bool jrk_sb_fd_read_all(jrk_StringBuilder *sb, i32 fd) { u64 sz = jrk_fd_size(fd); jrk_da_reserve(sb, sz); - if (read(fd, sb->items, sz) < 0) + if (read(fd, sb->items, sz) < 0) { jrk_ediev("jrk_sb_fd_read_all(%p, %d)", (void *)sb, fd); + return false; + } sb->count = sz; + return true; } -u64 +i64 jrk_sb_fd_write_all(jrk_StringBuilder *sb, i32 fd) { i64 result; result = write(fd, (void *) sb->items, sb->count); - if (result < 0) + if (result < 0) { jrk_ediev("jrk_sb_fd_write_all(%p, %d)", (void *)sb, fd); + return -1; + } return result; } @@ -583,20 +647,25 @@ jrk_fd_close(i32 fd) close(fd); } -void +bool jrk_sb_write_file(jrk_StringBuilder *sb, char *path) { i32 fd = jrk_fd_open_write(path); - jrk_sb_fd_write_all(sb, fd); + if (fd < 0) return false; + if (jrk_sb_fd_write_all(sb, fd) < 0) return false; jrk_fd_close(fd); + return true; } -void +bool jrk_sb_read_entire_file(jrk_StringBuilder *sb, char *path) { i32 fd = jrk_fd_open_read(path); - jrk_sb_fd_read_all(sb, fd); + if (fd < 0) return false; + if (!jrk_sb_fd_read_all(sb, fd)) return false; jrk_fd_close(fd); + + return true; } i32 @@ -604,8 +673,10 @@ jrk_fd_open_read(char *path) { i32 result = open(path, O_RDONLY); - if (result < 0) + if (result < 0) { jrk_ediev("jrk_fd_open_read(%s)", path); + return -1; + } return result; } @@ -617,8 +688,10 @@ jrk_fd_open_write(char *path) O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (result < 0) + if (result < 0) { jrk_ediev("jrk_fd_open_write(%s)", path); + return -1; + } return result; } @@ -630,8 +703,10 @@ jrk_fd_open_write_append(char *path) O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (result < 0) + if (result < 0) { jrk_ediev("jrk_fd_open_write_append(%s)", path); + return -1; + } return result; }