commit d3d88235076197305a01e6460f43ea302b8809d1
parent efabee7b081c5b9805bc3046e1c27eb54f45bd50
Author: Robert Russell <robertrussell.72001@gmail.com>
Date: Wed, 1 Feb 2023 21:19:23 -0800
Tentatively add error handling module
This is so my libraries can have a consistent API for error handling, rather
than me doing it ad hoc every time, which is what I'm currently doing.
Functions that, e.g., return a nonnegative int on success should probably still
use negative integers to signal errors, because
if (f(x) < 0) {...}
is much nicer than
if (R_ERR(f(x))) {...}
Although I'd probably write
rerr = f(x);
if (R_ERR(rerr)) {...}
instead of the latter.
In the future it might be worth adding an error source in rcx for libc/posix
errors.
Diffstat:
4 files changed, 64 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -6,6 +6,7 @@ SRC =\
src/alloc.c\
src/bench.c\
src/bits.c\
+ src/error.c\
src/log.c\
src/str.c\
src/unicode.c\
@@ -22,6 +23,7 @@ librcx.a: $(SRC:.c=.o)
src/alloc.o: src/alloc.c inc/rcx/alloc.h inc/rcx/def.h inc/rcx/log.h inc/rcx/rcx.h inc/rcx/internal/util.h config.mk
src/bench.o: src/bench.c inc/rcx/bench.h inc/rcx/def.h inc/rcx/log.h inc/rcx/rcx.h config.mk
src/bits.o: src/bits.c inc/rcx/bits.h inc/rcx/def.h inc/rcx/rcx.h config.mk
+src/error.o: src/error.c inc/rcx/def.h inc/rcx/error.h inc/rcx/log.h inc/rcx/rcx.h config.mk
src/log.o: src/log.c inc/rcx/def.h inc/rcx/log.h inc/rcx/rcx.h config.mk
src/opt.o: src/opt.c inc/rcx/def.h inc/rcx/opt.h inc/rcx/rcx.h config.mk
src/str.o: src/str.c inc/rcx/alloc.h inc/rcx/def.h inc/rcx/log.h inc/rcx/rcx.h inc/rcx/str.h config.mk
diff --git a/inc/rcx/all.h b/inc/rcx/all.h
@@ -2,6 +2,7 @@
#include "rcx/alloc.h"
#include "rcx/bits.h"
#include "rcx/deque.h"
+#include "rcx/error.h"
#include "rcx/log.h"
#include "rcx/opt.h"
#include "rcx/rcx.h"
diff --git a/inc/rcx/error.h b/inc/rcx/error.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "rcx/def.h"
+
+#define R_ERR(e) ((e).code != 0)
+
+typedef struct RError RError;
+typedef struct RErrorSource RErrorSource;
+
+struct RErrorSource {
+ char *name;
+ /* Convert err to a string and write the result to buf, which must have
+ * length len >= 128. If the string does not fit in the given buffer,
+ * truncate in a source-specific manner (e.g., append an ellipsis). */
+ void (*to_string)(char *buf, usize len, RError err);
+ /* Free any data associated with err. This field can be NULL. */
+ void (*free)(RError err);
+};
+
+struct RError {
+ int code; /* 0 iff success */
+ RErrorSource *src;
+ union {
+ i64 i;
+ u64 u;
+ double f;
+ char *s;
+ void *p;
+ } u; /* Subject to source-specific semantics. */
+};
+
+void r_error_string(char *buf, usize len, RError err);
+void r_error_fatal(RError err);
+void r_error_drop(RError err);
diff --git a/src/error.c b/src/error.c
@@ -0,0 +1,27 @@
+#include <assert.h>
+
+#include "rcx/error.h"
+#include "rcx/log.h"
+#include "rcx/rcx.h"
+
+void
+r_error_string(char *buf, usize len, RError err) {
+ assert(len >= 128);
+ err.src->to_string(buf, len, err);
+}
+
+void
+r_error_fatal(RError err) {
+ if (R_ERR(err)) {
+ char buf[128];
+ r_error_string(buf, sizeof buf, err);
+ r_fatalf("%s", buf);
+ }
+}
+
+void
+r_error_drop(RError err) {
+ if (R_ERR(err)) {
+ err.src->free(err);
+ }
+}