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