Files
libakgl/include/akgl/error.h
Andrew Kesterson f0858b0d38 Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".

Rewritten against the implementations, following the pattern libakstdlib
already uses:

- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
  (absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
  (filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
  and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
  written on a failure path. Where an argument is not checked, the doc says so:
  akgl_heap_next_actor's dest is a crash on NULL, not an error, and
  akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
  short. json_helpers.h states once that absence is an error here and that
  json_t * results are borrowed; heap.h explains the pool model and the
  acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
  including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
  timer_gravity are read by nothing, and say so.

Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.

Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:23:15 -04:00

79 lines
3.8 KiB
C

/**
* @file error.h
* @brief Declares the public error API.
*/
#ifndef _ERROR_H_
#define _ERROR_H_
#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
// 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.
#define DISABLE_GCC_WARNING_FORMAT_TRUNCATION \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wformat-truncation\"")
#define RESTORE_GCC_WARNINGS \
_Pragma("GCC diagnostic pop")
// 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);
#endif // _ERROR_H_