regularized spelling of license to match name of LICENSE file
[platform/upstream/nasm.git] / nasm.c
1 /* The Netwide Assembler main program module
2  *
3  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4  * Julian Hall. All rights reserved. The software is
5  * redistributable under the license given in the file "LICENSE"
6  * distributed in the NASM archive.
7  */
8
9 #include "compiler.h"
10
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <inttypes.h>
17 #include <limits.h>
18
19 #include "nasm.h"
20 #include "nasmlib.h"
21 #include "float.h"
22 #include "stdscan.h"
23 #include "insns.h"
24 #include "preproc.h"
25 #include "parser.h"
26 #include "eval.h"
27 #include "assemble.h"
28 #include "labels.h"
29 #include "outform.h"
30 #include "listing.h"
31
32 struct forwrefinfo {            /* info held on forward refs. */
33     int lineno;
34     int operand;
35 };
36
37 static int get_bits(char *value);
38 static uint32_t get_cpu(char *cpu_str);
39 static void parse_cmdline(int, char **);
40 static void assemble_file(char *);
41 static void register_output_formats(void);
42 static void report_error_gnu(int severity, const char *fmt, ...);
43 static void report_error_vc(int severity, const char *fmt, ...);
44 static void report_error_common(int severity, const char *fmt,
45                                 va_list args);
46 static int is_suppressed_warning(int severity);
47 static void usage(void);
48 static efunc report_error;
49
50 static int using_debug_info, opt_verbose_info;
51 bool tasm_compatible_mode = false;
52 int pass0;
53 int maxbits = 0;
54 int globalrel = 0;
55
56 static char inname[FILENAME_MAX];
57 static char outname[FILENAME_MAX];
58 static char listname[FILENAME_MAX];
59 static char errname[FILENAME_MAX];
60 static int globallineno;        /* for forward-reference tracking */
61 /* static int pass = 0; */
62 static struct ofmt *ofmt = NULL;
63
64 static FILE *error_file;        /* Where to write error messages */
65
66 static FILE *ofile = NULL;
67 int optimizing = -1;            /* number of optimization passes to take */
68 static int sb, cmd_sb = 16;     /* by default */
69 static uint32_t cmd_cpu = IF_PLEVEL;       /* highest level by default */
70 static uint32_t cpu = IF_PLEVEL;   /* passed to insn_size & assemble.c */
71 bool global_offset_changed;      /* referenced in labels.c */
72
73 static struct location location;
74 int in_abs_seg;                 /* Flag we are in ABSOLUTE seg */
75 int32_t abs_seg;                   /* ABSOLUTE segment basis */
76 int32_t abs_offset;                /* ABSOLUTE offset */
77
78 static struct RAA *offsets;
79
80 static struct SAA *forwrefs;    /* keep track of forward references */
81 static const struct forwrefinfo *forwref;
82
83 static Preproc *preproc;
84 enum op_type {
85     op_normal,                  /* Preprocess and assemble */
86     op_preprocess,              /* Preprocess only */
87     op_depend,                  /* Generate dependencies */
88     op_depend_missing_ok,       /* Generate dependencies, missing OK */
89 };
90 static enum op_type operating_mode;
91
92 /*
93  * Which of the suppressible warnings are suppressed. Entry zero
94  * isn't an actual warning, but it used for -w+error/-Werror.
95  */
96 static bool suppressed[ERR_WARN_MAX+1] = {
97     true, false, true, false, false, true, false, true, true, false
98 };
99
100 /*
101  * The option names for the suppressible warnings. As before, entry
102  * zero does nothing.
103  */
104 static const char *suppressed_names[ERR_WARN_MAX+1] = {
105     "error", "macro-params", "macro-selfref", "orphan-labels",
106     "number-overflow", "gnu-elf-extensions", "float-overflow",
107     "float-denorm", "float-underflow", "float-toolong"
108 };
109
110 /*
111  * The explanations for the suppressible warnings. As before, entry
112  * zero does nothing.
113  */
114 static const char *suppressed_what[ERR_WARN_MAX+1] = {
115     "treat warnings as errors",
116     "macro calls with wrong parameter count",
117     "cyclic macro references",
118     "labels alone on lines without trailing `:'",
119     "numeric constants does not fit in 64 bits",
120     "using 8- or 16-bit relocation in ELF32, a GNU extension",
121     "floating point overflow",
122     "floating point denormal",
123     "floating point underflow",
124     "too many digits in floating-point number"
125 };
126
127 /*
128  * This is a null preprocessor which just copies lines from input
129  * to output. It's used when someone explicitly requests that NASM
130  * not preprocess their source file.
131  */
132
133 static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *);
134 static char *no_pp_getline(void);
135 static void no_pp_cleanup(int);
136 static Preproc no_pp = {
137     no_pp_reset,
138     no_pp_getline,
139     no_pp_cleanup
140 };
141
142 /*
143  * get/set current offset...
144  */
145 #define GET_CURR_OFFS (in_abs_seg?abs_offset:\
146                       raa_read(offsets,location.segment))
147 #define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\
148                          (void)(offsets=raa_write(offsets,location.segment,(x))))
149
150 static int want_usage;
151 static int terminate_after_phase;
152 int user_nolist = 0;            /* fbk 9/2/00 */
153
154 static void nasm_fputs(const char *line, FILE * outfile)
155 {
156     if (outfile) {
157         fputs(line, outfile);
158         putc('\n', outfile);
159     } else
160         puts(line);
161 }
162
163 int main(int argc, char **argv)
164 {
165     pass0 = 1;
166     want_usage = terminate_after_phase = false;
167     report_error = report_error_gnu;
168
169     error_file = stderr;
170
171     nasm_set_malloc_error(report_error);
172     offsets = raa_init();
173     forwrefs = saa_init((int32_t)sizeof(struct forwrefinfo));
174
175     preproc = &nasmpp;
176     operating_mode = op_normal;
177
178     seg_init();
179
180     register_output_formats();
181
182     parse_cmdline(argc, argv);
183
184     if (terminate_after_phase) {
185         if (want_usage)
186             usage();
187         return 1;
188     }
189
190     /* If debugging info is disabled, suppress any debug calls */
191     if (!using_debug_info)
192         ofmt->current_dfmt = &null_debug_form;
193
194     if (ofmt->stdmac)
195         pp_extra_stdmac(ofmt->stdmac);
196     parser_global_info(ofmt, &location);
197     eval_global_info(ofmt, lookup_label, &location);
198
199     /* define some macros dependent of command-line */
200     {
201         char temp[64];
202         snprintf(temp, sizeof(temp), "__OUTPUT_FORMAT__=%s\n",
203                  ofmt->shortname);
204         pp_pre_define(temp);
205     }
206
207     switch (operating_mode) {
208     case op_depend_missing_ok:
209         pp_include_path(NULL);  /* "assume generated" */
210         /* fall through */
211     case op_depend:
212         {
213             char *line;
214             preproc->reset(inname, 0, report_error, evaluate, &nasmlist);
215             if (outname[0] == '\0')
216                 ofmt->filename(inname, outname, report_error);
217             ofile = NULL;
218             fprintf(stdout, "%s: %s", outname, inname);
219             while ((line = preproc->getline()))
220                 nasm_free(line);
221             preproc->cleanup(0);
222             putc('\n', stdout);
223         }
224         break;
225
226     case op_preprocess:
227         {
228             char *line;
229             char *file_name = NULL;
230             int32_t prior_linnum = 0;
231             int lineinc = 0;
232
233             if (*outname) {
234                 ofile = fopen(outname, "w");
235                 if (!ofile)
236                     report_error(ERR_FATAL | ERR_NOFILE,
237                                  "unable to open output file `%s'",
238                                  outname);
239             } else
240                 ofile = NULL;
241
242             location.known = false;
243
244 /*      pass = 1; */
245             preproc->reset(inname, 2, report_error, evaluate, &nasmlist);
246             while ((line = preproc->getline())) {
247                 /*
248                  * We generate %line directives if needed for later programs
249                  */
250                 int32_t linnum = prior_linnum += lineinc;
251                 int altline = src_get(&linnum, &file_name);
252                 if (altline) {
253                     if (altline == 1 && lineinc == 1)
254                         nasm_fputs("", ofile);
255                     else {
256                         lineinc = (altline != -1 || lineinc != 1);
257                         fprintf(ofile ? ofile : stdout,
258                                 "%%line %"PRId32"+%d %s\n", linnum, lineinc,
259                                 file_name);
260                     }
261                     prior_linnum = linnum;
262                 }
263                 nasm_fputs(line, ofile);
264                 nasm_free(line);
265             }
266             nasm_free(file_name);
267             preproc->cleanup(0);
268             if (ofile)
269                 fclose(ofile);
270             if (ofile && terminate_after_phase)
271                 remove(outname);
272         }
273         break;
274
275     case op_normal:
276         {
277             /*
278              * We must call ofmt->filename _anyway_, even if the user
279              * has specified their own output file, because some
280              * formats (eg OBJ and COFF) use ofmt->filename to find out
281              * the name of the input file and then put that inside the
282              * file.
283              */
284             ofmt->filename(inname, outname, report_error);
285
286             ofile = fopen(outname, "wb");
287             if (!ofile) {
288                 report_error(ERR_FATAL | ERR_NOFILE,
289                              "unable to open output file `%s'", outname);
290             }
291
292             /*
293              * We must call init_labels() before ofmt->init() since
294              * some object formats will want to define labels in their
295              * init routines. (eg OS/2 defines the FLAT group)
296              */
297             init_labels();
298
299             ofmt->init(ofile, report_error, define_label, evaluate);
300
301             assemble_file(inname);
302
303             if (!terminate_after_phase) {
304                 ofmt->cleanup(using_debug_info);
305                 cleanup_labels();
306             } else {
307                 /*
308                  * We had an fclose on the output file here, but we
309                  * actually do that in all the object file drivers as well,
310                  * so we're leaving out the one here.
311                  *     fclose (ofile);
312                  */
313                 remove(outname);
314                 if (listname[0])
315                     remove(listname);
316             }
317         }
318         break;
319     }
320
321     if (want_usage)
322         usage();
323
324     raa_free(offsets);
325     saa_free(forwrefs);
326     eval_cleanup();
327     stdscan_cleanup();
328
329     if (terminate_after_phase)
330         return 1;
331     else
332         return 0;
333 }
334
335 /*
336  * Get a parameter for a command line option.
337  * First arg must be in the form of e.g. -f...
338  */
339 static char *get_param(char *p, char *q, bool *advance)
340 {
341     *advance = false;
342     if (p[2]) {                 /* the parameter's in the option */
343         p += 2;
344         while (isspace(*p))
345             p++;
346         return p;
347     }
348     if (q && q[0]) {
349         *advance = true;
350         return q;
351     }
352     report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
353                  "option `-%c' requires an argument", p[1]);
354     return NULL;
355 }
356
357 /*
358  * Copy a filename
359  */
360 static void copy_filename(char *dst, const char *src)
361 {
362     size_t len = strlen(src);
363
364     if (len >= (size_t)FILENAME_MAX) {
365         report_error(ERR_FATAL | ERR_NOFILE, "file name too long");
366         return;
367     }
368     strncpy(dst, src, FILENAME_MAX);
369 }
370
371 struct textargs {
372     const char *label;
373     int value;
374 };
375
376 #define OPT_PREFIX 0
377 #define OPT_POSTFIX 1
378 struct textargs textopts[] = {
379     {"prefix", OPT_PREFIX},
380     {"postfix", OPT_POSTFIX},
381     {NULL, 0}
382 };
383
384 static bool stopoptions = false;
385 static bool process_arg(char *p, char *q)
386 {
387     char *param;
388     int i;
389     bool advance = false;
390     bool suppress;
391
392     if (!p || !p[0])
393         return false;
394
395     if (p[0] == '-' && !stopoptions) {
396         if (strchr("oOfpPdDiIlFXuUZwW", p[1])) {
397             /* These parameters take values */
398             if (!(param = get_param(p, q, &advance)))
399                 return advance;
400         }
401
402         switch (p[1]) {
403         case 's':
404             error_file = stdout;
405             break;
406
407         case 'o':               /* output file */
408             copy_filename(outname, param);
409             break;
410
411         case 'f':               /* output format */
412             ofmt = ofmt_find(param);
413             if (!ofmt) {
414                 report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
415                              "unrecognised output format `%s' - "
416                              "use -hf for a list", param);
417             } else {
418                 ofmt->current_dfmt = ofmt->debug_formats[0];
419             }
420             break;
421
422         case 'O':               /* Optimization level */
423         {
424             int opt;
425             
426             if (!*param) {
427                 /* Naked -O == -Ox */
428                 optimizing = INT_MAX >> 1; /* Almost unlimited */
429             } else {
430                 while (*param) {
431                     switch (*param) {
432                     case '0': case '1': case '2': case '3': case '4':
433                     case '5': case '6': case '7': case '8': case '9':
434                         opt = strtoul(param, &param, 10);
435                         
436                         /* -O0 -> optimizing == -1, 0.98 behaviour */
437                         /* -O1 -> optimizing == 0, 0.98.09 behaviour */
438                         if (opt < 2)
439                             optimizing = opt - 1;
440                         else if (opt <= 5)
441                             /* The optimizer seems to have problems with
442                                < 5 passes?  Hidden bug? */
443                             optimizing = 5;     /* 5 passes */
444                         else
445                             optimizing = opt;   /* More than 5 passes */
446                         break;
447                         
448                     case 'v':
449                     case '+':
450                         param++;
451                         opt_verbose_info = true;
452                         break;
453                         
454                     case 'x':
455                         param++;
456                         optimizing = INT_MAX >> 1; /* Almost unlimited */
457                         break;
458                         
459                     default:
460                         report_error(ERR_FATAL,
461                                      "unknown optimization option -O%c\n",
462                                      *param);
463                         break;
464                     }
465                 }
466             }
467             break;
468         }
469
470         case 'p':                       /* pre-include */
471         case 'P':
472             pp_pre_include(param);
473             break;
474
475         case 'd':                       /* pre-define */
476         case 'D':
477             pp_pre_define(param);
478             break;
479
480         case 'u':                       /* un-define */
481         case 'U':
482             pp_pre_undefine(param);
483             break;
484
485         case 'i':                       /* include search path */
486         case 'I':
487             pp_include_path(param);
488             break;
489
490         case 'l':                       /* listing file */
491             copy_filename(listname, param);
492             break;
493
494         case 'Z':                       /* error messages file */
495             strcpy(errname, param);
496             break;
497
498         case 'F':                       /* specify debug format */
499             ofmt->current_dfmt = dfmt_find(ofmt, param);
500             if (!ofmt->current_dfmt) {
501                 report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
502                              "unrecognized debug format `%s' for"
503                              " output format `%s'",
504                              param, ofmt->shortname);
505             }
506             break;
507
508         case 'X':               /* specify error reporting format */
509             if (nasm_stricmp("vc", param) == 0)
510                 report_error = report_error_vc;
511             else if (nasm_stricmp("gnu", param) == 0)
512                 report_error = report_error_gnu;
513             else
514                 report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
515                              "unrecognized error reporting format `%s'",
516                              param);
517             break;
518
519         case 'g':
520             using_debug_info = true;
521             break;
522
523         case 'h':
524             printf
525                 ("usage: nasm [-@ response file] [-o outfile] [-f format] "
526                  "[-l listfile]\n"
527                  "            [options...] [--] filename\n"
528                  "    or nasm -v   for version info\n\n"
529                  "    -t          assemble in SciTech TASM compatible mode\n"
530                  "    -g          generate debug information in selected format.\n");
531             printf
532                 ("    -E (or -e)  preprocess only (writes output to stdout by default)\n"
533                  "    -a          don't preprocess (assemble only)\n"
534                  "    -M          generate Makefile dependencies on stdout\n"
535                  "    -MG         d:o, missing files assumed generated\n\n"
536                  "    -Z<file>    redirect error messages to file\n"
537                  "    -s          redirect error messages to stdout\n\n"
538                  "    -F format   select a debugging format\n\n"
539                  "    -I<path>    adds a pathname to the include file path\n");
540             printf
541                 ("    -O<digit>   optimize branch offsets (-O0 disables, default)\n"
542                  "    -P<file>    pre-includes a file\n"
543                  "    -D<macro>[=<value>] pre-defines a macro\n"
544                  "    -U<macro>   undefines a macro\n"
545                  "    -X<format>  specifies error reporting format (gnu or vc)\n"
546                  "    -w+foo      enables warning foo (equiv. -Wfoo)\n"
547                  "    -w-foo      disable warning foo (equiv. -Wno-foo)\n"
548                  "Warnings:\n");
549             for (i = 0; i <= ERR_WARN_MAX; i++)
550                 printf("    %-23s %s (default %s)\n",
551                        suppressed_names[i], suppressed_what[i],
552                        suppressed[i] ? "off" : "on");
553             printf
554                 ("\nresponse files should contain command line parameters"
555                  ", one per line.\n");
556             if (p[2] == 'f') {
557                 printf("\nvalid output formats for -f are"
558                        " (`*' denotes default):\n");
559                 ofmt_list(ofmt, stdout);
560             } else {
561                 printf("\nFor a list of valid output formats, use -hf.\n");
562                 printf("For a list of debug formats, use -f <form> -y.\n");
563             }
564             exit(0);            /* never need usage message here */
565             break;
566
567         case 'y':
568             printf("\nvalid debug formats for '%s' output format are"
569                    " ('*' denotes default):\n", ofmt->shortname);
570             dfmt_list(ofmt, stdout);
571             exit(0);
572             break;
573
574         case 't':
575             tasm_compatible_mode = true;
576             break;
577
578         case 'v':
579             {
580                 const char *nasm_version_string =
581                     "NASM version " NASM_VER " compiled on " __DATE__
582 #ifdef DEBUG
583                     " with -DDEBUG"
584 #endif
585                     ;
586                 puts(nasm_version_string);
587                 exit(0);        /* never need usage message here */
588             }
589             break;
590
591         case 'e':              /* preprocess only */
592         case 'E':
593             operating_mode = op_preprocess;
594             break;
595
596         case 'a':              /* assemble only - don't preprocess */
597             preproc = &no_pp;
598             break;
599
600         case 'W':
601             if (param[0] == 'n' && param[1] == 'o' && param[2] == '-') {
602                 suppress = true;
603                 param += 3;
604             } else {
605                 suppress = false;
606             }
607             goto set_warning;
608
609         case 'w':
610             if (param[0] != '+' && param[0] != '-') {
611                 report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
612                              "invalid option to `-w'");
613                 break;
614             }
615             suppress = (param[0] == '-');
616             param++;
617             goto set_warning;
618         set_warning:
619             for (i = 0; i <= ERR_WARN_MAX; i++)
620                 if (!nasm_stricmp(param, suppressed_names[i]))
621                     break;
622             if (i <= ERR_WARN_MAX)
623                 suppressed[i] = suppress;
624             else if (!nasm_stricmp(param, "all"))
625                 for (i = 1; i <= ERR_WARN_MAX; i++)
626                     suppressed[i] = suppress;
627             else if (!nasm_stricmp(param, "none"))
628                 for (i = 1; i <= ERR_WARN_MAX; i++)
629                     suppressed[i] = !suppress;
630             else
631                 report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
632                              "invalid warning `%s'", param);
633             break;
634
635         case 'M':
636             operating_mode = p[2] == 'G' ? op_depend_missing_ok : op_depend;
637             break;
638
639         case '-':
640             {
641                 int s;
642
643                 if (p[2] == 0) {        /* -- => stop processing options */
644                     stopoptions = 1;
645                     break;
646                 }
647                 for (s = 0; textopts[s].label; s++) {
648                     if (!nasm_stricmp(p + 2, textopts[s].label)) {
649                         break;
650                     }
651                 }
652
653                 switch (s) {
654
655                 case OPT_PREFIX:
656                 case OPT_POSTFIX:
657                     {
658                         if (!q) {
659                             report_error(ERR_NONFATAL | ERR_NOFILE |
660                                          ERR_USAGE,
661                                          "option `--%s' requires an argument",
662                                          p + 2);
663                             break;
664                         } else {
665                             advance = 1, param = q;
666                         }
667
668                         if (s == OPT_PREFIX) {
669                             strncpy(lprefix, param, PREFIX_MAX - 1);
670                             lprefix[PREFIX_MAX - 1] = 0;
671                             break;
672                         }
673                         if (s == OPT_POSTFIX) {
674                             strncpy(lpostfix, param, POSTFIX_MAX - 1);
675                             lpostfix[POSTFIX_MAX - 1] = 0;
676                             break;
677                         }
678                         break;
679                     }
680                 default:
681                     {
682                         report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
683                                      "unrecognised option `--%s'", p + 2);
684                         break;
685                     }
686                 }
687                 break;
688             }
689
690         default:
691             if (!ofmt->setinfo(GI_SWITCH, &p))
692                 report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
693                              "unrecognised option `-%c'", p[1]);
694             break;
695         }
696     } else {
697         if (*inname) {
698             report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
699                          "more than one input file specified");
700         } else {
701             copy_filename(inname, p);
702         }
703     }
704
705     return advance;
706 }
707
708 #define ARG_BUF_DELTA 128
709
710 static void process_respfile(FILE * rfile)
711 {
712     char *buffer, *p, *q, *prevarg;
713     int bufsize, prevargsize;
714
715     bufsize = prevargsize = ARG_BUF_DELTA;
716     buffer = nasm_malloc(ARG_BUF_DELTA);
717     prevarg = nasm_malloc(ARG_BUF_DELTA);
718     prevarg[0] = '\0';
719
720     while (1) {                 /* Loop to handle all lines in file */
721         p = buffer;
722         while (1) {             /* Loop to handle long lines */
723             q = fgets(p, bufsize - (p - buffer), rfile);
724             if (!q)
725                 break;
726             p += strlen(p);
727             if (p > buffer && p[-1] == '\n')
728                 break;
729             if (p - buffer > bufsize - 10) {
730                 int offset;
731                 offset = p - buffer;
732                 bufsize += ARG_BUF_DELTA;
733                 buffer = nasm_realloc(buffer, bufsize);
734                 p = buffer + offset;
735             }
736         }
737
738         if (!q && p == buffer) {
739             if (prevarg[0])
740                 process_arg(prevarg, NULL);
741             nasm_free(buffer);
742             nasm_free(prevarg);
743             return;
744         }
745
746         /*
747          * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
748          * them are present at the end of the line.
749          */
750         *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
751
752         while (p > buffer && isspace(p[-1]))
753             *--p = '\0';
754
755         p = buffer;
756         while (isspace(*p))
757             p++;
758
759         if (process_arg(prevarg, p))
760             *p = '\0';
761
762         if ((int) strlen(p) > prevargsize - 10) {
763             prevargsize += ARG_BUF_DELTA;
764             prevarg = nasm_realloc(prevarg, prevargsize);
765         }
766         strncpy(prevarg, p, prevargsize);
767     }
768 }
769
770 /* Function to process args from a string of args, rather than the
771  * argv array. Used by the environment variable and response file
772  * processing.
773  */
774 static void process_args(char *args)
775 {
776     char *p, *q, *arg, *prevarg;
777     char separator = ' ';
778
779     p = args;
780     if (*p && *p != '-')
781         separator = *p++;
782     arg = NULL;
783     while (*p) {
784         q = p;
785         while (*p && *p != separator)
786             p++;
787         while (*p == separator)
788             *p++ = '\0';
789         prevarg = arg;
790         arg = q;
791         if (process_arg(prevarg, arg))
792             arg = NULL;
793     }
794     if (arg)
795         process_arg(arg, NULL);
796 }
797
798 static void parse_cmdline(int argc, char **argv)
799 {
800     FILE *rfile;
801     char *envreal, *envcopy = NULL, *p, *arg;
802
803     *inname = *outname = *listname = *errname = '\0';
804
805     /*
806      * First, process the NASMENV environment variable.
807      */
808     envreal = getenv("NASMENV");
809     arg = NULL;
810     if (envreal) {
811         envcopy = nasm_strdup(envreal);
812         process_args(envcopy);
813         nasm_free(envcopy);
814     }
815
816     /*
817      * Now process the actual command line.
818      */
819     while (--argc) {
820         bool advance;
821         argv++;
822         if (argv[0][0] == '@') {
823             /* We have a response file, so process this as a set of
824              * arguments like the environment variable. This allows us
825              * to have multiple arguments on a single line, which is
826              * different to the -@resp file processing below for regular
827              * NASM.
828              */
829             char *str = malloc(2048);
830             FILE *f = fopen(&argv[0][1], "r");
831             if (!str) {
832                 printf("out of memory");
833                 exit(-1);
834             }
835             if (f) {
836                 while (fgets(str, 2048, f)) {
837                     process_args(str);
838                 }
839                 fclose(f);
840             }
841             free(str);
842             argc--;
843             argv++;
844         }
845         if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
846             p = get_param(argv[0], argc > 1 ? argv[1] : NULL, &advance);
847             if (p) {
848                 rfile = fopen(p, "r");
849                 if (rfile) {
850                     process_respfile(rfile);
851                     fclose(rfile);
852                 } else
853                     report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
854                                  "unable to open response file `%s'", p);
855             }
856         } else
857             advance = process_arg(argv[0], argc > 1 ? argv[1] : NULL);
858         argv += advance, argc -= advance;
859     }
860
861     /* Look for basic command line typos.  This definitely doesn't
862        catch all errors, but it might help cases of fumbled fingers. */
863     if (!*inname)
864         report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
865                      "no input file specified");
866     else if (!strcmp(inname, errname) || !strcmp(inname, outname) ||
867         !strcmp(inname, listname))
868         report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
869                      "file `%s' is both input and output file",
870                      inname);
871
872     if (*errname) {
873         error_file = fopen(errname, "w");
874         if (!error_file) {
875             error_file = stderr;        /* Revert to default! */
876             report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
877                          "cannot open file `%s' for error messages",
878                          errname);
879         }
880     }
881 }
882
883 /* List of directives */
884 enum directives {
885     D_NONE, D_ABSOLUTE, D_BITS, D_COMMON, D_CPU, D_DEBUG, D_DEFAULT,
886     D_EXTERN, D_FLOAT, D_GLOBAL, D_LIST, D_SECTION, D_SEGMENT, D_WARNING
887 };
888 static const char *directives[] = {
889     "", "absolute", "bits", "common", "cpu", "debug", "default",
890     "extern", "float", "global", "list", "section", "segment", "warning"
891 };
892 static enum directives getkw(char **directive, char **value);
893
894 static void assemble_file(char *fname)
895 {
896     char *directive, *value, *p, *q, *special, *line, debugid[80];
897     insn output_ins;
898     int i, validid;
899     bool rn_error;
900     int32_t seg;
901     int64_t offs;
902     struct tokenval tokval;
903     expr *e;
904     int pass, pass_max;
905     int pass_cnt = 0;           /* count actual passes */
906
907     if (cmd_sb == 32 && cmd_cpu < IF_386)
908         report_error(ERR_FATAL, "command line: "
909                      "32-bit segment size requires a higher cpu");
910
911     pass_max = (optimizing > 0 ? optimizing : 0) + 2;   /* passes 1, optimizing, then 2 */
912     pass0 = !(optimizing > 0);  /* start at 1 if not optimizing */
913     for (pass = 1; pass <= pass_max && pass0 <= 2; pass++) {
914         int pass1, pass2;
915         ldfunc def_label;
916
917         pass1 = pass < pass_max ? 1 : 2;        /* seq is 1, 1, 1,..., 1, 2 */
918         pass2 = pass > 1 ? 2 : 1;       /* seq is 1, 2, 2,..., 2, 2 */
919         /*      pass0                            seq is 0, 0, 0,..., 1, 2 */
920
921         def_label = pass > 1 ? redefine_label : define_label;
922
923         globalbits = sb = cmd_sb;   /* set 'bits' to command line default */
924         cpu = cmd_cpu;
925         if (pass0 == 2) {
926             if (*listname)
927                 nasmlist.init(listname, report_error);
928         }
929         in_abs_seg = false;
930         global_offset_changed = false;  /* set by redefine_label */
931         location.segment = ofmt->section(NULL, pass2, &sb);
932         globalbits = sb;
933         if (pass > 1) {
934             saa_rewind(forwrefs);
935             forwref = saa_rstruct(forwrefs);
936             raa_free(offsets);
937             offsets = raa_init();
938         }
939         preproc->reset(fname, pass1, report_error, evaluate, &nasmlist);
940         globallineno = 0;
941         if (pass == 1)
942             location.known = true;
943         location.offset = offs = GET_CURR_OFFS;
944
945         while ((line = preproc->getline())) {
946             enum directives d;
947             globallineno++;
948
949             /* here we parse our directives; this is not handled by the 'real'
950              * parser. */
951             directive = line;
952             d = getkw(&directive, &value);
953             if (d) {
954                 int err = 0;
955
956                 switch (d) {
957                 case D_SEGMENT:         /* [SEGMENT n] */
958                 case D_SECTION:
959                     seg = ofmt->section(value, pass2, &sb);
960                     if (seg == NO_SEG) {
961                         report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC,
962                                      "segment name `%s' not recognized",
963                                      value);
964                     } else {
965                         in_abs_seg = false;
966                         location.segment = seg;
967                     }
968                     break;
969                 case D_EXTERN:          /* [EXTERN label:special] */
970                     if (*value == '$')
971                         value++;        /* skip initial $ if present */
972                     if (pass0 == 2) {
973                         q = value;
974                         while (*q && *q != ':')
975                             q++;
976                         if (*q == ':') {
977                             *q++ = '\0';
978                             ofmt->symdef(value, 0L, 0L, 3, q);
979                         }
980                     } else if (pass == 1) {     /* pass == 1 */
981                         q = value;
982                         validid = true;
983                         if (!isidstart(*q))
984                             validid = false;
985                         while (*q && *q != ':') {
986                             if (!isidchar(*q))
987                                 validid = false;
988                             q++;
989                         }
990                         if (!validid) {
991                             report_error(ERR_NONFATAL,
992                                          "identifier expected after EXTERN");
993                             break;
994                         }
995                         if (*q == ':') {
996                             *q++ = '\0';
997                             special = q;
998                         } else
999                             special = NULL;
1000                         if (!is_extern(value)) {        /* allow re-EXTERN to be ignored */
1001                             int temp = pass0;
1002                             pass0 = 1;  /* fake pass 1 in labels.c */
1003                             declare_as_global(value, special,
1004                                               report_error);
1005                             define_label(value, seg_alloc(), 0L, NULL,
1006                                          false, true, ofmt, report_error);
1007                             pass0 = temp;
1008                         }
1009                     }           /* else  pass0 == 1 */
1010                     break;
1011                 case D_BITS:            /* [BITS bits] */
1012                     globalbits = sb = get_bits(value);
1013                     break;
1014                 case D_GLOBAL:          /* [GLOBAL symbol:special] */
1015                     if (*value == '$')
1016                         value++;        /* skip initial $ if present */
1017                     if (pass0 == 2) {   /* pass 2 */
1018                         q = value;
1019                         while (*q && *q != ':')
1020                             q++;
1021                         if (*q == ':') {
1022                             *q++ = '\0';
1023                             ofmt->symdef(value, 0L, 0L, 3, q);
1024                         }
1025                     } else if (pass2 == 1) {    /* pass == 1 */
1026                         q = value;
1027                         validid = true;
1028                         if (!isidstart(*q))
1029                             validid = false;
1030                         while (*q && *q != ':') {
1031                             if (!isidchar(*q))
1032                                 validid = false;
1033                             q++;
1034                         }
1035                         if (!validid) {
1036                             report_error(ERR_NONFATAL,
1037                                          "identifier expected after GLOBAL");
1038                             break;
1039                         }
1040                         if (*q == ':') {
1041                             *q++ = '\0';
1042                             special = q;
1043                         } else
1044                             special = NULL;
1045                         declare_as_global(value, special, report_error);
1046                     }           /* pass == 1 */
1047                     break;
1048                 case D_COMMON:          /* [COMMON symbol size:special] */
1049                     if (*value == '$')
1050                         value++;        /* skip initial $ if present */
1051                     if (pass0 == 1) {
1052                         p = value;
1053                         validid = true;
1054                         if (!isidstart(*p))
1055                             validid = false;
1056                         while (*p && !isspace(*p)) {
1057                             if (!isidchar(*p))
1058                                 validid = false;
1059                             p++;
1060                         }
1061                         if (!validid) {
1062                             report_error(ERR_NONFATAL,
1063                                          "identifier expected after COMMON");
1064                             break;
1065                         }
1066                         if (*p) {
1067                             int64_t size;
1068
1069                             while (*p && isspace(*p))
1070                                 *p++ = '\0';
1071                             q = p;
1072                             while (*q && *q != ':')
1073                                 q++;
1074                             if (*q == ':') {
1075                                 *q++ = '\0';
1076                                 special = q;
1077                             } else
1078                                 special = NULL;
1079                             size = readnum(p, &rn_error);
1080                             if (rn_error)
1081                                 report_error(ERR_NONFATAL,
1082                                              "invalid size specified"
1083                                              " in COMMON declaration");
1084                             else
1085                                 define_common(value, seg_alloc(), size,
1086                                               special, ofmt, report_error);
1087                         } else
1088                             report_error(ERR_NONFATAL,
1089                                          "no size specified in"
1090                                          " COMMON declaration");
1091                     } else if (pass0 == 2) {    /* pass == 2 */
1092                         q = value;
1093                         while (*q && *q != ':') {
1094                             if (isspace(*q))
1095                                 *q = '\0';
1096                             q++;
1097                         }
1098                         if (*q == ':') {
1099                             *q++ = '\0';
1100                             ofmt->symdef(value, 0L, 0L, 3, q);
1101                         }
1102                     }
1103                     break;
1104                 case D_ABSOLUTE:                /* [ABSOLUTE address] */
1105                     stdscan_reset();
1106                     stdscan_bufptr = value;
1107                     tokval.t_type = TOKEN_INVALID;
1108                     e = evaluate(stdscan, NULL, &tokval, NULL, pass2,
1109                                  report_error, NULL);
1110                     if (e) {
1111                         if (!is_reloc(e))
1112                             report_error(pass0 ==
1113                                          1 ? ERR_NONFATAL : ERR_PANIC,
1114                                          "cannot use non-relocatable expression as "
1115                                          "ABSOLUTE address");
1116                         else {
1117                             abs_seg = reloc_seg(e);
1118                             abs_offset = reloc_value(e);
1119                         }
1120                     } else if (pass == 1)
1121                         abs_offset = 0x100;     /* don't go near zero in case of / */
1122                     else
1123                         report_error(ERR_PANIC, "invalid ABSOLUTE address "
1124                                      "in pass two");
1125                     in_abs_seg = true;
1126                     location.segment = NO_SEG;
1127                     break;
1128                 case D_DEBUG:           /* [DEBUG] */
1129                     p = value;
1130                     q = debugid;
1131                     validid = true;
1132                     if (!isidstart(*p))
1133                         validid = false;
1134                     while (*p && !isspace(*p)) {
1135                         if (!isidchar(*p))
1136                             validid = false;
1137                         *q++ = *p++;
1138                     }
1139                     *q++ = 0;
1140                     if (!validid) {
1141                         report_error(pass == 1 ? ERR_NONFATAL : ERR_PANIC,
1142                                      "identifier expected after DEBUG");
1143                         break;
1144                     }
1145                     while (*p && isspace(*p))
1146                         p++;
1147                     if (pass == pass_max)
1148                         ofmt->current_dfmt->debug_directive(debugid, p);
1149                     break;
1150                 case D_WARNING:         /* [WARNING {+|-}warn-name] */
1151                     if (pass1 == 1) {
1152                         while (*value && isspace(*value))
1153                             value++;
1154
1155                         if (*value == '+' || *value == '-') {
1156                             validid = (*value == '-') ? true : false;
1157                             value++;
1158                         } else
1159                             validid = false;
1160
1161                         for (i = 1; i <= ERR_WARN_MAX; i++)
1162                             if (!nasm_stricmp(value, suppressed_names[i]))
1163                                 break;
1164                         if (i <= ERR_WARN_MAX)
1165                             suppressed[i] = validid;
1166                         else
1167                             report_error(ERR_NONFATAL,
1168                                          "invalid warning id in WARNING directive");
1169                     }
1170                     break;
1171                 case D_CPU:             /* [CPU] */
1172                     cpu = get_cpu(value);
1173                     break;
1174                 case D_LIST:            /* [LIST {+|-}] */
1175                     while (*value && isspace(*value))
1176                         value++;
1177
1178                     if (*value == '+') {
1179                         user_nolist = 0;
1180                     } else {
1181                         if (*value == '-') {
1182                             user_nolist = 1;
1183                         } else {
1184                             err = 1;
1185                         }
1186                     }
1187                     break;
1188                 case D_DEFAULT:         /* [DEFAULT] */
1189                     stdscan_reset();
1190                     stdscan_bufptr = value;
1191                     tokval.t_type = TOKEN_INVALID;
1192                     if (stdscan(NULL, &tokval) == TOKEN_SPECIAL) {
1193                         switch ((int)tokval.t_integer) {
1194                         case S_REL:
1195                             globalrel = 1;
1196                             break;
1197                         case S_ABS:
1198                             globalrel = 0;
1199                             break;
1200                         default:
1201                             err = 1;
1202                             break;
1203                         }
1204                     } else {
1205                         err = 1;
1206                     }
1207                     break;
1208                 case D_FLOAT:
1209                     if (float_option(value)) {
1210                         report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC,
1211                                      "unknown 'float' directive: %s",
1212                                      value);
1213                     }
1214                     break;
1215                 default:
1216                     if (!ofmt->directive(directive, value, pass2))
1217                         report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC,
1218                                      "unrecognised directive [%s]",
1219                                      directive);
1220                 }
1221                 if (err) {
1222                     report_error(ERR_NONFATAL,
1223                                  "invalid parameter to [%s] directive",
1224                                  directive);
1225                 }
1226             } else {            /* it isn't a directive */
1227
1228                 parse_line(pass1, line, &output_ins,
1229                            report_error, evaluate, def_label);
1230
1231                 if (!(optimizing > 0) && pass == 2) {
1232                     if (forwref != NULL && globallineno == forwref->lineno) {
1233                         output_ins.forw_ref = true;
1234                         do {
1235                             output_ins.oprs[forwref->operand].opflags |=
1236                                 OPFLAG_FORWARD;
1237                             forwref = saa_rstruct(forwrefs);
1238                         } while (forwref != NULL
1239                                  && forwref->lineno == globallineno);
1240                     } else
1241                         output_ins.forw_ref = false;
1242                 }
1243
1244                 if (!(optimizing > 0) && output_ins.forw_ref) {
1245                     if (pass == 1) {
1246                         for (i = 0; i < output_ins.operands; i++) {
1247                             if (output_ins.oprs[i].
1248                                 opflags & OPFLAG_FORWARD) {
1249                                 struct forwrefinfo *fwinf =
1250                                     (struct forwrefinfo *)
1251                                     saa_wstruct(forwrefs);
1252                                 fwinf->lineno = globallineno;
1253                                 fwinf->operand = i;
1254                             }
1255                         }
1256                     } else {    /* pass == 2 */
1257                         /*
1258                          * Hack to prevent phase error in the code
1259                          *   rol ax,x
1260                          *   x equ 1
1261                          *
1262                          * If the second operand is a forward reference,
1263                          * the UNITY property of the number 1 in that
1264                          * operand is cancelled. Otherwise the above
1265                          * sequence will cause a phase error.
1266                          *
1267                          * This hack means that the above code will
1268                          * generate 286+ code.
1269                          *
1270                          * The forward reference will mean that the
1271                          * operand will not have the UNITY property on
1272                          * the first pass, so the pass behaviours will
1273                          * be consistent.
1274                          */
1275
1276                         if (output_ins.operands >= 2 &&
1277                             (output_ins.oprs[1].opflags & OPFLAG_FORWARD) &&
1278                             !(IMMEDIATE & ~output_ins.oprs[1].type))
1279                         {
1280                             /* Remove special properties bits */
1281                             output_ins.oprs[1].type &= ~REG_SMASK;
1282                         }
1283
1284                     }           /* pass == 2 */
1285
1286                 }
1287
1288                 /*  forw_ref */
1289                 if (output_ins.opcode == I_EQU) {
1290                     if (pass1 == 1) {
1291                         /*
1292                          * Special `..' EQUs get processed in pass two,
1293                          * except `..@' macro-processor EQUs which are done
1294                          * in the normal place.
1295                          */
1296                         if (!output_ins.label)
1297                             report_error(ERR_NONFATAL,
1298                                          "EQU not preceded by label");
1299
1300                         else if (output_ins.label[0] != '.' ||
1301                                  output_ins.label[1] != '.' ||
1302                                  output_ins.label[2] == '@') {
1303                             if (output_ins.operands == 1 &&
1304                                 (output_ins.oprs[0].type & IMMEDIATE) &&
1305                                 output_ins.oprs[0].wrt == NO_SEG) {
1306                                 int isext =
1307                                     output_ins.oprs[0].
1308                                     opflags & OPFLAG_EXTERN;
1309                                 def_label(output_ins.label,
1310                                           output_ins.oprs[0].segment,
1311                                           output_ins.oprs[0].offset, NULL,
1312                                           false, isext, ofmt,
1313                                           report_error);
1314                             } else if (output_ins.operands == 2
1315                                        && (output_ins.oprs[0].
1316                                            type & IMMEDIATE)
1317                                        && (output_ins.oprs[0].type & COLON)
1318                                        && output_ins.oprs[0].segment ==
1319                                        NO_SEG
1320                                        && output_ins.oprs[0].wrt == NO_SEG
1321                                        && (output_ins.oprs[1].
1322                                            type & IMMEDIATE)
1323                                        && output_ins.oprs[1].segment ==
1324                                        NO_SEG
1325                                        && output_ins.oprs[1].wrt ==
1326                                        NO_SEG) {
1327                                 def_label(output_ins.label,
1328                                           output_ins.oprs[0].
1329                                           offset | SEG_ABS,
1330                                           output_ins.oprs[1].offset, NULL,
1331                                           false, false, ofmt,
1332                                           report_error);
1333                             } else
1334                                 report_error(ERR_NONFATAL,
1335                                              "bad syntax for EQU");
1336                         }
1337                     } else {    /* pass == 2 */
1338                         /*
1339                          * Special `..' EQUs get processed here, except
1340                          * `..@' macro processor EQUs which are done above.
1341                          */
1342                         if (output_ins.label[0] == '.' &&
1343                             output_ins.label[1] == '.' &&
1344                             output_ins.label[2] != '@') {
1345                             if (output_ins.operands == 1 &&
1346                                 (output_ins.oprs[0].type & IMMEDIATE)) {
1347                                 define_label(output_ins.label,
1348                                              output_ins.oprs[0].segment,
1349                                              output_ins.oprs[0].offset,
1350                                              NULL, false, false, ofmt,
1351                                              report_error);
1352                             } else if (output_ins.operands == 2
1353                                        && (output_ins.oprs[0].
1354                                            type & IMMEDIATE)
1355                                        && (output_ins.oprs[0].type & COLON)
1356                                        && output_ins.oprs[0].segment ==
1357                                        NO_SEG
1358                                        && (output_ins.oprs[1].
1359                                            type & IMMEDIATE)
1360                                        && output_ins.oprs[1].segment ==
1361                                        NO_SEG) {
1362                                 define_label(output_ins.label,
1363                                              output_ins.oprs[0].
1364                                              offset | SEG_ABS,
1365                                              output_ins.oprs[1].offset,
1366                                              NULL, false, false, ofmt,
1367                                              report_error);
1368                             } else
1369                                 report_error(ERR_NONFATAL,
1370                                              "bad syntax for EQU");
1371                         }
1372                     }           /* pass == 2 */
1373                 } else {        /* instruction isn't an EQU */
1374
1375                     if (pass1 == 1) {
1376
1377                         int64_t l = insn_size(location.segment, offs, sb, cpu,
1378                                            &output_ins, report_error);
1379
1380                         /* if (using_debug_info)  && output_ins.opcode != -1) */
1381                         if (using_debug_info)
1382                         {       /* fbk 03/25/01 */
1383                             /* this is done here so we can do debug type info */
1384                             int32_t typeinfo =
1385                                 TYS_ELEMENTS(output_ins.operands);
1386                             switch (output_ins.opcode) {
1387                             case I_RESB:
1388                                 typeinfo =
1389                                     TYS_ELEMENTS(output_ins.oprs[0].
1390                                                  offset) | TY_BYTE;
1391                                 break;
1392                             case I_RESW:
1393                                 typeinfo =
1394                                     TYS_ELEMENTS(output_ins.oprs[0].
1395                                                  offset) | TY_WORD;
1396                                 break;
1397                             case I_RESD:
1398                                 typeinfo =
1399                                     TYS_ELEMENTS(output_ins.oprs[0].
1400                                                  offset) | TY_DWORD;
1401                                 break;
1402                             case I_RESQ:
1403                                 typeinfo =
1404                                     TYS_ELEMENTS(output_ins.oprs[0].
1405                                                  offset) | TY_QWORD;
1406                                 break;
1407                             case I_REST:
1408                                 typeinfo =
1409                                     TYS_ELEMENTS(output_ins.oprs[0].
1410                                                  offset) | TY_TBYTE;
1411                                 break;
1412                             case I_DB:
1413                                 typeinfo |= TY_BYTE;
1414                                 break;
1415                             case I_DW:
1416                                 typeinfo |= TY_WORD;
1417                                 break;
1418                             case I_DD:
1419                                 if (output_ins.eops_float)
1420                                     typeinfo |= TY_FLOAT;
1421                                 else
1422                                     typeinfo |= TY_DWORD;
1423                                 break;
1424                             case I_DQ:
1425                                 typeinfo |= TY_QWORD;
1426                                 break;
1427                             case I_DT:
1428                                 typeinfo |= TY_TBYTE;
1429                                 break;
1430                             case I_DO:
1431                                 typeinfo |= TY_OWORD;
1432                                 break;
1433                             default:
1434                                 typeinfo = TY_LABEL;
1435
1436                             }
1437
1438                             ofmt->current_dfmt->debug_typevalue(typeinfo);
1439
1440                         }
1441                         if (l != -1) {
1442                             offs += l;
1443                             SET_CURR_OFFS(offs);
1444                         }
1445                         /*
1446                          * else l == -1 => invalid instruction, which will be
1447                          * flagged as an error on pass 2
1448                          */
1449
1450                     } else {    /* pass == 2 */
1451                         offs += assemble(location.segment, offs, sb, cpu,
1452                                          &output_ins, ofmt, report_error,
1453                                          &nasmlist);
1454                         SET_CURR_OFFS(offs);
1455
1456                     }
1457                 }               /* not an EQU */
1458                 cleanup_insn(&output_ins);
1459             }
1460             nasm_free(line);
1461             location.offset = offs = GET_CURR_OFFS;
1462         }                       /* end while (line = preproc->getline... */
1463
1464         if (pass1 == 2 && global_offset_changed)
1465             report_error(ERR_NONFATAL,
1466                          "phase error detected at end of assembly.");
1467
1468         if (pass1 == 1)
1469             preproc->cleanup(1);
1470
1471         if (pass1 == 1 && terminate_after_phase) {
1472             fclose(ofile);
1473             remove(outname);
1474             if (want_usage)
1475                 usage();
1476             exit(1);
1477         }
1478         pass_cnt++;
1479         if (pass > 1 && !global_offset_changed) {
1480             pass0++;
1481             if (pass0 == 2)
1482                 pass = pass_max - 1;
1483         } else if (!(optimizing > 0))
1484             pass0++;
1485
1486     }                           /* for (pass=1; pass<=2; pass++) */
1487
1488     preproc->cleanup(0);
1489     nasmlist.cleanup();
1490 #if 1
1491     if (optimizing > 0 && opt_verbose_info)     /*  -On and -Ov switches */
1492         fprintf(stdout,
1493                 "info:: assembly required 1+%d+1 passes\n", pass_cnt - 2);
1494 #endif
1495 }                               /* exit from assemble_file (...) */
1496
1497 static enum directives getkw(char **directive, char **value)
1498 {
1499     char *p, *q, *buf;
1500
1501     buf = *directive;
1502
1503     /*  allow leading spaces or tabs */
1504     while (*buf == ' ' || *buf == '\t')
1505         buf++;
1506
1507     if (*buf != '[')
1508         return 0;
1509
1510     p = buf;
1511
1512     while (*p && *p != ']')
1513         p++;
1514
1515     if (!*p)
1516         return 0;
1517
1518     q = p++;
1519
1520     while (*p && *p != ';') {
1521         if (!isspace(*p))
1522             return 0;
1523         p++;
1524     }
1525     q[1] = '\0';
1526
1527     *directive = p = buf + 1;
1528     while (*buf && *buf != ' ' && *buf != ']' && *buf != '\t')
1529         buf++;
1530     if (*buf == ']') {
1531         *buf = '\0';
1532         *value = buf;
1533     } else {
1534         *buf++ = '\0';
1535         while (isspace(*buf))
1536             buf++;              /* beppu - skip leading whitespace */
1537         *value = buf;
1538         while (*buf != ']')
1539             buf++;
1540         *buf++ = '\0';
1541     }
1542
1543     return bsii(*directive, directives, elements(directives));
1544 }
1545
1546 /**
1547  * gnu style error reporting
1548  * This function prints an error message to error_file in the
1549  * style used by GNU. An example would be:
1550  * file.asm:50: error: blah blah blah
1551  * where file.asm is the name of the file, 50 is the line number on
1552  * which the error occurs (or is detected) and "error:" is one of
1553  * the possible optional diagnostics -- it can be "error" or "warning"
1554  * or something else.  Finally the line terminates with the actual
1555  * error message.
1556  *
1557  * @param severity the severity of the warning or error
1558  * @param fmt the printf style format string
1559  */
1560 static void report_error_gnu(int severity, const char *fmt, ...)
1561 {
1562     va_list ap;
1563
1564     if (is_suppressed_warning(severity))
1565         return;
1566
1567     if (severity & ERR_NOFILE)
1568         fputs("nasm: ", error_file);
1569     else {
1570         char *currentfile = NULL;
1571         int32_t lineno = 0;
1572         src_get(&lineno, &currentfile);
1573         fprintf(error_file, "%s:%"PRId32": ", currentfile, lineno);
1574         nasm_free(currentfile);
1575     }
1576     va_start(ap, fmt);
1577     report_error_common(severity, fmt, ap);
1578     va_end(ap);
1579 }
1580
1581 /**
1582  * MS style error reporting
1583  * This function prints an error message to error_file in the
1584  * style used by Visual C and some other Microsoft tools. An example
1585  * would be:
1586  * file.asm(50) : error: blah blah blah
1587  * where file.asm is the name of the file, 50 is the line number on
1588  * which the error occurs (or is detected) and "error:" is one of
1589  * the possible optional diagnostics -- it can be "error" or "warning"
1590  * or something else.  Finally the line terminates with the actual
1591  * error message.
1592  *
1593  * @param severity the severity of the warning or error
1594  * @param fmt the printf style format string
1595  */
1596 static void report_error_vc(int severity, const char *fmt, ...)
1597 {
1598     va_list ap;
1599
1600     if (is_suppressed_warning(severity))
1601         return;
1602
1603     if (severity & ERR_NOFILE)
1604         fputs("nasm: ", error_file);
1605     else {
1606         char *currentfile = NULL;
1607         int32_t lineno = 0;
1608         src_get(&lineno, &currentfile);
1609         fprintf(error_file, "%s(%"PRId32") : ", currentfile, lineno);
1610         nasm_free(currentfile);
1611     }
1612     va_start(ap, fmt);
1613     report_error_common(severity, fmt, ap);
1614     va_end(ap);
1615 }
1616
1617 /**
1618  * check for supressed warning
1619  * checks for suppressed warning or pass one only warning and we're
1620  * not in pass 1
1621  *
1622  * @param severity the severity of the warning or error
1623  * @return true if we should abort error/warning printing
1624  */
1625 static int is_suppressed_warning(int severity)
1626 {
1627     /*
1628      * See if it's a suppressed warning.
1629      */
1630     return ((severity & ERR_MASK) == ERR_WARNING &&
1631             (severity & ERR_WARN_MASK) != 0 &&
1632             suppressed[(severity & ERR_WARN_MASK) >> ERR_WARN_SHR]) ||
1633         /*
1634          * See if it's a pass-one only warning and we're not in pass one.
1635          */
1636         ((severity & ERR_PASS1) && pass0 == 2);
1637 }
1638
1639 /**
1640  * common error reporting
1641  * This is the common back end of the error reporting schemes currently
1642  * implemented.  It prints the nature of the warning and then the
1643  * specific error message to error_file and may or may not return.  It
1644  * doesn't return if the error severity is a "panic" or "debug" type.
1645  *
1646  * @param severity the severity of the warning or error
1647  * @param fmt the printf style format string
1648  */
1649 static void report_error_common(int severity, const char *fmt,
1650                                 va_list args)
1651 {
1652     switch (severity & ERR_MASK) {
1653     case ERR_WARNING:
1654         fputs("warning: ", error_file);
1655         break;
1656     case ERR_NONFATAL:
1657         fputs("error: ", error_file);
1658         break;
1659     case ERR_FATAL:
1660         fputs("fatal: ", error_file);
1661         break;
1662     case ERR_PANIC:
1663         fputs("panic: ", error_file);
1664         break;
1665     case ERR_DEBUG:
1666         fputs("debug: ", error_file);
1667         break;
1668     }
1669
1670     vfprintf(error_file, fmt, args);
1671     putc('\n', error_file);
1672
1673     if (severity & ERR_USAGE)
1674         want_usage = true;
1675
1676     switch (severity & ERR_MASK) {
1677     case ERR_DEBUG:
1678         /* no further action, by definition */
1679         break;
1680     case ERR_WARNING:
1681         if (!suppressed[0])     /* Treat warnings as errors */
1682             terminate_after_phase = true;
1683         break;
1684     case ERR_NONFATAL:
1685         terminate_after_phase = true;
1686         break;
1687     case ERR_FATAL:
1688         if (ofile) {
1689             fclose(ofile);
1690             remove(outname);
1691         }
1692         if (want_usage)
1693             usage();
1694         exit(1);                /* instantly die */
1695         break;                  /* placate silly compilers */
1696     case ERR_PANIC:
1697         fflush(NULL);
1698         /*      abort();        *//* halt, catch fire, and dump core */
1699         exit(3);
1700         break;
1701     }
1702 }
1703
1704 static void usage(void)
1705 {
1706     fputs("type `nasm -h' for help\n", error_file);
1707 }
1708
1709 static void register_output_formats(void)
1710 {
1711     ofmt = ofmt_register(report_error);
1712 }
1713
1714 #define BUF_DELTA 512
1715
1716 static FILE *no_pp_fp;
1717 static efunc no_pp_err;
1718 static ListGen *no_pp_list;
1719 static int32_t no_pp_lineinc;
1720
1721 static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval,
1722                         ListGen * listgen)
1723 {
1724     src_set_fname(nasm_strdup(file));
1725     src_set_linnum(0);
1726     no_pp_lineinc = 1;
1727     no_pp_err = error;
1728     no_pp_fp = fopen(file, "r");
1729     if (!no_pp_fp)
1730         no_pp_err(ERR_FATAL | ERR_NOFILE,
1731                   "unable to open input file `%s'", file);
1732     no_pp_list = listgen;
1733     (void)pass;                 /* placate compilers */
1734     (void)eval;                 /* placate compilers */
1735 }
1736
1737 static char *no_pp_getline(void)
1738 {
1739     char *buffer, *p, *q;
1740     int bufsize;
1741
1742     bufsize = BUF_DELTA;
1743     buffer = nasm_malloc(BUF_DELTA);
1744     src_set_linnum(src_get_linnum() + no_pp_lineinc);
1745
1746     while (1) {                 /* Loop to handle %line */
1747
1748         p = buffer;
1749         while (1) {             /* Loop to handle long lines */
1750             q = fgets(p, bufsize - (p - buffer), no_pp_fp);
1751             if (!q)
1752                 break;
1753             p += strlen(p);
1754             if (p > buffer && p[-1] == '\n')
1755                 break;
1756             if (p - buffer > bufsize - 10) {
1757                 int offset;
1758                 offset = p - buffer;
1759                 bufsize += BUF_DELTA;
1760                 buffer = nasm_realloc(buffer, bufsize);
1761                 p = buffer + offset;
1762             }
1763         }
1764
1765         if (!q && p == buffer) {
1766             nasm_free(buffer);
1767             return NULL;
1768         }
1769
1770         /*
1771          * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
1772          * them are present at the end of the line.
1773          */
1774         buffer[strcspn(buffer, "\r\n\032")] = '\0';
1775
1776         if (!nasm_strnicmp(buffer, "%line", 5)) {
1777             int32_t ln;
1778             int li;
1779             char *nm = nasm_malloc(strlen(buffer));
1780             if (sscanf(buffer + 5, "%"PRId32"+%d %s", &ln, &li, nm) == 3) {
1781                 nasm_free(src_set_fname(nm));
1782                 src_set_linnum(ln);
1783                 no_pp_lineinc = li;
1784                 continue;
1785             }
1786             nasm_free(nm);
1787         }
1788         break;
1789     }
1790
1791     no_pp_list->line(LIST_READ, buffer);
1792
1793     return buffer;
1794 }
1795
1796 static void no_pp_cleanup(int pass)
1797 {
1798     (void)pass;                     /* placate GCC */
1799     fclose(no_pp_fp);
1800 }
1801
1802 static uint32_t get_cpu(char *value)
1803 {
1804     if (!strcmp(value, "8086"))
1805         return IF_8086;
1806     if (!strcmp(value, "186"))
1807         return IF_186;
1808     if (!strcmp(value, "286"))
1809         return IF_286;
1810     if (!strcmp(value, "386"))
1811         return IF_386;
1812     if (!strcmp(value, "486"))
1813         return IF_486;
1814     if (!strcmp(value, "586") || !nasm_stricmp(value, "pentium"))
1815         return IF_PENT;
1816     if (!strcmp(value, "686") ||
1817         !nasm_stricmp(value, "ppro") ||
1818         !nasm_stricmp(value, "pentiumpro") || !nasm_stricmp(value, "p2"))
1819         return IF_P6;
1820     if (!nasm_stricmp(value, "p3") || !nasm_stricmp(value, "katmai"))
1821         return IF_KATMAI;
1822     if (!nasm_stricmp(value, "p4") ||   /* is this right? -- jrc */
1823         !nasm_stricmp(value, "willamette"))
1824         return IF_WILLAMETTE;
1825     if (!nasm_stricmp(value, "prescott"))
1826         return IF_PRESCOTT;
1827     if (!nasm_stricmp(value, "x64") ||
1828         !nasm_stricmp(value, "x86-64"))
1829         return IF_X86_64;
1830     if (!nasm_stricmp(value, "ia64") ||
1831         !nasm_stricmp(value, "ia-64") ||
1832         !nasm_stricmp(value, "itanium") ||
1833         !nasm_stricmp(value, "itanic") || !nasm_stricmp(value, "merced"))
1834         return IF_IA64;
1835
1836     report_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
1837                  "unknown 'cpu' type");
1838
1839     return IF_PLEVEL;           /* the maximum level */
1840 }
1841
1842 static int get_bits(char *value)
1843 {
1844     int i;
1845
1846     if ((i = atoi(value)) == 16)
1847         return i;               /* set for a 16-bit segment */
1848     else if (i == 32) {
1849         if (cpu < IF_386) {
1850             report_error(ERR_NONFATAL,
1851                          "cannot specify 32-bit segment on processor below a 386");
1852             i = 16;
1853         }
1854     } else if (i == 64) {
1855         if (cpu < IF_X86_64) {
1856             report_error(ERR_NONFATAL,
1857                          "cannot specify 64-bit segment on processor below an x86-64");
1858             i = 16;
1859         }
1860         if (i != maxbits) {
1861             report_error(ERR_NONFATAL,
1862                          "%s output format does not support 64-bit code",
1863                          ofmt->shortname);
1864             i = 16;
1865         }
1866     } else {
1867         report_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL,
1868                      "`%s' is not a valid segment size; must be 16, 32 or 64",
1869                      value);
1870         i = 16;
1871     }
1872     return i;
1873 }
1874
1875 /* end of nasm.c */