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-2019 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 #if SIZEOF_UNSIGNED_LONG >= SIZEOF_VOID_P
323 typedef unsigned long do_number_t;
324 #else
325 typedef uintptr_t do_number_t;
326 #endif
327
328 static char*
do_number(do_number_t num,char * after_last,int base,int flags)329 do_number(do_number_t num, char *after_last, int base, int flags)
330 {
331 const char *digits =
332 ((flags & ErrH::cf_uppercase) ? "0123456789ABCDEF" : "0123456789abcdef");
333 char *pos = after_last;
334 while (num) {
335 *--pos = digits[num % base];
336 num /= base;
337 }
338 if (pos == after_last)
339 *--pos = '0';
340 return pos;
341 }
342
343 static char *
do_number_flags(char * pos,char * after_last,int base,int flags,int precision,int field_width)344 do_number_flags(char *pos, char *after_last, int base, int flags,
345 int precision, int field_width)
346 {
347 // remove cf_alternate_form for zero results in base 16
348 if ((flags & ErrH::cf_alternate_form) && base == 16 && *pos == '0')
349 flags &= ~ErrH::cf_alternate_form;
350
351 // account for zero padding
352 if (precision >= 0)
353 while (after_last - pos < precision)
354 *--pos = '0';
355 else if (flags & ErrH::cf_zero_pad) {
356 if ((flags & ErrH::cf_alternate_form) && base == 16)
357 field_width -= 2;
358 if ((flags & ErrH::cf_negative)
359 || (flags & (ErrH::cf_plus_positive | ErrH::cf_space_positive)))
360 field_width--;
361 while (after_last - pos < field_width)
362 *--pos = '0';
363 }
364
365 // alternate forms
366 if ((flags & ErrH::cf_alternate_form) && base == 8 && pos[1] != '0')
367 *--pos = '0';
368 else if ((flags & ErrH::cf_alternate_form) && base == 16) {
369 *--pos = ((flags & ErrH::cf_uppercase) ? 'X' : 'x');
370 *--pos = '0';
371 }
372
373 // sign
374 if (flags & ErrH::cf_negative)
375 *--pos = '-';
376 else if (flags & ErrH::cf_plus_positive)
377 *--pos = '+';
378 else if (flags & ErrH::cf_space_positive)
379 *--pos = ' ';
380
381 return pos;
382 }
383
384 String
vxformat(int default_flags,const char * s,va_list val)385 ErrorHandler::vxformat(int default_flags, const char *s, va_list val)
386 {
387 StringAccum msg;
388
389 char numbuf[NUMBUF_SIZE]; // for numerics
390 numbuf[NUMBUF_SIZE-1] = 0;
391
392 String strstore; // to ensure temporaries aren't destroyed
393
394 // declare and initialize these here to make gcc shut up about possible
395 // use before initialization
396 int flags = 0;
397 int field_width = -1;
398 int precision = -1;
399 int width_flag = 0;
400 int base = 10;
401 while (1) {
402
403 const char *pct = strchr(s, '%');
404 if (!pct) {
405 if (*s)
406 msg << s;
407 break;
408 }
409 if (pct != s) {
410 msg.append(s, pct - s);
411 s = pct;
412 }
413
414 // parse flags
415 flags = default_flags;
416 flags:
417 switch (*++s) {
418 case '#': flags |= cf_alternate_form; goto flags;
419 case '0': flags |= cf_zero_pad; goto flags;
420 case '-': flags |= cf_left_just; goto flags;
421 case ' ': flags |= cf_space_positive; goto flags;
422 case '+': flags |= cf_plus_positive; goto flags;
423 case '\'': flags |= cf_singlequote; goto flags;
424 case '_': flags &= ~cf_utf8; goto flags;
425 }
426
427 // parse field width
428 field_width = -1;
429 if (*s == '*') {
430 field_width = va_arg(val, int);
431 if (field_width < 0) {
432 field_width = -field_width;
433 flags |= cf_left_just;
434 }
435 s++;
436 } else if (*s >= '0' && *s <= '9')
437 for (field_width = 0; *s >= '0' && *s <= '9'; s++)
438 field_width = 10*field_width + *s - '0';
439
440 // parse precision
441 precision = -1;
442 if (*s == '.') {
443 s++;
444 precision = 0;
445 if (*s == '*') {
446 precision = va_arg(val, int);
447 s++;
448 } else if (*s >= '0' && *s <= '9')
449 for (; *s >= '0' && *s <= '9'; s++)
450 precision = 10*precision + *s - '0';
451 }
452
453 // parse width flags
454 width_flag = 0;
455 width_flags:
456 switch (*s) {
457 case 'h': case 'l':
458 if (width_flag == *s)
459 width_flag = *s + 'A' - 'a';
460 else if (width_flag)
461 break;
462 else
463 width_flag = *s;
464 s++;
465 goto width_flags;
466 case 'z':
467 case 't':
468 if (width_flag)
469 break;
470 width_flag = *s++;
471 break;
472 case '^':
473 if (!isdigit((unsigned char) s[1]) || width_flag)
474 break;
475 for (s++; isdigit((unsigned char) *s); s++)
476 width_flag = width_flag * 10 + *s - '0';
477 width_flag = -width_flag;
478 break;
479 }
480
481 // conversion character
482 // after switch, data lies between `s1' and `s2'
483 const char *s1 = 0, *s2 = 0;
484 base = 10;
485 switch (*s++) {
486
487 case 's': {
488 s1 = va_arg(val, const char *);
489 if (!s1)
490 s1 = "(null)";
491
492 // fetch length
493 int len;
494 if (precision < 0)
495 len = strlen(s1);
496 else
497 len = strnlen(s1, precision);
498
499 // transform string if alternate form
500 if (flags & cf_alternate_form) {
501 strstore = String(s1, len).printable();
502 if (precision < 0 || strstore.length() < precision)
503 len = strstore.length();
504 }
505
506 // quote characters that look like annotations, readjusting length
507 if (flags & (cf_singlequote | cf_alternate_form)) {
508 if (!(flags & cf_alternate_form))
509 strstore = String(s1, len);
510
511 // check first line, considering trailing part of 'msg'
512 const char *mbegin = msg.end();
513 while (mbegin != msg.begin() && mbegin[-1] != '\n')
514 --mbegin;
515 if (skip_anno(strstore.begin(), strstore.end()) != strstore.begin()
516 && skip_anno(mbegin, msg.end()) == msg.end()) {
517 strstore = String::make_stable("{}", 2) + strstore;
518 len += 2;
519 }
520
521 // check subsequent lines
522 const char *s = std::find(strstore.begin(), strstore.end(), '\n');
523 while (s != strstore.end() && s + 1 != strstore.end()) {
524 size_t nextpos = (s + 1) - strstore.begin();
525 if (skip_anno(s + 1, strstore.end()) != s + 1) {
526 strstore = strstore.substring(strstore.begin(), s + 1)
527 + String::make_stable("{}", 2)
528 + strstore.substring(s + 1, strstore.end());
529 len += 2;
530 }
531 s = std::find(strstore.begin() + nextpos, strstore.end(), '\n');
532 }
533 }
534
535 // obtain begin and end pointers
536 if (flags & (cf_singlequote | cf_alternate_form))
537 s1 = strstore.begin();
538 s2 = s1 + len;
539 break;
540 }
541
542 case 'c': {
543 int c = va_arg(val, int);
544 // check for extension of 'signed char' to 'int'
545 if (c < 0)
546 c += 256;
547 // assume ASCII
548 if (c == '\n')
549 strcpy(numbuf, "\\n");
550 else if (c == '\t')
551 strcpy(numbuf, "\\t");
552 else if (c == '\r')
553 strcpy(numbuf, "\\r");
554 else if (c == '\0')
555 strcpy(numbuf, "\\0");
556 else if (c < 0 || c >= 256)
557 strcpy(numbuf, "(bad char)");
558 else if (c < 32 || c >= 0177)
559 sprintf(numbuf, "\\%03o", c);
560 else
561 sprintf(numbuf, "%c", c);
562 s1 = numbuf;
563 s2 = strchr(numbuf, 0);
564 break;
565 }
566
567 case '%': {
568 numbuf[0] = '%';
569 s1 = numbuf;
570 s2 = s1 + 1;
571 break;
572 }
573
574 case '<':
575 s1 = (flags & cf_utf8 ? "\342\200\230" : "\'");
576 s2 = s1 + strlen(s1);
577 break;
578
579 case '>':
580 case ',':
581 s1 = (flags & cf_utf8 ? "\342\200\231" : "\'");
582 s2 = s1 + strlen(s1);
583 break;
584
585 case 'd':
586 case 'i':
587 flags |= cf_signed;
588 /* fallthru */
589 case 'u':
590 number: {
591 // protect numbuf from overflow
592 if (field_width > NUMBUF_SIZE)
593 field_width = NUMBUF_SIZE;
594 if (precision > NUMBUF_SIZE - 4)
595 precision = NUMBUF_SIZE - 4;
596
597 s2 = numbuf + NUMBUF_SIZE;
598
599 do_number_t num;
600 switch (width_flag) {
601 case 'H':
602 case -8:
603 num = (unsigned char) va_arg(val, int);
604 if ((flags & cf_signed) && (signed char) num < 0)
605 num = -(signed char) num, flags |= cf_negative;
606 break;
607 case 'h':
608 case -16:
609 num = (unsigned short) va_arg(val, int);
610 if ((flags & cf_signed) && (short) num < 0)
611 num = -(short) num, flags |= cf_negative;
612 break;
613 case 0:
614 case -32:
615 #if SIZEOF_LONG == 4
616 case 'l':
617 #endif
618 #if SIZEOF_SIZE_T == 4
619 case 'z':
620 #endif
621 #if SIZEOF_PTRDIFF_T == 4
622 case 't':
623 #endif
624 num = va_arg(val, unsigned);
625 if ((flags & cf_signed) && (int) num < 0)
626 num = -(int) num, flags |= cf_negative;
627 break;
628 #if HAVE_INT64_TYPES
629 # if SIZEOF_LONG == 8
630 case 'l':
631 # endif
632 # if SIZEOF_LONG_LONG == 8
633 case 'L':
634 # endif
635 # if SIZEOF_SIZE_T == 8
636 case 'z':
637 # endif
638 # if SIZEOF_PTRDIFF_T == 8
639 case 't':
640 # endif
641 case -64: {
642 uint64_t qnum = va_arg(val, uint64_t);
643 if ((flags & cf_signed) && (int64_t)qnum < 0)
644 qnum = -(int64_t) qnum, flags |= cf_negative;
645 StringAccum sa;
646 sa.append_numeric(static_cast<String::uintmax_t>(qnum), base, (flags & cf_uppercase));
647 s1 = s2 - sa.length();
648 memcpy(const_cast<char*>(s1), sa.data(), s2 - s1);
649 goto got_number;
650 }
651 #endif
652 default:
653 goto error;
654 }
655 s1 = do_number(num, (char*) s2, base, flags);
656
657 #if HAVE_INT64_TYPES
658 got_number:
659 #endif
660 s1 = do_number_flags((char*)s1, (char*) s2, base, flags, precision, field_width);
661 break;
662 }
663
664 case 'o':
665 base = 8;
666 goto number;
667
668 case 'X':
669 flags |= cf_uppercase;
670 /* fallthru */
671 case 'x':
672 base = 16;
673 goto number;
674
675 case 'p': {
676 if (*s == '{') {
677 s1 = s2 = s + 1;
678 while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2))
679 ++s2;
680 if (*s2 == '}')
681 goto braces;
682 }
683 void* v = va_arg(val, void*);
684 s2 = numbuf + NUMBUF_SIZE;
685 s1 = do_number((do_number_t) v, (char*) s2, 16, flags);
686 s1 = do_number_flags((char*) s1, (char*) s2, 16, flags | cf_alternate_form, precision, field_width);
687 break;
688 }
689
690 #ifndef __KERNEL__
691 case 'e': case 'f': case 'g':
692 case 'E': case 'F': case 'G': {
693 char format[80], *f = format, new_numbuf[NUMBUF_SIZE];
694 *f++ = '%';
695 if (flags & cf_alternate_form)
696 *f++ = '#';
697 if (precision >= 0)
698 f += sprintf(f, ".%d", precision);
699 *f++ = s[-1];
700 *f++ = 0;
701
702 int len = sprintf(new_numbuf, format, va_arg(val, double));
703
704 s2 = numbuf + NUMBUF_SIZE;
705 s1 = s2 - len;
706 memcpy((char *)s1, new_numbuf, len); // note: no terminating \0
707 s1 = do_number_flags((char *)s1, (char *)s2, 10, flags & ~cf_alternate_form, -1, field_width);
708 break;
709 }
710 #endif
711
712 case '{':
713 s1 = s2 = s;
714 while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2))
715 ++s2;
716 if (*s2 != '}')
717 goto error;
718 goto braces;
719
720 braces:
721 s = s2 + 1;
722 for (Conversion *item = error_items; item; item = item->next)
723 if (item->name.equals(s1, s2 - s1)) {
724 strstore = item->hook(flags, VA_LIST_REF(val));
725 s1 = strstore.begin();
726 s2 = strstore.end();
727 goto got_result;
728 }
729 goto error;
730
731 error:
732 default:
733 assert(0 /* Bad % in error */);
734 break;
735
736 }
737
738 // add result of conversion
739 got_result:
740 int slen = s2 - s1;
741 if (slen > field_width)
742 field_width = slen;
743 char *dest = msg.extend(field_width);
744 if (flags & cf_left_just) {
745 memcpy(dest, s1, slen);
746 memset(dest + slen, ' ', field_width - slen);
747 } else {
748 memcpy(dest + field_width - slen, s1, slen);
749 memset(dest, (flags & cf_zero_pad ? '0' : ' '), field_width - slen);
750 }
751 }
752
753 return msg.take_string();
754 }
755
756 String
xformat(int default_flags,const char * fmt,...)757 ErrorHandler::xformat(int default_flags, const char *fmt, ...)
758 {
759 va_list val;
760 va_start(val, fmt);
761 String s = vxformat(default_flags, fmt, val);
762 va_end(val);
763 return s;
764 }
765
766 String
xformat(const char * fmt,...)767 ErrorHandler::xformat(const char *fmt, ...)
768 {
769 va_list val;
770 va_start(val, fmt);
771 String s = vxformat(0, fmt, val);
772 va_end(val);
773 return s;
774 }
775
776 String
format(const char * fmt,...)777 ErrorHandler::format(const char *fmt, ...)
778 {
779 va_list val;
780 va_start(val, fmt);
781 String s = vformat(fmt, val);
782 va_end(val);
783 return s;
784 }
785
786
787 // ERROR MESSAGE SHORTHAND
788
789 void
debug(const char * fmt,...)790 ErrorHandler::debug(const char *fmt, ...)
791 {
792 va_list val;
793 va_start(val, fmt);
794 xmessage(String::make_stable(e_debug, 3), fmt, val);
795 va_end(val);
796 }
797
798 void
message(const char * fmt,...)799 ErrorHandler::message(const char *fmt, ...)
800 {
801 va_list val;
802 va_start(val, fmt);
803 xmessage(String::make_stable(e_info, 3), fmt, val);
804 va_end(val);
805 }
806
807 int
warning(const char * fmt,...)808 ErrorHandler::warning(const char *fmt, ...)
809 {
810 va_list val;
811 va_start(val, fmt);
812 int r = xmessage(String::make_stable(e_warning_annotated, 12), fmt, val);
813 va_end(val);
814 return r;
815 }
816
817 int
error(const char * fmt,...)818 ErrorHandler::error(const char *fmt, ...)
819 {
820 va_list val;
821 va_start(val, fmt);
822 int r = xmessage(String::make_stable(e_error, 3), fmt, val);
823 va_end(val);
824 return r;
825 }
826
827 void
fatal(const char * fmt,...)828 ErrorHandler::fatal(const char *fmt, ...)
829 {
830 va_list val;
831 va_start(val, fmt);
832 (void) xmessage(String::make_stable(e_fatal, 4), fmt, val);
833 va_end(val);
834 abort();
835 }
836
837 void
ldebug(const String & landmark,const char * fmt,...)838 ErrorHandler::ldebug(const String &landmark, const char *fmt, ...)
839 {
840 va_list val;
841 va_start(val, fmt);
842 String l = make_landmark_anno(landmark);
843 xmessage(String::make_stable(e_debug, 3) + l, fmt, val);
844 va_end(val);
845 }
846
847 void
lmessage(const String & landmark,const char * fmt,...)848 ErrorHandler::lmessage(const String &landmark, const char *fmt, ...)
849 {
850 va_list val;
851 va_start(val, fmt);
852 String l = make_landmark_anno(landmark);
853 xmessage(String::make_stable(e_info, 3) + l, fmt, val);
854 va_end(val);
855 }
856
857 int
lwarning(const String & landmark,const char * fmt,...)858 ErrorHandler::lwarning(const String &landmark, const char *fmt, ...)
859 {
860 va_list val;
861 va_start(val, fmt);
862 String l = make_landmark_anno(landmark);
863 int r = xmessage(l + String::make_stable(e_warning_annotated, 12), fmt, val);
864 va_end(val);
865 return r;
866 }
867
868 int
lerror(const String & landmark,const char * fmt,...)869 ErrorHandler::lerror(const String &landmark, const char *fmt, ...)
870 {
871 va_list val;
872 va_start(val, fmt);
873 String l = make_landmark_anno(landmark);
874 int r = xmessage(String::make_stable(e_error, 3) + l, fmt, val);
875 va_end(val);
876 return r;
877 }
878
879 void
lfatal(const String & landmark,const char * fmt,...)880 ErrorHandler::lfatal(const String &landmark, const char *fmt, ...)
881 {
882 va_list val;
883 va_start(val, fmt);
884 String l = make_landmark_anno(landmark);
885 (void) xmessage(String::make_stable(e_fatal, 4) + l, fmt, val);
886 va_end(val);
887 abort();
888 }
889
890 int
xmessage(const String & str)891 ErrorHandler::xmessage(const String &str)
892 {
893 String xstr = decorate(str);
894
895 int min_level = 1000, xlevel = 1000;
896 const char *s = xstr.begin(), *end = xstr.end();
897 void *user_data = 0;
898 while (s != end) {
899 const char *l = parse_anno(xstr, s, end, "#<>", &xlevel,
900 (const char *) 0);
901 const char *nl = std::find(l, end, '\n');
902 String line = xstr.substring(s, nl);
903 s = nl + (nl != end);
904 user_data = emit(line, user_data, s != end);
905 min_level = (xlevel < min_level ? xlevel : min_level);
906 }
907
908 account(min_level);
909
910 return (min_level <= el_warning ? error_result : ok_result);
911 }
912
913 String
vformat(const char * fmt,va_list val)914 ErrorHandler::vformat(const char *fmt, va_list val)
915 {
916 return vxformat(0, fmt, val);
917 }
918
919 String
decorate(const String & str)920 ErrorHandler::decorate(const String &str)
921 {
922 return str;
923 }
924
925 void *
emit(const String &,void * user_data,bool)926 ErrorHandler::emit(const String &, void *user_data, bool)
927 {
928 return user_data;
929 }
930
931 void
account(int level)932 ErrorHandler::account(int level)
933 {
934 if (level <= el_error)
935 ++_nerrors;
936 #ifndef __KERNEL__
937 if (level <= el_abort)
938 abort();
939 else if (level <= el_fatal)
940 exit(-level);
941 #endif
942 }
943
944
945 #ifndef __KERNEL__
946 //
947 // FILE ERROR HANDLER
948 //
949
FileErrorHandler(FILE * f,const String & context)950 FileErrorHandler::FileErrorHandler(FILE *f, const String &context)
951 : _f(f), _context(context), _default_flags(0)
952 {
953 # if HAVE_UNISTD_H
954 if (isatty(fileno(_f))) {
955 # endif
956 char *s = getenv("LANG");
957 if (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0
958 || strstr(s, "utf8") != 0))
959 _default_flags |= cf_utf8;
960 # if HAVE_UNISTD_H
961 }
962 # endif
963 }
964
965 String
vformat(const char * fmt,va_list val)966 FileErrorHandler::vformat(const char *fmt, va_list val)
967 {
968 return vxformat(_default_flags, fmt, val);
969 }
970
971 void *
emit(const String & str,void *,bool)972 FileErrorHandler::emit(const String &str, void *, bool)
973 {
974 String landmark;
975 const char *s = parse_anno(str, str.begin(), str.end(),
976 "l", &landmark, (const char *) 0);
977 StringAccum sa;
978 sa << _context << clean_landmark(landmark, true)
979 << str.substring(s, str.end()) << '\n';
980 ssize_t result = fwrite(sa.begin(), 1, sa.length(), _f);
981 (void) result;
982 return 0;
983 }
984
985 #endif
986
987
988 //
989 // STATIC ERROR HANDLERS
990 //
991
992 ErrorHandler::Conversion *
add_conversion(const String & name,ConversionFunction function)993 ErrorHandler::add_conversion(const String &name, ConversionFunction function)
994 {
995 if (Conversion *c = new Conversion) {
996 c->name = name;
997 c->hook = function;
998 c->next = error_items;
999 error_items = c;
1000 return c;
1001 } else
1002 return 0;
1003 }
1004
1005 int
remove_conversion(ErrorHandler::Conversion * conv)1006 ErrorHandler::remove_conversion(ErrorHandler::Conversion *conv)
1007 {
1008 Conversion **pprev = &error_items;
1009 for (Conversion *c = error_items; c; pprev = &c->next, c = *pprev)
1010 if (c == conv) {
1011 *pprev = c->next;
1012 delete c;
1013 return 0;
1014 }
1015 return -1;
1016 }
1017
1018 ErrorHandler *
static_initialize(ErrorHandler * default_handler)1019 ErrorHandler::static_initialize(ErrorHandler *default_handler)
1020 {
1021 if (!the_silent_handler) {
1022 the_default_handler = default_handler;
1023 the_silent_handler = new SilentErrorHandler;
1024 }
1025 return default_handler;
1026 }
1027
1028 void
static_cleanup()1029 ErrorHandler::static_cleanup()
1030 {
1031 delete the_default_handler;
1032 delete the_silent_handler;
1033 the_default_handler = the_silent_handler = 0;
1034 while (error_items) {
1035 Conversion *next = error_items->next;
1036 delete error_items;
1037 error_items = next;
1038 }
1039 }
1040
1041 void
set_default_handler(ErrorHandler * errh)1042 ErrorHandler::set_default_handler(ErrorHandler *errh)
1043 {
1044 the_default_handler = errh;
1045 }
1046
1047
1048 //
1049 // ERROR VENEER
1050 //
1051
1052 String
vformat(const char * fmt,va_list val)1053 ErrorVeneer::vformat(const char *fmt, va_list val)
1054 {
1055 if (_errh)
1056 return _errh->vformat(fmt, val);
1057 else
1058 return ErrorHandler::vformat(fmt, val);
1059 }
1060
1061 String
decorate(const String & str)1062 ErrorVeneer::decorate(const String &str)
1063 {
1064 if (_errh)
1065 return _errh->decorate(str);
1066 else
1067 return ErrorHandler::decorate(str);
1068 }
1069
1070 void *
emit(const String & str,void * user_data,bool more)1071 ErrorVeneer::emit(const String &str, void *user_data, bool more)
1072 {
1073 if (_errh)
1074 return _errh->emit(str, user_data, more);
1075 else
1076 return ErrorHandler::emit(str, user_data, more);
1077 }
1078
1079 void
account(int level)1080 ErrorVeneer::account(int level)
1081 {
1082 ErrorHandler::account(level);
1083 if (_errh)
1084 _errh->account(level);
1085 }
1086
1087
1088 //
1089 // CONTEXT ERROR HANDLER
1090 //
1091
ContextErrorHandler(ErrorHandler * errh,const char * fmt,...)1092 ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, const char *fmt,
1093 ...)
1094 : ErrorVeneer(errh), _indent(String::make_stable(" ", 2)),
1095 _context_landmark("{l:}"), _context_printed(false)
1096 {
1097 va_list val;
1098 va_start(val, fmt);
1099 _context = ErrorVeneer::vformat(fmt, val);
1100 va_end(val);
1101 if (_context)
1102 _context = combine_anno(_context, String::make_stable("{context:context}", 17));
1103 }
1104
1105 String
decorate(const String & str)1106 ContextErrorHandler::decorate(const String &str)
1107 {
1108 String context_anno;
1109 const char *str_endanno = parse_anno(str, str.begin(), str.end(),
1110 "context", &context_anno,
1111 (const char *) 0);
1112 if (context_anno.equals("no", 2))
1113 return ErrorVeneer::decorate(str);
1114
1115 String istr;
1116 if (context_anno.equals("noindent", 8))
1117 istr = combine_anno(str, _context_landmark);
1118 else
1119 istr = combine_anno(str, _context_landmark + _indent);
1120
1121 if (!_context_printed && !context_anno.equals("nocontext", 9)) {
1122 String astr = combine_anno(combine_anno(_context, _context_landmark),
1123 str.substring(str.begin(), str_endanno));
1124 if (astr && astr.back() != '\n')
1125 astr += '\n';
1126 _context_printed = true;
1127 return ErrorVeneer::decorate(astr + istr);
1128 } else
1129 return ErrorVeneer::decorate(istr);
1130 }
1131
1132
1133 //
1134 // PREFIX ERROR HANDLER
1135 //
1136
PrefixErrorHandler(ErrorHandler * errh,const String & prefix)1137 PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh,
1138 const String &prefix)
1139 : ErrorVeneer(errh), _prefix(prefix)
1140 {
1141 }
1142
1143 String
decorate(const String & str)1144 PrefixErrorHandler::decorate(const String &str)
1145 {
1146 return ErrorVeneer::decorate(combine_anno(str, _prefix));
1147 }
1148
1149
1150 //
1151 // LANDMARK ERROR HANDLER
1152 //
1153
LandmarkErrorHandler(ErrorHandler * errh,const String & landmark)1154 LandmarkErrorHandler::LandmarkErrorHandler(ErrorHandler *errh, const String &landmark)
1155 : ErrorVeneer(errh), _landmark(make_landmark_anno(landmark))
1156 {
1157 }
1158
1159 String
decorate(const String & str)1160 LandmarkErrorHandler::decorate(const String &str)
1161 {
1162 return ErrorVeneer::decorate(combine_anno(str, _landmark));
1163 }
1164
1165
1166 //
1167 // BAIL ERROR HANDLER
1168 //
1169
1170 #ifndef __KERNEL__
1171
BailErrorHandler(ErrorHandler * errh,int l)1172 BailErrorHandler::BailErrorHandler(ErrorHandler *errh, int l)
1173 : ErrorVeneer(errh), _level(l)
1174 {
1175 }
1176
1177 void
account(int level)1178 BailErrorHandler::account(int level)
1179 {
1180 ErrorVeneer::account(level);
1181 if (level <= _level)
1182 exit(1);
1183 }
1184
1185 #endif
1186