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