diff options
author | Karl Berry <karl@freefriends.org> | 2008-02-17 19:29:39 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2008-02-17 19:29:39 +0000 |
commit | fc3b5d4d4f684baa6216685a0696efb853141529 (patch) | |
tree | 0694ed01c09b3c97fcd64453e2c1f647a3fb31ad /Build/source/texk/lcdf-typetools/liblcdf/error.cc | |
parent | 5fc0a693ca037d37d815b00c49660c138b332224 (diff) |
move lcdf-typetools to texk and update to 2.66
git-svn-id: svn://tug.org/texlive/trunk@6662 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/lcdf-typetools/liblcdf/error.cc')
-rw-r--r-- | Build/source/texk/lcdf-typetools/liblcdf/error.cc | 878 |
1 files changed, 878 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/liblcdf/error.cc b/Build/source/texk/lcdf-typetools/liblcdf/error.cc new file mode 100644 index 00000000000..2602f460bca --- /dev/null +++ b/Build/source/texk/lcdf-typetools/liblcdf/error.cc @@ -0,0 +1,878 @@ +// -*- c-basic-offset: 2; 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-2006 Eddie Kohler + * + * 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> +#endif + +struct ErrorHandler::Conversion { + String name; + ConversionHook hook; + Conversion *next; +}; +static ErrorHandler::Conversion *error_items; + +const int ErrorHandler::OK_RESULT = 0; +const int ErrorHandler::ERROR_RESULT = -EINVAL; + +int +ErrorHandler::min_verbosity() const +{ + return 0; +} + +void +ErrorHandler::debug(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_DEBUG, String(), format, val); + va_end(val); +} + +void +ErrorHandler::message(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_MESSAGE, String(), format, val); + va_end(val); +} + +int +ErrorHandler::warning(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_WARNING, String(), format, val); + va_end(val); + return ERROR_RESULT; +} + +int +ErrorHandler::error(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_ERROR, String(), format, val); + va_end(val); + return ERROR_RESULT; +} + +int +ErrorHandler::fatal(const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_FATAL, String(), format, val); + va_end(val); + return ERROR_RESULT; +} + +int +ErrorHandler::fatal(int exit_status, const char *format, ...) +{ + assert(exit_status >= 0 && exit_status < 0x1000); + va_list val; + va_start(val, format); + verror((Seriousness) (ERR_MIN_FATAL + (exit_status << ERRVERBOSITY_SHIFT)), String(), format, val); + va_end(val); + return ERROR_RESULT; +} + +void +ErrorHandler::ldebug(const String &where, const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_DEBUG, where, format, val); + va_end(val); +} + +void +ErrorHandler::lmessage(const String &where, const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_MESSAGE, where, format, val); + va_end(val); +} + +int +ErrorHandler::lwarning(const String &where, const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_WARNING, where, format, val); + va_end(val); + return ERROR_RESULT; +} + +int +ErrorHandler::lerror(const String &where, const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_ERROR, where, format, val); + va_end(val); + return ERROR_RESULT; +} + +int +ErrorHandler::lfatal(const String &where, const char *format, ...) +{ + va_list val; + va_start(val, format); + verror(ERR_FATAL, where, format, val); + va_end(val); + return ERROR_RESULT; +} + +int +ErrorHandler::lfatal(int exit_status, const String &where, const char *format, ...) +{ + assert(exit_status >= 0 && exit_status < 0x1000); + va_list val; + va_start(val, format); + verror((Seriousness) (ERR_MIN_FATAL + (exit_status << ERRVERBOSITY_SHIFT)), where, format, val); + va_end(val); + return ERROR_RESULT; +} + +String +ErrorHandler::make_text(Seriousness seriousness, const char *format, ...) +{ + va_list val; + va_start(val, format); + String s = make_text(seriousness, format, val); + va_end(val); + return s; +} + +#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::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 ALTERNATE_FORM for zero results in base 16 + if ((flags & ErrH::ALTERNATE_FORM) && base == 16 && *pos == '0') + flags &= ~ErrH::ALTERNATE_FORM; + + // account for zero padding + if (precision >= 0) + while (after_last - pos < precision) + *--pos = '0'; + else if (flags & ErrH::ZERO_PAD) { + if ((flags & ErrH::ALTERNATE_FORM) && base == 16) + field_width -= 2; + if ((flags & ErrH::NEGATIVE) + || (flags & (ErrH::PLUS_POSITIVE | ErrH::SPACE_POSITIVE))) + field_width--; + while (after_last - pos < field_width) + *--pos = '0'; + } + + // alternate forms + if ((flags & ErrH::ALTERNATE_FORM) && base == 8 && pos[1] != '0') + *--pos = '0'; + else if ((flags & ErrH::ALTERNATE_FORM) && base == 16) { + *--pos = ((flags & ErrH::UPPERCASE) ? 'X' : 'x'); + *--pos = '0'; + } + + // sign + if (flags & ErrH::NEGATIVE) + *--pos = '-'; + else if (flags & ErrH::PLUS_POSITIVE) + *--pos = '+'; + else if (flags & ErrH::SPACE_POSITIVE) + *--pos = ' '; + + return pos; +} + +String +ErrorHandler::make_text(Seriousness seriousness, const char *s, va_list val) +{ + StringAccum msg; + + char numbuf[NUMBUF_SIZE]; // for numerics + numbuf[NUMBUF_SIZE-1] = 0; + + String placeholder; // to ensure temporaries aren't destroyed + + // prepend 'warning: ' to every line if appropriate + String begin_lines; + if (seriousness >= ERR_MIN_WARNING && seriousness < ERR_MIN_ERROR) { + begin_lines = String::stable_string("warning: ", 9); + msg << begin_lines; + } + + // 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, '%'); + + // handle begin_lines + const char *nl; + while (begin_lines && (nl = strchr(s, '\n')) && (!pct || nl < pct)) { + msg.append(s, nl + 1 - s); + if (nl[1]) + msg.append(begin_lines.data(), begin_lines.length()); + s = nl + 1; + } + + if (!pct) { + if (*s) + msg << s; + break; + } + if (pct != s) { + msg.append(s, pct - s); + s = pct; + } + + // parse flags + flags = 0; + flags: + switch (*++s) { + case '#': flags |= ALTERNATE_FORM; goto flags; + case '0': flags |= ZERO_PAD; goto flags; + case '-': flags |= LEFT_JUST; goto flags; + case ' ': flags |= SPACE_POSITIVE; goto flags; + case '+': flags |= PLUS_POSITIVE; 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 |= 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': + width_flag = 'h'; s++; goto width_flags; + case 'l': + width_flag = (width_flag == 'l' ? 'q' : 'l'); s++; goto width_flags; + case 'L': case 'q': + width_flag = 'q'; s++; goto width_flags; + } + + // 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)"; + if (flags & ALTERNATE_FORM) { + placeholder = String(s1).printable(); + s1 = placeholder.c_str(); + } + for (s2 = s1; *s2 && precision != 0; s2++) + if (precision > 0) + precision--; + 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 'd': + case 'i': + flags |= 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; +#ifdef HAVE_INT64_TYPES + if (width_flag == 'q') { + uint64_t qnum = va_arg(val, uint64_t); + if ((flags & SIGNED) && (int64_t)qnum < 0) + qnum = -(int64_t)qnum, flags |= NEGATIVE; + String q = cp_unparse_unsigned64(qnum, base, flags & UPPERCASE); + s1 = s2 - q.length(); + memcpy((char *)s1, q.data(), q.length()); + goto got_number; + } +#endif + if (width_flag == 'h') { + num = (unsigned short)va_arg(val, int); + if ((flags & SIGNED) && (short)num < 0) + num = -(short)num, flags |= NEGATIVE; + } else if (width_flag == 'l') { + num = va_arg(val, unsigned long); + if ((flags & SIGNED) && (long)num < 0) + num = -(long)num, flags |= NEGATIVE; + } else { + num = va_arg(val, unsigned int); + if ((flags & SIGNED) && (int)num < 0) + num = -(int)num, flags |= NEGATIVE; + } + s1 = do_number(num, (char *)s2, base, flags); + +#ifdef 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 |= UPPERCASE; + case 'x': + base = 16; + goto number; + + case 'p': { + 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 | 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 & 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 & ~ALTERNATE_FORM, -1, field_width); + break; + } +#endif + + case '{': { + const char *rbrace = strchr(s, '}'); + if (!rbrace || rbrace == s) + assert(0 /* Bad %{ in error */); + String name(s, rbrace - s); + s = rbrace + 1; + for (Conversion *item = error_items; item; item = item->next) + if (item->name == name) { + placeholder = item->hook(flags, VA_LIST_REF(val)); + s1 = placeholder.data(); + s2 = s1 + placeholder.length(); + goto got_result; + } + assert(0 /* Bad %{ in error */); + break; + } + + 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 & LEFT_JUST) { + memcpy(dest, s1, slen); + memset(dest + slen, ' ', field_width - slen); + } else { + memcpy(dest + field_width - slen, s1, slen); + memset(dest, (flags & ZERO_PAD ? '0' : ' '), field_width - slen); + } + } + + return msg.take_string(); +} + +String +ErrorHandler::decorate_text(Seriousness, const String &landmark, const String &text) +{ + String new_text = text; + + // handle landmark + if (landmark + && !(landmark.length() > 2 && landmark[0] == '\\' + && landmark.back() == '\\')) { + // ignore special-purpose landmarks (begin and end with a backslash `\') + // fix landmark: skip trailing spaces and trailing colon + int i, len = landmark.length(); + for (i = len - 1; i >= 0; i--) + if (!isspace((unsigned char) landmark[i])) + break; + if (i >= 0 && landmark[i] == ':') + i--; + + // prepend landmark, unless all spaces + if (i >= 0) + new_text = prepend_lines(landmark.substring(0, i+1) + ": ", new_text); + } + + return new_text; +} + +int +ErrorHandler::verror(Seriousness seriousness, const String &where, + const char *s, va_list val) +{ + String text = make_text(seriousness, s, val); + text = decorate_text(seriousness, where, text); + handle_text(seriousness, text); + return count_error(seriousness, text); +} + +int +ErrorHandler::verror_text(Seriousness seriousness, const String &where, + const String &text) +{ + // text is already made + String dec_text = decorate_text(seriousness, where, text); + handle_text(seriousness, dec_text); + return count_error(seriousness, dec_text); +} + +void +ErrorHandler::set_error_code(int) +{ +} + +String +ErrorHandler::prepend_lines(const String &prepend, const String &text) +{ + if (!prepend) + return text; + + StringAccum sa; + const char *begin = text.begin(); + const char *end = text.end(); + while (begin < end) { + const char *nl = std::find(begin, end, '\n'); + if (nl < end) + nl++; + sa << prepend << text.substring(begin, nl); + begin = nl; + } + + return sa.take_string(); +} + + +// +// BASE ERROR HANDLER +// + +int +BaseErrorHandler::count_error(Seriousness seriousness, const String &) +{ + if (seriousness < ERR_MIN_WARNING) + /* do nothing */; + else if (seriousness < ERR_MIN_ERROR) + _nwarnings++; + else + _nerrors++; + return (seriousness < ERR_MIN_WARNING ? OK_RESULT : ERROR_RESULT); +} + + +#ifndef __KERNEL__ +// +// FILE ERROR HANDLER +// + +FileErrorHandler::FileErrorHandler(FILE *f, const String &context) + : _f(f), _context(context) +{ +} + +void +FileErrorHandler::handle_text(Seriousness seriousness, const String &message) +{ + String text = prepend_lines(_context, message); + if (text && text.back() != '\n') + text += '\n'; + fwrite(text.data(), 1, text.length(), _f); + + if (seriousness >= ERR_MIN_FATAL) { + int exit_status = (seriousness - ERR_MIN_FATAL) >> ERRVERBOSITY_SHIFT; + exit(exit_status); + } +} +#endif + + +// +// SILENT ERROR HANDLER +// + +void +SilentErrorHandler::handle_text(Seriousness, const String &) +{ +} + + +// +// STATIC ERROR HANDLERS +// + +static ErrorHandler *the_default_handler = 0; +static ErrorHandler *the_ignore_handler = 0; + +ErrorHandler::Conversion * +ErrorHandler::add_conversion(const String &name, ConversionHook hook) +{ + if (Conversion *c = new Conversion) { + c->name = name; + c->hook = hook; + 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) +{ + the_default_handler = default_handler; + return the_default_handler; +} + +void +ErrorHandler::static_cleanup() +{ + delete the_default_handler; + delete the_ignore_handler; + the_default_handler = the_ignore_handler = 0; + while (error_items) { + Conversion *next = error_items->next; + delete error_items; + error_items = next; + } +} + +bool +ErrorHandler::has_default_handler() +{ + return the_default_handler ? true : false; +} + +ErrorHandler * +ErrorHandler::default_handler() +{ + assert(the_default_handler != 0); + return the_default_handler; +} + +ErrorHandler * +ErrorHandler::ignore_handler() +{ + if (!the_ignore_handler) + the_ignore_handler = new SilentErrorHandler; + return the_ignore_handler; +} + +void +ErrorHandler::set_default_handler(ErrorHandler *errh) +{ + the_default_handler = errh; +} + + +// +// ERROR VENEER +// + +int +ErrorVeneer::nwarnings() const +{ + return _errh->nwarnings(); +} + +int +ErrorVeneer::nerrors() const +{ + return _errh->nerrors(); +} + +void +ErrorVeneer::reset_counts() +{ + _errh->reset_counts(); +} + +String +ErrorVeneer::make_text(Seriousness seriousness, const char *s, va_list val) +{ + return _errh->make_text(seriousness, s, val); +} + +String +ErrorVeneer::decorate_text(Seriousness seriousness, const String &landmark, const String &text) +{ + return _errh->decorate_text(seriousness, landmark, text); +} + +void +ErrorVeneer::handle_text(Seriousness seriousness, const String &text) +{ + _errh->handle_text(seriousness, text); +} + +int +ErrorVeneer::count_error(Seriousness seriousness, const String &text) +{ + return _errh->count_error(seriousness, text); +} + + +// +// CONTEXT ERROR HANDLER +// + +ContextErrorHandler::ContextErrorHandler(ErrorHandler *errh, + const String &context, + const String &indent, + const String &context_landmark) + : ErrorVeneer(errh), _context(context), _indent(indent), + _context_landmark(context_landmark) +{ +} + +String +ContextErrorHandler::decorate_text(Seriousness seriousness, const String &landmark, const String &text) +{ + String context_lines; + if (_context) { + // do not print context or indent if underlying ErrorHandler doesn't want + // context + if (_errh->min_verbosity() > ERRVERBOSITY_CONTEXT) + _context = _indent = String(); + else { + context_lines = _errh->decorate_text(ERR_MESSAGE, (_context_landmark ? _context_landmark : landmark), _context); + if (context_lines && context_lines.back() != '\n') + context_lines += '\n'; + _context = String(); + } + } + return context_lines + _errh->decorate_text(seriousness, (landmark ? landmark : _context_landmark), prepend_lines(_indent, text)); +} + + +// +// PREFIX ERROR HANDLER +// + +PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh, + const String &prefix) + : ErrorVeneer(errh), _prefix(prefix) +{ +} + +String +PrefixErrorHandler::decorate_text(Seriousness seriousness, const String &landmark, const String &text) +{ + return _errh->decorate_text(seriousness, landmark, prepend_lines(_prefix, text)); +} + + +// +// LANDMARK ERROR HANDLER +// + +LandmarkErrorHandler::LandmarkErrorHandler(ErrorHandler *errh, const String &landmark) + : ErrorVeneer(errh), _landmark(landmark) +{ +} + +String +LandmarkErrorHandler::decorate_text(Seriousness seriousness, const String &lm, const String &text) +{ + if (lm) + return _errh->decorate_text(seriousness, lm, text); + else + return _errh->decorate_text(seriousness, _landmark, text); +} + + +// +// VERBOSE FILTER ERROR HANDLER +// + +VerboseFilterErrorHandler::VerboseFilterErrorHandler(ErrorHandler *errh, int min_verbosity) + : ErrorVeneer(errh), _min_verbosity(min_verbosity) +{ +} + +int +VerboseFilterErrorHandler::min_verbosity() const +{ + int m = _errh->min_verbosity(); + return (m >= _min_verbosity ? m : _min_verbosity); +} + +void +VerboseFilterErrorHandler::handle_text(Seriousness s, const String &text) +{ + if ((s & ERRVERBOSITY_MASK) >= _min_verbosity) + _errh->handle_text(s, text); +} + + +// +// BAIL ERROR HANDLER +// + +#ifndef __KERNEL__ + +BailErrorHandler::BailErrorHandler(ErrorHandler *errh, Seriousness s) + : ErrorVeneer(errh), _exit_seriousness(s) +{ +} + +void +BailErrorHandler::handle_text(Seriousness s, const String &text) +{ + _errh->handle_text(s, text); + if (s >= _exit_seriousness) + exit(1); +} + +#endif |