|
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 |