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