PageRenderTime 107ms CodeModel.GetById 12ms app.highlight 86ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/error.cc

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