mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-11-08 23:27:15 -05:00
Tidy up a *lot* of code by moving error functions into separate source files. This required breaking out some of the assembler-only files into a separate library, as it conflicts with stubs in the disassembler. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
754 lines
19 KiB
C
754 lines
19 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
/* Copyright 1996-2025 The NASM Authors - All Rights Reserved */
|
|
|
|
/*
|
|
* error.c - error message handling routines for the assembler
|
|
*/
|
|
|
|
#include "compiler.h"
|
|
#include "nasmlib.h"
|
|
#include "error.h"
|
|
#include "listing.h"
|
|
#include "srcfile.h"
|
|
#include "strlist.h"
|
|
|
|
struct error_format {
|
|
const char *beforeline; /* Before line number, if present */
|
|
const char *afterline; /* After line number, if present */
|
|
const char *beforemsg; /* Before actual message */
|
|
};
|
|
|
|
enum error_formats {
|
|
ERRFMT_GNU,
|
|
ERRFMT_MSVC
|
|
};
|
|
static const struct error_format errfmts[] = {
|
|
{ ":", "", ": " }, /* ERRFMT_GNU */
|
|
{ "(", ")", " : " } /* ERRFMT_MSVC */
|
|
};
|
|
static const struct error_format *errfmt = &errfmts[ERRFMT_GNU];
|
|
|
|
static void usage(void);
|
|
|
|
/*
|
|
* Warning stack management. Note that there is an implicit "push"
|
|
* after the command line has been parsed, but this particular push
|
|
* cannot be popped.
|
|
*/
|
|
struct warning_stack {
|
|
struct warning_stack *next;
|
|
uint8_t state[sizeof warning_state];
|
|
};
|
|
static struct warning_stack *warning_stack, *warning_state_init;
|
|
static struct strlist *warn_list;
|
|
|
|
/* Push the warning status onto the warning stack */
|
|
void push_warnings(void)
|
|
{
|
|
struct warning_stack *ws;
|
|
|
|
ws = nasm_malloc(sizeof *ws);
|
|
memcpy(ws->state, warning_state, sizeof warning_state);
|
|
ws->next = warning_stack;
|
|
warning_stack = ws;
|
|
}
|
|
|
|
/* Pop the warning status off the warning stack */
|
|
void pop_warnings(void)
|
|
{
|
|
struct warning_stack *ws = warning_stack;
|
|
|
|
memcpy(warning_state, ws->state, sizeof warning_state);
|
|
if (!ws->next) {
|
|
nasm_warn(WARN_WARN_STACK_EMPTY, "warning stack empty");
|
|
} else {
|
|
warning_stack = ws->next;
|
|
nasm_free(ws);
|
|
}
|
|
}
|
|
|
|
/* Called after the command line is parsed, but before the first pass */
|
|
static void init_warnings(void)
|
|
{
|
|
push_warnings();
|
|
warning_state_init = warning_stack;
|
|
}
|
|
|
|
void error_init(void)
|
|
{
|
|
erropt.worst = 0;
|
|
init_warnings();
|
|
}
|
|
|
|
/* Called before each pass. Buffer warnings if "final" is false. */
|
|
void error_pass_start(bool final)
|
|
{
|
|
nasm_assert(!warn_list);
|
|
|
|
erropt.worst = 0;
|
|
if (!final)
|
|
warn_list = strlist_alloc(false);
|
|
}
|
|
|
|
/*
|
|
* Called after the completion of each pass. This MUST preserve erropt.worst!
|
|
*/
|
|
static void reset_warnings(void)
|
|
{
|
|
struct warning_stack *ws = warning_stack;
|
|
|
|
/* Unwind the warning stack. We do NOT delete the last entry! */
|
|
while (ws->next) {
|
|
struct warning_stack *wst = ws;
|
|
ws = ws->next;
|
|
nasm_free(wst);
|
|
}
|
|
warning_stack = ws;
|
|
memcpy(warning_state, ws->state, sizeof warning_state);
|
|
}
|
|
|
|
void error_pass_end(void)
|
|
{
|
|
strlist_free(&warn_list);
|
|
reset_warnings();
|
|
}
|
|
|
|
/*
|
|
* This is called when processing a -w or -W option, or a warning directive.
|
|
* Returns ok if the action was successful.
|
|
*
|
|
* Special pseudo-warnings (see warnings.dat):
|
|
* all - all possible warnings
|
|
* other - any warning not specifically assigned a class
|
|
*/
|
|
bool set_warning_status(const char *value)
|
|
{
|
|
enum warn_action { WID_OFF, WID_ON, WID_RESET };
|
|
enum warn_action action;
|
|
const struct warning_alias *wa;
|
|
size_t vlen;
|
|
bool ok = false;
|
|
uint8_t mask;
|
|
|
|
value = nasm_skip_spaces(value);
|
|
|
|
switch (*value) {
|
|
case '-':
|
|
action = WID_OFF;
|
|
value++;
|
|
break;
|
|
case '+':
|
|
action = WID_ON;
|
|
value++;
|
|
break;
|
|
case '*':
|
|
action = WID_RESET;
|
|
value++;
|
|
break;
|
|
case 'N':
|
|
case 'n':
|
|
if (!nasm_strnicmp(value, "no-", 3)) {
|
|
action = WID_OFF;
|
|
value += 3;
|
|
break;
|
|
} else if (!nasm_stricmp(value, "none")) {
|
|
action = WID_OFF;
|
|
value = NULL;
|
|
break;
|
|
}
|
|
/* else fall through */
|
|
default:
|
|
action = WID_ON;
|
|
break;
|
|
}
|
|
|
|
mask = WARN_ST_ENABLED;
|
|
|
|
if (value && !nasm_strnicmp(value, "error", 5)) {
|
|
switch (value[5]) {
|
|
case '=':
|
|
mask = WARN_ST_ERROR;
|
|
value += 6;
|
|
break;
|
|
case '\0':
|
|
mask = WARN_ST_ERROR;
|
|
value = NULL;
|
|
break;
|
|
default:
|
|
/* Just an accidental prefix? */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (value && !nasm_stricmp(value, "all"))
|
|
value = NULL;
|
|
|
|
vlen = value ? strlen(value) : 0;
|
|
|
|
/*
|
|
* This is inefficient, but it shouldn't matter.
|
|
* Note: warning_alias[0] is "all".
|
|
*/
|
|
for (wa = warning_alias+1;
|
|
wa < &warning_alias[NUM_WARNING_ALIAS]; wa++) {
|
|
enum warn_index i = wa->warning;
|
|
|
|
if (value) {
|
|
char sep;
|
|
|
|
if (nasm_strnicmp(value, wa->name, vlen))
|
|
continue; /* Not a prefix */
|
|
|
|
sep = wa->name[vlen];
|
|
if (sep != '\0' && sep != '-')
|
|
continue; /* Not a valid prefix */
|
|
}
|
|
|
|
ok = true; /* At least one action taken */
|
|
switch (action) {
|
|
case WID_OFF:
|
|
warning_state[i] &= ~mask;
|
|
break;
|
|
case WID_ON:
|
|
warning_state[i] |= mask;
|
|
break;
|
|
case WID_RESET:
|
|
warning_state[i] &= ~mask;
|
|
warning_state[i] |= warning_state_init->state[i] & mask;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!ok && value) {
|
|
nasm_warn(WARN_UNKNOWN_WARNING, "unknown warning name: %s", value);
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
/*
|
|
* The various error type prefixes
|
|
*/
|
|
const char *error_pfx(errflags severity)
|
|
{
|
|
switch (severity & ERR_MASK) {
|
|
case ERR_LISTMSG:
|
|
return ";;; ";
|
|
case ERR_NOTE:
|
|
return "note: ";
|
|
case ERR_DEBUG:
|
|
return "debug: ";
|
|
case ERR_INFO:
|
|
return "info: ";
|
|
case ERR_WARNING:
|
|
return "warning: ";
|
|
case ERR_NONFATAL:
|
|
return "error: ";
|
|
case ERR_FATAL:
|
|
return "fatal: ";
|
|
case ERR_CRITICAL:
|
|
return "critical: ";
|
|
case ERR_PANIC:
|
|
return "panic: ";
|
|
default:
|
|
return "internal error: ";
|
|
}
|
|
}
|
|
|
|
static bool skip_this_pass(errflags severity)
|
|
{
|
|
errflags type = severity & ERR_MASK;
|
|
|
|
/*
|
|
* See if it's a pass-specific error or warning which should be skipped.
|
|
* We can never skip fatal errors as by definition they cannot be
|
|
* resumed from.
|
|
*/
|
|
if (type >= ERR_FATAL)
|
|
return false;
|
|
|
|
/*
|
|
* ERR_LISTMSG and ERR_NOTE messages are always skipped; the list
|
|
* file receives them anyway as this function is not consulted for
|
|
* sending to the list file.
|
|
*/
|
|
if (type <= ERR_NOTE)
|
|
return true;
|
|
|
|
/*
|
|
* This message is not applicable unless it is the last pass we
|
|
* are going to execute; this can be either the final
|
|
* code-generation pass or the single pass executed in
|
|
* preproc-only mode.
|
|
*/
|
|
return (severity & ERR_PASS2) && !pass_final_or_preproc();
|
|
}
|
|
|
|
/**
|
|
* check for suppressed message (usually warnings or notes)
|
|
*
|
|
* @param severity the severity of the warning or error
|
|
* @return true if we should abort error/warning printing
|
|
*/
|
|
static bool is_suppressed(errflags flags)
|
|
{
|
|
const errflags severity = flags & ERR_MASK;
|
|
const errflags level = WARN_IDX(flags);
|
|
|
|
if (severity >= ERR_FATAL) {
|
|
/* Fatal errors or higher can never be suppressed */
|
|
return false;
|
|
}
|
|
|
|
if (flags & erropt.never)
|
|
return true;
|
|
|
|
switch (severity) {
|
|
case ERR_WARNING:
|
|
if (!(warning_state[level] & WARN_ST_ENABLED))
|
|
return true;
|
|
break;
|
|
|
|
case ERR_INFO:
|
|
if (!info_level(level))
|
|
return true;
|
|
break;
|
|
|
|
case ERR_DEBUG:
|
|
if (!debug_level(level))
|
|
return true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Suppressed by the preprocessor? */
|
|
if (!(flags & ERR_PP_LISTMACRO))
|
|
return pp_suppress_error(flags);
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Return the true error type (the ERR_MASK part) of the given
|
|
* severity, accounting for warnings that may need to be promoted to
|
|
* error.
|
|
*
|
|
* @param severity the severity of the warning or error
|
|
* @return true if we should error out
|
|
*/
|
|
static errflags pure_func true_error_type(errflags severity)
|
|
{
|
|
const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR;
|
|
int type;
|
|
|
|
type = severity & ERR_MASK;
|
|
|
|
if (type == ERR_WARNING) {
|
|
/* Promote warning to error? */
|
|
uint8_t state = warning_state[WARN_IDX(severity)];
|
|
if ((state & warn_is_err) == warn_is_err)
|
|
type = ERR_NONFATAL;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static const char no_file_name[] = "nasm"; /* What to print if no file name */
|
|
|
|
/*
|
|
* For fatal/critical/panic errors, kill this process.
|
|
*
|
|
* For FATAL errors doing cleanups, tidying up the list process,
|
|
* and so in is acceptable.
|
|
*
|
|
* For CRITICAL errors, minimize dependencies on memory allocation
|
|
* and/or having a system valid state.
|
|
*
|
|
* For PANIC, if abort_on_panic is set, abort without any other action.
|
|
*/
|
|
static_fatal_func die_hard(errflags true_type, errflags severity)
|
|
{
|
|
if (true_type < ERR_PANIC || !erropt.abort_on_panic) {
|
|
if (true_type < ERR_CRITICAL) {
|
|
/* FATAL shutdown, general cleanup actions are valid */
|
|
print_final_report(true);
|
|
lfmt->cleanup();
|
|
}
|
|
|
|
fflush(NULL);
|
|
|
|
close_output(true);
|
|
|
|
if (severity & ERR_USAGE)
|
|
usage();
|
|
|
|
/* Terminate immediately (exit closes any still open files) */
|
|
exit(true_type - ERR_FATAL + 1);
|
|
}
|
|
|
|
/*
|
|
* abort() shouldn't ever return, but be paranoid about this,
|
|
* plus it helps some compilers clue in to the fact that this
|
|
* function can never, ever return.
|
|
*/
|
|
while (1)
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Returns the struct src_location appropriate for use, after some
|
|
* potential filename mangling.
|
|
*/
|
|
static struct src_location error_where(errflags severity)
|
|
{
|
|
struct src_location where;
|
|
|
|
if (severity & ERR_NOFILE) {
|
|
where.filename = NULL;
|
|
where.lineno = 0;
|
|
} else {
|
|
where = src_where_error();
|
|
|
|
if (!where.filename) {
|
|
where.filename =
|
|
inname && inname[0] ? inname :
|
|
outname && outname[0] ? outname :
|
|
NULL;
|
|
where.lineno = 0;
|
|
}
|
|
}
|
|
|
|
return where;
|
|
}
|
|
|
|
/*
|
|
* error reporting for critical and panic errors: minimize
|
|
* the amount of system dependencies for getting a message out,
|
|
* and in particular try to avoid memory allocations.
|
|
*/
|
|
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args)
|
|
{
|
|
struct src_location where;
|
|
errflags true_type = severity & ERR_MASK;
|
|
static bool been_here = false;
|
|
|
|
while (unlikely(been_here))
|
|
abort(); /* Recursive critical error... just die */
|
|
|
|
been_here = true;
|
|
|
|
erropt.worst = true_type;
|
|
|
|
where = error_where(severity);
|
|
if (!where.filename)
|
|
where.filename = no_file_name;
|
|
|
|
fputs(error_pfx(severity), erropt.file);
|
|
fputs(where.filename, erropt.file);
|
|
if (where.lineno) {
|
|
fprintf(erropt.file, "%s%"PRId32"%s",
|
|
errfmt->beforeline, where.lineno, errfmt->afterline);
|
|
}
|
|
fputs(errfmt->beforemsg, erropt.file);
|
|
vfprintf(erropt.file, fmt, args);
|
|
fputc('\n', erropt.file);
|
|
|
|
die_hard(true_type, severity);
|
|
unreachable();
|
|
}
|
|
|
|
/**
|
|
* Stack of tentative error hold lists.
|
|
*/
|
|
struct nasm_errtext {
|
|
struct nasm_errtext *next;
|
|
char *msg; /* Owned by this structure */
|
|
struct src_location where; /* Owned by the srcfile system */
|
|
errflags severity;
|
|
errflags true_type;
|
|
int c_errno; /* Saved errno (for ERR_PERROR) */
|
|
};
|
|
struct nasm_errhold {
|
|
struct nasm_errhold *up;
|
|
struct nasm_errtext *head, **tail;
|
|
};
|
|
|
|
static struct strlist *warn_list;
|
|
static struct nasm_errhold *errhold_stack;
|
|
|
|
static void nasm_free_error(struct nasm_errtext *et)
|
|
{
|
|
nasm_free(et->msg);
|
|
nasm_free(et);
|
|
}
|
|
|
|
static void nasm_issue_error(struct nasm_errtext *et);
|
|
|
|
struct nasm_errhold *nasm_error_hold_push(void)
|
|
{
|
|
struct nasm_errhold *eh;
|
|
|
|
nasm_new(eh);
|
|
eh->up = errhold_stack;
|
|
eh->tail = &eh->head;
|
|
errhold_stack = eh;
|
|
|
|
return eh;
|
|
}
|
|
|
|
/* Pop an error hold. Returns the highest severity issued or dropped. */
|
|
errflags nasm_error_hold_pop(struct nasm_errhold *eh, bool issue)
|
|
{
|
|
struct nasm_errtext *et, *etmp;
|
|
errflags worst = 0;
|
|
|
|
/*
|
|
* Allow calling with a null argument saying no hold in the first place.
|
|
*/
|
|
if (!eh)
|
|
return worst;
|
|
|
|
/* This *must* be the current top of the errhold stack */
|
|
nasm_assert(eh == errhold_stack);
|
|
|
|
if (eh->head) {
|
|
if (issue) {
|
|
if (eh->up) {
|
|
/* Commit the current hold list to the previous level */
|
|
*eh->up->tail = eh->head;
|
|
eh->up->tail = eh->tail;
|
|
} else {
|
|
/* Issue errors */
|
|
list_for_each_safe(et, etmp, eh->head) {
|
|
if (et->true_type > worst)
|
|
worst = et->true_type;
|
|
nasm_issue_error(et);
|
|
}
|
|
}
|
|
} else {
|
|
/* Free the list, drop errors */
|
|
list_for_each_safe(et, etmp, eh->head) {
|
|
if (et->true_type > worst)
|
|
worst = et->true_type;
|
|
nasm_free_error(et);
|
|
}
|
|
}
|
|
}
|
|
|
|
errhold_stack = eh->up;
|
|
nasm_free(eh);
|
|
return worst;
|
|
}
|
|
|
|
/**
|
|
* common error reporting
|
|
* This is the common back end of the error reporting schemes currently
|
|
* implemented. It prints the nature of the warning and then the
|
|
* specific error message to erropt.file and may or may not return. It
|
|
* doesn't return if the error severity is a "panic" or "debug" type.
|
|
*
|
|
* @param severity the severity of the warning or error
|
|
* @param fmt the printf style format string
|
|
*/
|
|
void nasm_verror(errflags severity, const char *fmt, va_list args)
|
|
{
|
|
struct nasm_errtext *et;
|
|
int c_errno = errno;
|
|
errflags true_type = true_error_type(severity);
|
|
|
|
if (true_type >= ERR_CRITICAL) {
|
|
nasm_verror_critical(severity, fmt, args);
|
|
abort();
|
|
}
|
|
|
|
if (is_suppressed(severity))
|
|
return;
|
|
|
|
nasm_new(et);
|
|
et->c_errno = c_errno;
|
|
et->severity = severity;
|
|
et->true_type = true_type;
|
|
et->msg = nasm_vasprintf(fmt, args);
|
|
et->where = error_where(severity);
|
|
|
|
if (errhold_stack && true_type <= ERR_NONFATAL) {
|
|
/* It is a tentative error */
|
|
*errhold_stack->tail = et;
|
|
errhold_stack->tail = &et->next;
|
|
} else {
|
|
nasm_issue_error(et);
|
|
}
|
|
|
|
/*
|
|
* Don't do this before then, if we do, we lose messages in the list
|
|
* file, as the list file is only generated in the last pass.
|
|
*/
|
|
if (skip_this_pass(severity))
|
|
return;
|
|
|
|
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO)))
|
|
pp_error_list_macros(severity);
|
|
}
|
|
|
|
/*
|
|
* Actually print, list and take action on an error
|
|
*/
|
|
static void nasm_issue_error(struct nasm_errtext *et)
|
|
{
|
|
const char *pfx;
|
|
char warnsuf[64]; /* Warning suffix */
|
|
char linestr[64]; /* Formatted line number if applicable */
|
|
const errflags severity = et->severity;
|
|
const errflags true_type = et->true_type;
|
|
const struct src_location where = et->where;
|
|
const char *cerrsep = "";
|
|
const char *cerrmsg = "";
|
|
bool buffer = true_type < ERR_NONFATAL || (severity & ERR_HOLD);
|
|
|
|
if (severity & ERR_NO_SEVERITY)
|
|
pfx = "";
|
|
else
|
|
pfx = error_pfx(true_type);
|
|
|
|
*warnsuf = 0;
|
|
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO))) {
|
|
switch (severity & ERR_MASK) {
|
|
case ERR_WARNING:
|
|
{
|
|
const unsigned int level = WARN_IDX(severity);
|
|
snprintf(warnsuf, sizeof warnsuf, " [-w+%s%s]",
|
|
(true_type >= ERR_NONFATAL) ? "error=" : "",
|
|
warning_name[level]);
|
|
break;
|
|
}
|
|
case ERR_DEBUG:
|
|
snprintf(warnsuf, sizeof warnsuf, " [--debug=%u]", erropt.debug_nasm);
|
|
break;
|
|
case ERR_INFO:
|
|
snprintf(warnsuf, sizeof warnsuf, " [--info=%u]", erropt.verbose_info);
|
|
break;
|
|
default:
|
|
/* Not WARNING, DEBUG or INFO, not suppressible */
|
|
break;
|
|
}
|
|
|
|
if (severity & ERR_PERROR) {
|
|
cerrsep = ":";
|
|
cerrmsg = strerror(et->c_errno);
|
|
}
|
|
}
|
|
|
|
*linestr = 0;
|
|
if (where.lineno) {
|
|
snprintf(linestr, sizeof linestr, "%s%"PRId32"%s",
|
|
errfmt->beforeline, where.lineno, errfmt->afterline);
|
|
}
|
|
|
|
if (!skip_this_pass(severity)) {
|
|
const char *file = where.filename ? where.filename : no_file_name;
|
|
const char *here = "";
|
|
|
|
if (severity & ERR_HERE) {
|
|
here = where.filename ? " here" : " in an unknown location";
|
|
}
|
|
|
|
if (!warn_list)
|
|
buffer = false;
|
|
|
|
if (buffer) {
|
|
/*
|
|
* Buffer up warnings and held errors until we either get
|
|
* an error or we are on the code-generation pass.
|
|
*/
|
|
strlist_printf(warn_list, "%s%s%s%s%s%s%s%s%s",
|
|
file, linestr, errfmt->beforemsg,
|
|
pfx, et->msg, cerrsep, cerrmsg,
|
|
here, warnsuf);
|
|
} else {
|
|
/*
|
|
* Actually output an error. If we have buffered
|
|
* warnings, and this is a non-warning, output them now.
|
|
*/
|
|
if (warn_list) {
|
|
strlist_write(warn_list, "\n", erropt.file);
|
|
strlist_free(&warn_list);
|
|
}
|
|
|
|
fprintf(erropt.file, "%s%s%s%s%s%s%s%s%s\n",
|
|
file, linestr, errfmt->beforemsg,
|
|
pfx, et->msg, cerrsep, cerrmsg,
|
|
here, warnsuf);
|
|
}
|
|
}
|
|
|
|
/* Are we recursing from error_list_macros? */
|
|
if (severity & ERR_PP_LISTMACRO)
|
|
goto done;
|
|
|
|
/*
|
|
* Don't suppress this with skip_this_pass(), or we don't get
|
|
* pass1 or preprocessor warnings in the list file
|
|
*/
|
|
if (severity & ERR_HERE) {
|
|
if (where.lineno)
|
|
lfmt->error(severity, "%s%s at %s:%"PRId32"%s",
|
|
pfx, et->msg, where.filename, where.lineno, warnsuf);
|
|
else if (where.filename)
|
|
lfmt->error(severity, "%s%s in file %s%s",
|
|
pfx, et->msg, where.filename, warnsuf);
|
|
else
|
|
lfmt->error(severity, "%s%s in an unknown location%s",
|
|
pfx, et->msg, warnsuf);
|
|
} else {
|
|
lfmt->error(severity, "%s%s%s", pfx, et->msg, warnsuf);
|
|
}
|
|
|
|
if (skip_this_pass(severity))
|
|
goto done;
|
|
|
|
if (true_type >= ERR_FATAL) {
|
|
die_hard(true_type, severity);
|
|
} else if (!buffer) {
|
|
if (true_type > erropt.worst)
|
|
erropt.worst = true_type;
|
|
|
|
if (true_type >= ERR_NONFATAL)
|
|
erropt.never |= ERR_UNDEAD;
|
|
}
|
|
|
|
done:
|
|
nasm_free_error(et);
|
|
}
|
|
|
|
|
|
int set_error_format(const char *fmt)
|
|
{
|
|
if (!nasm_stricmp("vc", fmt) ||
|
|
!nasm_stricmp("msvc", fmt) ||
|
|
!nasm_stricmp("ms", fmt))
|
|
errfmt = &errfmts[ERRFMT_MSVC];
|
|
else if (!nasm_stricmp("gnu", fmt) ||
|
|
!nasm_stricmp("gcc", fmt))
|
|
errfmt = &errfmts[ERRFMT_GNU];
|
|
else
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
fprintf(erropt.file,
|
|
"Usage: %s [-@ response_file] [options...] [--] filename\n"
|
|
" For additional help:\n"
|
|
" %s -h [run|topics|all|-option]\n",
|
|
_progname, _progname);
|
|
}
|
|
|
|
void warn_dollar_hex(void)
|
|
{
|
|
nasm_warn(WARN_NUMBER_DEPRECATED_HEX,
|
|
"$ prefix for hexadecimal is deprecated");
|
|
}
|