Yasm Assembler mainline development tree (ffmpeg 依赖)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

342 lines
8.4 KiB

/*
* Error and warning reporting and related functions.
*
* Copyright (C) 2001 Peter Johnson
*
* This file is part of YASM.
*
* YASM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* YASM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "util.h"
/*@unused@*/ RCSID("$IdPath$");
#include <ctype.h>
#ifdef STDC_HEADERS
# include <stdarg.h>
#endif
#ifdef gettext_noop
#define N_(String) gettext_noop(String)
#else
#define N_(String) (String)
#endif
#include "globals.h"
#include "errwarn.h"
/* ALL warnings are disabled if this is nonzero. */
int warnings_disabled = 0;
/* Warnings are treated as errors if this is nonzero.
* =2 indicates that warnings are treated as errors, and the message to the
* user saying that has been output.
*/
int warning_error = 0;
/* Default enabled warnings. See errwarn.h for a list. */
unsigned long warning_flags =
(1<<WARN_UNRECOGNIZED_CHAR);
/* Total error count for entire assembler run.
* Assembler should exit with EXIT_FAILURE if this is >= 0 on finish. */
static unsigned int error_count = 0;
/* Total warning count for entire assembler run.
* Should not affect exit value of assembler. */
static unsigned int warning_count = 0;
/* See errwarn.h for constants that match up to these strings.
* When adding a string here, keep errwarn.h in sync! */
/* Fatal error messages. Match up with fatal_num enum in errwarn.h. */
/*@-observertrans@*/
static const char *fatal_msgs[] = {
N_("unknown"),
N_("out of memory")
};
/*@=observertrans@*/
typedef /*@reldef@*/ STAILQ_HEAD(errwarnhead_s, errwarn_s) errwarnhead;
static /*@only@*/ /*@null@*/ errwarnhead *errwarns = (errwarnhead *)NULL;
typedef struct errwarn_s {
/*@reldef@*/ STAILQ_ENTRY(errwarn_s) link;
enum { WE_ERROR, WE_WARNING } type;
unsigned long line;
/* FIXME: This should not be a fixed size. But we don't have vasprintf()
* right now. */
char msg[1024];
} errwarn;
/* Line number of the previous error. Set and checked by Error(). */
static unsigned long previous_error_line = 0;
/* Is the last error a parser error? Error() lets other errors override parser
* errors. Set by yyerror(), read and reset by Error(). */
static int previous_error_parser = 0;
/* Line number of the previous warning. Set and checked by Warning(). */
static unsigned long previous_warning_line = 0;
/* Static buffer for use by conv_unprint(). */
static char unprint[5];
/* Convert a possibly unprintable character into a printable string, using
* standard cat(1) convention for unprintable characters. */
char *
conv_unprint(char ch)
{
int pos = 0;
if (((ch & ~0x7F) != 0) /*!isascii(ch)*/ && !isprint(ch)) {
unprint[pos++] = 'M';
unprint[pos++] = '-';
ch &= toascii(ch);
}
if (iscntrl(ch)) {
unprint[pos++] = '^';
unprint[pos++] = (ch == '\177') ? '?' : ch | 0100;
} else
unprint[pos++] = ch;
unprint[pos] = '\0';
return unprint;
}
/* Parser error handler. Moves error into our error handling system. */
void
ParserError(const char *s)
{
Error("%s %s", _("parser error:"), s);
previous_error_parser = 1;
}
/* Report an internal error. Essentially a fatal error with trace info.
* Exit immediately because it's essentially an assert() trap. */
void
InternalError_(const char *file, unsigned int line, const char *message)
{
fprintf(stderr, _("INTERNAL ERROR at %s, line %d: %s\n"), file, line,
message);
#ifdef HAVE_ABORT
abort();
#else
exit(EXIT_FAILURE);
#endif
}
/* Report a fatal error. These are unrecoverable (such as running out of
* memory), so just exit immediately. */
void
Fatal(fatal_num num)
{
fprintf(stderr, "%s %s\n", _("FATAL:"), gettext(fatal_msgs[num]));
#ifdef HAVE_ABORT
abort();
#else
exit(EXIT_FAILURE);
#endif
}
/* Register an error. Uses argtypes as described above to specify the
* argument types. Does not print the error, only stores it for
* OutputAllErrorWarning() to print. */
void
Error(const char *fmt, ...)
{
va_list ap;
errwarn *we;
if ((previous_error_line == line_index) && !previous_error_parser)
return;
if (!errwarns) {
errwarns = xmalloc(sizeof(errwarnhead));
STAILQ_INIT(errwarns);
}
if (previous_error_parser) {
/* overwrite last (parser) error */
we = STAILQ_LAST(errwarns, errwarn_s, link);
} else {
we = xmalloc(sizeof(errwarn));
we->type = WE_ERROR;
we->line = line_index;
}
assert(we != NULL);
va_start(ap, fmt);
vsprintf(we->msg, fmt, ap);
va_end(ap);
/*@-branchstate@*/
if (!previous_error_parser)
STAILQ_INSERT_TAIL(errwarns, we, link);
/*@=branchstate@*/
previous_error_line = line_index;
previous_error_parser = 0;
error_count++;
}
/* Register a warning. Uses argtypes as described above to specify the
* argument types. Does not print the warning, only stores it for
* OutputAllErrorWarning() to print. */
void
Warning(const char *fmt, ...)
{
va_list ap;
errwarn *we;
if (warnings_disabled)
return;
if (previous_warning_line == line_index)
return;
previous_warning_line = line_index;
we = xmalloc(sizeof(errwarn));
we->type = WE_WARNING;
we->line = line_index;
va_start(ap, fmt);
vsprintf(we->msg, fmt, ap);
va_end(ap);
if (!errwarns) {
errwarns = xmalloc(sizeof(errwarnhead));
STAILQ_INIT(errwarns);
}
STAILQ_INSERT_TAIL(errwarns, we, link);
warning_count++;
}
void
ErrorNow(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
void
WarningNow(const char *fmt, ...)
{
va_list ap;
if (warnings_disabled)
return;
fprintf(stderr, "%s ", _("warning:"));
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
void
ErrorAt(unsigned long lindex, const char *fmt, ...)
{
/* XXX: Should insert into list instead of printing immediately */
va_list ap;
const char *filename;
unsigned long line;
line_lookup(lindex, &filename, &line);
fprintf(stderr, "%s:%lu: ", filename?filename:"(NULL)", line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
void
WarningAt(unsigned long lindex, const char *fmt, ...)
{
/* XXX: Should insert into list instead of printing immediately */
va_list ap;
const char *filename;
unsigned long line;
if (warnings_disabled)
return;
line_lookup(lindex, &filename, &line);
fprintf(stderr, "%s:%lu: %s ", filename?filename:"NULL", line,
_("warning:"));
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
/* Output all previously stored errors and warnings to stderr. */
unsigned int
OutputAllErrorWarning(void)
{
errwarn *we, *we2;
const char *filename;
unsigned long line;
/* If errwarns hasn't been initialized, there are no messages. */
if (!errwarns) {
if (warning_error)
return error_count+warning_count;
else
return error_count;
}
/* If we're treating warnings as errors, tell the user about it. */
if (warning_error && warning_error != 2) {
fprintf(stderr, "%s\n", _("warnings being treated as errors"));
warning_error = 2;
}
/* Output error and warning messages. */
STAILQ_FOREACH(we, errwarns, link) {
line_lookup(we->line, &filename, &line);
if (we->type == WE_ERROR)
fprintf(stderr, "%s:%lu: %s\n", filename, line, we->msg);
else
fprintf(stderr, "%s:%lu: %s %s\n", filename, line, _("warning:"),
we->msg);
}
/* Delete messages. */
we = STAILQ_FIRST(errwarns);
while (we) {
we2 = STAILQ_NEXT(we, link);
xfree(we);
we = we2;
}
/* Return the total error count up to this point.
* If we're treating warnings as errors, add that to the total as well.
*/
if (warning_error)
return error_count+warning_count;
return error_count;
}