diff --git a/Makefile.in b/Makefile.in index 030a2ef2e..6b8bfc2a1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -165,7 +165,7 @@ LIBOBJ_COM = \ nasmlib/perfhash.$(O) nasmlib/badenum.$(O) \ nasmlib/readnum.$(O) \ \ - common/common.$(O) common/errstubs.$(O) \ + common/common.$(O) common/errstubs.$(O) common/files.$(O) \ \ x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsn.$(O) \ x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) \ diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak index 4117df2e4..981f93206 100644 --- a/Mkfiles/msvc.mak +++ b/Mkfiles/msvc.mak @@ -117,7 +117,7 @@ LIBOBJ_COM = \ nasmlib\perfhash.obj nasmlib\badenum.obj \ nasmlib\readnum.obj \ \ - common\common.obj common\errstubs.obj \ + common\common.obj common\errstubs.obj common\files.obj \ \ x86\insnsa.obj x86\insnsb.obj x86\insnsn.obj \ x86\regs.obj x86\regvals.obj x86\regflags.obj \ diff --git a/Mkfiles/openwcom.mak b/Mkfiles/openwcom.mak index f2ec979b8..b3cba01aa 100644 --- a/Mkfiles/openwcom.mak +++ b/Mkfiles/openwcom.mak @@ -114,7 +114,7 @@ LIBOBJ_COM = & nasmlib/perfhash.obj nasmlib/badenum.obj & nasmlib/readnum.obj & & - common/common.obj common/errstubs.obj & + common/common.obj common/errstubs.obj common/files.obj & & x86/insnsa.obj x86/insnsb.obj x86/insnsn.obj & x86/regs.obj x86/regvals.obj x86/regflags.obj & diff --git a/asm/error.c b/asm/error.c index a43f0696c..77f498389 100644 --- a/asm/error.c +++ b/asm/error.c @@ -8,6 +8,7 @@ #include "compiler.h" #include "nasmlib.h" #include "error.h" +#include "files.h" #include "listing.h" #include "srcfile.h" #include "strlist.h" @@ -411,10 +412,14 @@ static struct src_location error_where(errflags severity) where = src_where_error(); if (!where.filename) { - where.filename = - inname && inname[0] ? inname : - outname && outname[0] ? outname : - NULL; + enum filenames fn; + for (fn = FN_INFILE; fn <= FN_OUTFILE; fn++) { + const char *name = get_filename(fn); + if (name && *name) { + where.filename = name; + break; + } + } where.lineno = 0; } } diff --git a/asm/nasm.c b/asm/nasm.c index 020e1ce3f..383f38876 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -27,6 +27,7 @@ #include "iflag.h" #include "quote.h" #include "ver.h" +#include "files.h" #include "error.h" /* @@ -68,11 +69,6 @@ int64_t _passn; struct compile_time official_compile_time; -const char *inname; -const char *outname; -static const char *listname; -static const char *errname; - static int64_t globallineno; /* for forward-reference tracking */ const struct ofmt *ofmt = &OF_DEFAULT; @@ -109,7 +105,6 @@ static unsigned int operating_mode; static bool depend_emit_phony = false; static bool depend_missing_ok = false; static char *depend_target = NULL; -static char *depend_file = NULL; struct strlist *depend_list; static inline bool terminate_after_phase(void) @@ -439,6 +434,7 @@ static void emit_dependencies(struct strlist *list) bool wmake = (quote_for_make == quote_for_wmake); const char *wrapstr, *nulltarget; const struct strlist_entry *l; + const char * const depend_file = get_filename(FN_DEPENDFILE); if (!list) return; @@ -579,6 +575,59 @@ static void timestamp(void) } } +static const char *fix_outfile_name(void) +{ + const char * const outname = get_filename(FN_OUTFILE); + const char *inname; + char *newname; + + if (outname) + return outname; /* Output file already set */ + + if (operating_mode & OP_PREPROCESS) + return NULL; /* Preprocessing to stdout */ + + /* + * No filename specified, and not in preprocessing mode, create + * a default output file name. + */ + inname = get_filename(FN_INFILE); + newname = filename_set_extension(inname, ofmt->extension); + if (!strcmp(newname, inname)) { + nasm_strdupto(&newname, "nasm.out"); + nasm_warn(WARN_OTHER, + "default output file same as input, using `%s' for output\n", + newname); + } + return set_filename(FN_OUTFILE, newname); +} + +static const char *fix_dependfile_name(void) +{ + const char * const depend_file = get_filename(FN_DEPENDFILE); + const char *outname, *inname; + char *newname; + + if (depend_file) + return depend_file; + + if (!(operating_mode & ~OP_DEPEND)) + return NULL; /* ONLY doing dependencies -> stdout */ + + outname = get_filename(FN_OUTFILE); + if (outname) { + newname = nasm_strcat(outname, ".d"); + } else { + inname = get_filename(FN_INFILE); + if (inname) + newname = filename_set_extension(inname, ".d"); + else + newname = nasm_strdup("nasm.d"); + } + + return set_filename(FN_DEPENDFILE, newname); +} + int main(int argc, char **argv) { /* Do these as early as possible */ @@ -649,31 +698,18 @@ int main(int argc, char **argv) error_init(); memcpy(nasm_limit_from_cmdline, nasm_limit, sizeof nasm_limit); - /* Dependency filename if we are also doing other things */ - if (!depend_file && (operating_mode & ~OP_DEPEND)) { - if (outname) - depend_file = nasm_strcat(outname, ".d"); - else - depend_file = filename_set_extension(inname, ".d"); - } - /* - * If no output file name provided and this - * is preprocess mode, we're perfectly - * fine to output into stdout. + * Set output and depend file names to defaults as needed. + * Call fix_dependfile_name() first - its defaults depend on + * whether or not the outfile name is a generated default. */ - if (!outname && !(operating_mode & OP_PREPROCESS)) { - outname = filename_set_extension(inname, ofmt->extension); - if (!strcmp(outname, inname)) { - outname = "nasm.out"; - nasm_warn(WARN_OTHER, "default output file same as input, using `%s' for output\n", outname); - } - } + fix_dependfile_name(); + fix_outfile_name(); depend_list = (operating_mode & OP_DEPEND) ? strlist_alloc(true) : NULL; if (!depend_target) - depend_target = quote_for_make(outname); + depend_target = quote_for_make(get_filename(FN_OUTFILE)); reset_global_defaults(cmd_sb); @@ -685,7 +721,7 @@ int main(int argc, char **argv) if (depend_missing_ok) pp_include_path(NULL); /* "assume generated" */ - pp_reset(inname, PP_DEPS, depend_list); + pp_reset(get_filename(FN_INFILE), PP_DEPS, depend_list); ofile = NULL; while ((line = pp_getline())) nasm_free(line); @@ -697,6 +733,7 @@ int main(int argc, char **argv) char *quoted_file_name = nasm_quote_filename(file_name); int32_t linnum = 0; int32_t lineinc = 0; + const char *outname = get_filename(FN_OUTFILE); if (outname) { ofile = nasm_open_write(outname, NF_TEXT); @@ -710,7 +747,7 @@ int main(int argc, char **argv) location.known = false; _pass_type = PASS_PREPROC; - pp_reset(inname, PP_PREPROC, depend_list); + pp_reset(get_filename(FN_INFILE), PP_PREPROC, depend_list); error_pass_start(true); while ((line = pp_getline())) { @@ -763,6 +800,7 @@ int main(int argc, char **argv) } if (operating_mode & OP_NORMAL) { + const char *outname = get_filename(FN_OUTFILE); ofile = nasm_open_write(outname, (ofmt->flags & OFMT_TEXT) ? NF_TEXT : NF_BINARY); if (!ofile) nasm_fatalf(ERR_PERROR, "unable to open output file `%s'", outname); @@ -770,7 +808,7 @@ int main(int argc, char **argv) ofmt->init(); dfmt->init(); - assemble_file(inname, depend_list); + assemble_file(get_filename(FN_INFILE), depend_list); if (!terminate_after_phase()) { ofmt->cleanup(); @@ -795,7 +833,7 @@ int main(int argc, char **argv) stdscan_cleanup(); src_free(); strlist_free(&include_path); - nasm_free(depend_file); + cleanup_filenames(); nasm_free(depend_target); return terminate_after_phase(); @@ -826,17 +864,6 @@ static char *get_param(char *p, char *q, bool *advance) return r; } -/* - * Copy a filename - */ -static void copy_filename(const char **dst, const char *src, const char *what) -{ - if (*dst) - nasm_fatal("more than one %s file specified: %s\n", what, src); - - *dst = nasm_strdup(src); -} - /* * Convert a string to a POSIX make-safe form; returns a newly allocated * string. @@ -1079,7 +1106,7 @@ static bool process_arg(char *p, char *q, int pass) case 'o': /* output file */ if (pass == 2) - copy_filename(&outname, param, "output"); + copy_filename(FN_OUTFILE, param); break; case 'f': /* output format */ @@ -1165,7 +1192,7 @@ static bool process_arg(char *p, char *q, int pass) case 'l': /* listing file */ if (pass == 2) - copy_filename(&listname, param, "listing"); + copy_filename(FN_LISTFILE, param); break; case 'L': /* listing options */ @@ -1175,7 +1202,7 @@ static bool process_arg(char *p, char *q, int pass) case 'Z': /* error messages file */ if (pass == 1) - copy_filename(&errname, param, "error"); + copy_filename(FN_ERRFILE, param); break; case 'F': /* specify debug format */ @@ -1279,12 +1306,12 @@ static bool process_arg(char *p, char *q, int pass) case 'D': operating_mode |= OP_DEPEND; if (q && (q[0] != '-' || q[1] == '\0')) { - nasm_strdupto(&depend_file, q); + copy_filename(FN_DEPENDFILE, q); advance = true; } break; case 'F': - nasm_strdupto(&depend_file, q); + copy_filename(FN_DEPENDFILE, q); advance = true; break; case 'T': @@ -1449,8 +1476,12 @@ static bool process_arg(char *p, char *q, int pass) break; } } else if (pass == 2) { - /* In theory we could allow multiple input files... */ - copy_filename(&inname, p, "input"); + /* + * In theory we could allow multiple input files, but that + * would require making this a list, and probably would require + * some other more complicated changes. + */ + copy_filename(FN_INFILE, p); } return advance; @@ -1571,6 +1602,23 @@ static void open_and_process_respfile(char *respfile, int pass) } } +static void open_errfile(const char *errfile) +{ + if (!errfile || !*errfile) + return; + + if (errfile[0] == '-' && !errfile[1]) { + erropt.file = stdout; + return; + } + + erropt.file = nasm_open_write(errfile, NF_TEXT); + if (!erropt.file) { + nasm_fatalf(ERR_PERROR, "cannot open file `%s' for error messages", + errfile); + } +} + static void parse_cmdline(int argc, char **argv, int pass) { char *envreal, *envcopy = NULL; @@ -1621,23 +1669,12 @@ static void parse_cmdline(int argc, char **argv, int pass) if (pass != 2) return; - if (!inname) + if (!get_filename(FN_INFILE)) nasm_fatalf(ERR_USAGE, "no input file specified"); - else if ((errname && !strcmp(inname, errname)) || - (outname && !strcmp(inname, outname)) || - (listname && !strcmp(inname, listname)) || - (depend_file && !strcmp(inname, depend_file))) - nasm_fatal("will not overwrite input file"); - if (errname) { - FILE *error_file = nasm_open_write(errname, NF_TEXT); - if (erropt.file) { - erropt.file = error_file; - } else { - nasm_fatalf(ERR_PERROR, "cannot open file `%s' for error messages", - errname); - } - } + check_overwrite_files(); + + open_errfile(get_filename(FN_ERRFILE)); } static void forward_refs(insn *instruction) @@ -1714,12 +1751,13 @@ static void assemble_file(const char *fname, struct strlist *depend_list) prev_offset_changed = INT64_MAX; - if (listname && !keep_all) { - /* Remove the list file in case we die before the output pass */ - remove(listname); - } + /* Remove the list file in case we die before the output pass */ + if (!keep_all) + nasm_remove(get_filename(FN_LISTFILE)); while (!terminate_after_phase() && !pass_final()) { + const char *listname; + _passn++; switch (pass_type()) { case PASS_INIT: @@ -1745,6 +1783,7 @@ static void assemble_file(const char *fname, struct strlist *depend_list) reset_global_defaults(cmd_sb); cpu = cmd_cpu; + listname = get_filename(FN_LISTFILE); if (listname) { if (list_on_this_pass()) { /* @@ -1758,7 +1797,7 @@ static void assemble_file(const char *fname, struct strlist *depend_list) */ lfmt->cleanup(); if (!keep_all) - remove(listname); + nasm_remove(listname); } } @@ -1865,7 +1904,7 @@ void close_output(bool error) } else { fclose(ofile); if (error && !keep_all) - remove(outname); + nasm_remove(get_filename(FN_OUTFILE)); } ofile = NULL; } diff --git a/common/files.c b/common/files.c new file mode 100644 index 000000000..8b01657d2 --- /dev/null +++ b/common/files.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* Copyright 2026 The NASM Authors - All Rights Reserved */ + +#include "compiler.h" +#include "files.h" +#include "error.h" + +static const char * const filename_names[FN_NFILES] = { + "input", + "output", + "error", + "list", + "dependency" +}; + +const char *_filenames[FN_NFILES]; + +const char *copy_filename(enum filenames fn, const char *src) +{ + return set_filename(fn, nasm_strdup(src)); +} + +const char *set_filename(enum filenames fn, char *src) +{ + const char **dstp, *dst; + nasm_assert((size_t)fn < ARRAY_SIZE(_filenames)); + + dstp = &_filenames[fn]; + dst = *dstp; + + if (dst) { + nasm_fatal("more than one %s file specified: %s and %s", + filename_names[fn], dst, src); + } + + return *dstp = src; +} + +void check_overwrite_files(void) +{ + enum filenames fn; + const char *inname = get_filename(FN_INFILE); + + if (!inname) + return; + + for (fn = FN_INFILE+1; fn < FN_NFILES; fn++) { + const char *outname = get_filename(fn); + if (outname && !strcmp(inname, outname)) { + nasm_fatal("%s file would overwrite input file", + filename_names[fn]); + } + } +} + +void cleanup_filenames(void) +{ + enum filenames fn; + + for (fn = 0; fn < FN_NFILES; fn++) { + nasm_free((char *)_filenames[fn]); + _filenames[fn] = NULL; + } +} diff --git a/include/files.h b/include/files.h new file mode 100644 index 000000000..314dea184 --- /dev/null +++ b/include/files.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* Copyright 2026 The NASM Authors - All Rights Reserved */ + +#ifndef NASM_FILES_H +#define NASM_FILES_H 1 + +#include "compiler.h" +#include "nasmlib.h" /* For nasm_assert() */ + +/* + * Primary file names set on the command line etc. + * Wrapped in accessors to make them as constant as possible. + */ +enum filenames { + /* These two entries must be first, in this order */ + FN_INFILE, /* Primary input file */ + FN_OUTFILE, /* Primary output file */ + + FN_ERRFILE, /* Error message file */ + FN_LISTFILE, /* Listing file */ + FN_DEPENDFILE, /* Dependency file */ + FN_NFILES +}; + +extern const char *_filenames[FN_NFILES]; + +static inline const char *get_filename(enum filenames fn) +{ + nasm_assert((size_t)fn < ARRAY_SIZE(_filenames)); + return _filenames[fn]; +} + +/* + * copy_filename() makes a private copy for the files subsystem, + * set_nocopy() expects an allocated string for the files subsystem to + * take over. + */ +const char *copy_filename(enum filenames fn, const char *src); +const char *set_filename(enum filenames fn, char *src); +void check_overwrite_files(void); +void cleanup_filenames(void); + +#endif /* NASM_FILES_H */ diff --git a/include/nasm.h b/include/nasm.h index e81c3ec82..136f2741b 100644 --- a/include/nasm.h +++ b/include/nasm.h @@ -1575,9 +1575,6 @@ struct globalopt { extern struct globalopt globl; void reset_global_defaults(int bits); -extern const char *inname; /* primary input filename */ -extern const char *outname; /* output filename */ - /* * Switch to a different segment and return the current offset */ diff --git a/output/codeview.c b/output/codeview.c index 0e89d571b..553cb7353 100644 --- a/output/codeview.c +++ b/output/codeview.c @@ -11,6 +11,7 @@ #include "nasm.h" #include "nasmlib.h" +#include "files.h" #include "error.h" #include "preproc.h" #include "saa.h" @@ -277,7 +278,7 @@ static void cv8_cleanup(void) struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect]; struct coff_Section *type_sect = coff_sects[cv8_state.type_sect]; - cv8_state.outfile.name = nasm_realpath(outname); + cv8_state.outfile.name = nasm_realpath(get_filename(FN_OUTFILE)); cv8_state.outfile.namebytes = strlen(cv8_state.outfile.name) + 1; build_symbol_table(symbol_sect); diff --git a/output/outas86.c b/output/outas86.c index edbd244cc..8b7891862 100644 --- a/output/outas86.c +++ b/output/outas86.c @@ -12,6 +12,7 @@ #include "nasm.h" #include "nasmlib.h" +#include "files.h" #include "error.h" #include "saa.h" #include "raa.h" @@ -25,7 +26,7 @@ struct Piece { int type; /* 0 = absolute, 1 = seg, 2 = sym */ int32_t offset; /* relative offset */ int number; /* symbol/segment number (4=bss) */ - int32_t bytes; /* size of reloc or of absolute data */ + int32_t bytes; /* size of reloc or of absolute data */ bool relative; /* relative address? */ }; @@ -103,7 +104,7 @@ static void as86_init(void) strslen = 0; /* as86 module name = input file minus extension */ - module_name = filename_set_extension(inname, ""); + module_name = filename_set_extension(get_filename(FN_INFILE), ""); as86_add_string(module_name); nasm_free(module_name); } diff --git a/output/outbin.c b/output/outbin.c index c5886b4cf..7f7d8f7b3 100644 --- a/output/outbin.c +++ b/output/outbin.c @@ -49,6 +49,7 @@ #include "nasm.h" #include "nasmlib.h" +#include "files.h" #include "error.h" #include "saa.h" #include "stdscan.h" @@ -543,7 +544,7 @@ static void bin_cleanup(void) for (h = 63; h; h--) fputc('-', rf); fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n", - inname, outname); + get_filename(FN_INFILE), get_filename(FN_OUTFILE)); if (map_control & MAP_ORIGIN) { /* Display program origin. */ fprintf(rf, "-- Program origin "); diff --git a/output/outcoff.c b/output/outcoff.c index adcaf3a41..8a0a3216c 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -15,6 +15,7 @@ #include "nasm.h" #include "nasmlib.h" #include "ilog2.h" +#include "files.h" #include "error.h" #include "saa.h" #include "raa.h" @@ -1341,7 +1342,7 @@ static void coff_write_symbols(void) if (reproducible) memset(filename, 0, 18); else - strncpy(filename, inname, 18); + strncpy(filename, get_filename(FN_INFILE), 18); nasm_write(filename, 18, ofile); /* diff --git a/output/outdbg.c b/output/outdbg.c index 174de15bc..599b01869 100644 --- a/output/outdbg.c +++ b/output/outdbg.c @@ -13,6 +13,7 @@ #include "nasm.h" #include "nasmlib.h" +#include "files.h" #include "outform.h" #include "outlib.h" #include "insns.h" @@ -36,8 +37,8 @@ static void dbg_init(void) { dbgsect = NULL; fprintf(ofile, "NASM Output format debug dump\n"); - fprintf(ofile, "input file = %s\n", inname); - fprintf(ofile, "output file = %s\n", outname); + fprintf(ofile, "input file = %s\n", get_filename(FN_INFILE)); + fprintf(ofile, "output file = %s\n", get_filename(FN_OUTFILE)); init_seg = seg_alloc(); } diff --git a/output/outelf.c b/output/outelf.c index 2a0566b4f..0f20ddf6d 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -10,6 +10,7 @@ #include "nasm.h" #include "nasmlib.h" +#include "files.h" #include "error.h" #include "saa.h" #include "raa.h" @@ -510,10 +511,11 @@ static void elf64_init(void) static void elf_populate_dirs(void) { - char *cur_path = nasm_realpath(inname); + const char * const infile = get_filename(FN_INFILE); + char *cur_path = nasm_realpath(infile); char *dir_name = nasm_dirname(cur_path); - strlcpy(elf_module, inname, sizeof(elf_module)); + strlcpy(elf_module, infile, sizeof(elf_module)); strlcpy(elf_dir, dir_name, sizeof(elf_dir)); nasm_free(dir_name); diff --git a/output/outieee.c b/output/outieee.c index 9e26cec90..a00f25dc6 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -45,6 +45,7 @@ #include "nasmlib.h" #include "asmutil.h" #include "error.h" +#include "files.h" #include "ver.h" #include "outform.h" @@ -178,7 +179,7 @@ static void ieee_unqualified_name(char *, char *); */ static void ieee_init(void) { - strlcpy(ieee_infile, inname, sizeof(ieee_infile)); + strlcpy(ieee_infile, get_filename(FN_INFILE), sizeof(ieee_infile)); any_segs = false; fpubhead = NULL; fpubtail = &fpubhead; diff --git a/output/outmacho.c b/output/outmacho.c index d0e2a2fd5..233f1f93a 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -14,6 +14,7 @@ #include "nasmlib.h" #include "ilog2.h" #include "labels.h" +#include "files.h" #include "error.h" #include "saa.h" #include "raa.h" @@ -324,7 +325,7 @@ static int32_t macho_gotpcrel_sect; static void macho_init(void) { - module_name = inname; + module_name = get_filename(FN_INFILE); sects = NULL; sectstail = §s; diff --git a/output/outobj.c b/output/outobj.c index 685c5933e..2059a0cac 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -17,6 +17,7 @@ #include "error.h" #include "stdscan.h" #include "eval.h" +#include "files.h" #include "ver.h" #include "outform.h" @@ -656,7 +657,7 @@ static const char *get_default_class(const char *segment) static void obj_init(void) { - strlcpy(obj_infile, inname, sizeof(obj_infile)); + strlcpy(obj_infile, get_filename(FN_INFILE), sizeof(obj_infile)); first_seg = seg_alloc(); any_segs = false; fpubhead = NULL; diff --git a/travis/test/mout.stderr b/travis/test/mout.stderr index cc76ff6d4..2c626d528 100644 --- a/travis/test/mout.stderr +++ b/travis/test/mout.stderr @@ -1,2 +1 @@ -mout.bin: fatal: more than one output file specified: ./travis/test/mout.1.out - +mout.bin: fatal: more than one output file specified: mout.bin and ./travis/test/mout.1.out