#include "error.h"
#include "log.h"
const struct error_list general_errors = ERROR_LIST("general",
ERROR_TYPE( ERR_MEM, "memory allocation error" ),
ERROR_TYPE_STRING( ERR_NOT_IMPLEMENTED, "function not implmented" ),
ERROR_TYPE_STRING( ERR_MISC, "miscellaneous error" ),
ERROR_TYPE_STRING( ERR_CMD_OPT, "invalid command line option" ),
ERROR_TYPE( ERR_UNKNOWN, "unknown error" )
);
const struct error_type* error_lookup_code (const struct error_list *list, err_t code)
{
const struct error_type *type;
// find matching code
for (type = list->list; type->code; type++) {
if (type->code == code)
// found
return type;
}
// not found
return NULL;
}
const struct error_type* error_lookup (const error_t *err)
{
struct error_item *item;
struct error_type *type = NULL, *list;
// traverse stack
for (item = err->cur; item && item >= err->stack; item--) {
if (!list)
// initial type
list = item->list;
// verify list/type
if (!list)
log_warn("Uknown type");
else if (!(type = error_lookup_code(list, item->code)))
log_warn("Uknown code %#04x for list %s", item->code, list->name);
else
// expected list for next item
list = type->sublist;
}
// return what we found
return type;
}
const char* error_name (const struct error_list *list, err_t code);
{
struct error_type *type;
// just do a lookup
if ((type = error_lookup_code(list, code)))
return "[unknown]";
else
return type->name;
}
const char* error_msg (const error_t *err)
{
// XXX: bad to have a single buffer
static char buf[ERROR_MSG_MAX];
char *buf_ptr = buf;
size_t buf_size = sizeof(buf);
struct error_item *item;
struct error_type *type;
// traverse stack
for (item = err->cur; item && item >= err->stack; item--) {
if (!list)
// initial lookup table
list = item->list;
// verify list/type
if (!list) {
// no type info at all
buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%#04x]", item->code));
} else if (!(type = error_lookup_code(list, item->code))) {
// couldn't find code in list
buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%s:%#02x]", list->name, item->code));
} else {
// found code's type
// delimit using colons, except at the end
buf_ptr += str_advance(&buf_size, NULL, str_append(buf_ptr, buf_size, "[%s] %s%s",
list->name, type->name, item == err->stack ? "" : ": "
));
// expected list for next item
list = type->sublist;
}
}
// add info for extra
if (err->extra_type != type->extra_type) {
// type mismatch
buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": [error_extra type mismatch: %s <=> %s",
err->extra_type ? err->extra_type->name : NULL,
item->extra_type ? item->extra_type->name : NULL
));
} else if (err->extra_type) {
// add extra info
buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": %s",
err->extra_type->msg_func(item->extra_type, &item->extra_value)
));
}
// ok, return message
return buf;
}
bool error_cmp_eq (const error_t *a, const error_t *b)
{
// XXX: implement
return true;
}
void error_reset (error_t *err)
{
memset(err, 0, sizeof(*err));
}
/**
* Advance error stack to next position, and return pointer.
*
* Returns NULL if the stack runs out of space.
*/
struct error_item* error_next (error_t *err)
{
if (!err->cur)
// initial position
return (err->cur = err->stack);
else if (err->cur < err->stack + ERR_DEPTH_MAX)
return (err->cur++);
else
return NULL;
}
void error_set (error_t *err, const struct error_list *list, err_t code)
{
struct error_item *item;
// empty
error_reset(err);
// next
if (!(item = error_next(err)))
return;
// store
item->code = code;
item->list = list;
}
void error_set_extra (error_t *err, const struct error_list *list, err_t code, const struct error_extra_type *type, union error_extra extra)
{
struct error_item *item;
// empty
error_reset(err);
// next
if (!(item = error_next(err)))
return;
// store
item->code = code;
item->list = list;
err->extra_type = type;
err->extra_value = extra;
}
void error_push (error_t *err, const struct error_list *list, err_t code)
{
struct error_item *item;
// next
if (!(item = error_next(err)))
return;
// store
item->code = code;
item->list = list;
}
void error_copy (error_t *dst, const error_t *src)
{
struct error_item *item;
// reset
error_reset(dst);
// copy each item
for (item = src->stack; src->cur && item <= src->cur; item++)
// push it on separately
error_push(dst, item->list, item->code);
// store extra
dst->extra_type = src->extra_type;
dst->extra_value = src->extra_value;
}
/*
* Weird trickery to call log_msg_va2 with the fmt's in the right order (prefix).
*
* XXX: log should provide similar functionality
*/
void _error_abort_ (const char *fmt2, va_list fmtargs2, const char *fmt1, ...)
{
va_list vargs;
va_start(vargs, fmt1);
_log_msg_va2(LOG_FATAL, "error_abort", fmt1, vargs, fmt2, fmtargs2);
va_end(vargs);
}
void _error_abort (const char *file, const char *line, const char *func, const char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
_error_abort_(fmt, vargs, "%s:%d[%s]", file, line, func);
va_end(vargs);
}