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