changeset 547:c7664b679a95

misc: remove error codes for now
author David Demelier <markand@malikania.fr>
date Mon, 06 Mar 2023 20:03:00 +0100
parents b7da58230a66
children 75944708c55c
files examples/example-action/example-action.c examples/example-animation/example-animation.c examples/example-audio/example-audio.c examples/example-cursor/example-cursor.c examples/example-debug/example-debug.c examples/example-drawable/example-drawable.c examples/example-font/example-font.c examples/example-gridmenu/example-gridmenu.c examples/example-label/example-label.c examples/example-message/example-message.c examples/example-notify/example-notify.c examples/example-sprite/example-sprite.c examples/example-trace/example-trace.c examples/example-ui/example-ui.c libmlk-core/mlk/core/action-script.c libmlk-core/mlk/core/action-stack.c libmlk-core/mlk/core/drawable-stack.c libmlk-core/mlk/core/err.c libmlk-core/mlk/core/err.h libmlk-core/mlk/core/font.c libmlk-core/mlk/core/game.c libmlk-core/mlk/core/image.c libmlk-core/mlk/core/panic.c libmlk-core/mlk/core/panic.h libmlk-core/mlk/core/sys.c libmlk-core/mlk/core/texture.c libmlk-core/mlk/core/window.c libmlk-example/mlk/example/registry.c libmlk-rpg/mlk/rpg/map-file.c libmlk-rpg/mlk/rpg/message.c libmlk-rpg/mlk/rpg/save.c libmlk-rpg/mlk/rpg/tileset-file.c libmlk-ui/mlk/ui/gridmenu.c libmlk-ui/mlk/ui/label.c libmlk-ui/mlk/ui/ui.c tests/test-action-script.c tests/test-action.c tests/test-drawable.c
diffstat 38 files changed, 227 insertions(+), 200 deletions(-) [+]
line wrap: on
line diff
--- a/examples/example-action/example-action.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-action/example-action.c	Mon Mar 06 20:03:00 2023 +0100
@@ -209,7 +209,6 @@
 static void
 script_init(struct dialog *msgs, size_t msgsz)
 {
-	int err;
 	struct mlk_action *action;
 
 	mlk_action_script_init(&script);
@@ -217,8 +216,8 @@
 	for (size_t i = 0; i < msgsz; ++i) {
 		action = dialog_init(&msgs[i]);
 
-		if ((err = mlk_action_script_append(&script, action)) < 0)
-			mlk_panicf("%s", mlk_err_string(err));
+		if (mlk_action_script_append(&script, action) < 0)
+			mlk_panic();
 	}
 
 	mlk_action_script_start(&script);
@@ -275,10 +274,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-action")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-action") < 0)
+		mlk_panic();
 
 	chests_init();
 	label_init();
--- a/examples/example-animation/example-animation.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-animation/example-animation.c	Mon Mar 06 20:03:00 2023 +0100
@@ -50,10 +50,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-animation")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-animation") < 0)
+		mlk_panic();
 }
 
 static void
--- a/examples/example-audio/example-audio.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-audio/example-audio.c	Mon Mar 06 20:03:00 2023 +0100
@@ -52,10 +52,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-audio")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-audio") < 0)
+		mlk_panic();
 
 	sound = &mlk_registry_sounds[MLK_REGISTRY_SOUND_FIRE];
 	music = &mlk_registry_music[MLK_REGISTRY_MUSIC_ROMANCE];
@@ -72,12 +70,10 @@
 {
 	(void)st;
 
-	int err;
-
 	switch (ev->type) {
 	case MLK_EVENT_CLICKDOWN:
-		if ((err = mlk_sound_play(sound)) < 0)
-			mlk_panic(err);
+		if (mlk_sound_play(sound) < 0)
+			mlk_panic();
 		break;
 	case MLK_EVENT_KEYDOWN:
 		switch (ev->key.key) {
--- a/examples/example-cursor/example-cursor.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-cursor/example-cursor.c	Mon Mar 06 20:03:00 2023 +0100
@@ -47,10 +47,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-cursor")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-cursor") < 0)
+		mlk_panic();
 }
 
 static void
--- a/examples/example-debug/example-debug.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-debug/example-debug.c	Mon Mar 06 20:03:00 2023 +0100
@@ -37,10 +37,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-debug")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-debug") < 0)
+		mlk_panic();
 
 	mlk_debug_options.enable = 1;
 }
--- a/examples/example-drawable/example-drawable.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-drawable/example-drawable.c	Mon Mar 06 20:03:00 2023 +0100
@@ -72,10 +72,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-drawable")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-drawable") < 0)
+		mlk_panic();
 
 	explosion_tex = &mlk_registry_textures[MLK_REGISTRY_TEXTURE_EXPLOSION];
 	explosion_sprite = &mlk_registry_sprites[MLK_REGISTRY_TEXTURE_EXPLOSION];
--- a/examples/example-font/example-font.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-font/example-font.c	Mon Mar 06 20:03:00 2023 +0100
@@ -51,10 +51,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-font")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-font") < 0)
+		mlk_panic();
 }
 
 static void
@@ -101,13 +99,12 @@
 
 	struct mlk_font *font = mlk_ui_fonts[MLK_UI_FONT_INTERFACE];
 	struct mlk_texture tex;
-	int err;
 
 	mlk_painter_set_color(MLK_EXAMPLE_BG);
 	mlk_painter_clear();
 
-	if ((err = mlk_font_render(font, &tex, "Example of text. Use <Left>/<Right> to change color and <Space> to toggle antialiasing.", colors[ci])) < 0)
-		mlk_panic(err);
+	if (mlk_font_render(font, &tex, "Example of text. Use <Left>/<Right> to change color and <Space> to toggle antialiasing.", colors[ci]) < 0)
+		mlk_panic();
 
 	mlk_texture_draw(&tex, 10, 10);
 	mlk_painter_present();
--- a/examples/example-gridmenu/example-gridmenu.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-gridmenu/example-gridmenu.c	Mon Mar 06 20:03:00 2023 +0100
@@ -95,10 +95,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-gridmenu")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-gridmenu") < 0)
+		mlk_panic();
 
 	menu_style = mlk_gridmenu_style;
 	mlk_glower_init(&menu_glower);
--- a/examples/example-label/example-label.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-label/example-label.c	Mon Mar 06 20:03:00 2023 +0100
@@ -143,11 +143,10 @@
 init(void)
 {
 	unsigned int w, h;
-	int err;
 	struct mlk_label *l;
 
-	if ((err = mlk_example_init("example-label")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-label") < 0)
+		mlk_panic();
 
 	for (size_t i = 0; i < MLK_UTIL_SIZE(table); ++i) {
 		l = &table[i].label;
--- a/examples/example-message/example-message.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-message/example-message.c	Mon Mar 06 20:03:00 2023 +0100
@@ -44,10 +44,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-message")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-message") < 0)
+		mlk_panic();
 }
 
 static void
--- a/examples/example-notify/example-notify.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-notify/example-notify.c	Mon Mar 06 20:03:00 2023 +0100
@@ -46,10 +46,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-notify")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-notify") < 0)
+		mlk_panic();
 
 	icon = &mlk_registry_textures[MLK_REGISTRY_TEXTURE_SWORD];
 }
--- a/examples/example-sprite/example-sprite.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-sprite/example-sprite.c	Mon Mar 06 20:03:00 2023 +0100
@@ -62,10 +62,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-sprite")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-sprite") < 0)
+		mlk_panic();
 
 	sprite = &mlk_registry_sprites[MLK_REGISTRY_TEXTURE_PEOPLE];
 }
--- a/examples/example-trace/example-trace.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-trace/example-trace.c	Mon Mar 06 20:03:00 2023 +0100
@@ -36,10 +36,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-trace")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-trace") < 0)
+		mlk_panic();
 
 	mlk_trace_handler = mlk_trace_hud_handler;
 }
--- a/examples/example-ui/example-ui.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/examples/example-ui/example-ui.c	Mon Mar 06 20:03:00 2023 +0100
@@ -323,10 +323,8 @@
 static void
 init(void)
 {
-	int err;
-
-	if ((err = mlk_example_init("example-ui")) < 0)
-		mlk_panicf("mlk_example_init: %s", mlk_err_string(err));
+	if (mlk_example_init("example-ui") < 0)
+		mlk_panic();
 
 	button_glower_init(&ui.buttons.download_glower, &ui.buttons.download);
 }
--- a/libmlk-core/mlk/core/action-script.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/action-script.c	Mon Mar 06 20:03:00 2023 +0100
@@ -49,7 +49,7 @@
 	assert(a);
 
 	if (s->length >= s->actionsz)
-		return MLK_ERR_NO_MEM;
+		return mlk_errf("no space in action script");
 
 	s->actions[s->length++] = a;
 
--- a/libmlk-core/mlk/core/action-stack.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/action-stack.c	Mon Mar 06 20:03:00 2023 +0100
@@ -48,7 +48,7 @@
 		}
 	}
 
-	return MLK_ERR_NO_MEM;
+	return mlk_errf("no space in action stack");
 }
 
 int
--- a/libmlk-core/mlk/core/drawable-stack.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/drawable-stack.c	Mon Mar 06 20:03:00 2023 +0100
@@ -48,7 +48,7 @@
 		}
 	}
 
-	return MLK_ERR_NO_MEM;
+	return mlk_errf("no space in drawable stack");
 }
 
 int
--- a/libmlk-core/mlk/core/err.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/err.c	Mon Mar 06 20:03:00 2023 +0100
@@ -16,23 +16,52 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <SDL.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <mlk/util/util.h>
 
 #include "err.h"
 
-const char *
-mlk_err_string(int e)
+#define ERR_MAX         128
+#define DEFAULT_ERR     "no error"
+
+static _Thread_local char err[ERR_MAX] = DEFAULT_ERR;
+
+int
+mlk_errf(const char *fmt, ...)
 {
-	switch (e) {
-	case MLK_ERR_SDL:
-		return SDL_GetError();
-	case MLK_ERR_NO_MEM:
-		return "out of memory";
-	case MLK_ERR_NO_SUPPORT:
-		return "operation not supported";
-	case MLK_ERR_FORMAT:
-		return "invalid format or corrupt file";
-	default:
-		return "no error";
-	}
+	assert(fmt);
+
+	va_list ap;
+
+	va_start(ap, fmt);
+	mlk_errva(fmt, ap);
+	va_end(ap);
+
+	return -1;
 }
+
+int
+mlk_errva(const char *fmt, va_list ap)
+{
+	assert(fmt);
+
+	int ret;
+
+	/* Don't keep an empty string... */
+	ret = vsnprintf(err, sizeof (err), fmt, ap);
+
+	if (ret < 0)
+		mlk_util_strlcpy(err, "unknown error", sizeof (err));
+	else if (ret == 0)
+		mlk_util_strlcpy(err, DEFAULT_ERR, sizeof (err));
+
+	return -1;
+}
+
+const char *
+mlk_err(void)
+{
+	return err;
+}
--- a/libmlk-core/mlk/core/err.h	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/err.h	Mon Mar 06 20:03:00 2023 +0100
@@ -19,16 +19,45 @@
 #ifndef MLK_ERR_H
 #define MLK_ERR_H
 
-#define MLK_ERR_NONE            0
-#define MLK_ERR_NO_MEM         -1
-#define MLK_ERR_NO_SUPPORT     -2
-#define MLK_ERR_FORMAT         -3
-#define MLK_ERR_SDL            -4
-#define MLK_ERR_ERRNO          -5
-#define MLK_ERR_OPENAL         -6
-#define MLK_ERR_DATABASE       -7
+#include <stdarg.h>
+
+/**
+ * \file mlk/core/err.h
+ * \brief Error handling
+ *
+ * Because the Molko's Adventure framework use many different external
+ * libraries, it is not an easy task to transform all external error codes to
+ * a general one.
+ *
+ * Instead, the library stores a thread-local [errno]-like API that the user
+ * can access as a string. When a function fails, the user should retrieve the
+ * error as early as possible.
+ *
+ * [errno]: https://en.cppreference.com/w/c/error/errno
+ */
+
+/**
+ * Set the error using printf format string.
+ *
+ * \pre fmt != NULL
+ * \param fmt the format string
+ * \return -1 for convenience
+ */
+int
+mlk_errf(const char *fmt, ...);
+
+/**
+ * Similar to ::mlk_errf but using a `va_list` instead.
+ *
+ * \pre fmt != NULL
+ * \param fmt the printf format string
+ * \param ap the variadic handle
+ * \return -1 for convenience
+ */
+int
+mlk_errva(const char *fmt, va_list ap);
 
 const char *
-mlk_err_string(int e);
+mlk_err(void);
 
 #endif /* !MLK_ERROR_H */
--- a/libmlk-core/mlk/core/font.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/font.c	Mon Mar 06 20:03:00 2023 +0100
@@ -34,7 +34,7 @@
 	assert(path);
 
 	if (!(font->handle = TTF_OpenFont(path, size)))
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -52,7 +52,7 @@
 
 	if (!(ops = SDL_RWFromConstMem(buffer, buflen)) ||
 	   (!(font->handle = TTF_OpenFontRW(ops, 1, size))))
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -88,7 +88,7 @@
 	}
 
 	if (!(surface = func(font->handle, text, fg)))
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return mlk__texture_from_surface(tex, surface);
 }
@@ -113,7 +113,7 @@
 		*h = 0;
 
 	if (TTF_SizeUTF8(font->handle, text, (int *)w, (int *)h) != 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
--- a/libmlk-core/mlk/core/game.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/game.c	Mon Mar 06 20:03:00 2023 +0100
@@ -53,7 +53,7 @@
 	}
 
 	if (mlk_game.state == &mlk_game.states[mlk_game.statesz - 1])
-		return MLK_ERR_NO_MEM;
+		return mlk_errf("no space in game states stack");
 
 	mlk_state_suspend(*mlk_game.state);
 	mlk_state_start(*(++mlk_game.state) = state);
--- a/libmlk-core/mlk/core/image.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/image.c	Mon Mar 06 20:03:00 2023 +0100
@@ -44,7 +44,7 @@
 	assert(path);
 
 	if (!(tex->handle = IMG_LoadTexture(MLK__RENDERER(), path)))
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	dimensions(tex);
 
@@ -59,7 +59,7 @@
 	SDL_RWops *ops = SDL_RWFromConstMem(buffer, size);
 
 	if (!ops || !(tex->handle = IMG_LoadTexture_RW(MLK__RENDERER(), ops, 1)))
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	dimensions(tex);
 
--- a/libmlk-core/mlk/core/panic.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/panic.c	Mon Mar 06 20:03:00 2023 +0100
@@ -78,7 +78,7 @@
 }
 
 void
-mlk_panic(int err)
+mlk_panic(void)
 {
-	mlk_panicf("%s", mlk_err_string(err));
+	mlk_panicf("%s", mlk_err());
 }
--- a/libmlk-core/mlk/core/panic.h	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/panic.h	Mon Mar 06 20:03:00 2023 +0100
@@ -36,7 +36,7 @@
 mlk_panicva(const char *, va_list);
 
 void
-mlk_panic(int err);
+mlk_panic(void);
 
 #if defined(__cplusplus)
 }
--- a/libmlk-core/mlk/core/sys.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/sys.c	Mon Mar 06 20:03:00 2023 +0100
@@ -98,10 +98,10 @@
 #ifdef _WIN32
 	/* TODO: add error using the convenient FormatMessage function. */
 	if (!CreateDirectoryA(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
-		return MLK_ERR_ERRNO;
+		return -1;
 #else
 	if (mkdir(path, 0755) < 0 && errno != EEXIST)
-		return MLK_ERR_ERRNO;
+		return mlk_errf("%s", strerror(errno));
 #endif
 
 	return 0;
@@ -156,16 +156,17 @@
 	return vio->offset;
 }
 
-static inline int
-sndfile_to_err(int e)
+static void
+audio_finish(void)
 {
-	switch (e) {
-	case SF_ERR_UNRECOGNISED_FORMAT:
-	case SF_ERR_MALFORMED_FILE:
-	case SF_ERR_UNSUPPORTED_ENCODING:
-		return MLK_ERR_FORMAT;
-	default:
-		return MLK_ERR_NO_MEM;
+	if (mlk__audio_ctx) {
+		alcMakeContextCurrent(NULL);
+		alcDestroyContext(mlk__audio_ctx);
+		mlk__audio_ctx = NULL;
+	}
+	if (mlk__audio_dev) {
+		alcCloseDevice(mlk__audio_dev);
+		mlk__audio_dev = NULL;
 	}
 }
 
@@ -184,11 +185,11 @@
 
 	/* SDL2. */
 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 	if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 	if (TTF_Init() < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	/* OpenAL. */
 #if defined(MLK_OS_WINDOW)
@@ -197,14 +198,25 @@
 	putenv("ALSOFT_LOGLEVEL=0");
 #endif
 
-	if (!(mlk__audio_dev = alcOpenDevice(NULL)))
-		return MLK_ERR_OPENAL;
-	if (!(mlk__audio_ctx = alcCreateContext(mlk__audio_dev, NULL)))
-		return MLK_ERR_OPENAL;
-
-	alcMakeContextCurrent(mlk__audio_ctx);
+	if (!(mlk__audio_dev = alcOpenDevice(NULL))) {
+		mlk_errf("unable to open audio device");
+		goto err;
+	}
+	if (!(mlk__audio_ctx = alcCreateContext(mlk__audio_dev, NULL))) {
+		mlk_errf("%s", alcGetError(mlk__audio_dev));
+		goto err;
+	}
+	if (alcMakeContextCurrent(mlk__audio_ctx) != ALC_TRUE) {
+		mlk_errf("%s", alcGetError(mlk__audio_dev));
+		goto err;
+	}
 
 	return 0;
+
+err:
+	audio_finish();
+
+	return -1;
 }
 
 const char *
@@ -253,16 +265,6 @@
 	IMG_Quit();
 	SDL_Quit();
 
-	alcMakeContextCurrent(NULL);
-
-	if (mlk__audio_ctx) {
-		alcDestroyContext(mlk__audio_ctx);
-		mlk__audio_ctx = NULL;
-	}
-	if (mlk__audio_dev) {
-		alcCloseDevice(mlk__audio_dev);
-		mlk__audio_dev = NULL;
-	}
 }
 
 static int
@@ -283,7 +285,7 @@
 		free(stream->samples);
 		free(stream);
 		stream = NULL;
-		ret = sndfile_to_err(sf_error(file));
+		ret = mlk_errf("%s", sf_error(file));
 	}
 
 	alGenBuffers(1, &stream->buffer);
@@ -332,7 +334,7 @@
 	};
 
 	if (!(file = sf_open_virtual(&io, SFM_READ, &info, &viodata)))
-		return sndfile_to_err(sf_error(NULL));;
+		return mlk_errf("%s", sf_strerror(NULL));
 
 	return create_audiostream(stream, file, &info);
 }
--- a/libmlk-core/mlk/core/texture.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/texture.c	Mon Mar 06 20:03:00 2023 +0100
@@ -38,7 +38,7 @@
 
 	if (!tex->handle) {
 		tex->w = tex->h = 0;
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 	}
 
 	tex->w = w;
@@ -67,7 +67,7 @@
 	};
 
 	if (SDL_SetTextureBlendMode(tex->handle, table[blend]) < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -79,7 +79,7 @@
 	assert(alpha <= 255);
 
 	if (SDL_SetTextureAlphaMod(tex->handle, alpha) < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -90,7 +90,7 @@
 	assert(mlk_texture_ok(tex));
 
 	if (SDL_SetTextureColorMod(tex->handle, MLK_COLOR_R(color), MLK_COLOR_G(color), MLK_COLOR_B(color)) < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -108,7 +108,7 @@
 	};
 
 	if (SDL_RenderCopy(MLK__RENDERER(), tex->handle, NULL, &dst) < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -139,7 +139,7 @@
 	};
 
 	if (SDL_RenderCopyEx(MLK__RENDERER(), tex->handle, &src, &dst, angle, NULL, SDL_FLIP_NONE) < 0)
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	return 0;
 }
@@ -165,7 +165,7 @@
 
 	if (!(tex->handle = SDL_CreateTextureFromSurface(MLK__RENDERER(), surface))) {
 		tex->w = tex->h = 0;
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 	}
 
 	tex->w = surface->w;
--- a/libmlk-core/mlk/core/window.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-core/mlk/core/window.c	Mon Mar 06 20:03:00 2023 +0100
@@ -84,7 +84,7 @@
 	assert(title);
 
 	if (!load_window(title, w, h) || !load_renderer())
-		return MLK_ERR_SDL;
+		return mlk_errf("%s", SDL_GetError());
 
 	mlk_window.w = w;
 	mlk_window.h = h;
--- a/libmlk-example/mlk/example/registry.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-example/mlk/example/registry.c	Mon Mar 06 20:03:00 2023 +0100
@@ -105,14 +105,13 @@
 static void
 load_images(void)
 {
-	int err;
 	struct mlk_texture *texture;
 
 	for (size_t i = 0; i < MLK_UTIL_SIZE(images); ++i) {
 		texture = &mlk_registry_images[images[i].index];
 
-		if ((err = mlk_image_openmem(texture, images[i].data, images[i].datasz)) < 0)
-			mlk_panic(err);
+		if (mlk_image_openmem(texture, images[i].data, images[i].datasz) < 0)
+			mlk_panic();
 	}
 }
 
@@ -121,14 +120,13 @@
 {
 	struct mlk_texture *texture;
 	struct mlk_sprite *sprite;
-	int err;
 
 	for (size_t i = 0; i < MLK_UTIL_SIZE(textures); ++i) {
 		texture = &mlk_registry_textures[textures[i].index];
 		sprite = &mlk_registry_sprites[textures[i].index];
 
-		if ((err = mlk_image_openmem(texture, textures[i].data, textures[i].datasz)) < 0)
-			mlk_panic(err);
+		if (mlk_image_openmem(texture, textures[i].data, textures[i].datasz) < 0)
+			mlk_panic();
 
 		if (textures[i].cellw == 0 || textures[i].cellh == 0) {
 			sprite->cellw = texture->w;
@@ -146,28 +144,26 @@
 static void
 load_sounds(void)
 {
-	int err;
 	struct mlk_sound *sound;
 
 	for (size_t i = 0; i < MLK_UTIL_SIZE(sounds); ++i) {
 		sound = &mlk_registry_sounds[sounds[i].index];
 
-		if ((err = mlk_sound_openmem(sound, sounds[i].data, sounds[i].datasz)) < 0)
-			mlk_panic(err);
+		if (mlk_sound_openmem(sound, sounds[i].data, sounds[i].datasz) < 0)
+			mlk_panic();
 	}
 }
 
 static void
 load_music(void)
 {
-	int err;
 	struct mlk_music *music;
 
 	for (size_t i = 0; i < MLK_UTIL_SIZE(musics); ++i) {
 		music = &mlk_registry_music[musics[i].index];
 
-		if ((err = mlk_music_openmem(music, musics[i].data, musics[i].datasz)) < 0)
-			mlk_panic(err);
+		if (mlk_music_openmem(music, musics[i].data, musics[i].datasz) < 0)
+			mlk_panic();
 	}
 }
 
--- a/libmlk-rpg/mlk/rpg/map-file.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/map-file.c	Mon Mar 06 20:03:00 2023 +0100
@@ -56,7 +56,7 @@
 	else if (strcmp(layer_name, "above") == 0)
 		layer_type = MAP_LAYER_TYPE_ABOVE;
 	else
-		return MLK_ERR_FORMAT;
+		return mlk_errf("invalid layer type: %s", layer_name);
 
 	amount = ctx->map->columns * ctx->map->rows;
 	current = 0;
@@ -125,11 +125,11 @@
 
 	/* Check if weight/height has been specified. */
 	if (ctx->map->columns == 0 || ctx->map->rows == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing map dimensions before layer");
 
 	/* Determine layer type. */
 	if (sscanf(line, "layer|%32s", layer_name) <= 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing layer type definition");
 
 	if (strcmp(layer_name, "actions") == 0)
 		return parse_actions(ctx);
@@ -145,7 +145,7 @@
 	struct tileset_file *tf = &mf->tileset_file;
 
 	if (!(p = strchr(line, '|')))
-		return MLK_ERR_FORMAT;
+		return mlk_errf("could not parse tileset");
 
 	snprintf(path, sizeof (path), "%s/%s", ctx->basedir, p + 1);
 
@@ -161,7 +161,7 @@
 parse_title(struct context *ctx, const char *line)
 {
 	if (sscanf(line, "title|" MAX_F(MAP_FILE_TITLE_MAX), ctx->mf->title) != 1 || strlen(ctx->mf->title) == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("null map title");
 
 	ctx->map->title = ctx->mf->title;
 
@@ -172,7 +172,7 @@
 parse_columns(struct context *ctx, const char *line)
 {
 	if (sscanf(line, "columns|%u", &ctx->map->columns) != 1 || ctx->map->columns == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("null map columns");
 
 	return 0;
 }
@@ -181,7 +181,7 @@
 parse_rows(struct context *ctx, const char *line)
 {
 	if (sscanf(line, "rows|%u", &ctx->map->rows) != 1 || ctx->map->rows == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("null map rows");
 
 	return 0;
 }
@@ -190,7 +190,7 @@
 parse_origin(struct context *ctx, const char *line)
 {
 	if (sscanf(line, "origin|%d|%d", &ctx->map->player_x, &ctx->map->player_y) != 2)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("invalid origin");
 
 	return 0;
 }
@@ -243,18 +243,18 @@
 	 * Check that we have parsed every required components.
 	 */
 	if (!map->title)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing title");
 
 	/*
 	 * We don't need to check width/height because parsing layers and
 	 * tilesets already check for their presence, so only check layers.
 	 */
 	if (!map->layers[0].tiles)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing background layer");
 	if (!map->layers[1].tiles)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing foreground layer");
 	if (!tileset_ok(map->tileset))
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing tileset");
 
 	return 0;
 }
--- a/libmlk-rpg/mlk/rpg/message.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/message.c	Mon Mar 06 20:03:00 2023 +0100
@@ -108,7 +108,7 @@
 	struct mlk_font *font;
 	struct mlk_texture texture;
 	unsigned long color;
-	int err, x, y;
+	int x, y;
 
 	style = MLK__STYLE(msg, mlk_message_style);
 	font = style_font(msg);
@@ -122,8 +122,8 @@
 		else
 			color = style->text_color;
 
-		if ((err = mlk_font_render(font, &texture, msg->lines[i], color)) < 0) {
-			mlk_tracef("%s", mlk_err_string(err));
+		if (mlk_font_render(font, &texture, msg->lines[i], color) < 0) {
+			mlk_tracef("unable to render message text", mlk_err());
 			continue;
 		}
 
@@ -222,7 +222,7 @@
 	}
 
 	if ((err = mlk_texture_new(&tex, msg->w, msg->h)) < 0)
-		mlk_panic(err);
+		mlk_panic();
 
 	MLK_PAINTER_BEGIN(&tex);
 	draw_frame(msg);
@@ -289,7 +289,7 @@
 	if (h)
 		*h = 0;
 
-	return MLK_ERR_NO_SUPPORT;
+	return 0;
 }
 
 void
--- a/libmlk-rpg/mlk/rpg/save.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/save.c	Mon Mar 06 20:03:00 2023 +0100
@@ -38,11 +38,17 @@
 #define SQL_COMMIT      "COMMIT"
 #define SQL_ROLLBACK    "ROLLBACK"
 
-static int
+static inline int
+set_error(struct save *db)
+{
+	return mlk_errf("%s", sqlite3_errmsg(db->handle));
+}
+
+static inline int
 exec(struct save *db, const char *sql)
 {
 	if (sqlite3_exec(db->handle, sql, NULL, NULL, NULL) != SQLITE_OK)
-		return MLK_ERR_DATABASE;
+		return set_error(db);
 
 	return 0;
 }
@@ -110,14 +116,14 @@
 		case ' ':
 			break;
 		default:
-			return MLK_ERR_DATABASE;
+			return set_error(s);
 		}
 	}
 
 	return 0;
 
 sqlite3_err:
-	return MLK_ERR_DATABASE;
+	return set_error(s);
 }
 
 static int
@@ -127,7 +133,7 @@
 
 	for (int c = 0; args && *args; ++args) {
 		if (c >= ncols)
-			return MLK_ERR_DATABASE;
+			return set_error(stmt->parent);
 
 		/* TODO: type check. */
 		switch (*args) {
@@ -148,7 +154,7 @@
 		case ' ':
 			break;
 		default:
-			return MLK_ERR_DATABASE;
+			return set_error(stmt->parent);
 		}
 	}
 
@@ -189,11 +195,12 @@
 	return verify(db);
 
 sqlite3_err:
+	set_error(db);
 	sqlite3_close(db->handle);
 
 	memset(db, 0, sizeof (*db));
 
-	return MLK_ERR_DATABASE;
+	return -1;
 }
 
 int
--- a/libmlk-rpg/mlk/rpg/tileset-file.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-rpg/mlk/rpg/tileset-file.c	Mon Mar 06 20:03:00 2023 +0100
@@ -128,7 +128,7 @@
 parse_tilewidth(struct context *ctx, const char *line)
 {
 	if (sscanf(line, "tilewidth|%u", &ctx->tilewidth) != 1 || ctx->tilewidth == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("tilewidth is null");
 
 	return 0;
 }
@@ -137,7 +137,7 @@
 parse_tileheight(struct context *ctx, const char *line)
 {
 	if (sscanf(line, "tileheight|%u", &ctx->tileheight) != 1 || ctx->tileheight == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("tileheight is null");
 
 	return 0;
 }
@@ -235,14 +235,13 @@
 parse_image(struct context *ctx, const char *line)
 {
 	char *p;
-	int err;
 
 	if (ctx->tilewidth == 0 || ctx->tileheight == 0)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing tile dimensions before image");
 	if (!(p = strchr(line, '|')))
-		return MLK_ERR_FORMAT;
-	if ((err = mlk_image_open(&ctx->tf->image, mlk_util_pathf("%s/%s", ctx->basedir, p + 1))) < 0)
-		return err;
+		return mlk_errf("could not parse image");
+	if (mlk_image_open(&ctx->tf->image, mlk_util_pathf("%s/%s", ctx->basedir, p + 1)) < 0)
+		return -1;
 
 	ctx->tf->sprite.texture = &ctx->tf->image;
 	ctx->tf->sprite.cellw = ctx->tilewidth;
@@ -299,7 +298,7 @@
 check(const struct tileset *tileset)
 {
 	if (!tileset->sprite)
-		return MLK_ERR_FORMAT;
+		return mlk_errf("missing tileset image");
 
 	return 0;
 }
--- a/libmlk-ui/mlk/ui/gridmenu.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-ui/mlk/ui/gridmenu.c	Mon Mar 06 20:03:00 2023 +0100
@@ -185,7 +185,7 @@
 	struct mlk_texture tex;
 	struct mlk_font *font;
 	unsigned long color;
-	int x, y, err;
+	int x, y;
 
 	/*
 	 * Select the first top-left column based on the current selection and
@@ -211,8 +211,8 @@
 		else
 			color = style->text_color;
 
-		if ((err = mlk_font_render(font, &tex, menu->items[item], color)) < 0) {
-			mlk_tracef("unable to render grid menu item: %s", mlk_err_string(err));
+		if (mlk_font_render(font, &tex, menu->items[item], color) < 0) {
+			mlk_tracef("unable to render grid menu item: %s", mlk_err());
 			continue;
 		}
 
--- a/libmlk-ui/mlk/ui/label.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-ui/mlk/ui/label.c	Mon Mar 06 20:03:00 2023 +0100
@@ -97,16 +97,12 @@
 
 	MLK__DELEGATE_INVOKE_RET(label->delegate, mlk_label_delegate, query, label, w, h);
 
-	/*
-	 * Reached only if user decided to set NULL to query which isn't the
-	 * default.
-	 */
 	if (w)
 		*w = 0;
 	if (h)
 		*h = 0;
 
-	return MLK_ERR_NO_SUPPORT;
+	return 0;
 }
 
 void
--- a/libmlk-ui/mlk/ui/ui.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/libmlk-ui/mlk/ui/ui.c	Mon Mar 06 20:03:00 2023 +0100
@@ -91,10 +91,10 @@
 	assert(text && strlen(text) > 0);
 
 	struct mlk_texture texture;
-	int x, y, err;
+	int x, y;
 
-	if ((err = mlk_font_render(font, &texture, text, color)) < 0)
-		mlk_tracef("mlk_font_render: %s", mlk_err_string(err));
+	if (mlk_font_render(font, &texture, text, color) < 0)
+		mlk_tracef("unable to render text: %s", mlk_err());
 	else {
 		mlk_align(align, &x, &y, texture.w, texture.h, px, py, pw, ph);
 		mlk_texture_draw(&texture, x, y);
--- a/tests/test-action-script.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/tests/test-action-script.c	Mon Mar 06 20:03:00 2023 +0100
@@ -152,7 +152,7 @@
 	DT_EQ_PTR(sc.actions[2], &actions[2]);
 
 	/* This can not fit. */
-	DT_ASSERT(mlk_action_script_append(&sc, &actions[3]) == MLK_ERR_NO_MEM);
+	DT_ASSERT(mlk_action_script_append(&sc, &actions[3]) == -1);
 
 	mlk_action_script_finish(&sc);
 
--- a/tests/test-action.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/tests/test-action.c	Mon Mar 06 20:03:00 2023 +0100
@@ -227,7 +227,7 @@
 		DT_EQ_INT(mlk_action_stack_add(&st, &act), 0);
 
 	/* This one should not fit in. */
-	DT_EQ_INT(mlk_action_stack_add(&st, &act), MLK_ERR_NO_MEM);
+	DT_EQ_INT(mlk_action_stack_add(&st, &act), -1);
 }
 
 static void
--- a/tests/test-drawable.c	Mon Mar 06 20:01:00 2023 +0100
+++ b/tests/test-drawable.c	Mon Mar 06 20:03:00 2023 +0100
@@ -165,7 +165,7 @@
 		DT_EQ_INT(mlk_drawable_stack_add(&st, &dw), 0);
 
 	/* This one should not fit in. */
-	DT_EQ_INT(mlk_drawable_stack_add(&st, &dw), MLK_ERR_NO_MEM);
+	DT_EQ_INT(mlk_drawable_stack_add(&st, &dw), -1);
 }
 
 static void