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