Files
libakerror/docs/status-codes.md

47 lines
2.2 KiB
Markdown
Raw Normal View History

Split the README reference material into docs/ The README was 794 lines: the summary, the design rationale, the whole macro reference, the threading contract, the build internals and the exit-status specification in one file. It is now 178 lines -- summary, installation, quickstart, and an index -- and the reference material lives in docs/, one file per topic: architecture, usage, status-codes, uncaught-errors, exit-status, thread-safety, building. The prose moved as written. Inbound references followed it: UPGRADING.md, TODO.md, include/akerror.tmpl.h and tests/err_threads_handoff.c now name the docs/ file that owns the text they cite, and AGENTS.md says where new documentation goes so the README does not grow back. Five factual errors fixed in the moved text: - Both NULL-pointer examples inverted their test. FAIL_ZERO_* fails when the expression is zero, so `(somePointer == NULL)` failed on a *valid* pointer. They now read `(somePointer != NULL)`. - AKERROR_NOIGNORE, four times including the #define, is AKERR_NOIGNORE. - FINISH_NORExbTURN is FINISH_NORETURN. - "functiions" is "functions". - The architecture link pointed at include/akerror.h, which is generated and not in the tree; it points at include/akerror.tmpl.h. The quickstart is new text. It compiles under -Wall -Wextra -Werror and was run through all three of its paths: handled usage error exits 0, unhandled IO error prints a trace and exits with the status, success exits 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 16:56:07 -04:00
# Error codes
The library uses integer values to specify error codes inside of its context. These integer return codes are defined in `akerror.h` in the form of `AKERR_xxxxx` where `xxxxx` is the name of the error code in question. See `akerror.h` for a list of defined errors and their descriptions.
You can define additional error types as integer constants. Values 0 through 255
are reserved by libakerror (the host's errno values plus the `AKERR_*` codes);
consumers allocate codes starting at `AKERR_FIRST_CONSUMER_STATUS` (256). Status
names are stored sparsely, so any `int` is a legal status and no compile
definition is needed to use large values. Note that no consumer status can be a
process exit code — see [Exit status](exit-status.md).
Every library that may coexist in one process must reserve its range during
initialization. `akerr_reserve_status_range()` and
`akerr_register_status_name()` report failure the way everything else in this
library does — they return `akerr_ErrorContext *`, and they are marked
`AKERR_NOIGNORE` — so a collision is an exception you can `CATCH`, `HANDLE`, or
`PASS` up out of your initialization:
```c
#define MYLIB_OWNER "my-library"
akerr_ErrorContext AKERR_NOIGNORE *mylib_init(void)
{
PREPARE_ERROR(errctx);
/* Another component owning part of the range propagates to our caller. */
PASS(errctx, akerr_reserve_status_range(256, 16, MYLIB_OWNER));
/* Then name each code, quoting the owner you reserved with. */
PASS(errctx, akerr_register_status_name(MYLIB_OWNER, 256,
"Some Error Code Description"));
SUCCEED_RETURN(errctx);
}
```
Reservations are process-local, fixed-capacity, and idempotent when the same
owner repeats the exact same range. They preserve compile-time integer constants
so `HANDLE` still works, since `case` labels require them.
Naming a status outside your reservation raises `AKERR_STATUS_NAME_FOREIGN`, and
naming one nobody reserved raises `AKERR_STATUS_NAME_UNRESERVED`; a colliding
reservation raises `AKERR_STATUS_RANGE_OVERLAP`, with a message naming the real
owner. See [UPGRADING.md](../UPGRADING.md) for the full list of statuses these two
functions raise, the capacity limits and how to raise them, and thread-safety
rules.