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