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