Files
libakerror/include/akerror.tmpl.h

259 lines
9.6 KiB
C

#ifndef _AKERR_H_
#define _AKERR_H_
#if (defined(AKERR_USE_STDLIB) && AKERR_USE_STDLIB == 1) || (!defined(AKERR_USE_STDLIB))
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#endif
#define AKERR_MAX_ERROR_CONTEXT_STRING_LENGTH 1024
#define AKERR_MAX_ERROR_NAME_LENGTH 64
#define AKERR_MAX_ERROR_FNAME_LENGTH 256
#define AKERR_MAX_ERROR_FUNCTION_LENGTH 128
#define AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH 2048
#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 (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];
#define AKERR_MAX_ARRAY_ERROR 128
typedef struct
{
char message[AKERR_MAX_ERROR_CONTEXT_STRING_LENGTH];
int arrayid;
int status;
bool handled;
int refcount;
char fname[AKERR_MAX_ERROR_FNAME_LENGTH];
char function[AKERR_MAX_ERROR_FNAME_LENGTH];
int lineno;
bool reported;
char stacktracebuf[AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH];
char *stacktracebufptr;
} akerr_ErrorContext;
#define AKERR_NOIGNORE __attribute__((warn_unused_result))
typedef void (*akerr_ErrorUnhandledErrorHandler)(akerr_ErrorContext *errctx);
typedef void (*akerr_ErrorLogFunction)(const char *f, ...);
extern akerr_ErrorContext AKERR_ARRAY_ERROR[AKERR_MAX_ARRAY_ERROR];
extern akerr_ErrorUnhandledErrorHandler akerr_handler_unhandled_error;
extern akerr_ErrorLogFunction akerr_log_method;
extern akerr_ErrorContext *__akerr_last_ignored;
extern akerr_ErrorContext *__akerr_last_prepared;
extern int __akerr_last_attempt_id;
akerr_ErrorContext AKERR_NOIGNORE *akerr_release_error(akerr_ErrorContext *ptr);
akerr_ErrorContext AKERR_NOIGNORE *akerr_next_error();
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); \
#define LOG_ERROR(__err_context) \
LOG_ERROR_WITH_MESSAGE(__err_context, "");
#define RELEASE_ERROR(__err_context) \
if ( __err_context != NULL ) { \
__err_context = akerr_release_error(__err_context); \
}
#define PREPARE_ERROR(__err_context) \
akerr_init(); \
akerr_ErrorContext __attribute__ ((unused)) *__err_context = NULL;
#define ENSURE_ERROR_READY(__err_context) \
if ( __err_context == NULL ) { \
__err_context = akerr_next_error(); \
if ( __err_context == NULL ) { \
akerr_log_method("%s:%s:%d: Unable to pull an error context from the array!", __FILE__, (char *)__func__, __LINE__); \
exit(1); \
} \
} \
__err_context->refcount += 1;
/*
* Failure and success methods for functions that return akerr_ErrorContext *
*/
#define FAIL_ZERO_RETURN(__err_context, __x, __err, __message, ...) \
if ( __x == 0 ) { \
FAIL(__err_context, __err, __message, ##__VA_ARGS__); \
return __err_context; \
}
#define FAIL_NONZERO_RETURN(__err_context, __x, __err, __message, ...) \
if ( __x != 0 ) { \
FAIL(__err_context, __err, __message, ##__VA_ARGS__); \
return __err_context; \
}
#define FAIL_RETURN(__err_context, __err, __message, ...) \
FAIL(__err_context, __err, __message, ##__VA_ARGS__); \
return __err_context;
#define SUCCEED_RETURN(__err_context) \
RELEASE_ERROR(__err_context); \
return NULL;
/*
* Failure and success methods for use inside of ATTEMPT() blocks
*/
#define FAIL_ZERO_BREAK(__err_context, __x, __err, __message, ...) \
if ( __x == 0 ) { \
FAIL(__err_context, __err, __message, ##__VA_ARGS__); \
break; \
}
#define FAIL_NONZERO_BREAK(__err_context, __x, __err, __message, ...) \
if ( __x != 0 ) { \
FAIL(__err_context, __err, __message, ##__VA_ARGS__); \
break; \
}
#define FAIL_BREAK(__err_context, __err_, __message, ...) \
FAIL(__err_context, __err_, __message, ##__VA_ARGS__); \
break;
#define SUCCEED_BREAK(__err_context) \
SUCCEED(__err_context); \
break;
/*
* General failure and success methods
*/
#define FAIL(__err_context, __err, __message, ...) \
ENSURE_ERROR_READY(__err_context); \
__err_context->status = __err; \
snprintf((char *)__err_context->fname, AKERR_MAX_ERROR_FNAME_LENGTH, __FILE__); \
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 == NULL ? "" : __err_context->message));
#define SUCCEED(__err_context) \
ENSURE_ERROR_READY(__err_context); \
__err_context->status = 0;
/*
* Defines for the ATTEMPT/CATCH/CLEANUP/PROCESS/HANDLE/FINISH process
*/
#define ATTEMPT \
switch ( 0 ) { \
case 0: \
#define DETECT(__err_context, __stmt) \
__stmt; \
if ( __err_context != NULL ) { \
__err_context->stacktracebufptr += snprintf(__err_context->stacktracebufptr, AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH, "%s:%s:%d: Detected error %d from array (refcount %d)\n", (char *)__FILE__, (char *)__func__, __LINE__, __err_context->arrayid, __err_context->refcount); \
if ( __err_context->status != 0 ) { \
__err_context->stacktracebufptr += snprintf(__err_context->stacktracebufptr, AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH, "%s:%s:%d\n", (char *)__FILE__, (char *)__func__, __LINE__); \
break; \
} \
}
#define CATCH(__err_context, __stmt) \
DETECT(__err_context, __err_context = __stmt);
#define IGNORE(__stmt) \
__akerr_last_ignored = __stmt; \
if ( __akerr_last_ignored != NULL ) { \
LOG_ERROR_WITH_MESSAGE(__akerr_last_ignored, "** IGNORED ERROR **"); \
}
#define CLEANUP \
};
#define PROCESS(__err_context) \
if ( __err_context != NULL ) { \
switch ( __err_context->status ) { \
case 0: \
__err_context->handled = true;
#define HANDLE(__err_context, __err_status) \
break; \
case __err_status: \
__err_context->stacktracebufptr = (char *)&__err_context->stacktracebuf; \
__err_context->handled = true;
#define HANDLE_GROUP(__err_context, __err_status) \
case __err_status: \
__err_context->stacktracebufptr = (char *)&__err_context->stacktracebuf; \
__err_context->handled = true;
#define HANDLE_DEFAULT(__err_context) \
break; \
default: \
__err_context->stacktracebufptr = (char *)&__err_context->stacktracebuf; \
__err_context->handled = true;
#define FINISH(__err_context, __pass_up) \
}; \
}; \
if ( __err_context != NULL ) { \
__err_context->stacktracebufptr += snprintf(__err_context->stacktracebufptr, AKERR_MAX_ERROR_STACKTRACE_BUF_LENGTH, "%s:%s:%d\n", (char *)__FILE__, (char *)__func__, __LINE__); \
if ( __err_context->handled == false && __pass_up == true && __err_context->arrayid > 0 ) { \
return __err_context; \
} else if ( __err_context->handled == false ) { \
LOG_ERROR_WITH_MESSAGE(__err_context, "Unhandled Error"); \
akerr_handler_unhandled_error(__err_context); \
} \
} \
RELEASE_ERROR(__err_context);
#define FINISH_NORETURN(__err_context) \
}; \
}; \
if ( __err_context != NULL ) { \
if ( __err_context->handled == false ) { \
LOG_ERROR_WITH_MESSAGE(__err_context, "Unhandled Error"); \
akerr_handler_unhandled_error(__err_context); \
} \
} \
RELEASE_ERROR(__err_context);
#define CATCH_AND_RETURN(__err_context, __stmt) \
ATTEMPT { \
CATCH(__err_context, __stmt); \
} CLEANUP { \
} PROCESS(__err_context) { \
} FINISH(__err_context, true);
#endif // _AKERR_H_