/* * Error and warning reporting and related functions. * * Copyright (C) 2001 Peter Johnson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define YASM_LIB_INTERNAL #include "util.h" /*@unused@*/ RCSID("$Id$"); #include #ifdef STDC_HEADERS # include #endif #include "coretype.h" #include "linemgr.h" #include "errwarn.h" #define MSG_MAXSIZE 1024 /* Default handlers for replacable functions */ static /*@exits@*/ void def_internal_error_ (const char *file, unsigned int line, const char *message); static /*@exits@*/ void def_fatal(const char *message, va_list va); static const char *def_gettext_hook(const char *msgid); /* Storage for errwarn's "extern" functions */ /*@exits@*/ void (*yasm_internal_error_) (const char *file, unsigned int line, const char *message) = def_internal_error_; /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal; const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook; /* Enabled warnings. See errwarn.h for a list. */ static unsigned long warn_class_enabled; /* Total error count */ static unsigned int error_count; /* Total warning count */ static unsigned int warning_count; typedef /*@reldef@*/ SLIST_HEAD(errwarndatahead_s, errwarn_data) errwarndatahead; static /*@only@*/ /*@null@*/ errwarndatahead errwarns; typedef struct errwarn_data { /*@reldef@*/ SLIST_ENTRY(errwarn_data) link; enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type; unsigned long line; unsigned long displine; /* FIXME: This should not be a fixed size. But we don't have vasprintf() * right now. */ char msg[MSG_MAXSIZE]; } errwarn_data; /* Last inserted error/warning. Used to speed up insertions. */ static /*@null@*/ errwarn_data *previous_we; /* Static buffer for use by conv_unprint(). */ static char unprint[5]; static const char * def_gettext_hook(const char *msgid) { return msgid; } void yasm_errwarn_initialize(void) { /* Default enabled warnings. See errwarn.h for a list. */ warn_class_enabled = (1UL<line) { if (ins_we == first) action = INS_HEAD; else ins_we = first; } else if (!next) action = INS_AFTER; else if (line >= ins_we->line && line < next->line) action = INS_AFTER; else ins_we = next; } if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) { /* overwrite last error */ we = ins_we; } else { /* add a new error */ we = yasm_xmalloc(sizeof(errwarn_data)); we->type = WE_UNKNOWN; we->line = line; we->displine = displine; if (action == INS_HEAD) SLIST_INSERT_HEAD(&errwarns, we, link); else if (action == INS_AFTER) { assert(ins_we != NULL); SLIST_INSERT_AFTER(ins_we, we, link); } else yasm_internal_error(N_("Unexpected errwarn insert action")); } /* Remember previous err/warn */ previous_we = we; return we; } /* Register an error at line line, displaying line displine. Does not print * the error, only stores it for output_all() to print. */ void yasm__error_va_at(unsigned long line, unsigned long displine, const char *fmt, va_list va) { errwarn_data *we = errwarn_data_new(line, displine, 1); we->type = WE_ERROR; #ifdef HAVE_VSNPRINTF vsnprintf(we->msg, MSG_MAXSIZE, yasm_gettext_hook(fmt), va); #else vsprintf(we->msg, yasm_gettext_hook(fmt), va); #endif error_count++; } /* Register an warning at line line, displaying line displine. Does not print * the warning, only stores it for output_all() to print. */ void yasm__warning_va_at(yasm_warn_class num, unsigned long line, unsigned long displine, const char *fmt, va_list va) { errwarn_data *we; if (!(warn_class_enabled & (1UL<type = WE_WARNING; #ifdef HAVE_VSNPRINTF vsnprintf(we->msg, MSG_MAXSIZE, yasm_gettext_hook(fmt), va); #else vsprintf(we->msg, yasm_gettext_hook(fmt), va); #endif warning_count++; } /* Register an error at line line. Does not print the error, only stores it * for output_all() to print. */ void yasm__error(unsigned long line, const char *fmt, ...) { va_list va; va_start(va, fmt); yasm__error_va_at(line, line, fmt, va); va_end(va); } /* Register an error at line line, displaying line displine. Does not print * the error, only stores it for output_all() to print. */ void yasm__error_at(unsigned long line, unsigned long displine, const char *fmt, ...) { va_list va; va_start(va, fmt); yasm__error_va_at(line, displine, fmt, va); va_end(va); } /* Register an warning at line line. Does not print the warning, only stores * it for output_all() to print. */ void yasm__warning(yasm_warn_class num, unsigned long line, const char *fmt, ...) { va_list va; va_start(va, fmt); yasm__warning_va_at(num, line, line, fmt, va); va_end(va); } /* Register an warning at line line, displaying line displine. Does not print * the warning, only stores it for output_all() to print. */ void yasm__warning_at(yasm_warn_class num, unsigned long line, unsigned long displine, const char *fmt, ...) { va_list va; va_start(va, fmt); yasm__warning_va_at(num, line, line, fmt, va); va_end(va); } /* Parser error handler. Moves YACC-style error into our error handling * system. */ void yasm__parser_error(unsigned long line, const char *s) { yasm__error(line, N_("parser error: %s"), s); previous_we->type = WE_PARSERERROR; } void yasm_warn_enable(yasm_warn_class num) { warn_class_enabled |= (1UL<displine, &filename, &line); if (we->type == WE_ERROR) print_error(filename, line, we->msg); else print_warning(filename, line, we->msg); } } void yasm__fatal(const char *message, ...) { va_list va; va_start(va, message); yasm_fatal(message, va); /*@notreached@*/ va_end(va); }