src/lib/error.c
branchnew-lib-errors
changeset 216 a10ba529ae39
child 217 7728d6ec3abf
equal deleted inserted replaced
215:85863b89e38b 216:a10ba529ae39
       
     1 #include "error.h"
       
     2 #include "log.h"
       
     3 
       
     4 const struct error_type* error_lookup_code (const struct error_list *list, err_t code)
       
     5 {
       
     6     const struct error_type *type;
       
     7 
       
     8     // find matching code
       
     9     for (type = list->list; type->code; type++) {
       
    10         if (type->code == code)
       
    11             // found
       
    12             return type;
       
    13     }
       
    14     
       
    15     // not found
       
    16     return NULL;
       
    17 }
       
    18 
       
    19 const struct error_type* error_lookup (const error_t *err)
       
    20 {
       
    21     struct error_item *item;
       
    22     struct error_type *type = NULL, *list;
       
    23 
       
    24     // traverse stack
       
    25     for (item = err->cur; item && item >= err->stack; item--) {
       
    26         if (!list)
       
    27             // initial type
       
    28             list = item->list;
       
    29 
       
    30         // verify list/type
       
    31         if (!list)
       
    32             log_warn("Uknown type");
       
    33 
       
    34         else if (!(type = error_lookup_code(list, item->code)))
       
    35             log_warn("Uknown code %#04x for list %s", item->code, list->name);
       
    36 
       
    37         else
       
    38             // expected list for next item
       
    39             list = type->sublist;
       
    40     }
       
    41 
       
    42     // return what we found
       
    43     return type;
       
    44 }
       
    45 
       
    46 const char* error_name (const error_t *err)
       
    47 {
       
    48     struct error_type *type;
       
    49     
       
    50     // just do a lookup
       
    51     if ((type = error_lookup(err)))
       
    52         return "[unknown]";
       
    53 
       
    54     else
       
    55         return type->name;
       
    56 }
       
    57 
       
    58 const char* error_msg (const error_t *err)
       
    59 {
       
    60     // XXX: bad to have a single buffer
       
    61     static char buf[ERROR_MSG_MAX];
       
    62 
       
    63     char *buf_ptr = buf; 
       
    64     size_t buf_size = sizeof(buf);
       
    65 
       
    66     struct error_item *item;
       
    67     struct error_type *type;
       
    68 
       
    69     // traverse stack
       
    70     for (item = err->cur; item && item >= err->stack; item--) {
       
    71         if (!list)
       
    72             // initial lookup table
       
    73             list = item->list;
       
    74 
       
    75         // verify list/type
       
    76         if (!list) {
       
    77             // no type info at all
       
    78             buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%#04x]", item->code));
       
    79 
       
    80         } else if (!(type = error_lookup_code(list, item->code))) {
       
    81             // couldn't find code in list
       
    82             buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%s:%#02x]", list->name, item->code));
       
    83 
       
    84         } else {
       
    85             // found code's type
       
    86             // delimit using colons, except at the end
       
    87             buf_ptr += str_advance(&buf_size, NULL, str_append(buf_ptr, buf_size, "[%s] %s%s", 
       
    88                 list->name, type->name, item == err->stack ? "" : ": "
       
    89             ));
       
    90 
       
    91             // expected list for next item
       
    92             list = type->sublist;
       
    93         }
       
    94     }
       
    95     
       
    96     // add info for extra
       
    97     if (err->extra_type != type->extra_type) {
       
    98         // type mismatch
       
    99         buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": [error_extra type mismatch: %s <=> %s",
       
   100             err->extra_type ? err->extra_type->name : NULL,
       
   101             item->extra_type ? item->extra_type->name : NULL
       
   102         ));
       
   103 
       
   104     } else if (err->extra_type) {
       
   105         // add extra info
       
   106         buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": %s", 
       
   107             err->extra_type->msg_func(item->extra_type, &item->extra_value)
       
   108         ));
       
   109 
       
   110     }
       
   111     
       
   112     // ok, return message
       
   113     return buf;
       
   114 }
       
   115 
       
   116 bool error_cmp_eq (const error_t *a, const error_t *b)
       
   117 {
       
   118     // XXX: implement
       
   119     return true;
       
   120 }
       
   121 
       
   122 /**
       
   123  * Advance error stack to next position, and return pointer.
       
   124  *
       
   125  * Returns NULL if the stack runs out of space.
       
   126  */
       
   127 struct error_item* error_next (error_t *err)
       
   128 {
       
   129     if (!err->cur)
       
   130         // initial position
       
   131         return (err->cur = err->stack);
       
   132 
       
   133     else if (err->cur < err->stack + ERR_DEPTH_MAX)
       
   134         return (err->cur++);
       
   135 
       
   136     else
       
   137         return NULL;
       
   138 }
       
   139 
       
   140 void error_set (error_t *err, const struct error_list *list, err_t code)
       
   141 {
       
   142     struct error_item *item;
       
   143 
       
   144     // empty
       
   145     error_reset(err);
       
   146 
       
   147     // next
       
   148     if (!(item = error_next(err)))
       
   149         return;
       
   150 
       
   151     // store
       
   152     item->code = code;
       
   153     item->list = list;
       
   154 }
       
   155 
       
   156 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)
       
   157 {
       
   158     struct error_item *item;
       
   159 
       
   160     // empty
       
   161     error_reset(err);
       
   162 
       
   163     // next
       
   164     if (!(item = error_next(err)))
       
   165         return;
       
   166 
       
   167     // store
       
   168     item->code = code;
       
   169     item->list = list;
       
   170     err->extra_type = type;
       
   171     err->extra_value = extra;
       
   172 }
       
   173 
       
   174 void error_push (error_t *err, const struct error_list *list, err_t code)
       
   175 {
       
   176     struct error_item *item;
       
   177 
       
   178     // next
       
   179     if (!(item = error_next(err)))
       
   180         return;
       
   181 
       
   182     // store
       
   183     item->code = code;
       
   184     item->list = list;
       
   185 }
       
   186 
       
   187 void error_copy (error_t *dst, const error_t *src)
       
   188 {
       
   189     struct error_item *item;
       
   190 
       
   191     // reset
       
   192     error_reset(dst);
       
   193 
       
   194     // copy each item
       
   195     for (item = src->stack; src->cur && item <= src->cur; item++)
       
   196         // push it on separately
       
   197         error_push(dst, item->list, item->code);
       
   198 
       
   199     // store extra
       
   200     dst->extra_type = src->extra_type;
       
   201     dst->extra_value = src->extra_value;
       
   202 }
       
   203 
       
   204 /*
       
   205  * Weird trickery to call log_msg_va2 with the fmt's in the right order (prefix).
       
   206  *
       
   207  * XXX: log should provide similar functionality
       
   208  */
       
   209 void _error_abort_ (const char *fmt2, va_list fmtargs2, const char *fmt1, ...)
       
   210 {
       
   211     va_list vargs;
       
   212 
       
   213     va_start(vargs, fmt1);
       
   214     _log_msg_va2(LOG_FATAL, "error_abort", fmt1, vargs, fmt2, fmtargs2);
       
   215     va_end(vargs);
       
   216 }
       
   217 
       
   218 void _error_abort (const char *file, const char *line, const char *func, const char *fmt, ...)
       
   219 {
       
   220     va_list vargs;
       
   221 
       
   222     va_start(vargs, fmt);
       
   223     _error_abort_(fmt, vargs, "%s:%d[%s]", file, line, func);
       
   224     va_end(vargs);
       
   225 }
       
   226