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(AKERR_USE_STDLIB 1 CACHE BOOL "Use the C standard library")
|
||||||
set(akerror_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/akerror")
|
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)
|
find_package(PkgConfig REQUIRED)
|
||||||
add_library(akerror STATIC
|
add_library(akerror STATIC
|
||||||
src/error.c
|
src/error.c
|
||||||
|
src/errno.c
|
||||||
)
|
)
|
||||||
|
add_dependencies(akerror generrno)
|
||||||
|
|
||||||
target_compile_definitions(akerror
|
target_compile_definitions(akerror
|
||||||
PUBLIC AKERR_USE_STDLIB=${AKERR_USE_STDLIB}
|
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.
|
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
|
```c
|
||||||
error_name_for_status(129, "Some Error Code Description")
|
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
|
# Installation
|
||||||
|
|
||||||
@@ -78,6 +79,14 @@ cmake --build build
|
|||||||
cmake --install 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
|
## 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:
|
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.
|
`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
|
# Capturing errors
|
||||||
|
|||||||
@@ -14,23 +14,27 @@
|
|||||||
#define AKERR_MAX_ERROR_FUNCTION_LENGTH 128
|
#define AKERR_MAX_ERROR_FUNCTION_LENGTH 128
|
||||||
#define AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH 2048
|
#define AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH 2048
|
||||||
|
|
||||||
#define AKERR_NULLPOINTER 1
|
#define AKERR_LAST_ERRNO_VALUE AKERR_LAST_ERRNO_VALUE_SED
|
||||||
#define AKERR_OUTOFBOUNDS 2
|
|
||||||
#define AKERR_API 3
|
#define AKERR_NULLPOINTER (AKERR_LAST_ERRNO_VALUE + 1)
|
||||||
#define AKERR_ATTRIBUTE 4
|
#define AKERR_OUTOFBOUNDS (AKERR_LAST_ERRNO_VALUE + 2)
|
||||||
#define AKERR_TYPE 5
|
#define AKERR_API (AKERR_LAST_ERRNO_VALUE + 3)
|
||||||
#define AKERR_KEY 6
|
#define AKERR_ATTRIBUTE (AKERR_LAST_ERRNO_VALUE + 4)
|
||||||
#define AKERR_HEAP 7
|
#define AKERR_TYPE (AKERR_LAST_ERRNO_VALUE + 5)
|
||||||
#define AKERR_INDEX 8
|
#define AKERR_KEY (AKERR_LAST_ERRNO_VALUE + 6)
|
||||||
#define AKERR_FORMAT 9
|
#define AKERR_HEAP (AKERR_LAST_ERRNO_VALUE + 7)
|
||||||
#define AKERR_IO 10
|
#define AKERR_INDEX (AKERR_LAST_ERRNO_VALUE + 8)
|
||||||
#define AKERR_REGISTRY 11
|
#define AKERR_FORMAT (AKERR_LAST_ERRNO_VALUE + 9)
|
||||||
#define AKERR_VALUE 12
|
#define AKERR_IO (AKERR_LAST_ERRNO_VALUE + 10)
|
||||||
#define AKERR_BEHAVIOR 13
|
#define AKERR_REGISTRY (AKERR_LAST_ERRNO_VALUE + 11)
|
||||||
#define AKERR_RELATIONSHIP 14
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
extern char __AKERR_ERROR_NAMES[AKERR_MAX_ERR_VALUE+1][AKERR_MAX_ERROR_NAME_LENGTH];
|
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_init();
|
||||||
void akerr_default_handler_unhandled_error(akerr_ErrorContext *ptr);
|
void akerr_default_handler_unhandled_error(akerr_ErrorContext *ptr);
|
||||||
void akerr_default_logger(const char *f, ...);
|
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) \
|
#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); \
|
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__); \
|
snprintf((char *)__err_context->function, AKERR_MAX_ERROR_FUNCTION_LENGTH, __func__); \
|
||||||
__err_context->lineno = __LINE__; \
|
__err_context->lineno = __LINE__; \
|
||||||
snprintf((char *)__err_context->message, AKERR_MAX_ERROR_CONTEXT_STRING_LENGTH, __message, ## __VA_ARGS__); \
|
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) \
|
#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