1 // -*- related-file-name: "../include/click/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-2008 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 #include <click/config.h>
22 #include <click/error.hh>
23 #include <click/straccum.hh>
24 #ifndef CLICK_TOOL
25 # include <click/element.hh>
26 #endif
27 #include <click/ipaddress.hh>
28 #include <click/etheraddress.hh>
29 #include <click/timestamp.hh>
30 #include <click/confparse.hh>
31 #include <click/algorithm.hh>
32 #if CLICK_USERLEVEL || CLICK_TOOL || CLICK_MINIOS
33 # include <unistd.h>
34 #endif
35 CLICK_DECLS
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 (likely(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 == '}' && likely(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 (likely(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 #if HAVE_STRNLEN
498 		len = strnlen(s1, precision);
499 #else
500 		for (len = 0; len < precision && s1[len] != 0; ++len)
501 		    /* do nothing */;
502 #endif
503 	    }
504 
505 	    // transform string if alternate form
506 	    if (flags & cf_alternate_form) {
507 		strstore = String(s1, len).printable();
508 		if (precision < 0 || strstore.length() < precision)
509 		    len = strstore.length();
510 	    }
511 
512 	    // quote characters that look like annotations, readjusting length
513 	    if (flags & (cf_singlequote | cf_alternate_form)) {
514 		if (!(flags & cf_alternate_form))
515 		    strstore = String(s1, len);
516 
517 		// check first line, considering trailing part of 'msg'
518 		const char *mbegin = msg.end();
519 		while (mbegin != msg.begin() && mbegin[-1] != '\n')
520 		    --mbegin;
521 		if (skip_anno(strstore.begin(), strstore.end()) != strstore.begin()
522 		    && skip_anno(mbegin, msg.end()) == msg.end()) {
523 		    strstore = String::make_stable("{}", 2) + strstore;
524 		    len += 2;
525 		}
526 
527 		// check subsequent lines
528 		const char *s = find(strstore.begin(), strstore.end(), '\n');
529 		while (s != strstore.end() && s + 1 != strstore.end()) {
530 		    size_t nextpos = (s + 1) - strstore.begin();
531 		    if (skip_anno(s + 1, strstore.end()) != s + 1) {
532 			strstore = strstore.substring(strstore.begin(), s + 1)
533 			    + String::make_stable("{}", 2)
534 			    + strstore.substring(s + 1, strstore.end());
535 			len += 2;
536 		    }
537 		    s = find(strstore.begin() + nextpos, strstore.end(), '\n');
538 		}
539 	    }
540 
541 	    // obtain begin and end pointers
542 	    if (flags & (cf_singlequote | cf_alternate_form))
543 		s1 = strstore.begin();
544 	    s2 = s1 + len;
545 	    break;
546 	}
547 
548 	case 'c': {
549 	    int c = va_arg(val, int);
550 	    // check for extension of 'signed char' to 'int'
551 	    if (c < 0)
552 		c += 256;
553 	    // assume ASCII
554 	    if (c == '\n')
555 		strcpy(numbuf, "\\n");
556 	    else if (c == '\t')
557 		strcpy(numbuf, "\\t");
558 	    else if (c == '\r')
559 		strcpy(numbuf, "\\r");
560 	    else if (c == '\0')
561 		strcpy(numbuf, "\\0");
562 	    else if (c < 0 || c >= 256)
563 		strcpy(numbuf, "(bad char)");
564 	    else if (c < 32 || c >= 0177)
565 		sprintf(numbuf, "\\%03o", c);
566 	    else
567 		sprintf(numbuf, "%c", c);
568 	    s1 = numbuf;
569 	    s2 = strchr(numbuf, 0);
570 	    break;
571 	}
572 
573 	case '%': {
574 	    numbuf[0] = '%';
575 	    s1 = numbuf;
576 	    s2 = s1 + 1;
577 	    break;
578 	}
579 
580 	case '<':
581 	    s1 = (flags & cf_utf8 ? "\342\200\230" : "\'");
582 	    s2 = s1 + strlen(s1);
583 	    break;
584 
585 	case '>':
586 	case ',':
587 	    s1 = (flags & cf_utf8 ? "\342\200\231" : "\'");
588 	    s2 = s1 + strlen(s1);
589 	    break;
590 
591 	case 'd':
592 	case 'i':
593 	    flags |= cf_signed;
594 	case 'u':
595 	number: {
596 	    // protect numbuf from overflow
597 	    if (field_width > NUMBUF_SIZE)
598 		field_width = NUMBUF_SIZE;
599 	    if (precision > NUMBUF_SIZE - 4)
600 		precision = NUMBUF_SIZE - 4;
601 
602 	    s2 = numbuf + NUMBUF_SIZE;
603 
604 	    unsigned long num;
605 	    switch (width_flag) {
606 	    case 'H':
607 	    case -8:
608 		num = (unsigned char) va_arg(val, int);
609 		if ((flags & cf_signed) && (signed char) num < 0)
610 		    num = -(signed char) num, flags |= cf_negative;
611 		break;
612 	    case 'h':
613 	    case -16:
614 		num = (unsigned short) va_arg(val, int);
615 		if ((flags & cf_signed) && (short) num < 0)
616 		    num = -(short) num, flags |= cf_negative;
617 		break;
618 	    case 0:
619 	    case -32:
620 #if SIZEOF_LONG == 4
621 	    case 'l':
622 #endif
623 #if SIZEOF_SIZE_T == 4
624 	    case 'z':
625 #endif
626 #if SIZEOF_PTRDIFF_T == 4
627 	    case 't':
628 #endif
629 		num = va_arg(val, unsigned);
630 		if ((flags & cf_signed) && (int) num < 0)
631 		    num = -(int) num, flags |= cf_negative;
632 		break;
633 #if HAVE_INT64_TYPES
634 # if SIZEOF_LONG == 8
635 	    case 'l':
636 # endif
637 # if SIZEOF_LONG_LONG == 8
638 	    case 'L':
639 # endif
640 # if SIZEOF_SIZE_T == 8
641 	    case 'z':
642 # endif
643 # if SIZEOF_PTRDIFF_T == 8
644 	    case 't':
645 # endif
646 	    case -64: {
647 		uint64_t qnum = va_arg(val, uint64_t);
648 		if ((flags & cf_signed) && (int64_t)qnum < 0)
649 		    qnum = -(int64_t) qnum, flags |= cf_negative;
650 		StringAccum sa;
651 		sa.append_numeric(static_cast<String::uintmax_t>(qnum), base, (flags & cf_uppercase));
652 		s1 = s2 - sa.length();
653 		memcpy(const_cast<char*>(s1), sa.data(), s2 - s1);
654 		goto got_number;
655 	    }
656 #endif
657 	    default:
658 		goto error;
659 	    }
660 	    s1 = do_number(num, (char *)s2, base, flags);
661 
662 #if HAVE_INT64_TYPES
663 	got_number:
664 #endif
665 	    s1 = do_number_flags((char *)s1, (char *)s2, base, flags,
666 				 precision, field_width);
667 	    break;
668 	}
669 
670 	case 'o':
671 	    base = 8;
672 	    goto number;
673 
674 	case 'X':
675 	    flags |= cf_uppercase;
676 	case 'x':
677 	    base = 16;
678 	    goto number;
679 
680 	case 'p': {
681 	    if (*s == '{') {
682 		s1 = s2 = s + 1;
683 		while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2))
684 		    ++s2;
685 		if (*s2 == '}')
686 		    goto braces;
687 	    }
688 	    void* v = va_arg(val, void*);
689 	    s2 = numbuf + NUMBUF_SIZE;
690 	    s1 = do_number((do_number_t) v, (char*) s2, 16, flags);
691 	    s1 = do_number_flags((char*) s1, (char*) s2, 16, flags | cf_alternate_form, precision, field_width);
692 	    break;
693 	}
694 
695 #if HAVE_FLOAT_TYPES
696 	case 'e': case 'f': case 'g':
697 	case 'E': case 'F': case 'G': {
698 	    char format[80], *f = format, new_numbuf[NUMBUF_SIZE];
699 	    *f++ = '%';
700 	    if (flags & cf_alternate_form)
701 		*f++ = '#';
702 	    if (precision >= 0)
703 		f += sprintf(f, ".%d", precision);
704 	    *f++ = s[-1];
705 	    *f++ = 0;
706 
707 	    int len = sprintf(new_numbuf, format, va_arg(val, double));
708 
709 	    s2 = numbuf + NUMBUF_SIZE;
710 	    s1 = s2 - len;
711 	    memcpy((char *)s1, new_numbuf, len); // note: no terminating \0
712 	    s1 = do_number_flags((char *)s1, (char *)s2, 10, flags & ~cf_alternate_form, -1, field_width);
713 	    break;
714 	}
715 #endif
716 
717 	case '{':
718 	    s1 = s2 = s;
719 	    while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2))
720 		++s2;
721 	    if (*s2 != '}')
722 		goto error;
723 	    goto braces;
724 
725 	braces:
726 	    s = s2 + 1;
727 	    for (Conversion *item = error_items; item; item = item->next)
728 		if (item->name.equals(s1, s2 - s1)) {
729 		    strstore = item->hook(flags, VA_LIST_REF(val));
730 		    s1 = strstore.begin();
731 		    s2 = strstore.end();
732 		    goto got_result;
733 		}
734 	    goto error;
735 
736 	error:
737 	default:
738 	    assert(0 /* Bad % in error */);
739 	    break;
740 
741 	}
742 
743 	// add result of conversion
744     got_result:
745 	int slen = s2 - s1;
746 	if (slen > field_width)
747 	    field_width = slen;
748 	char *dest = msg.extend(field_width);
749 	if (flags & cf_left_just) {
750 	    memcpy(dest, s1, slen);
751 	    memset(dest + slen, ' ', field_width - slen);
752 	} else {
753 	    memcpy(dest + field_width - slen, s1, slen);
754 	    memset(dest, (flags & cf_zero_pad ? '0' : ' '), field_width - slen);
755 	}
756     }
757 
758     return msg.take_string();
759 }
760 
761 String
xformat(int default_flags,const char * fmt,...)762 ErrorHandler::xformat(int default_flags, const char *fmt, ...)
763 {
764     va_list val;
765     va_start(val, fmt);
766     String s = vxformat(default_flags, fmt, val);
767     va_end(val);
768     return s;
769 }
770 
771 String
xformat(const char * fmt,...)772 ErrorHandler::xformat(const char *fmt, ...)
773 {
774     va_list val;
775     va_start(val, fmt);
776     String s = vxformat(0, fmt, val);
777     va_end(val);
778     return s;
779 }
780 
781 String
format(const char * fmt,...)782 ErrorHandler::format(const char *fmt, ...)
783 {
784     va_list val;
785     va_start(val, fmt);
786     String s = vformat(fmt, val);
787     va_end(val);
788     return s;
789 }
790 
791 
792 // ERROR MESSAGE SHORTHAND
793 
794 void
debug(const char * fmt,...)795 ErrorHandler::debug(const char *fmt, ...)
796 {
797     va_list val;
798     va_start(val, fmt);
799     xmessage(String::make_stable(e_debug, 3), fmt, val);
800     va_end(val);
801 }
802 
803 void
message(const char * fmt,...)804 ErrorHandler::message(const char *fmt, ...)
805 {
806     va_list val;
807     va_start(val, fmt);
808     xmessage(String::make_stable(e_info, 3), fmt, val);
809     va_end(val);
810 }
811 
812 int
warning(const char * fmt,...)813 ErrorHandler::warning(const char *fmt, ...)
814 {
815     va_list val;
816     va_start(val, fmt);
817     int r = xmessage(String::make_stable(e_warning_annotated, 12), fmt, val);
818     va_end(val);
819     return r;
820 }
821 
822 int
error(const char * fmt,...)823 ErrorHandler::error(const char *fmt, ...)
824 {
825     va_list val;
826     va_start(val, fmt);
827     int r = xmessage(String::make_stable(e_error, 3), fmt, val);
828     va_end(val);
829     return r;
830 }
831 
832 int
fatal(const char * fmt,...)833 ErrorHandler::fatal(const char *fmt, ...)
834 {
835     va_list val;
836     va_start(val, fmt);
837     int r = xmessage(String::make_stable(e_fatal, 4), fmt, val);
838     va_end(val);
839     return r;
840 }
841 
842 void
ldebug(const String & landmark,const char * fmt,...)843 ErrorHandler::ldebug(const String &landmark, const char *fmt, ...)
844 {
845     va_list val;
846     va_start(val, fmt);
847     String l = make_landmark_anno(landmark);
848     xmessage(String::make_stable(e_debug, 3) + l, fmt, val);
849     va_end(val);
850 }
851 
852 void
lmessage(const String & landmark,const char * fmt,...)853 ErrorHandler::lmessage(const String &landmark, const char *fmt, ...)
854 {
855     va_list val;
856     va_start(val, fmt);
857     String l = make_landmark_anno(landmark);
858     xmessage(String::make_stable(e_info, 3) + l, fmt, val);
859     va_end(val);
860 }
861 
862 int
lwarning(const String & landmark,const char * fmt,...)863 ErrorHandler::lwarning(const String &landmark, const char *fmt, ...)
864 {
865     va_list val;
866     va_start(val, fmt);
867     String l = make_landmark_anno(landmark);
868     int r = xmessage(l + String::make_stable(e_warning_annotated, 12), fmt, val);
869     va_end(val);
870     return r;
871 }
872 
873 int
lerror(const String & landmark,const char * fmt,...)874 ErrorHandler::lerror(const String &landmark, const char *fmt, ...)
875 {
876     va_list val;
877     va_start(val, fmt);
878     String l = make_landmark_anno(landmark);
879     int r = xmessage(String::make_stable(e_error, 3) + l, fmt, val);
880     va_end(val);
881     return r;
882 }
883 
884 int
lfatal(const String & landmark,const char * fmt,...)885 ErrorHandler::lfatal(const String &landmark, const char *fmt, ...)
886 {
887     va_list val;
888     va_start(val, fmt);
889     String l = make_landmark_anno(landmark);
890     int r = xmessage(String::make_stable(e_fatal, 4) + l, fmt, val);
891     va_end(val);
892     return r;
893 }
894 
895 int
xmessage(const String & str)896 ErrorHandler::xmessage(const String &str)
897 {
898     String xstr = decorate(str);
899 
900     int min_level = 1000, xlevel = 1000;
901     const char *s = xstr.begin(), *end = xstr.end();
902     void *user_data = 0;
903     while (s != end) {
904 	const char *l = parse_anno(xstr, s, end, "#<>", &xlevel,
905 				   (const char *) 0);
906 	const char *nl = find(l, end, '\n');
907 	String line = xstr.substring(s, nl);
908 	s = nl + (nl != end);
909 	user_data = emit(line, user_data, s != end);
910 	min_level = (xlevel < min_level ? xlevel : min_level);
911     }
912 
913     account(min_level);
914 
915     return (min_level <= el_warning ? error_result : ok_result);
916 }
917 
918 String
vformat(const char * fmt,va_list val)919 ErrorHandler::vformat(const char *fmt, va_list val)
920 {
921     return vxformat(0, fmt, val);
922 }
923 
924 String
decorate(const String & str)925 ErrorHandler::decorate(const String &str)
926 {
927     return str;
928 }
929 
930 void *
emit(const String &,void * user_data,bool)931 ErrorHandler::emit(const String &, void *user_data, bool)
932 {
933     return user_data;
934 }
935 
936 
937 #if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL) || defined(CLICK_MINIOS)
938 //
939 // FILE ERROR HANDLER
940 //
941 
FileErrorHandler(FILE * f,const String & context)942 FileErrorHandler::FileErrorHandler(FILE *f, const String &context)
943     : _f(f), _context(context), _default_flags(0)
944 {
945     if (isatty(fileno(_f))) {
946 	char *s = getenv("LANG");
947 	if (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0
948 		  || strstr(s, "utf8") != 0))
949 	    _default_flags |= cf_utf8;
950     }
951 }
952 
953 String
vformat(const char * fmt,va_list val)954 FileErrorHandler::vformat(const char *fmt, va_list val)
955 {
956     return vxformat(_default_flags, fmt, val);
957 }
958 
959 void *
emit(const String & str,void *,bool)960 FileErrorHandler::emit(const String &str, void *, bool)
961 {
962     String landmark;
963     const char *s = parse_anno(str, str.begin(), str.end(),
964 			       "l", &landmark, (const char *) 0);
965     StringAccum sa;
966     sa << _context << clean_landmark(landmark, true)
967        << str.substring(s, str.end()) << '\n';
968     ignore_result(fwrite(sa.begin(), 1, sa.length(), _f));
969     return 0;
970 }
971 
972 void
account(int level)973 FileErrorHandler::account(int level)
974 {
975     ErrorHandler::account(level);
976     if (level <= el_abort)
977 	abort();
978     else if (level <= el_fatal)
979 	exit(-level);
980 }
981 
982 #endif
983 
984 
985 //
986 // STATIC ERROR HANDLERS
987 //
988 
989 ErrorHandler::Conversion *
add_conversion(const String & name,ConversionFunction function)990 ErrorHandler::add_conversion(const String &name, ConversionFunction function)
991 {
992     if (Conversion *c = new Conversion) {
993 	c->name = name;
994 	c->hook = function;
995 	c->next = error_items;
996 	error_items = c;
997 	return c;
998     } else
999 	return 0;
1000 }
1001 
1002 int
remove_conversion(ErrorHandler::Conversion * conv)1003 ErrorHandler::remove_conversion(ErrorHandler::Conversion *conv)
1004 {
1005     Conversion **pprev = &error_items;
1006     for (Conversion *c = error_items; c; pprev = &c->next, c = *pprev)
1007 	if (c == conv) {
1008 	    *pprev = c->next;
1009 	    delete c;
1010 	    return 0;
1011 	}
1012     return -1;
1013 }
1014 
1015 static String
timeval_error_hook(int,VA_LIST_REF_T val)1016 timeval_error_hook(int, VA_LIST_REF_T val)
1017 {
1018     const struct timeval *tvp = va_arg(VA_LIST_DEREF(val), const struct timeval *);
1019     if (tvp) {
1020 	StringAccum sa;
1021 	sa << *tvp;
1022 	return sa.take_string();
1023     } else
1024 	return String::make_stable("(null)", 6);
1025 }
1026 
1027 static String
timestamp_error_hook(int,VA_LIST_REF_T val)1028 timestamp_error_hook(int, VA_LIST_REF_T val)
1029 {
1030     const Timestamp *tsp = va_arg(VA_LIST_DEREF(val), const Timestamp *);
1031     if (tsp) {
1032 	StringAccum sa;
1033 	sa << *tsp;
1034 	return sa.take_string();
1035     } else
1036 	return String::make_stable("(null)", 6);
1037 }
1038 
1039 static String
ip_ptr_error_hook(int,VA_LIST_REF_T val)1040 ip_ptr_error_hook(int, VA_LIST_REF_T val)
1041 {
1042     const IPAddress *ipp = va_arg(VA_LIST_DEREF(val), const IPAddress *);
1043     if (ipp)
1044 	return ipp->unparse();
1045     else
1046 	return String::make_stable("(null)", 6);
1047 }
1048 
1049 static String
ether_ptr_error_hook(int,VA_LIST_REF_T val)1050 ether_ptr_error_hook(int, VA_LIST_REF_T val)
1051 {
1052     const EtherAddress *ethp = va_arg(VA_LIST_DEREF(val), const EtherAddress *);
1053     if (ethp)
1054 	return ethp->unparse();
1055     else
1056 	return String::make_stable("(null)", 6);
1057 }
1058 
1059 #ifndef CLICK_TOOL
1060 static String
element_error_hook(int,VA_LIST_REF_T val)1061 element_error_hook(int, VA_LIST_REF_T val)
1062 {
1063     const Element *e = va_arg(VA_LIST_DEREF(val), const Element *);
1064     if (e)
1065 	return e->declaration();
1066     else
1067 	return String::make_stable("(null)", 6);
1068 }
1069 #endif
1070 
1071 ErrorHandler *
static_initialize(ErrorHandler * default_handler)1072 ErrorHandler::static_initialize(ErrorHandler *default_handler)
1073 {
1074     if (!the_silent_handler) {
1075 	the_default_handler = default_handler;
1076 	the_silent_handler = new SilentErrorHandler;
1077 	add_conversion("timeval", timeval_error_hook);
1078 	add_conversion("timestamp", timestamp_error_hook);
1079 #ifndef CLICK_TOOL
1080 	add_conversion("element", element_error_hook);
1081 #endif
1082 	add_conversion("ip_ptr", ip_ptr_error_hook);
1083 	add_conversion("ether_ptr", ether_ptr_error_hook);
1084     }
1085     return default_handler;
1086 }
1087 
1088 void
static_cleanup()1089 ErrorHandler::static_cleanup()
1090 {
1091     delete the_default_handler;
1092     delete the_silent_handler;
1093     the_default_handler = the_silent_handler = 0;
1094     while (error_items) {
1095 	Conversion *next = error_items->next;
1096 	delete error_items;
1097 	error_items = next;
1098     }
1099 }
1100 
1101 void
set_default_handler(ErrorHandler * errh)1102 ErrorHandler::set_default_handler(ErrorHandler *errh)
1103 {
1104     the_default_handler = errh;
1105 }
1106 
1107 
1108 //
1109 // ERROR VENEER
1110 //
1111 
1112 String
vformat(const char * fmt,va_list val)1113 ErrorVeneer::vformat(const char *fmt, va_list val)
1114 {
1115     if (_errh)
1116 	return _errh->vformat(fmt, val);
1117     else
1118 	return ErrorHandler::vformat(fmt, val);
1119 }
1120 
1121 String
decorate(const String & str)1122 ErrorVeneer::decorate(const String &str)
1123 {
1124     if (_errh)
1125 	return _errh->decorate(str);
1126     else
1127 	return ErrorHandler::decorate(str);
1128 }
1129 
1130 void *
emit(const String & str,void * user_data,bool more)1131 ErrorVeneer::emit(const String &str, void *user_data, bool more)
1132 {
1133     if (_errh)
1134 	return _errh->emit(str, user_data, more);
1135     else
1136 	return ErrorHandler::emit(str, user_data, more);
1137 }
1138 
1139 void
account(int level)1140 ErrorVeneer::account(int level)
1141 {
1142     ErrorHandler::account(level);
1143     if (_errh)
1144 	_errh->account(level);
1145 }
1146 
1147 
1148 //
1149 // CONTEXT ERROR HANDLER
1150 //
1151 
ContextErrorHandler(ErrorHandler * errh,const char * fmt,...)1152 ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, const char *fmt,
1153 					 ...)
1154     : ErrorVeneer(errh), _indent(String::make_stable("  ", 2)),
1155       _context_printed(false)
1156 {
1157     va_list val;
1158     va_start(val, fmt);
1159     _context = ErrorVeneer::vformat(fmt, val);
1160     va_end(val);
1161     if (_context)
1162 	_context = combine_anno(_context, String::make_stable("{context:context}", 17));
1163 }
1164 
1165 String
decorate(const String & str)1166 ContextErrorHandler::decorate(const String &str)
1167 {
1168     String context_anno;
1169     const char *str_endanno = parse_anno(str, str.begin(), str.end(),
1170 					 "context", &context_anno,
1171 					 (const char *) 0);
1172     if (context_anno.equals("no", 2))
1173 	return ErrorVeneer::decorate(str);
1174 
1175     String istr;
1176     if (context_anno.equals("noindent", 8))
1177 	istr = combine_anno(str, _context_landmark);
1178     else
1179 	istr = combine_anno(str, _context_landmark + _indent);
1180 
1181     if (!_context_printed && !context_anno.equals("nocontext", 9)) {
1182 	String astr = combine_anno(combine_anno(_context, _context_landmark),
1183 				   str.substring(str.begin(), str_endanno));
1184 	if (astr && astr.back() != '\n')
1185 	    astr += '\n';
1186 	_context_printed = true;
1187 	return ErrorVeneer::decorate(astr + istr);
1188     } else
1189 	return ErrorVeneer::decorate(istr);
1190 }
1191 
1192 
1193 //
1194 // PREFIX ERROR HANDLER
1195 //
1196 
PrefixErrorHandler(ErrorHandler * errh,const String & prefix)1197 PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh,
1198 				       const String &prefix)
1199     : ErrorVeneer(errh), _prefix(prefix)
1200 {
1201 }
1202 
1203 String
decorate(const String & str)1204 PrefixErrorHandler::decorate(const String &str)
1205 {
1206     return ErrorVeneer::decorate(combine_anno(str, _prefix));
1207 }
1208 
1209 
1210 //
1211 // LANDMARK ERROR HANDLER
1212 //
1213 
LandmarkErrorHandler(ErrorHandler * errh,const String & landmark)1214 LandmarkErrorHandler::LandmarkErrorHandler(ErrorHandler *errh, const String &landmark)
1215     : ErrorVeneer(errh), _landmark(make_landmark_anno(landmark))
1216 {
1217 }
1218 
1219 String
decorate(const String & str)1220 LandmarkErrorHandler::decorate(const String &str)
1221 {
1222     return ErrorVeneer::decorate(combine_anno(str, _landmark));
1223 }
1224 
1225 
1226 //
1227 // BAIL ERROR HANDLER
1228 //
1229 
1230 #if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL) || defined(CLICK_MINIOS)
1231 
BailErrorHandler(ErrorHandler * errh,int l)1232 BailErrorHandler::BailErrorHandler(ErrorHandler *errh, int l)
1233     : ErrorVeneer(errh), _level(l)
1234 {
1235 }
1236 
1237 void
account(int level)1238 BailErrorHandler::account(int level)
1239 {
1240     ErrorVeneer::account(level);
1241     if (level <= _level)
1242 	exit(1);
1243 }
1244 
1245 #endif
1246 
1247 CLICK_ENDDECLS
1248