2 * Error and warning reporting and related functions.
4 * Copyright (C) 2001-2007 Peter Johnson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
38 #define MSG_MAXSIZE 1024
40 #if !defined(HAVE_TOASCII) || defined(lint)
41 # define toascii(c) ((c) & 0x7F)
44 /* Default handlers for replacable functions */
45 static /*@exits@*/ void def_internal_error_
46 (const char *file, unsigned int line, const char *message);
47 static /*@exits@*/ void def_fatal(const char *message, va_list va);
48 static const char *def_gettext_hook(const char *msgid);
50 /* Storage for errwarn's "extern" functions */
51 /*@exits@*/ void (*yasm_internal_error_)
52 (const char *file, unsigned int line, const char *message)
53 = def_internal_error_;
54 /*@exits@*/ void (*yasm_fatal) (const char *message, va_list va) = def_fatal;
55 const char * (*yasm_gettext_hook) (const char *msgid) = def_gettext_hook;
58 /* yasm_eclass is not static so that yasm_error_occurred macro can access it */
59 yasm_error_class yasm_eclass;
60 static /*@only@*/ /*@null@*/ char *yasm_estr;
61 static unsigned long yasm_exrefline;
62 static /*@only@*/ /*@null@*/ char *yasm_exrefstr;
64 /* Warning indicator */
66 /*@reldef@*/ STAILQ_ENTRY(warn) link;
68 yasm_warn_class wclass;
69 /*@owned@*/ /*@null@*/ char *wstr;
71 static STAILQ_HEAD(warn_head, warn) yasm_warns;
73 /* Enabled warnings. See errwarn.h for a list. */
74 static unsigned long warn_class_enabled;
76 typedef struct errwarn_data {
77 /*@reldef@*/ SLIST_ENTRY(errwarn_data) link;
79 enum { WE_UNKNOWN, WE_ERROR, WE_WARNING, WE_PARSERERROR } type;
82 unsigned long xrefline;
83 /*@owned@*/ char *msg;
84 /*@owned@*/ char *xrefmsg;
87 struct yasm_errwarns {
88 /*@reldef@*/ SLIST_HEAD(errwarn_head, errwarn_data) errwarns;
90 /* Total error count */
93 /* Total warning count */
96 /* Last inserted error/warning. Used to speed up insertions. */
97 /*@null@*/ errwarn_data *previous_we;
100 /* Static buffer for use by conv_unprint(). */
101 static char unprint[5];
105 def_gettext_hook(const char *msgid)
111 yasm_errwarn_initialize(void)
113 /* Default enabled warnings. See errwarn.h for a list. */
115 (1UL<<YASM_WARN_GENERAL) | (1UL<<YASM_WARN_UNREC_CHAR) |
116 (1UL<<YASM_WARN_PREPROC) | (0UL<<YASM_WARN_ORPHAN_LABEL) |
117 (1UL<<YASM_WARN_UNINIT_CONTENTS) | (0UL<<YASM_WARN_SIZE_OVERRIDE) |
118 (1UL<<YASM_WARN_IMPLICIT_SIZE_OVERRIDE);
120 yasm_eclass = YASM_ERROR_NONE;
123 yasm_exrefstr = NULL;
125 STAILQ_INIT(&yasm_warns);
129 yasm_errwarn_cleanup(void)
135 /* Convert a possibly unprintable character into a printable string, using
136 * standard cat(1) convention for unprintable characters.
139 yasm__conv_unprint(int ch)
143 if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) {
144 unprint[pos++] = 'M';
145 unprint[pos++] = '-';
149 unprint[pos++] = '^';
150 unprint[pos++] = (ch == '\177') ? '?' : ch | 0100;
158 /* Report an internal error. Essentially a fatal error with trace info.
159 * Exit immediately because it's essentially an assert() trap.
162 def_internal_error_(const char *file, unsigned int line, const char *message)
165 yasm_gettext_hook(N_("INTERNAL ERROR at %s, line %u: %s\n")),
166 file, line, yasm_gettext_hook(message));
174 /* Report a fatal error. These are unrecoverable (such as running out of
175 * memory), so just exit immediately.
178 def_fatal(const char *fmt, va_list va)
180 fprintf(stderr, "%s: ", yasm_gettext_hook(N_("FATAL")));
181 vfprintf(stderr, yasm_gettext_hook(fmt), va);
186 /* Create an errwarn structure in the correct linked list location.
187 * If replace_parser_error is nonzero, overwrites the last error if its
188 * type is WE_PARSERERROR.
190 static errwarn_data *
191 errwarn_data_new(yasm_errwarns *errwarns, unsigned long line,
192 int replace_parser_error)
194 errwarn_data *first, *next, *ins_we, *we;
195 enum { INS_NONE, INS_HEAD, INS_AFTER } action = INS_NONE;
197 /* Find the entry with either line=line or the last one with line<line.
198 * Start with the last entry added to speed the search.
200 ins_we = errwarns->previous_we;
201 first = SLIST_FIRST(&errwarns->errwarns);
202 if (!ins_we || !first)
204 while (action == INS_NONE) {
205 next = SLIST_NEXT(ins_we, link);
206 if (line < ins_we->line) {
213 else if (line >= ins_we->line && line < next->line)
219 if (replace_parser_error && ins_we && ins_we->type == WE_PARSERERROR) {
220 /* overwrite last error */
223 /* add a new error */
224 we = yasm_xmalloc(sizeof(errwarn_data));
226 we->type = WE_UNKNOWN;
232 if (action == INS_HEAD)
233 SLIST_INSERT_HEAD(&errwarns->errwarns, we, link);
234 else if (action == INS_AFTER) {
235 assert(ins_we != NULL);
236 SLIST_INSERT_AFTER(ins_we, we, link);
238 yasm_internal_error(N_("Unexpected errwarn insert action"));
241 /* Remember previous err/warn */
242 errwarns->previous_we = we;
248 yasm_error_clear(void)
251 yasm_xfree(yasm_estr);
253 yasm_xfree(yasm_exrefstr);
254 yasm_eclass = YASM_ERROR_NONE;
257 yasm_exrefstr = NULL;
261 yasm_error_matches(yasm_error_class eclass)
263 if (yasm_eclass == YASM_ERROR_NONE)
264 return eclass == YASM_ERROR_NONE;
265 if (yasm_eclass == YASM_ERROR_GENERAL)
266 return eclass == YASM_ERROR_GENERAL;
267 return (yasm_eclass & eclass) == eclass;
271 yasm_error_set_va(yasm_error_class eclass, const char *format, va_list va)
273 if (yasm_eclass != YASM_ERROR_NONE)
276 yasm_eclass = eclass;
277 yasm_estr = yasm_xmalloc(MSG_MAXSIZE+1);
278 #ifdef HAVE_VSNPRINTF
279 vsnprintf(yasm_estr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
281 vsprintf(yasm_estr, yasm_gettext_hook(format), va);
286 yasm_error_set(yasm_error_class eclass, const char *format, ...)
289 va_start(va, format);
290 yasm_error_set_va(eclass, format, va);
295 yasm_error_set_xref_va(unsigned long xrefline, const char *format, va_list va)
297 if (yasm_eclass != YASM_ERROR_NONE)
300 yasm_exrefline = xrefline;
302 yasm_exrefstr = yasm_xmalloc(MSG_MAXSIZE+1);
303 #ifdef HAVE_VSNPRINTF
304 vsnprintf(yasm_exrefstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
306 vsprintf(yasm_exrefstr, yasm_gettext_hook(format), va);
311 yasm_error_set_xref(unsigned long xrefline, const char *format, ...)
314 va_start(va, format);
315 yasm_error_set_xref_va(xrefline, format, va);
320 yasm_error_fetch(yasm_error_class *eclass, char **str, unsigned long *xrefline,
323 *eclass = yasm_eclass;
325 *xrefline = yasm_exrefline;
326 *xrefstr = yasm_exrefstr;
327 yasm_eclass = YASM_ERROR_NONE;
330 yasm_exrefstr = NULL;
333 void yasm_warn_clear(void)
335 /* Delete all error/warnings */
336 while (!STAILQ_EMPTY(&yasm_warns)) {
337 warn *w = STAILQ_FIRST(&yasm_warns);
342 STAILQ_REMOVE_HEAD(&yasm_warns, link);
348 yasm_warn_occurred(void)
350 if (STAILQ_EMPTY(&yasm_warns))
351 return YASM_WARN_NONE;
352 return STAILQ_FIRST(&yasm_warns)->wclass;
356 yasm_warn_set_va(yasm_warn_class wclass, const char *format, va_list va)
360 if (!(warn_class_enabled & (1UL<<wclass)))
361 return; /* warning is part of disabled class */
363 w = yasm_xmalloc(sizeof(warn));
365 w->wstr = yasm_xmalloc(MSG_MAXSIZE+1);
366 #ifdef HAVE_VSNPRINTF
367 vsnprintf(w->wstr, MSG_MAXSIZE, yasm_gettext_hook(format), va);
369 vsprintf(w->wstr, yasm_gettext_hook(format), va);
371 STAILQ_INSERT_TAIL(&yasm_warns, w, link);
375 yasm_warn_set(yasm_warn_class wclass, const char *format, ...)
378 va_start(va, format);
379 yasm_warn_set_va(wclass, format, va);
384 yasm_warn_fetch(yasm_warn_class *wclass, char **str)
386 warn *w = STAILQ_FIRST(&yasm_warns);
389 *wclass = YASM_WARN_NONE;
397 STAILQ_REMOVE_HEAD(&yasm_warns, link);
402 yasm_warn_enable(yasm_warn_class num)
404 warn_class_enabled |= (1UL<<num);
408 yasm_warn_disable(yasm_warn_class num)
410 warn_class_enabled &= ~(1UL<<num);
414 yasm_warn_disable_all(void)
416 warn_class_enabled = 0;
420 yasm_errwarns_create(void)
422 yasm_errwarns *errwarns = yasm_xmalloc(sizeof(yasm_errwarns));
423 SLIST_INIT(&errwarns->errwarns);
424 errwarns->ecount = 0;
425 errwarns->wcount = 0;
426 errwarns->previous_we = NULL;
431 yasm_errwarns_destroy(yasm_errwarns *errwarns)
435 /* Delete all error/warnings */
436 while (!SLIST_EMPTY(&errwarns->errwarns)) {
437 we = SLIST_FIRST(&errwarns->errwarns);
441 yasm_xfree(we->xrefmsg);
443 SLIST_REMOVE_HEAD(&errwarns->errwarns, link);
447 yasm_xfree(errwarns);
451 yasm_errwarn_propagate(yasm_errwarns *errwarns, unsigned long line)
453 if (yasm_eclass != YASM_ERROR_NONE) {
454 errwarn_data *we = errwarn_data_new(errwarns, line, 1);
455 yasm_error_class eclass;
457 yasm_error_fetch(&eclass, &we->msg, &we->xrefline, &we->xrefmsg);
458 if (eclass != YASM_ERROR_GENERAL
459 && (eclass & YASM_ERROR_PARSE) == YASM_ERROR_PARSE)
460 we->type = WE_PARSERERROR;
466 while (!STAILQ_EMPTY(&yasm_warns)) {
467 errwarn_data *we = errwarn_data_new(errwarns, line, 0);
468 yasm_warn_class wclass;
470 yasm_warn_fetch(&wclass, &we->msg);
471 we->type = WE_WARNING;
477 yasm_errwarns_num_errors(yasm_errwarns *errwarns, int warning_as_error)
479 if (warning_as_error)
480 return errwarns->ecount+errwarns->wcount;
482 return errwarns->ecount;
486 yasm_errwarns_output_all(yasm_errwarns *errwarns, yasm_linemap *lm,
487 int warning_as_error,
488 yasm_print_error_func print_error,
489 yasm_print_warning_func print_warning)
492 const char *filename, *xref_filename;
493 unsigned long line, xref_line;
495 /* If we're treating warnings as errors, tell the user about it. */
496 if (warning_as_error && warning_as_error != 2) {
498 yasm_gettext_hook(N_("warnings being treated as errors")),
500 warning_as_error = 2;
503 /* Output error/warnings. */
504 SLIST_FOREACH(we, &errwarns->errwarns, link) {
505 /* Output error/warning */
506 yasm_linemap_lookup(lm, we->line, &filename, &line);
508 yasm_linemap_lookup(lm, we->xrefline, &xref_filename, &xref_line);
510 xref_filename = NULL;
513 if (we->type == WE_ERROR || we->type == WE_PARSERERROR)
514 print_error(filename, line, we->msg, xref_filename, xref_line,
517 print_warning(filename, line, we->msg);
522 yasm__fatal(const char *message, ...)
525 va_start(va, message);
526 yasm_fatal(message, va);