src/lib/error.c
branchnew-lib-errors
changeset 216 a10ba529ae39
child 217 7728d6ec3abf
--- /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);
+}
+