Import all system definitions of errno including their string representations, then layer our error definitions on top of that
This commit is contained in:
@@ -7,10 +7,27 @@ include(CMakePackageConfigHelpers)
|
||||
set(AKERR_USE_STDLIB 1 CACHE BOOL "Use the C standard library")
|
||||
set(akerror_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/akerror")
|
||||
|
||||
set(SCRIPT ${CMAKE_SOURCE_DIR}/scripts/generrno.sh)
|
||||
set(INFILE ${CMAKE_SOURCE_DIR}/include/akerror.tmpl.h)
|
||||
set(OUTFILES ${CMAKE_SOURCE_DIR}/src/errno.c ${CMAKE_SOURCE_DIR}/include/akerror.h)
|
||||
add_custom_command(
|
||||
OUTPUT ${OUTFILES}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_SOURCE_DIR}
|
||||
COMMAND /usr/bin/env bash ${SCRIPT} ${CMAKE_SOURCE_DIR}
|
||||
DEPENDS ${SCRIPT} ${INFILE}
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set_source_files_properties(src/errno.c PROPERTIES GENERATED TRUE)
|
||||
|
||||
add_custom_target(generrno DEPENDS src/errno.c)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
add_library(akerror STATIC
|
||||
src/error.c
|
||||
src/error.c
|
||||
src/errno.c
|
||||
)
|
||||
add_dependencies(akerror generrno)
|
||||
|
||||
target_compile_definitions(akerror
|
||||
PUBLIC AKERR_USE_STDLIB=${AKERR_USE_STDLIB}
|
||||
|
||||
15
README.md
15
README.md
@@ -62,13 +62,14 @@ Any function which uses the `PREPARE_ERROR` macro should have a return type of `
|
||||
|
||||
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 by defining additional `AKERR_xxxxx` values. Error values up to 127 are reserved by the library, so begin your error values at 128. Define a human-friendly name for the error with the `error_name_for_status` method:
|
||||
You can define additional error types by defining additional `AKERR_xxxxx` values. Error values up to 255 are reserved by the library (`AKERR_xxxxx` begins where `errno` stops), so please begin your error values at 256. When you add additional error codes, you need to define `-DAKERR_MAX_ERR_VALUE=n` to the compiler, where `n` is the maximum error code you have defined. If you define custom error codes, `AKERR_MAX_ERR_VALUE` must be >= 256 or the compiler will throw an error.
|
||||
|
||||
Define a human-friendly name for the error with the `error_name_for_status` method somewhere in your code's initialization before the error may be used:
|
||||
|
||||
```c
|
||||
error_name_for_status(129, "Some Error Code Description")
|
||||
```
|
||||
|
||||
When you add additional error codes, you need to define `-DAKERR_MAX_ERR_VALUE=n` to the compiler, where `n` is the maximum error code you have defined.
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -78,6 +79,14 @@ cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
## Templating and autogenerated code
|
||||
|
||||
The build process relies upon `scripts/generrno.sh` which performs the following:
|
||||
|
||||
1. Executes `errno --list` and gathers up the output
|
||||
1. Templates `include/akerror.tmpl.h` into `include/akerror.h` to set the `AKERR_LAST_ERRNO_VALUE` equal to the highest integer defined by `errno`
|
||||
2. Generates `src/errno.c` which contains a function called by `akerr_init` which initializes all of the status names for the previously defined values of `errno`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This library depends upon `stdlib`. If you don't want to link against stdlib, you must modify the library code to include headers and link against a library that provides the following:
|
||||
@@ -172,7 +181,7 @@ ATTEMPT {
|
||||
|
||||
`PROCESS(errctx) { ... }` is the block within which you will handle any errors that were caught inside of the `ATTEMPT` block. See "Handling Errors" below.
|
||||
|
||||
`FINISH(errctx, true)` terminates the attempt operation. The `FINISH` macro takes two arguments: the name of the akerr_ErrorContext, and a boolean regarding whether or not to pass unhandled errors up to the calling function. Unless you are inside of your `main()` method, this should be true. Inside of your `main()` method, call `FINISH_NORETURN(errctx)` instead.
|
||||
`FINISH(errctx, true)` terminates the attempt operation. The `FINISH` macro takes two arguments: the name of the akerr_ErrorContext, and a boolean regarding whether or not to pass unhandled errors up to the calling function. Unless you are inside of your `main()` method, this should be true. Inside of your `main()` method, call `FINISH_NORExbTURN(errctx)` instead.
|
||||
|
||||
|
||||
# Capturing errors
|
||||
|
||||
@@ -14,23 +14,27 @@
|
||||
#define AKERR_MAX_ERROR_FUNCTION_LENGTH 128
|
||||
#define AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH 2048
|
||||
|
||||
#define AKERR_NULLPOINTER 1
|
||||
#define AKERR_OUTOFBOUNDS 2
|
||||
#define AKERR_API 3
|
||||
#define AKERR_ATTRIBUTE 4
|
||||
#define AKERR_TYPE 5
|
||||
#define AKERR_KEY 6
|
||||
#define AKERR_HEAP 7
|
||||
#define AKERR_INDEX 8
|
||||
#define AKERR_FORMAT 9
|
||||
#define AKERR_IO 10
|
||||
#define AKERR_REGISTRY 11
|
||||
#define AKERR_VALUE 12
|
||||
#define AKERR_BEHAVIOR 13
|
||||
#define AKERR_RELATIONSHIP 14
|
||||
#define AKERR_LAST_ERRNO_VALUE AKERR_LAST_ERRNO_VALUE_SED
|
||||
|
||||
#define AKERR_NULLPOINTER (AKERR_LAST_ERRNO_VALUE + 1)
|
||||
#define AKERR_OUTOFBOUNDS (AKERR_LAST_ERRNO_VALUE + 2)
|
||||
#define AKERR_API (AKERR_LAST_ERRNO_VALUE + 3)
|
||||
#define AKERR_ATTRIBUTE (AKERR_LAST_ERRNO_VALUE + 4)
|
||||
#define AKERR_TYPE (AKERR_LAST_ERRNO_VALUE + 5)
|
||||
#define AKERR_KEY (AKERR_LAST_ERRNO_VALUE + 6)
|
||||
#define AKERR_HEAP (AKERR_LAST_ERRNO_VALUE + 7)
|
||||
#define AKERR_INDEX (AKERR_LAST_ERRNO_VALUE + 8)
|
||||
#define AKERR_FORMAT (AKERR_LAST_ERRNO_VALUE + 9)
|
||||
#define AKERR_IO (AKERR_LAST_ERRNO_VALUE + 10)
|
||||
#define AKERR_REGISTRY (AKERR_LAST_ERRNO_VALUE + 11)
|
||||
#define AKERR_VALUE (AKERR_LAST_ERRNO_VALUE + 12)
|
||||
#define AKERR_BEHAVIOR (AKERR_LAST_ERRNO_VALUE + 13)
|
||||
#define AKERR_RELATIONSHIP (AKERR_LAST_ERRNO_VALUE + 14)
|
||||
|
||||
#ifndef AKERR_MAX_ERR_VALUE
|
||||
#define AKERR_MAX_ERR_VALUE 14
|
||||
#define AKERR_MAX_ERR_VALUE (AKERR_LAST_ERRNO_VALUE + 14)
|
||||
#elif AKERR_MAX_ERR_VALUE < 256
|
||||
#error user-defined AKERR_MAX_ERR_VALUE must be >= 256
|
||||
#endif
|
||||
|
||||
extern char __AKERR_ERROR_NAMES[AKERR_MAX_ERR_VALUE+1][AKERR_MAX_ERROR_NAME_LENGTH];
|
||||
@@ -69,6 +73,8 @@ char *akerr_name_for_status(int status, char *name);
|
||||
void akerr_init();
|
||||
void akerr_default_handler_unhandled_error(akerr_ErrorContext *ptr);
|
||||
void akerr_default_logger(const char *f, ...);
|
||||
/* defined in src/errno.c which is built dynamically at build time from system errno definitions */
|
||||
void akerr_init_errno(void);
|
||||
|
||||
#define LOG_ERROR_WITH_MESSAGE(__err_context, __err_message) \
|
||||
akerr_log_method("%s%s:%s:%d: %s %d (%s): %s", (char *)&__err_context->stacktracebuf, (char *)__FILE__, (char *)__func__, __LINE__, __err_message, __err_context->status, akerr_name_for_status(__err_context->status, NULL), __err_context->message); \
|
||||
@@ -154,7 +160,7 @@ void akerr_default_logger(const char *f, ...);
|
||||
snprintf((char *)__err_context->function, AKERR_MAX_ERROR_FUNCTION_LENGTH, __func__); \
|
||||
__err_context->lineno = __LINE__; \
|
||||
snprintf((char *)__err_context->message, AKERR_MAX_ERROR_CONTEXT_STRING_LENGTH, __message, ## __VA_ARGS__); \
|
||||
__err_context->stacktracebufptr += snprintf(__err_context->stacktracebufptr, AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH, "%s:%s:%d: %d (%s) : %s\n", (char *)__err_context->fname, (char *)__err_context->function, __err_context->lineno, __err_context->status, akerr_name_for_status(__err_context->status, NULL), __err_context->message);
|
||||
__err_context->stacktracebufptr += snprintf(__err_context->stacktracebufptr, AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH, "%s:%s:%d: %d (%s) : %s\n", (char *)__err_context->fname, (char *)__err_context->function, __err_context->lineno, __err_context->status, akerr_name_for_status(__err_context->status, NULL), (__err_context->message == NULL ? "" : __err_context->message));
|
||||
|
||||
|
||||
#define SUCCEED(__err_context) \
|
||||
16
scripts/generrno.sh
Normal file
16
scripts/generrno.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
srcdir=$1
|
||||
rm -f ${srcdir}/src/errno.c
|
||||
echo "#include <akerror.h>" >> ${srcdir}/src/errno.c
|
||||
echo "#include <errno.h>" >> ${srcdir}/src/errno.c
|
||||
echo "void akerr_init_errno(void) {" >> ${srcdir}/src/errno.c
|
||||
maxval=$(errno --list | cut -d ' ' -f 2 | sort -g | tail -n 1)
|
||||
errno --list | while read LINE; do
|
||||
define=$(echo "$LINE" | cut -d ' ' -f 1);
|
||||
value=$(echo "$LINE" | cut -d ' ' -f 2);
|
||||
desc=$(echo "$LINE" | cut -d ' ' -f 3-);
|
||||
echo " akerr_name_for_status(${define}, \"${desc}\");" >> ${srcdir}/src/errno.c ;
|
||||
done;
|
||||
echo "}" >> ${srcdir}/src/errno.c
|
||||
sed "s/#define AKERR_LAST_ERRNO_VALUE .*/#define AKERR_LAST_ERRNO_VALUE ${maxval}/" ${srcdir}/include/akerror.tmpl.h > ${srcdir}/include/akerror.h
|
||||
Reference in New Issue
Block a user