--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/error.c Wed May 27 23:07:00 2009 +0300
@@ -0,0 +1,226 @@
+#include "error.h"
+#include "log.h"
+
+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 error_t *err)
+{
+ struct error_type *type;
+
+ // just do a lookup
+ if ((type = error_lookup(err)))
+ 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;
+}
+
+/**
+ * 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);
+}
+