diff options
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc | 1169 |
1 files changed, 1169 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc new file mode 100644 index 00000000000..cfef2f07de9 --- /dev/null +++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/liblcdf/error.cc @@ -0,0 +1,1169 @@ +// -*- related-file-name: "../include/lcdf/error.hh" -*- +/* + * error.{cc,hh} -- flexible classes for error reporting + * Eddie Kohler + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * Copyright (c) 2001-2013 Eddie Kohler + * Copyright (c) 2008 Meraki, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <lcdf/error.hh> +#include <lcdf/straccum.hh> +#include <lcdf/hashmap.hh> +#include <errno.h> +#include <ctype.h> +#include <algorithm> +#ifndef __KERNEL__ +# include <stdlib.h> +# if HAVE_UNISTD_H +# include <unistd.h> +# endif +#endif + +/** @file error.hh + * @brief Flexible error handling classes. + */ + +struct ErrorHandler::Conversion { + String name; + ConversionFunction hook; + Conversion *next; +}; +static ErrorHandler::Conversion *error_items; + +const char ErrorHandler::e_abort[] = "<-999>"; +const char ErrorHandler::e_fatal[] = "<-1>"; +const char ErrorHandler::e_emergency[] = "<0>"; +const char ErrorHandler::e_alert[] = "<1>"; +const char ErrorHandler::e_critical[] = "<2>"; +const char ErrorHandler::e_error[] = "<3>"; +const char ErrorHandler::e_warning[] = "<4>"; +const char ErrorHandler::e_warning_annotated[] = "<4>warning: "; +const char ErrorHandler::e_notice[] = "<5>"; +const char ErrorHandler::e_info[] = "<6>"; +const char ErrorHandler::e_debug[] = "<7>"; + +const int ErrorHandler::ok_result = 0; +const int ErrorHandler::error_result = -EINVAL; + +ErrorHandler *ErrorHandler::the_default_handler = 0; +ErrorHandler *ErrorHandler::the_silent_handler = 0; + + +// ANNOTATION MANAGEMENT + +static const char * +parse_level(const char *begin, const char *end, int *result) +{ + int x = 0; + const char *s = begin; + + bool negative = false; + if (s != end && *s == '-') { + negative = true; + ++s; + } else if (s != end && *s == '+') + ++s; + + const char *digits = s; + for (; s != end && *s >= '0' && *s <= '9'; ++s) + x = x * 10 + *s - '0'; + + if (s != end && *s == '.') + for (++s; s != end && *s >= '0' && *s <= '9'; ++s) + /* nada */; + + if (s == digits || (s == digits + 1 && s[-1] == '.')) + return begin; + if (result) + *result = (negative ? -x : x); + return s; +} + +String +ErrorHandler::make_anno(const char *name, const String &value) +{ + StringAccum sa; + sa.reserve(value.length() + 10); + + // level annotation requires special handling + if (name[0] == '<' && name[1] == '>' && name[2] == 0) { + if (parse_level(value.begin(), value.end(), 0) == value.end()) { + sa << '<' << value << '>'; + return sa.take_string(); + } else + return String(); + } + + sa << '{' << name << ':'; + const char *last = value.begin(), *end = value.end(); + for (const char *s = value.begin(); s != end; ++s) + if (*s == '\\' || *s == '}') { + sa.append(last, s); + sa << '\\' << *s; + last = s + 1; + } else if (*s == '\n') { + sa.append(last, s); + sa << '\\' << 'n'; + last = s + 1; + } + sa.append(last, end); + sa << '}'; + return sa.take_string(); +} + +const char * +ErrorHandler::skip_anno(const String &str, const char *begin, const char *end, + String *name_result, String *value_result, bool raw) +{ + String name, value; + const char *s = begin; + + if (s + 3 <= end && *s == '<') { + const char *x = parse_level(s + 1, end, 0); + if (x != s + 1 && x != end && *x == '>') { + name = String::make_stable("<>", 2); + if (str) + value = str.substring(begin + 1, x); + begin = x + 1; + } + + } else if (s + 2 <= end && *s == '{' && s[1] == '}') + begin = s + 2; + + else if (s + 3 <= end && *s == '{' && str) { + for (++s; s != end && isalnum((unsigned char) *s); ++s) + /* nada */; + if (s == end || s == begin + 1 || (*s != '}' && *s != ':')) + /* not an annotation */; + else if (*s == '}' && str) { + name = str.substring(begin + 1, s); + begin = s + 1; + } else if (*s == '}') { + name = String::make_stable("{}", 2); + begin = s + 1; + } else if (str) { + const char *x, *last = s + 1; + StringAccum sa; + for (x = s + 1; x != end && *x != '\n' && *x != '}'; ++x) + if (*x == '\\' && x + 1 != end && x[1] != '\n') { + if (!raw) { + sa.append(last, x); + sa << (x[1] == 'n' ? '\n' : x[1]); + last = x + 2; + } + ++x; + } + if (x != end && *x == '}') { + name = str.substring(begin + 1, s); + if (sa) { + sa.append(last, x); + value = sa.take_string(); + } else + value = str.substring(s + 1, x); + begin = x + 1; + } + } else { + const char *x; + for (x = s + 1; x != end && *x != '\n' && *x != '}'; ++x) + if (*x == '\\' && x + 1 != end && x[1] != '\n') + ++x; + if (x != end && *x == '}') { + name = String::make_stable("{}", 2); + begin = x + 1; + } + } + } + + if (name_result) + *name_result = name; + if (value_result) + *value_result = value; + return begin; +} + +const char * +ErrorHandler::parse_anno(const String &str, const char *begin, const char *end, + ...) +{ + const char *names[8]; + void *values[8]; + int nanno = 0; + + va_list val; + va_start(val, end); + while (const char *n = va_arg(val, const char *)) { + assert(nanno < 8); + names[nanno] = n; + if (n[0] == '#') + values[nanno] = va_arg(val, int *); + else + values[nanno] = va_arg(val, String *); + ++nanno; + } + + String name, value; + while (1) { + begin = skip_anno(str, begin, end, &name, &value, false); + if (!name) + break; + for (int i = 0; i < nanno; ++i) + if (names[i][0] == '#') { + if (name == (names[i] + 1)) + parse_level(value.begin(), value.end(), (int *) values[i]); + } else { + if (name == names[i]) + *(String *) values[i] = value; + } + } + + return begin; +} + +String +ErrorHandler::combine_anno(const String &text, const String &anno) +{ + if (!anno) + return text; + + String names[8], values[8]; + int nanno = 0; + const char *abegin = anno.begin(); + while (abegin != anno.end()) { + assert(nanno < 8); + abegin = skip_anno(anno, abegin, anno.end(), &names[nanno], &values[nanno], true); + if (names[nanno]) + ++nanno; + else + break; + } + + const char *last = text.begin(), *s = last; + String name; + StringAccum sa; + while (s != text.end()) { + const char *line = s; + uint32_t mask = (1U << nanno) - 1; + while (1) { + s = skip_anno(text, s, text.end(), &name, 0, false); + if (!name) + break; + for (int i = 0; i < nanno; ++i) + if (name == names[i]) + mask &= ~(1U << i); + } + + if (mask) { + sa.append(last, line); + for (int i = 0; i < nanno; ++i) + if (mask & (1U << i)) { + if (names[i].equals("<>", 2)) + sa << '<' << values[i] << '>'; + else + sa << '{' << names[i] << ':' << values[i] << '}'; + } + last = line; + } + if (abegin != anno.end()) { + sa.append(last, s); + sa.append(abegin, anno.end()); + last = s; + } + + while (s != text.end() && *s != '\n') + ++s; + if (s != text.end()) + ++s; + } + + if (sa) { + sa.append(last, text.end()); + return sa.take_string(); + } else + return text; +} + +String +ErrorHandler::clean_landmark(const String &landmark, bool with_colon) +{ + const char *end = landmark.end(); + while (end != landmark.begin() && isspace((unsigned char) end[-1])) + --end; + if (end != landmark.begin() && end[-1] == ':') + --end; + if (end == landmark.begin()) + return String(); + else if (with_colon) + return landmark.substring(landmark.begin(), end) + ": "; + else + return landmark.substring(landmark.begin(), end); +} + + +// FORMATTING + +#define NUMBUF_SIZE 128 +#define ErrH ErrorHandler + +static char * +do_number(unsigned long num, char *after_last, int base, int flags) +{ + const char *digits = + ((flags & ErrH::cf_uppercase) ? "0123456789ABCDEF" : "0123456789abcdef"); + char *pos = after_last; + while (num) { + *--pos = digits[num % base]; + num /= base; + } + if (pos == after_last) + *--pos = '0'; + return pos; +} + +static char * +do_number_flags(char *pos, char *after_last, int base, int flags, + int precision, int field_width) +{ + // remove cf_alternate_form for zero results in base 16 + if ((flags & ErrH::cf_alternate_form) && base == 16 && *pos == '0') + flags &= ~ErrH::cf_alternate_form; + + // account for zero padding + if (precision >= 0) + while (after_last - pos < precision) + *--pos = '0'; + else if (flags & ErrH::cf_zero_pad) { + if ((flags & ErrH::cf_alternate_form) && base == 16) + field_width -= 2; + if ((flags & ErrH::cf_negative) + || (flags & (ErrH::cf_plus_positive | ErrH::cf_space_positive))) + field_width--; + while (after_last - pos < field_width) + *--pos = '0'; + } + + // alternate forms + if ((flags & ErrH::cf_alternate_form) && base == 8 && pos[1] != '0') + *--pos = '0'; + else if ((flags & ErrH::cf_alternate_form) && base == 16) { + *--pos = ((flags & ErrH::cf_uppercase) ? 'X' : 'x'); + *--pos = '0'; + } + + // sign + if (flags & ErrH::cf_negative) + *--pos = '-'; + else if (flags & ErrH::cf_plus_positive) + *--pos = '+'; + else if (flags & ErrH::cf_space_positive) + *--pos = ' '; + + return pos; +} + +String +ErrorHandler::vxformat(int default_flags, const char *s, va_list val) +{ + StringAccum msg; + + char numbuf[NUMBUF_SIZE]; // for numerics + numbuf[NUMBUF_SIZE-1] = 0; + + String strstore; // to ensure temporaries aren't destroyed + + // declare and initialize these here to make gcc shut up about possible + // use before initialization + int flags = 0; + int field_width = -1; + int precision = -1; + int width_flag = 0; + int base = 10; + while (1) { + + const char *pct = strchr(s, '%'); + if (!pct) { + if (*s) + msg << s; + break; + } + if (pct != s) { + msg.append(s, pct - s); + s = pct; + } + + // parse flags + flags = default_flags; + flags: + switch (*++s) { + case '#': flags |= cf_alternate_form; goto flags; + case '0': flags |= cf_zero_pad; goto flags; + case '-': flags |= cf_left_just; goto flags; + case ' ': flags |= cf_space_positive; goto flags; + case '+': flags |= cf_plus_positive; goto flags; + case '\'': flags |= cf_singlequote; goto flags; + case '_': flags &= ~cf_utf8; goto flags; + } + + // parse field width + field_width = -1; + if (*s == '*') { + field_width = va_arg(val, int); + if (field_width < 0) { + field_width = -field_width; + flags |= cf_left_just; + } + s++; + } else if (*s >= '0' && *s <= '9') + for (field_width = 0; *s >= '0' && *s <= '9'; s++) + field_width = 10*field_width + *s - '0'; + + // parse precision + precision = -1; + if (*s == '.') { + s++; + precision = 0; + if (*s == '*') { + precision = va_arg(val, int); + s++; + } else if (*s >= '0' && *s <= '9') + for (; *s >= '0' && *s <= '9'; s++) + precision = 10*precision + *s - '0'; + } + + // parse width flags + width_flag = 0; + width_flags: + switch (*s) { + case 'h': case 'l': + if (width_flag == *s) + width_flag = *s + 'A' - 'a'; + else if (width_flag) + break; + else + width_flag = *s; + s++; + goto width_flags; + case 'z': + if (width_flag) + break; + width_flag = *s++; + break; + case '^': + if (!isdigit((unsigned char) s[1]) || width_flag) + break; + for (s++; isdigit((unsigned char) *s); s++) + width_flag = width_flag * 10 + *s - '0'; + width_flag = -width_flag; + break; + } + + // conversion character + // after switch, data lies between `s1' and `s2' + const char *s1 = 0, *s2 = 0; + base = 10; + switch (*s++) { + + case 's': { + s1 = va_arg(val, const char *); + if (!s1) + s1 = "(null)"; + + // fetch length + int len; + if (precision < 0) + len = strlen(s1); + else + len = strnlen(s1, precision); + + // transform string if alternate form + if (flags & cf_alternate_form) { + strstore = String(s1, len).printable(); + if (precision < 0 || strstore.length() < precision) + len = strstore.length(); + } + + // quote characters that look like annotations, readjusting length + if (flags & (cf_singlequote | cf_alternate_form)) { + if (!(flags & cf_alternate_form)) + strstore = String(s1, len); + + // check first line, considering trailing part of 'msg' + const char *mbegin = msg.end(); + while (mbegin != msg.begin() && mbegin[-1] != '\n') + --mbegin; + if (skip_anno(strstore.begin(), strstore.end()) != strstore.begin() + && skip_anno(mbegin, msg.end()) == msg.end()) { + strstore = String::make_stable("{}", 2) + strstore; + len += 2; + } + + // check subsequent lines + const char *s = std::find(strstore.begin(), strstore.end(), '\n'); + while (s != strstore.end() && s + 1 != strstore.end()) { + size_t nextpos = (s + 1) - strstore.begin(); + if (skip_anno(s + 1, strstore.end()) != s + 1) { + strstore = strstore.substring(strstore.begin(), s + 1) + + String::make_stable("{}", 2) + + strstore.substring(s + 1, strstore.end()); + len += 2; + } + s = std::find(strstore.begin() + nextpos, strstore.end(), '\n'); + } + } + + // obtain begin and end pointers + if (flags & (cf_singlequote | cf_alternate_form)) + s1 = strstore.begin(); + s2 = s1 + len; + break; + } + + case 'c': { + int c = va_arg(val, int); + // check for extension of 'signed char' to 'int' + if (c < 0) + c += 256; + // assume ASCII + if (c == '\n') + strcpy(numbuf, "\\n"); + else if (c == '\t') + strcpy(numbuf, "\\t"); + else if (c == '\r') + strcpy(numbuf, "\\r"); + else if (c == '\0') + strcpy(numbuf, "\\0"); + else if (c < 0 || c >= 256) + strcpy(numbuf, "(bad char)"); + else if (c < 32 || c >= 0177) + sprintf(numbuf, "\\%03o", c); + else + sprintf(numbuf, "%c", c); + s1 = numbuf; + s2 = strchr(numbuf, 0); + break; + } + + case '%': { + numbuf[0] = '%'; + s1 = numbuf; + s2 = s1 + 1; + break; + } + + case '<': + s1 = (flags & cf_utf8 ? "\342\200\230" : "\'"); + s2 = s1 + strlen(s1); + break; + + case '>': + case ',': + s1 = (flags & cf_utf8 ? "\342\200\231" : "\'"); + s2 = s1 + strlen(s1); + break; + + case 'd': + case 'i': + flags |= cf_signed; + case 'u': + number: { + // protect numbuf from overflow + if (field_width > NUMBUF_SIZE) + field_width = NUMBUF_SIZE; + if (precision > NUMBUF_SIZE - 4) + precision = NUMBUF_SIZE - 4; + + s2 = numbuf + NUMBUF_SIZE; + + unsigned long num; + switch (width_flag) { + case 'H': + case -8: + num = (unsigned char) va_arg(val, int); + if ((flags & cf_signed) && (signed char) num < 0) + num = -(signed char) num, flags |= cf_negative; + break; + case 'h': + case -16: + num = (unsigned short) va_arg(val, int); + if ((flags & cf_signed) && (short) num < 0) + num = -(short) num, flags |= cf_negative; + break; + case 0: + case -32: +#if SIZEOF_LONG == 4 + case 'l': +#endif +#if SIZEOF_SIZE_T == 4 + case 'z': +#endif + num = va_arg(val, unsigned); + if ((flags & cf_signed) && (int) num < 0) + num = -(int) num, flags |= cf_negative; + break; +#if HAVE_INT64_TYPES +# if SIZEOF_LONG == 8 + case 'l': +# endif +# if SIZEOF_LONG_LONG == 8 + case 'L': +# endif +# if SIZEOF_SIZE_T == 8 + case 'z': +# endif + case -64: { + uint64_t qnum = va_arg(val, uint64_t); + if ((flags & cf_signed) && (int64_t)qnum < 0) + qnum = -(int64_t) qnum, flags |= cf_negative; + StringAccum sa; + sa.append_numeric(static_cast<String::uintmax_t>(qnum), base, (flags & cf_uppercase)); + s1 = s2 - sa.length(); + memcpy(const_cast<char*>(s1), sa.data(), s2 - s1); + goto got_number; + } +#endif + default: + goto error; + } + s1 = do_number(num, (char *)s2, base, flags); + +#if HAVE_INT64_TYPES + got_number: +#endif + s1 = do_number_flags((char *)s1, (char *)s2, base, flags, + precision, field_width); + break; + } + + case 'o': + base = 8; + goto number; + + case 'X': + flags |= cf_uppercase; + case 'x': + base = 16; + goto number; + + case 'p': { + if (*s == '{') { + s1 = s2 = s + 1; + while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2)) + ++s2; + if (*s2 == '}') + goto braces; + } + void *v = va_arg(val, void *); + s2 = numbuf + NUMBUF_SIZE; + s1 = do_number((unsigned long)v, (char *)s2, 16, flags); + s1 = do_number_flags((char *)s1, (char *)s2, 16, flags | cf_alternate_form, + precision, field_width); + break; + } + +#ifndef __KERNEL__ + case 'e': case 'f': case 'g': + case 'E': case 'F': case 'G': { + char format[80], *f = format, new_numbuf[NUMBUF_SIZE]; + *f++ = '%'; + if (flags & cf_alternate_form) + *f++ = '#'; + if (precision >= 0) + f += sprintf(f, ".%d", precision); + *f++ = s[-1]; + *f++ = 0; + + int len = sprintf(new_numbuf, format, va_arg(val, double)); + + s2 = numbuf + NUMBUF_SIZE; + s1 = s2 - len; + memcpy((char *)s1, new_numbuf, len); // note: no terminating \0 + s1 = do_number_flags((char *)s1, (char *)s2, 10, flags & ~cf_alternate_form, -1, field_width); + break; + } +#endif + + case '{': + s1 = s2 = s; + while (*s2 && *s2 != '}' && !isspace((unsigned char) *s2)) + ++s2; + if (*s2 != '}') + goto error; + goto braces; + + braces: + s = s2 + 1; + for (Conversion *item = error_items; item; item = item->next) + if (item->name.equals(s1, s2 - s1)) { + strstore = item->hook(flags, VA_LIST_REF(val)); + s1 = strstore.begin(); + s2 = strstore.end(); + goto got_result; + } + goto error; + + error: + default: + assert(0 /* Bad % in error */); + break; + + } + + // add result of conversion + got_result: + int slen = s2 - s1; + if (slen > field_width) + field_width = slen; + char *dest = msg.extend(field_width); + if (flags & cf_left_just) { + memcpy(dest, s1, slen); + memset(dest + slen, ' ', field_width - slen); + } else { + memcpy(dest + field_width - slen, s1, slen); + memset(dest, (flags & cf_zero_pad ? '0' : ' '), field_width - slen); + } + } + + return msg.take_string(); +} + +String +ErrorHandler::xformat(int default_flags, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String s = vxformat(default_flags, fmt, val); + va_end(val); + return s; +} + +String +ErrorHandler::xformat(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String s = vxformat(0, fmt, val); + va_end(val); + return s; +} + +String +ErrorHandler::format(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String s = vformat(fmt, val); + va_end(val); + return s; +} + + +// ERROR MESSAGE SHORTHAND + +void +ErrorHandler::debug(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + vxmessage(String::make_stable(e_debug, 3), fmt, val); + va_end(val); +} + +void +ErrorHandler::message(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + vxmessage(String::make_stable(e_info, 3), fmt, val); + va_end(val); +} + +int +ErrorHandler::warning(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + int r = vxmessage(String::make_stable(e_warning_annotated, 12), fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::error(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + int r = vxmessage(String::make_stable(e_error, 3), fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::fatal(const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + int r = vxmessage(String::make_stable(e_fatal, 4), fmt, val); + va_end(val); + return r; +} + +void +ErrorHandler::ldebug(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + vxmessage(String::make_stable(e_debug, 3) + l, fmt, val); + va_end(val); +} + +void +ErrorHandler::lmessage(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + vxmessage(String::make_stable(e_info, 3) + l, fmt, val); + va_end(val); +} + +int +ErrorHandler::lwarning(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + int r = vxmessage(l + String::make_stable(e_warning_annotated, 12), fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::lerror(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + int r = vxmessage(String::make_stable(e_error, 3) + l, fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::lfatal(const String &landmark, const char *fmt, ...) +{ + va_list val; + va_start(val, fmt); + String l = make_landmark_anno(landmark); + int r = vxmessage(String::make_stable(e_fatal, 4) + l, fmt, val); + va_end(val); + return r; +} + +int +ErrorHandler::xmessage(const String &str) +{ + String xstr = decorate(str); + + int min_level = 1000, xlevel = 1000; + const char *s = xstr.begin(), *end = xstr.end(); + void *user_data = 0; + while (s != end) { + const char *l = parse_anno(xstr, s, end, "#<>", &xlevel, + (const char *) 0); + const char *nl = std::find(l, end, '\n'); + String line = xstr.substring(s, nl); + s = nl + (nl != end); + user_data = emit(line, user_data, s != end); + min_level = (xlevel < min_level ? xlevel : min_level); + } + + account(min_level); + + return (min_level <= el_warning ? error_result : ok_result); +} + +String +ErrorHandler::vformat(const char *fmt, va_list val) +{ + return vxformat(0, fmt, val); +} + +String +ErrorHandler::decorate(const String &str) +{ + return str; +} + +void * +ErrorHandler::emit(const String &, void *user_data, bool) +{ + return user_data; +} + + +#ifndef __KERNEL__ +// +// FILE ERROR HANDLER +// + +FileErrorHandler::FileErrorHandler(FILE *f, const String &context) + : _f(f), _context(context), _default_flags(0) +{ +# if HAVE_UNISTD_H + if (isatty(fileno(_f))) { +# endif + char *s = getenv("LANG"); + if (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0 + || strstr(s, "utf8") != 0)) + _default_flags |= cf_utf8; +# if HAVE_UNISTD_H + } +# endif +} + +String +FileErrorHandler::vformat(const char *fmt, va_list val) +{ + return vxformat(_default_flags, fmt, val); +} + +void * +FileErrorHandler::emit(const String &str, void *, bool) +{ + String landmark; + const char *s = parse_anno(str, str.begin(), str.end(), + "l", &landmark, (const char *) 0); + StringAccum sa; + sa << _context << clean_landmark(landmark, true) + << str.substring(s, str.end()) << '\n'; + ssize_t result = fwrite(sa.begin(), 1, sa.length(), _f); + (void) result; + return 0; +} + +void +FileErrorHandler::account(int level) +{ + ErrorHandler::account(level); + if (level <= el_abort) + abort(); + else if (level <= el_fatal) + exit(-level); +} + +#endif + + +// +// STATIC ERROR HANDLERS +// + +ErrorHandler::Conversion * +ErrorHandler::add_conversion(const String &name, ConversionFunction function) +{ + if (Conversion *c = new Conversion) { + c->name = name; + c->hook = function; + c->next = error_items; + error_items = c; + return c; + } else + return 0; +} + +int +ErrorHandler::remove_conversion(ErrorHandler::Conversion *conv) +{ + Conversion **pprev = &error_items; + for (Conversion *c = error_items; c; pprev = &c->next, c = *pprev) + if (c == conv) { + *pprev = c->next; + delete c; + return 0; + } + return -1; +} + +ErrorHandler * +ErrorHandler::static_initialize(ErrorHandler *default_handler) +{ + if (!the_silent_handler) { + the_default_handler = default_handler; + the_silent_handler = new SilentErrorHandler; + } + return default_handler; +} + +void +ErrorHandler::static_cleanup() +{ + delete the_default_handler; + delete the_silent_handler; + the_default_handler = the_silent_handler = 0; + while (error_items) { + Conversion *next = error_items->next; + delete error_items; + error_items = next; + } +} + +void +ErrorHandler::set_default_handler(ErrorHandler *errh) +{ + the_default_handler = errh; +} + + +// +// ERROR VENEER +// + +String +ErrorVeneer::vformat(const char *fmt, va_list val) +{ + if (_errh) + return _errh->vformat(fmt, val); + else + return ErrorHandler::vformat(fmt, val); +} + +String +ErrorVeneer::decorate(const String &str) +{ + if (_errh) + return _errh->decorate(str); + else + return ErrorHandler::decorate(str); +} + +void * +ErrorVeneer::emit(const String &str, void *user_data, bool more) +{ + if (_errh) + return _errh->emit(str, user_data, more); + else + return ErrorHandler::emit(str, user_data, more); +} + +void +ErrorVeneer::account(int level) +{ + ErrorHandler::account(level); + if (_errh) + _errh->account(level); +} + + +// +// CONTEXT ERROR HANDLER +// + +ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, const char *fmt, + ...) + : ErrorVeneer(errh), _indent(String::make_stable(" ", 2)), + _context_printed(false) +{ + va_list val; + va_start(val, fmt); + _context = ErrorVeneer::vformat(fmt, val); + va_end(val); + if (_context) + _context = combine_anno(_context, String::make_stable("{context:context}", 17)); +} + +String +ContextErrorHandler::decorate(const String &str) +{ + String context_anno; + const char *str_endanno = parse_anno(str, str.begin(), str.end(), + "context", &context_anno, + (const char *) 0); + if (context_anno.equals("no", 2)) + return ErrorVeneer::decorate(str); + + String istr; + if (context_anno.equals("noindent", 8)) + istr = combine_anno(str, _context_landmark); + else + istr = combine_anno(str, _context_landmark + _indent); + + if (!_context_printed && !context_anno.equals("nocontext", 9)) { + String astr = combine_anno(combine_anno(_context, _context_landmark), + str.substring(str.begin(), str_endanno)); + if (astr && astr.back() != '\n') + astr += '\n'; + _context_printed = true; + return ErrorVeneer::decorate(astr + istr); + } else + return ErrorVeneer::decorate(istr); +} + + +// +// PREFIX ERROR HANDLER +// + +PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh, + const String &prefix) + : ErrorVeneer(errh), _prefix(prefix) +{ +} + +String +PrefixErrorHandler::decorate(const String &str) +{ + return ErrorVeneer::decorate(combine_anno(str, _prefix)); +} + + +// +// LANDMARK ERROR HANDLER +// + +LandmarkErrorHandler::LandmarkErrorHandler(ErrorHandler *errh, const String &landmark) + : ErrorVeneer(errh), _landmark(make_landmark_anno(landmark)) +{ +} + +String +LandmarkErrorHandler::decorate(const String &str) +{ + return ErrorVeneer::decorate(combine_anno(str, _landmark)); +} + + +// +// BAIL ERROR HANDLER +// + +#ifndef __KERNEL__ + +BailErrorHandler::BailErrorHandler(ErrorHandler *errh, int l) + : ErrorVeneer(errh), _level(l) +{ +} + +void +BailErrorHandler::account(int level) +{ + ErrorVeneer::account(level); + if (level <= _level) + exit(1); +} + +#endif |