2026-07-30 01:10:31 -04:00
|
|
|
/**
|
|
|
|
|
* @file error.h
|
|
|
|
|
* @brief Declares the public error API.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-05-04 00:02:31 -04:00
|
|
|
#ifndef _ERROR_H_
|
|
|
|
|
#define _ERROR_H_
|
|
|
|
|
|
Migrate to the libakerror 1.0.0 status registry
libakerror 1.0.0 replaced the consumer-sized status-name array with a
private registry and made status-code ownership explicit and enforced.
AKERR_MAX_ERR_VALUE and __AKERR_ERROR_NAMES are gone, and the registry
entry points raise akerr_ErrorContext * instead of returning int. See
deps/libakerror/UPGRADING.md.
The break was not only source-level. libakgl's codes sat at
AKERR_LAST_ERRNO_VALUE + 18 through + 22, and 1.0.0 claimed exactly
those five offsets for its own AKERR_STATUS_* registry codes, so every
AKGL_ERR_* was aliasing a libakerror status. HANDLE(e,
AKGL_ERR_LOGICINTERRUPT) at physics.c:222 would have swallowed a
foreign-name refusal.
- Move the band to AKERR_FIRST_CONSUMER_STATUS (256) as fixed offsets,
so a libc that grows an errno cannot move the codes, and add
AKGL_ERR_OWNER, AKGL_ERR_LIMIT and AKGL_ERR_COUNT to describe it.
- Reserve the range and register the names through the owned entry
points, PASS-ing each: these are AKERR_NOIGNORE, and the old
akerr_name_for_status calls discarded failure silently.
- Drop the AKERR_MAX_ERR_VALUE=256 compile definition.
- Guard on AKERR_FIRST_CONSUMER_STATUS in include/akgl/error.h, which
now includes <akerror.h> so the guard is reliable. The embedded build
is fine, but the find_package path can pick up a stale installed
header, and 1.0.0 has an soname, so that pairing is an ABI mismatch
rather than a compile problem. Same guard libakstdlib already carries.
Registration also moves out of akgl_heap_init into a new akgl_error_init
in src/error.c. It was in the heap pool's initializer only because that
was the first thing akgl_game_init called, and the upgrade turned five
fire-and-forget name calls into a library-wide ownership claim that can
fail. That placement was hiding a defect: game.c raises AKGL_ERR_SDL
when SDL_CreateMutex fails, five lines before akgl_heap_init ran, so the
earliest error path in the library was guaranteed to print "Unknown
Error". akgl_error_init is now the first statement in akgl_game_init.
Callers that drive subsystems directly must call akgl_error_init first;
it is idempotent, so ordering it precisely is not required. The eleven
test suites that relied on akgl_heap_init to name their statuses now
call it explicitly, or their failure messages would have degraded to
"Unknown Error".
Add tests/error.c: assert every code reads back its registered name,
that the name table and AKGL_ERR_COUNT agree, that a foreign owner is
refused with AKERR_STATUS_NAME_FOREIGN and AKERR_STATUS_RANGE_OVERLAP,
and that repeating the init is a no-op. That last one is a live
constraint, not a triviality -- libakerror treats only an identical
reservation as a repeat, so a subset or superset raises.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:20:28 -04:00
|
|
|
#include <akerror.h>
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* libakerror 1.0.0 is the floor. That release moved the status-name table into a
|
|
|
|
|
* private registry -- AKERR_MAX_ERR_VALUE and __AKERR_ERROR_NAMES are gone, the
|
|
|
|
|
* registry entry points raise akerr_ErrorContext * instead of returning int, and
|
|
|
|
|
* the library gained an soname -- so a translation unit that pairs this header
|
|
|
|
|
* with a pre-1.0.0 akerror.h is an ABI mismatch, not just a compile problem.
|
|
|
|
|
*
|
|
|
|
|
* libakerror publishes no version macro, so this feature-tests on
|
|
|
|
|
* AKERR_FIRST_CONSUMER_STATUS, which that release introduced, rather than on a
|
|
|
|
|
* version number that does not exist. Without the guard an embedded build is
|
|
|
|
|
* fine but a stale installed header fails much further in, on the AKGL_ERR_*
|
|
|
|
|
* codes below and again inside src/heap.c.
|
|
|
|
|
*
|
|
|
|
|
* See deps/libakerror/UPGRADING.md.
|
|
|
|
|
*/
|
|
|
|
|
#ifndef AKERR_FIRST_CONSUMER_STATUS
|
|
|
|
|
#error "libakgl requires libakerror >= 1.0.0: the akerror.h on the include path predates the status registry. Rebuild and reinstall libakerror."
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-05-24 09:51:58 -04:00
|
|
|
// This macro is used to silence warnings on string concatenation operations that may fail.
|
|
|
|
|
// e.g., combining two element of PATH_MAX into a string buffer of AKGL_STRING_MAX_LENGTH.
|
|
|
|
|
// We have to draw a line in the sand somewhere or we will just let our buffers grow forever
|
|
|
|
|
// to keep the compiler happy.
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
#define DISABLE_GCC_WARNING_FORMAT_TRUNCATION \
|
|
|
|
|
_Pragma("GCC diagnostic push") \
|
2026-05-24 09:51:58 -04:00
|
|
|
_Pragma("GCC diagnostic ignored \"-Wformat-truncation\"")
|
|
|
|
|
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
#define RESTORE_GCC_WARNINGS \
|
2026-05-24 09:51:58 -04:00
|
|
|
_Pragma("GCC diagnostic pop")
|
|
|
|
|
|
Migrate to the libakerror 1.0.0 status registry
libakerror 1.0.0 replaced the consumer-sized status-name array with a
private registry and made status-code ownership explicit and enforced.
AKERR_MAX_ERR_VALUE and __AKERR_ERROR_NAMES are gone, and the registry
entry points raise akerr_ErrorContext * instead of returning int. See
deps/libakerror/UPGRADING.md.
The break was not only source-level. libakgl's codes sat at
AKERR_LAST_ERRNO_VALUE + 18 through + 22, and 1.0.0 claimed exactly
those five offsets for its own AKERR_STATUS_* registry codes, so every
AKGL_ERR_* was aliasing a libakerror status. HANDLE(e,
AKGL_ERR_LOGICINTERRUPT) at physics.c:222 would have swallowed a
foreign-name refusal.
- Move the band to AKERR_FIRST_CONSUMER_STATUS (256) as fixed offsets,
so a libc that grows an errno cannot move the codes, and add
AKGL_ERR_OWNER, AKGL_ERR_LIMIT and AKGL_ERR_COUNT to describe it.
- Reserve the range and register the names through the owned entry
points, PASS-ing each: these are AKERR_NOIGNORE, and the old
akerr_name_for_status calls discarded failure silently.
- Drop the AKERR_MAX_ERR_VALUE=256 compile definition.
- Guard on AKERR_FIRST_CONSUMER_STATUS in include/akgl/error.h, which
now includes <akerror.h> so the guard is reliable. The embedded build
is fine, but the find_package path can pick up a stale installed
header, and 1.0.0 has an soname, so that pairing is an ABI mismatch
rather than a compile problem. Same guard libakstdlib already carries.
Registration also moves out of akgl_heap_init into a new akgl_error_init
in src/error.c. It was in the heap pool's initializer only because that
was the first thing akgl_game_init called, and the upgrade turned five
fire-and-forget name calls into a library-wide ownership claim that can
fail. That placement was hiding a defect: game.c raises AKGL_ERR_SDL
when SDL_CreateMutex fails, five lines before akgl_heap_init ran, so the
earliest error path in the library was guaranteed to print "Unknown
Error". akgl_error_init is now the first statement in akgl_game_init.
Callers that drive subsystems directly must call akgl_error_init first;
it is idempotent, so ordering it precisely is not required. The eleven
test suites that relied on akgl_heap_init to name their statuses now
call it explicitly, or their failure messages would have degraded to
"Unknown Error".
Add tests/error.c: assert every code reads back its registered name,
that the name table and AKGL_ERR_COUNT agree, that a foreign owner is
refused with AKERR_STATUS_NAME_FOREIGN and AKERR_STATUS_RANGE_OVERLAP,
and that repeating the init is a no-op. That last one is a live
constraint, not a triviality -- libakerror treats only an identical
reservation as a repeat, so a subset or superset raises.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 22:20:28 -04:00
|
|
|
// libakerror reserves statuses 0-255 for the host's errno values and its own
|
|
|
|
|
// AKERR_* codes; consumers allocate from AKERR_FIRST_CONSUMER_STATUS upward.
|
|
|
|
|
// These are fixed offsets from that base rather than from AKERR_LAST_ERRNO_VALUE
|
|
|
|
|
// so that a libc which grows an errno cannot move them out from under us.
|
|
|
|
|
//
|
|
|
|
|
// akgl_error_init() reserves this whole band in one call and registers a name
|
|
|
|
|
// for every code below. Add a code here and you must name it there, or it
|
|
|
|
|
// prints as "Unknown Error" in every stack trace that carries it.
|
|
|
|
|
#define AKGL_ERR_OWNER "libakgl"
|
|
|
|
|
#define AKGL_ERR_BASE AKERR_FIRST_CONSUMER_STATUS
|
|
|
|
|
|
|
|
|
|
#define AKGL_ERR_SDL (AKGL_ERR_BASE + 0) /** An SDL call failed; the message carries SDL_GetError() */
|
|
|
|
|
#define AKGL_ERR_REGISTRY (AKGL_ERR_BASE + 1) /** A registry property or lookup operation failed */
|
|
|
|
|
#define AKGL_ERR_HEAP (AKGL_ERR_BASE + 2) /** A heap pool has no free object left to hand out */
|
|
|
|
|
#define AKGL_ERR_BEHAVIOR (AKGL_ERR_BASE + 3) /** A component did not behave the way its contract requires */
|
|
|
|
|
#define AKGL_ERR_LOGICINTERRUPT (AKGL_ERR_BASE + 4) /** Actor logic is telling the physics simulator to skip it */
|
|
|
|
|
|
|
|
|
|
// One past the last libakgl status. The reservation is all-or-nothing -- a
|
|
|
|
|
// subset or superset of an existing one is refused -- so this must stay one
|
|
|
|
|
// past the highest code above.
|
|
|
|
|
#define AKGL_ERR_LIMIT (AKGL_ERR_BASE + 5)
|
|
|
|
|
#define AKGL_ERR_COUNT (AKGL_ERR_LIMIT - AKGL_ERR_BASE)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Claim the libakgl status band and register a name for every code in it.
|
|
|
|
|
*
|
|
|
|
|
* Call this before anything else in libakgl. Every other subsystem raises
|
|
|
|
|
* AKGL_ERR_* codes, and a code raised before this runs carries no name into its
|
|
|
|
|
* stack trace. Repeating the call is a no-op, so a program that cannot order its
|
|
|
|
|
* initialization precisely may call it more than once.
|
|
|
|
|
*
|
|
|
|
|
* @throws AKERR_STATUS_RANGE_OVERLAP When another component already owns part of the band.
|
|
|
|
|
* @throws AKERR_STATUS_RANGE_FULL When libakerror has no reservation slots left.
|
|
|
|
|
* @throws AKERR_STATUS_NAME_FULL When libakerror's name registry is full.
|
|
|
|
|
*/
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_error_init(void);
|
2026-05-04 00:02:31 -04:00
|
|
|
|
|
|
|
|
#endif // _ERROR_H_
|