1 // -*- related-file-name: "../include/lcdf/error.hh" -*-
2 /*
3 * error.{cc,hh} -- flexible classes for error reporting
4 * Eddie Kohler
5 *
6 * Copyright (c) 1999-2000 Massachusetts Institute of Technology
7 * Copyright (c) 2001-2013 Eddie Kohler
8 * Copyright (c) 2008 Meraki, Inc.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, subject to the conditions
13 * listed in the Click LICENSE file. These conditions include: you must
14 * preserve this copyright notice, and you cannot mention the copyright
15 * holders in advertising related to the Software without their permission.
16 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
17 * notice is a summary of the Click LICENSE file; the license in that file is
18 * legally binding.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 #include <lcdf/error.hh>
25 #include <lcdf/straccum.hh>
26 #include <lcdf/hashmap.hh>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <algorithm>
30 #ifndef __KERNEL__
31 # include <stdlib.h>
32 # if HAVE_UNISTD_H
33 # include <unistd.h>
34 # endif
35 #endif
36
37 /** @file error.hh
38 * @brief Flexible error handling classes.
39 */
40
41 struct ErrorHandler::Conversion {
42 String name;
43 ConversionFunction hook;
44 Conversion *next;
45 };
46 static ErrorHandler::Conversion *error_items;
47
48 const char ErrorHandler::e_abort[] = "<-999>";
49 const char ErrorHandler::e_fatal[] = "<-1>";
50 const char ErrorHandler::e_emergency[] = "<0>";
51 const char ErrorHandler::e_alert[] = "<1>";
52 const char ErrorHandler::e_critical[] = "<2>";
53 const char ErrorHandler::e_error[] = "<3>";
54 const char ErrorHandler::e_warning[] = "<4>";
55 const char ErrorHandler::e_warning_annotated[] = "<4>warning: ";
56 const char ErrorHandler::e_notice[] = "<5>";
57 const char ErrorHandler::e_info[] = "<6>";
58 const char ErrorHandler::e_debug[] = "<7>";
59
60 const int ErrorHandler::ok_result = 0;
61 const int ErrorHandler::error_result = -EINVAL;
62
63 ErrorHandler *ErrorHandler::the_default_handler = 0;
64 ErrorHandler *ErrorHandler::the_silent_handler = 0;
65
66
67 // ANNOTATION MANAGEMENT
68
69 static const char *
parse_level(const char * begin,const char * end,int * result)70 parse_level(const char *begin, const char *end, int *result)
71 {
72 int x = 0;
73 const char *s = begin;
74
75 bool negative = false;
76 if (s != end && *s == '-') {
77 negative = true;
78 ++s;
79 } else if (s != end && *s == '+')
80 ++s;
81
82 const char *digits = s;
83 for (; s != end && *s >= '0' && *s <= '9'; ++s)
84 x = x * 10 + *s - '0';
85
86 if (s != end && *s == '.')
87 for (++s; s != end && *s >= '0' && *s <= '9'; ++s)
88 /* nada */;
89
90 if (s == digits || (s == digits + 1 && s[-1] == '.'))
91 return begin;
92 if (result)
93 *result = (negative ? -x : x);
94 return s;
95 }
96
97 String
make_anno(const char * name,const String & value)98 ErrorHandler::make_anno(const char *name, const String &value)
99 {
100 StringAccum sa;
101 sa.reserve(value.length() + 10);
102
103 // level annotation requires special handling
104 if (name[0] == '<' && name[1] == '>' && name[2] == 0) {
105 if (parse_level(value.begin(), value.end(), 0) == value.end()) {
106 sa << '<' << value << '>';
107 return sa.take_string();
108 } else
109 return String();
110 }
111
112 sa << '{' << name << ':';
113 const char *last = value.begin(), *end = value.end();
114 for (const char *s = value.begin(); s != end; ++s)
115 if (*s == '\\' || *s == '}') {
116 sa.append(last, s);
117 sa << '\\' << *s;
118 last = s + 1;
119 } else if (*s == '\n') {
120 sa.append(last, s);
121 sa << '\\' << 'n';
122 last = s + 1;
123 }
124 sa.append(last, end);
125 sa << '}';
126 return sa.take_string();
127 }
128
129 const char *
skip_anno(const String & str,const char * begin,const char * end,String * name_result,String * value_result,bool raw)130 ErrorHandler::skip_anno(const String &str, const char *begin, const char *end,
131 String *name_result, String *value_result, bool raw)
132 {
133 String name, value;
134 const char *s = begin;
135
136 if (s + 3 <= end && *s == '<') {
137 const char *x = parse_level(s + 1, end, 0);
138 if (x != s + 1 && x != end && *x == '>') {
139 name = String::make_stable("<>", 2);
140 if (str)
141 value = str.substring(begin + 1, x);
142 begin = x + 1;
143 }
144
145 } else if (s + 2 <= end && *s == '{' && s[1] == '}')
146 begin = s + 2;
147
148 else if (s + 3 <= end && *s == '{' && str) {
149 for (++s; s != end && isalnum((unsigned char) *s); ++s)
150 /* nada */;
151 if (s == end || s == begin + 1 || (*s != '}' && *s != ':'))
152 /* not an annotation */;
153 else if (*s == '}' && str) {
154 name = str.substring(begin + 1, s);
155 begin = s + 1;
156 } else if (*s == '}') {
157 name = String::make_stable("{}", 2);
158 begin = s + 1;
159 } else if (str) {
160 const char *x, *last = s + 1;
161 StringAccum sa;
162 for (x = s + 1; x != end && *x != '\n' && *x != '}'; ++x)
163 if (*x == '\\' && x + 1 != end && x[1] != '\n') {
164 if (!raw) {
165 sa.append(last, x);
166 sa << (x[1] == 'n' ? '\n' : x[1]);
167 last = x + 2;
168 }
169 ++x;
170 }
171 if (x != end && *x == '}') {
172 name = str.substring(begin + 1, s);
173 if (sa) {
174 sa.append(last, x);
175 value = sa.take_string();
176 } else
177 value = str.substring(s + 1, x);
178 begin = x + 1;
179 }
180 } else {
181 const char *x;
182 for (x = s + 1; x != end && *x != '\n' && *x != '}'; ++x)
183 if (*x == '\\' && x + 1 != end && x[1] != '\n')
184 ++x;
185 if (x != end && *x == '}') {
186 name = String::make_stable("{}", 2);
187 begin = x + 1;
188 }
189 }
190 }
191
192 if (name_result)
193 *name_result = name;
194 if (value_result)
195 *value_result = value;
196 return begin;
197 }
198
199 const char *
parse_anno(const String & str,const char * begin,const char * end,...)200 ErrorHandler::parse_anno(const String &str, const char *begin, const char *end,
201 ...)
202 {
203 const char *names[8];
204 void *values[8];
205 int nanno = 0;
206
207 va_list val;
208 va_start(val, end);
209 while (const char *n = va_arg(val, const char *)) {
210 assert(nanno < 8);
211 names[nanno] = n;
212 if (n[0] == '#')
213 values[nanno] = va_arg(val, int *);
214 else
215 values[nanno] = va_arg(val, String *);
216 ++nanno;
217 }
218
219 String name, value;
220 while (1) {
221 begin = skip_anno(str, begin, end, &name, &value, false);
222 if (!name)
223 break;
224 for (int i = 0; i < nanno; ++i)
225 if (names[i][0] == '#') {
226 if (name == (names[i] + 1))
227 parse_level(value.begin(), value.end(), (int *) values[i]);
228 } else {
229 if (name == names[i])
230 *(String *) values[i] = value;
231 }
232 }
233
234 return begin;
235 }
236
237 String
combine_anno(const String & text,const String & anno)238 ErrorHandler::combine_anno(const String &text, const String &anno)
239 {
240 if (!anno)
241 return text;
242
243 String names[8], values[8];
244 int nanno = 0;
245 const char *abegin = anno.begin();
246 while (abegin != anno.end()) {
247 assert(nanno < 8);
248 abegin = skip_anno(anno, abegin, anno.end(), &names[nanno], &values[nanno], true);
249 if (names[nanno])
250 ++nanno;
251 else
252 break;
253 }
254
255 const char *last = text.begin(), *s = last;
256 String name;
257 StringAccum sa;
258 while (s != text.end()) {
259 const char *line = s;
260 uint32_t mask = (1U << nanno) - 1;
261 while (1) {
262 s = skip_anno(text, s, text.end(), &name, 0, false);
263 if (!name)
264 break;
265 for (int i = 0; i < nanno; ++i)
266 if (name == names[i])
267 mask &= ~(1U << i);
268 }
269
270 if (mask) {
271 sa.append(last, line);
272 for (int i = 0; i < nanno; ++i)
273 if (mask & (1U << i)) {
274 if (names[i].equals("<>", 2))
275 sa << '<' << values[i] << '>';
276 else
277 sa << '{' << names[i] << ':' << values[i] << '}';
278 }
279 last = line;
280 }
281 if (abegin != anno.end()) {
282 sa.append(last, s);
283 sa.append(abegin, anno.end());
284 last = s;
285 }
286
287 while (s != text.end() && *s != '\n')
288 ++s;
289 if (s != text.end())
290 ++s;
291 }
292
293 if (sa) {
294 sa.append(last, text.end());
295 return sa.take_string();
296 } else
297 return text;
298 }
299
300 String
clean_landmark(const String & landmark,bool with_colon)301 ErrorHandler::clean_landmark(const String &landmark, bool with_colon)
302 {
303 const char *end = landmark.end();
304 while (end != landmark.begin() && isspace((unsigned char) end[-1]))
305 --end;
306 if (end != landmark.begin() && end[-1] == ':')
307 --end;
308 if (end == landmark.begin())
309 return String();
310 else if (with_colon)
311 return landmark.substring(landmark.begin(), end) + ": ";
312 else
313 return landmark.substring(landmark.begin(), end);
314 }
315
316
317 // FORMATTING
318
319 #define NUMBUF_SIZE 128
320 #define ErrH ErrorHandler
321
322 static char *
do_number(uintptr_t num,char * after_last,int base,int flags)323 do_number(uintptr_t num, char *after_last, int base, int flags)
324 {
325 const char *digits =
326 ((flags & ErrH::cf_uppercase) ? "0123456789ABCDEF" : "0123456789abcdef");
327 char *pos = after_last;
328 while (num) {
329 *--pos = digits[num % base];
330 num /= base;
331 }
332 if (pos == after_last)
333 *--pos = '0';
334 return pos;
335 }
336
337 static char *
do_number_flags(char * pos,char * after_last,int base,int flags,int precision,int field_width)338 do_number_flags(char *pos, char *after_last, int base, int flags,
339 int precision, int field_width)
340 {
341 // remove cf_alternate_form for zero results in base 16
342 if ((flags & ErrH::cf_alternate_form) && base == 16 && *pos == '0')
343 flags &= ~ErrH::cf_alternate_form;
344
345 // account for zero padding
346 if (precision >= 0)
347 while (after_last - pos < precision)
348 *--pos = '0';
349 else if (flags & ErrH::cf_zero_pad) {
350 if ((flags & ErrH::cf_alternate_form) && base == 16)
351 field_width -= 2;
352 if ((flags & ErrH::cf_negative)
353 || (flags & (ErrH::cf_plus_positive | ErrH::cf_space_positive)))
354 field_width--;
355 while (after_last - pos < field_width)
356 *--pos = '0';
357 }
358
359 // alternate forms
360 if ((flags & ErrH::cf_alternate_form) && base == 8 && pos[1] != '0')
361 *--pos = '0';
362 else if ((flags & ErrH::cf_alternate_form) && base == 16) {
363 *--pos = ((flags & ErrH::cf_uppercase) ? 'X' : 'x');
364 *--pos = '0';
365 }
366
367 // sign
368 if (flags & ErrH::cf_negative)
369 *--pos = '-';
370 else if (flags & ErrH::cf_plus_positive)
371 *--pos = '+';
372 else if (flags & ErrH::cf_space_positive)
373 *--pos = ' ';
374
375 return pos;
376 }
377
378 String
vxformat(int default_flags,const char * s,va_list val)379 ErrorHandler::vxformat(int default_flags, const char *s, va_list val)
380 {
381 StringAccum msg;
382
383 char numbuf[NUMBUF_SIZE]; // for numerics
384 numbuf[NUMBUF_SIZE-1] = 0;
385
386 String strstore; // to ensure temporaries aren't destroyed
387
388 // declare and initialize these here to make gcc shut up about possible
389 // use before initialization
390 int flags = 0;
391 int field_width = -1;
392 int precision = -1;
393 int width_flag = 0;
394 int base = 10;
395 while (1) {
396
397 const char *pct = strchr(s, '%');
398 if (!pct) {
399 if (*s)
400 msg << s;
401 break;
402 }
403 if (pct != s) {
404 msg.append(s, pct - s);
405 s = pct;
406 }
407
408 // parse flags
409 flags = default_flags;
410 flags:
411 switch (*++s) {
412 case '#': flags |= cf_alternate_form; goto flags;
413 case '0': flags |= cf_zero_pad; goto flags;
414 case '-': flags |= cf_left_just; goto flags;
415 case ' ': flags |= cf_space_positive; goto flags;
416 case '+': flags |= cf_plus_positive; goto flags;
417 case '\'': flags |= cf_singlequote; goto flags;
418 case '_': flags &= ~cf_utf8; goto flags;
419 }
420
421 // parse field width
422 field_width = -1;
423 if (*s == '*') {
424 field_width = va_arg(val, int);
425 if (field_width < 0) {
426 field_width = -field_width;
427 flags |= cf_left_just;
428 }
429 s++;
430 } else if (*s >= '0' && *s <= '9')
431 for (field_width = 0; *s >= '0' && *s <= '9'; s++)
432 field_width = 10*field_width + *s - '0';
433
434 // parse precision
435 precision = -1;
436 if (*s == '.') {
437 s++;
438 precision = 0;
439 if (*s == '*') {
440 precision = va_arg(val, int);
441 s++;
442 } else if (*s >= '0' && *s <= '9')
443 for (; *s >= '0' && *s <= '9'; s++)
444 precision = 10*precision + *s - '0';
445 }
446
447 // parse width flags
448 width_flag = 0;
449 width_flags:
450 switch (*s) {
451 case 'h': case 'l':
452 if (width_flag == *s)
453 width_flag = *s + 'A' - 'a';
454 else if (width_flag)
455 break;
456 else
457 width_flag = *s;
458 s++;
459 goto width_flags;
460 case 'z':
461 if (width_flag)
462 break;
463 width_flag = *s++;
464 break;
465 case '^':
466 if (!isdigit((unsigned char) s[1]) || width_flag)
467 break;
468 for (s++; isdigit((unsigned char) *s); s++)
469 width_flag = width_flag * 10 + *s - '0';
470 width_flag = -width_flag;
471 break;
472 }
473
474 // conversion character
475 // after switch, data lies between `s1' and `s2'
476 const char *s1 = 0, *s2 = 0;
477 base = 10;
478 switch (*s++) {
479
480 case 's': {
481 s1 = va_arg(val, const char *);
482 if (!s1)
483 s1 = "(null)";
484
485 // fetch length
486 int len;
487 if (precision < 0)
488 len = strlen(s1);
489 else
490 len = strnlen(s1, precision);
491
492 // transform string if alternate form
493 if (flags & cf_alternate_form) {
494 strstore = String(s1, len).printable();
495 if (precision < 0 || strstore.length() < precision)
496 len = strstore.length();
497 }
498
499 // quote characters that look like annotations, readjusting length
500 if (flags & (cf_singlequote | cf_alternate_form)) {
501 if (!(flags & cf_alternate_form))
502 strstore = String(s1, len);
503
504 // check first line, considering trailing part of 'msg'
505 const char *mbegin = msg.end();
506 while (mbegin != msg.begin() && mbegin[-1] != '\n')
507 --mbegin;
508 if (skip_anno(strstore.begin(), strstore.end()) != strstore.begin()
509 && skip_anno(mbegin, msg.end()) == msg.end()) {
510 strstore = String::make_stable("{}", 2) + strstore;
511 len += 2;
512 }
513
514 // check subsequent lines
515 const char *s = std::find(strstore.begin(), strstore.end(), '\n');
516 while (s != strstore.end() && s + 1 != strstore.end()) {
517 size_t nextpos = (s + 1) - strstore.begin();
518 if (skip_anno(s + 1, strstore.end()) != s + 1) {
519 strstore = strstore.substring(strstore.begin(), s + 1)
520 + String::make_stable("{}", 2)
521 + strstore.substring(s + 1, strstore.end());
522 len += 2;
523 }
524 s = std::find(strstore.begin() + nextpos, strstore.end(), '\n');
525 }
526 }
527
528 // obtain begin and end pointers
529 if (flags & (cf_singlequote | cf_alternate_form))
530 s1 = strstore.begin();
531 s2 = s1 + len;
532 break;
533 }
534
535 case 'c': {
536 int c = va_arg(val, int);
537 // check for extension of 'signed char' to 'int'
538 if (c < 0)
539 c += 256;
540 // assume ASCII
541 if (c == '\n')
542 strcpy(numbuf, "\\n");
543 else if (c == '\t')
544 strcpy(numbuf, "\\t");
545 else if (c == '\r')
546 strcpy(numbuf, "\\r");
547 else if (c == '\0')
548 strcpy(numbuf, "\\0");
549 else if (c < 0 || c >= 256)
550 strcpy(numbuf, "(bad char)");
551 else if (c < 32 || c >= 0177)
552 sprintf(numbuf, "\\%03o", c);
553 else
554 sprintf(numbuf, "%c", c);
555 s1 = numbuf;
556 s2 = strchr(numbuf, 0);
557 break;
558 }
559
560 case '%': {
561 numbuf[0] = '%';
562 s1 = numbuf;
563 s2 = s1 + 1;
564 break;
565 }
566
567 case '<':
568 s1 = (flags & cf_utf8 ? "\342\200\230" : "\'");
569 s2 = s1 + strlen(s1);
570 break;
571
572 case '>':
573 case ',':
574 s1 = (flags & cf_utf8 ? "\342\200\231" : "\'");
575 s2 = s1 + strlen(s1);
576 break;
577
578 case 'd':
579 case 'i':
580 flags |= cf_signed;
581 case 'u':
582 number: {
583 // protect numbuf from overflow
584 if (field_width > NUMBUF_SIZE)
585 field_width = NUMBUF_SIZE;
586 if (precision > NUMBUF_SIZE - 4)
587 precision = NUMBUF_SIZE - 4;
588
589 s2 = numbuf + NUMBUF_SIZE;
590
591 unsigned long num;
592 switch (width_flag) {
593 case 'H':
594 case -8:
595 num = (unsigned char) va_arg(val, int);
596 if ((flags & cf_signed) && (signed char) num < 0)
597 num = -(signed char) num, flags |= cf_negative;
598 break;
599 case 'h':
600 case -16:
601 num = (unsigned short) va_arg(val, int);
602 if ((flags & cf_signed) && (short) num < 0)
603 num = -(short) num, flags |= cf_negative;
604 break;
605 case 0:
606 case -32:
607 #if SIZEOF_LONG == 4
608 case 'l':
609 #endif
610 #if SIZEOF_SIZE_T == 4
611 case 'z':
612 #endif
613 num = va_arg(val, unsigned);
614 if ((flags & cf_signed) && (int) num < 0)
615 num = -(int) num, flags |= cf_negative;
616 break;
617 #if HAVE_INT64_TYPES
618 # if SIZEOF_LONG == 8
619 case 'l':
620 # endif
621 # if SIZEOF_LONG_LONG == 8
622 case 'L':
623 # endif
624 # if SIZEOF_SIZE_T == 8
625 case 'z':
626 # endif
627 case -64: {
628 uint64_t qnum = va_arg(val, uint64_t);
629 if ((flags & cf_signed) && (int64_t)qnum < 0)
630 qnum = -(int64_t) qnum, flags |= cf_negative;
631 StringAccum sa;
632 sa.append_numeric(static_cast<String::uintmax_t>(qnum), base, (flags & cf_uppercase));
633 s1 = s2 - sa.length();
634 memcpy(const_cast<char*>(s1), sa.data(), s2 - s1);
635 goto got_number;
636 }
637 #endif
638 default:
639 goto error;
640 }
641 s1 = do_number(num, (char *)s2, base, flags);
642
643 #if HAVE_INT64_TYPES
644 got_number:
645 #endif
646 s1 = do_number_flags((char *)s1, (char *)s2, base, flags,
647 precision, field_width);
648 break;
649 }
650
651 case 'o':
652 base = 8;
653 goto number;
654
655 case 'X':
656 flags |= cf_uppercase;
657 case 'x':
658 base = 16;
659 goto number;
660
661 case 'p': {
662 if (*s == '{') {
663 s1 = s2 = s + 1;
664 while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2))
665 ++s2;
666 if (*s2 == '}')
667 goto braces;
668 }
669 void *v = va_arg(val, void *);
670 s2 = numbuf + NUMBUF_SIZE;
671 s1 = do_number((uintptr_t)v, (char *)s2, 16, flags);
672 s1 = do_number_flags((char *)s1, (char *)s2, 16, flags | cf_alternate_form,
673 precision, field_width);
674 break;
675 }
676
677 #ifndef __KERNEL__
678 case 'e': case 'f': case 'g':
679 case 'E': case 'F': case 'G': {
680 char format[80], *f = format, new_numbuf[NUMBUF_SIZE];
681 *f++ = '%';
682 if (flags & cf_alternate_form)
683 *f++ = '#';
684 if (precision >= 0)
685 f += sprintf(f, ".%d", precision);
686 *f++ = s[-1];
687 *f++ = 0;
688
689 int len = sprintf(new_numbuf, format, va_arg(val, double));
690
691 s2 = numbuf + NUMBUF_SIZE;
692 s1 = s2 - len;
693 memcpy((char *)s1, new_numbuf, len); // note: no terminating \0
694 s1 = do_number_flags((char *)s1, (char *)s2, 10, flags & ~cf_alternate_form, -1, field_width);
695 break;
696 }
697 #endif
698
699 case '{':
700 s1 = s2 = s;
701 while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2))
702 ++s2;
703 if (*s2 != '}')
704 goto error;
705 goto braces;
706
707 braces:
708 s = s2 + 1;
709 for (Conversion *item = error_items; item; item = item->next)
710 if (item->name.equals(s1, s2 - s1)) {
711 strstore = item->hook(flags, VA_LIST_REF(val));
712 s1 = strstore.begin();
713 s2 = strstore.end();
714 goto got_result;
715 }
716 goto error;
717
718 error:
719 default:
720 assert(0 /* Bad % in error */);
721 break;
722
723 }
724
725 // add result of conversion
726 got_result:
727 int slen = s2 - s1;
728 if (slen > field_width)
729 field_width = slen;
730 char *dest = msg.extend(field_width);
731 if (flags & cf_left_just) {
732 memcpy(dest, s1, slen);
733 memset(dest + slen, ' ', field_width - slen);
734 } else {
735 memcpy(dest + field_width - slen, s1, slen);
736 memset(dest, (flags & cf_zero_pad ? '0' : ' '), field_width - slen);
737 }
738 }
739
740 return msg.take_string();
741 }
742
743 String
xformat(int default_flags,const char * fmt,...)744 ErrorHandler::xformat(int default_flags, const char *fmt, ...)
745 {
746 va_list val;
747 va_start(val, fmt);
748 String s = vxformat(default_flags, fmt, val);
749 va_end(val);
750 return s;
751 }
752
753 String
xformat(const char * fmt,...)754 ErrorHandler::xformat(const char *fmt, ...)
755 {
756 va_list val;
757 va_start(val, fmt);
758 String s = vxformat(0, fmt, val);
759 va_end(val);
760 return s;
761 }
762
763 String
format(const char * fmt,...)764 ErrorHandler::format(const char *fmt, ...)
765 {
766 va_list val;
767 va_start(val, fmt);
768 String s = vformat(fmt, val);
769 va_end(val);
770 return s;
771 }
772
773
774 // ERROR MESSAGE SHORTHAND
775
776 void
debug(const char * fmt,...)777 ErrorHandler::debug(const char *fmt, ...)
778 {
779 va_list val;
780 va_start(val, fmt);
781 vxmessage(String::make_stable(e_debug, 3), fmt, val);
782 va_end(val);
783 }
784
785 void
message(const char * fmt,...)786 ErrorHandler::message(const char *fmt, ...)
787 {
788 va_list val;
789 va_start(val, fmt);
790 vxmessage(String::make_stable(e_info, 3), fmt, val);
791 va_end(val);
792 }
793
794 int
warning(const char * fmt,...)795 ErrorHandler::warning(const char *fmt, ...)
796 {
797 va_list val;
798 va_start(val, fmt);
799 int r = vxmessage(String::make_stable(e_warning_annotated, 12), fmt, val);
800 va_end(val);
801 return r;
802 }
803
804 int
error(const char * fmt,...)805 ErrorHandler::error(const char *fmt, ...)
806 {
807 va_list val;
808 va_start(val, fmt);
809 int r = vxmessage(String::make_stable(e_error, 3), fmt, val);
810 va_end(val);
811 return r;
812 }
813
814 int
fatal(const char * fmt,...)815 ErrorHandler::fatal(const char *fmt, ...)
816 {
817 va_list val;
818 va_start(val, fmt);
819 int r = vxmessage(String::make_stable(e_fatal, 4), fmt, val);
820 va_end(val);
821 return r;
822 }
823
824 void
ldebug(const String & landmark,const char * fmt,...)825 ErrorHandler::ldebug(const String &landmark, const char *fmt, ...)
826 {
827 va_list val;
828 va_start(val, fmt);
829 String l = make_landmark_anno(landmark);
830 vxmessage(String::make_stable(e_debug, 3) + l, fmt, val);
831 va_end(val);
832 }
833
834 void
lmessage(const String & landmark,const char * fmt,...)835 ErrorHandler::lmessage(const String &landmark, const char *fmt, ...)
836 {
837 va_list val;
838 va_start(val, fmt);
839 String l = make_landmark_anno(landmark);
840 vxmessage(String::make_stable(e_info, 3) + l, fmt, val);
841 va_end(val);
842 }
843
844 int
lwarning(const String & landmark,const char * fmt,...)845 ErrorHandler::lwarning(const String &landmark, const char *fmt, ...)
846 {
847 va_list val;
848 va_start(val, fmt);
849 String l = make_landmark_anno(landmark);
850 int r = vxmessage(l + String::make_stable(e_warning_annotated, 12), fmt, val);
851 va_end(val);
852 return r;
853 }
854
855 int
lerror(const String & landmark,const char * fmt,...)856 ErrorHandler::lerror(const String &landmark, const char *fmt, ...)
857 {
858 va_list val;
859 va_start(val, fmt);
860 String l = make_landmark_anno(landmark);
861 int r = vxmessage(String::make_stable(e_error, 3) + l, fmt, val);
862 va_end(val);
863 return r;
864 }
865
866 int
lfatal(const String & landmark,const char * fmt,...)867 ErrorHandler::lfatal(const String &landmark, const char *fmt, ...)
868 {
869 va_list val;
870 va_start(val, fmt);
871 String l = make_landmark_anno(landmark);
872 int r = vxmessage(String::make_stable(e_fatal, 4) + l, fmt, val);
873 va_end(val);
874 return r;
875 }
876
877 int
xmessage(const String & str)878 ErrorHandler::xmessage(const String &str)
879 {
880 String xstr = decorate(str);
881
882 int min_level = 1000, xlevel = 1000;
883 const char *s = xstr.begin(), *end = xstr.end();
884 void *user_data = 0;
885 while (s != end) {
886 const char *l = parse_anno(xstr, s, end, "#<>", &xlevel,
887 (const char *) 0);
888 const char *nl = std::find(l, end, '\n');
889 String line = xstr.substring(s, nl);
890 s = nl + (nl != end);
891 user_data = emit(line, user_data, s != end);
892 min_level = (xlevel < min_level ? xlevel : min_level);
893 }
894
895 account(min_level);
896
897 return (min_level <= el_warning ? error_result : ok_result);
898 }
899
900 String
vformat(const char * fmt,va_list val)901 ErrorHandler::vformat(const char *fmt, va_list val)
902 {
903 return vxformat(0, fmt, val);
904 }
905
906 String
decorate(const String & str)907 ErrorHandler::decorate(const String &str)
908 {
909 return str;
910 }
911
912 void *
emit(const String &,void * user_data,bool)913 ErrorHandler::emit(const String &, void *user_data, bool)
914 {
915 return user_data;
916 }
917
918
919 #ifndef __KERNEL__
920 //
921 // FILE ERROR HANDLER
922 //
923
FileErrorHandler(FILE * f,const String & context)924 FileErrorHandler::FileErrorHandler(FILE *f, const String &context)
925 : _f(f), _context(context), _default_flags(0)
926 {
927 # if HAVE_UNISTD_H
928 if (isatty(fileno(_f))) {
929 # endif
930 char *s = getenv("LANG");
931 if (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0
932 || strstr(s, "utf8") != 0))
933 _default_flags |= cf_utf8;
934 # if HAVE_UNISTD_H
935 }
936 # endif
937 }
938
939 String
vformat(const char * fmt,va_list val)940 FileErrorHandler::vformat(const char *fmt, va_list val)
941 {
942 return vxformat(_default_flags, fmt, val);
943 }
944
945 void *
emit(const String & str,void *,bool)946 FileErrorHandler::emit(const String &str, void *, bool)
947 {
948 String landmark;
949 const char *s = parse_anno(str, str.begin(), str.end(),
950 "l", &landmark, (const char *) 0);
951 StringAccum sa;
952 sa << _context << clean_landmark(landmark, true)
953 << str.substring(s, str.end()) << '\n';
954 ssize_t result = fwrite(sa.begin(), 1, sa.length(), _f);
955 (void) result;
956 return 0;
957 }
958
959 void
account(int level)960 FileErrorHandler::account(int level)
961 {
962 ErrorHandler::account(level);
963 if (level <= el_abort)
964 abort();
965 else if (level <= el_fatal)
966 exit(-level);
967 }
968
969 #endif
970
971
972 //
973 // STATIC ERROR HANDLERS
974 //
975
976 ErrorHandler::Conversion *
add_conversion(const String & name,ConversionFunction function)977 ErrorHandler::add_conversion(const String &name, ConversionFunction function)
978 {
979 if (Conversion *c = new Conversion) {
980 c->name = name;
981 c->hook = function;
982 c->next = error_items;
983 error_items = c;
984 return c;
985 } else
986 return 0;
987 }
988
989 int
remove_conversion(ErrorHandler::Conversion * conv)990 ErrorHandler::remove_conversion(ErrorHandler::Conversion *conv)
991 {
992 Conversion **pprev = &error_items;
993 for (Conversion *c = error_items; c; pprev = &c->next, c = *pprev)
994 if (c == conv) {
995 *pprev = c->next;
996 delete c;
997 return 0;
998 }
999 return -1;
1000 }
1001
1002 ErrorHandler *
static_initialize(ErrorHandler * default_handler)1003 ErrorHandler::static_initialize(ErrorHandler *default_handler)
1004 {
1005 if (!the_silent_handler) {
1006 the_default_handler = default_handler;
1007 the_silent_handler = new SilentErrorHandler;
1008 }
1009 return default_handler;
1010 }
1011
1012 void
static_cleanup()1013 ErrorHandler::static_cleanup()
1014 {
1015 delete the_default_handler;
1016 delete the_silent_handler;
1017 the_default_handler = the_silent_handler = 0;
1018 while (error_items) {
1019 Conversion *next = error_items->next;
1020 delete error_items;
1021 error_items = next;
1022 }
1023 }
1024
1025 void
set_default_handler(ErrorHandler * errh)1026 ErrorHandler::set_default_handler(ErrorHandler *errh)
1027 {
1028 the_default_handler = errh;
1029 }
1030
1031
1032 //
1033 // ERROR VENEER
1034 //
1035
1036 String
vformat(const char * fmt,va_list val)1037 ErrorVeneer::vformat(const char *fmt, va_list val)
1038 {
1039 if (_errh)
1040 return _errh->vformat(fmt, val);
1041 else
1042 return ErrorHandler::vformat(fmt, val);
1043 }
1044
1045 String
decorate(const String & str)1046 ErrorVeneer::decorate(const String &str)
1047 {
1048 if (_errh)
1049 return _errh->decorate(str);
1050 else
1051 return ErrorHandler::decorate(str);
1052 }
1053
1054 void *
emit(const String & str,void * user_data,bool more)1055 ErrorVeneer::emit(const String &str, void *user_data, bool more)
1056 {
1057 if (_errh)
1058 return _errh->emit(str, user_data, more);
1059 else
1060 return ErrorHandler::emit(str, user_data, more);
1061 }
1062
1063 void
account(int level)1064 ErrorVeneer::account(int level)
1065 {
1066 ErrorHandler::account(level);
1067 if (_errh)
1068 _errh->account(level);
1069 }
1070
1071
1072 //
1073 // CONTEXT ERROR HANDLER
1074 //
1075
ContextErrorHandler(ErrorHandler * errh,const char * fmt,...)1076 ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, const char *fmt,
1077 ...)
1078 : ErrorVeneer(errh), _indent(String::make_stable(" ", 2)),
1079 _context_printed(false)
1080 {
1081 va_list val;
1082 va_start(val, fmt);
1083 _context = ErrorVeneer::vformat(fmt, val);
1084 va_end(val);
1085 if (_context)
1086 _context = combine_anno(_context, String::make_stable("{context:context}", 17));
1087 }
1088
1089 String
decorate(const String & str)1090 ContextErrorHandler::decorate(const String &str)
1091 {
1092 String context_anno;
1093 const char *str_endanno = parse_anno(str, str.begin(), str.end(),
1094 "context", &context_anno,
1095 (const char *) 0);
1096 if (context_anno.equals("no", 2))
1097 return ErrorVeneer::decorate(str);
1098
1099 String istr;
1100 if (context_anno.equals("noindent", 8))
1101 istr = combine_anno(str, _context_landmark);
1102 else
1103 istr = combine_anno(str, _context_landmark + _indent);
1104
1105 if (!_context_printed && !context_anno.equals("nocontext", 9)) {
1106 String astr = combine_anno(combine_anno(_context, _context_landmark),
1107 str.substring(str.begin(), str_endanno));
1108 if (astr && astr.back() != '\n')
1109 astr += '\n';
1110 _context_printed = true;
1111 return ErrorVeneer::decorate(astr + istr);
1112 } else
1113 return ErrorVeneer::decorate(istr);
1114 }
1115
1116
1117 //
1118 // PREFIX ERROR HANDLER
1119 //
1120
PrefixErrorHandler(ErrorHandler * errh,const String & prefix)1121 PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh,
1122 const String &prefix)
1123 : ErrorVeneer(errh), _prefix(prefix)
1124 {
1125 }
1126
1127 String
decorate(const String & str)1128 PrefixErrorHandler::decorate(const String &str)
1129 {
1130 return ErrorVeneer::decorate(combine_anno(str, _prefix));
1131 }
1132
1133
1134 //
1135 // LANDMARK ERROR HANDLER
1136 //
1137
LandmarkErrorHandler(ErrorHandler * errh,const String & landmark)1138 LandmarkErrorHandler::LandmarkErrorHandler(ErrorHandler *errh, const String &landmark)
1139 : ErrorVeneer(errh), _landmark(make_landmark_anno(landmark))
1140 {
1141 }
1142
1143 String
decorate(const String & str)1144 LandmarkErrorHandler::decorate(const String &str)
1145 {
1146 return ErrorVeneer::decorate(combine_anno(str, _landmark));
1147 }
1148
1149
1150 //
1151 // BAIL ERROR HANDLER
1152 //
1153
1154 #ifndef __KERNEL__
1155
BailErrorHandler(ErrorHandler * errh,int l)1156 BailErrorHandler::BailErrorHandler(ErrorHandler *errh, int l)
1157 : ErrorVeneer(errh), _level(l)
1158 {
1159 }
1160
1161 void
account(int level)1162 BailErrorHandler::account(int level)
1163 {
1164 ErrorVeneer::account(level);
1165 if (level <= _level)
1166 exit(1);
1167 }
1168
1169 #endif
1170