cleaned up a little the gbz80 and z80 ports
[fw/sdcc] / src / SDCCmain.c
1 /*-------------------------------------------------------------------------
2   SDCCmain.c - main file
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #ifdef _WIN32
26 #include <io.h>
27 #else
28 #include <unistd.h>
29 #endif
30
31 #include <signal.h>
32 #include "common.h"
33 #include <ctype.h>
34 #include "newalloc.h"
35 #include "SDCCerr.h"
36 #include "BuildCmd.h"
37 #include "MySystem.h"
38 #include "SDCCmacro.h"
39 #include "SDCCutil.h"
40 #include "SDCCdebug.h"
41 #include "SDCCargs.h"
42
43 #ifdef _WIN32
44 #include <process.h>
45 #else
46 #include <sys/stat.h>
47 #include <unistd.h>
48 #endif
49
50 /* REMOVE ME!!! */
51 extern int yyparse (void);
52
53 FILE *srcFile;                  /* source file          */
54 char *fullSrcFileName;          /* full name for the source file; */
55                                 /* can be NULL while c1mode or linking without compiling */
56 char *fullDstFileName;          /* full name for the output file; */
57                                 /* only given by -o, otherwise NULL */
58 char *dstFileName;              /* destination file name without extension */
59 char *dstPath = "";             /* path for the output files; */
60                                 /* "" is equivalent with cwd */
61 char *moduleName;               /* module name is source file without path and extension */
62                                 /* can be NULL while linking without compiling */
63 int currRegBank = 0;
64 int RegBankUsed[4] = {1, 0, 0, 0}; /*JCF: Reg Bank 0 used by default*/
65 struct optimize optimize;
66 struct options options;
67 int preProcOnly = 0;
68 int noAssemble = 0;
69 set *preArgvSet = NULL;         /* pre-processor arguments  */
70 set *asmOptionsSet = NULL;      /* set of assembler options */
71 set *linkOptionsSet = NULL;     /* set of linker options */
72 set *libFilesSet = NULL;
73 set *libPathsSet = NULL;
74 set *relFilesSet = NULL;
75 set *dataDirsSet = NULL;        /* list of data search directories */
76 set *includeDirsSet = NULL;     /* list of include search directories */
77 set *libDirsSet = NULL;         /* list of lib search directories */
78
79 /* uncomment JAMIN_DS390 to always override and use ds390 port
80   for mcs51 work.  This is temporary, for compatibility testing. */
81 /* #define JAMIN_DS390 */
82 #ifdef JAMIN_DS390
83 int ds390_jammed = 0;
84 #endif
85
86 /* Globally accessible scratch buffer for file names. */
87 char scratchFileName[PATH_MAX];
88 char buffer[PATH_MAX * 2];
89
90 #define OPTION_HELP     "-help"
91
92 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
93
94 #define OPTION_STACK_8BIT       "--stack-8bit"
95 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
96 #define OPTION_LARGE_MODEL      "--model-large"
97 #define OPTION_MEDIUM_MODEL     "--model-medium"
98 #define OPTION_SMALL_MODEL      "--model-small"
99 #define OPTION_FLAT24_MODEL     "--model-flat24"
100 #define OPTION_DUMP_ALL         "--dumpall"
101 #define OPTION_PEEP_FILE        "--peep-file"
102 #define OPTION_LIB_PATH         "--lib-path"
103 #define OPTION_XSTACK_LOC       "--xstack-loc"
104 #define OPTION_CALLEE_SAVES     "--callee-saves"
105 #define OPTION_STACK_LOC        "--stack-loc"
106 #define OPTION_XRAM_LOC         "--xram-loc"
107 #define OPTION_IRAM_SIZE        "--iram-size"
108 #define OPTION_VERSION          "--version"
109 #define OPTION_DATA_LOC         "--data-loc"
110 #define OPTION_CODE_LOC         "--code-loc"
111 #define OPTION_IDATA_LOC        "--idata-loc"
112 #define OPTION_NO_LABEL_OPT     "--nolabelopt"
113 #define OPTION_NO_LOOP_INV      "--noinvariant"
114 #define OPTION_NO_LOOP_IND      "--noinduction"
115 #define OPTION_LESS_PEDANTIC    "--less-pedantic"
116 #define OPTION_NO_GCSE          "--nogcse"
117 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
118 #define OPTION_TINI_LIBID       "--tini-libid"
119 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
120 #define OPTION_XRAM_SIZE        "--xram-size"
121 #define OPTION_CODE_SIZE        "--code-size"
122 #define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
123 #define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
124 #define OPTION_PRINT_SEARCH_DIRS "--print-search-dirs"
125 #define OPTION_MSVC_ERROR_STYLE "--vc"
126 #define OPTION_USE_STDOUT "--use-stdout"
127
128 static const OPTION
129 optionsTable[] = {
130     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
131     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
132     { 'd',  NULL,                   NULL, NULL },
133     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
134     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
135     { 'A',  NULL,                   NULL, NULL },
136     { 'U',  NULL,                   NULL, NULL },
137     { 'C',  NULL,                   NULL, "Preprocessor option" },
138     { 'M',  NULL,                   NULL, "Preprocessor option" },
139     { 'V',  NULL,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
140     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
141     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
142     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
143     { 'l',  NULL,                   NULL, "Include the given library in the link" },
144     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
145     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
146     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
147 #if !OPT_DISABLE_DS390
148     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
149 #endif
150     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
151 #if !OPT_DISABLE_DS390
152     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
153     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
154 #endif
155     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
156     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
157     { 0,    OPTION_NO_LABEL_OPT,    NULL, "Disable label optimisation" },
158     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
159     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
160     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
161     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
162     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
163     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
164     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
165     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
166     { 0,    "--dumploop",           &options.dump_loop, NULL },
167     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
168     { 0,    "--dumpliverange",      &options.dump_range, NULL },
169     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
170     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
171     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
172     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
173     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
174     { 0,    OPTION_XRAM_SIZE,       NULL, "<nnnn> External Ram size" },
175     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
176     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
177     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
178     { 0,    OPTION_CODE_SIZE,       NULL, "<nnnn> Code Segment size" },
179     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
180     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
181     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
182     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
183     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
184     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
185     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
186     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
187     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
188     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
189     { 0,    "--nooverlay",          &options.noOverlay, NULL },
190     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
191     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
192     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
193     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
194     { 0,    "--peep-asm",           &options.asmpeep, NULL },
195     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
196     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
197     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
198     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code." },
199     { 0,    "--help",               NULL, "Display this help" },
200     { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
201     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
202     { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
203     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
204     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
205     { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
206     { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
207     { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
208     { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
209 #if !OPT_DISABLE_DS390
210     { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
211 #endif
212     { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
213 #if !OPT_DISABLE_TININative
214     { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
215 #endif
216 #if !OPT_DISABLE_DS390
217     { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
218 #endif
219 #if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51
220     { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
221 #endif
222     { 0,    OPTION_NO_XINIT_OPT,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
223     { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
224     { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
225     { 0,    OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
226     { 0,    OPTION_MSVC_ERROR_STYLE, &options.vc_err_style, "messages are compatible with Micro$oft visual studio"},
227     { 0,    OPTION_USE_STDOUT, &options.use_stdout, "send errors to stdout instead of stderr"},
228     /* End of options */
229 #if 0 /* 10jun03 !OPT_DISABLE_PIC16 */
230     { 0,    "--no-movff",           &options.no_movff, "disable generating MOVFF opcode in PIC16 port"},
231     { 0,    "--gen-banksel",        &options.gen_banksel, "enable the generation of banksel assembler directives in PIC16 port"},
232 #endif
233     { 0,    NULL }
234 };
235
236 /** Table of all unsupported options and help text to display when one
237     is used.
238 */
239 typedef struct {
240     /** shortOpt as in OPTIONS. */
241     char shortOpt;
242     /** longOpt as in OPTIONS. */
243     const char *longOpt;
244     /** Message to display inside W_UNSUPPORTED_OPT when this option
245         is used. */
246     const char *message;
247 } UNSUPPORTEDOPT;
248
249 static const UNSUPPORTEDOPT 
250 unsupportedOptTable[] = {
251     { 'X',  NULL,       "use --xstack-loc instead" },
252     { 'x',  NULL,       "use --xstack instead" },
253     { 'i',  NULL,       "use --idata-loc instead" },
254     { 'r',  NULL,       "use --xdata-loc instead" },
255     { 's',  NULL,       "use --code-loc instead" },
256     { 'Y',  NULL,       "use -I instead" }
257 };
258
259 /** List of all default constant macros.
260  */
261 static const char *_baseValues[] = {
262   "cpp", "sdcpp",
263   "cppextraopts", "",
264   /* Path seperator character */
265   "sep", DIR_SEPARATOR_STRING,
266   NULL
267 };
268
269 static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
270
271 PORT *port;
272
273 static PORT *_ports[] =
274 {
275 #if !OPT_DISABLE_MCS51
276   &mcs51_port,
277 #endif
278 #if !OPT_DISABLE_GBZ80
279   &gbz80_port,
280 #endif
281 #if !OPT_DISABLE_Z80
282   &z80_port,
283 #endif
284 #if !OPT_DISABLE_AVR
285   &avr_port,
286 #endif
287 #if !OPT_DISABLE_DS390
288   &ds390_port,
289 #endif
290 #if !OPT_DISABLE_PIC
291   &pic_port,
292 #endif
293 #if !OPT_DISABLE_PIC16
294   &pic16_port,
295 #endif
296 #if !OPT_DISABLE_TININative
297   &tininative_port,
298 #endif
299 #if !OPT_DISABLE_XA51
300   &xa51_port,
301 #endif
302 #if !OPT_DISABLE_DS400
303   &ds400_port,  
304 #endif  
305 };
306
307 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
308
309 /** Sets the port to the one given by the command line option.
310     @param    The name minus the option (eg 'mcs51')
311     @return     0 on success.
312 */
313 static void
314 _setPort (const char *name)
315 {
316   int i;
317   for (i = 0; i < NUM_PORTS; i++)
318     {
319       if (!strcmp (_ports[i]->target, name))
320         {
321           port = _ports[i];
322           return;
323         }
324     }
325   /* Error - didnt find */
326   werror (E_UNKNOWN_TARGET, name);
327   exit (1);
328 }
329
330 /* Override the default processor with the one specified 
331  * on the command line */
332 static void
333 _setProcessor (char *_processor)
334 {
335   port->processor = _processor;
336   fprintf(stderr,"Processor: %s\n",_processor);
337 }
338
339 static void
340 _validatePorts (void)
341 {
342   int i;
343   for (i = 0; i < NUM_PORTS; i++)
344     {
345       if (_ports[i]->magic != PORT_MAGIC)
346         {
347           /* Uncomment this line to debug which port is causing the problem
348            * (the target name is close to the beginning of the port struct 
349            * and probably can be accessed just fine). */
350           fprintf(stderr,"%s :",_ports[i]->target);
351           wassertl (0, "Port definition structure is incomplete");
352         }
353     }
354 }
355
356 /* search through the command line options for the port */
357 static void
358 _findPort (int argc, char **argv)
359 {
360   _validatePorts ();
361
362   while (argc--)
363     {
364       if (!strncmp (*argv, "-m", 2))
365         {
366           _setPort (*argv + 2);
367           return;
368         }
369       argv++;
370     }
371
372   /* Use the first in the list */
373 #if defined(DEFAULT_PORT)
374         /* VR - 13/5/2003 DEFAULT_PORT is defined in port.h */
375         port = &DEFAULT_PORT;
376 #else
377         port = _ports[0];
378 #endif
379
380 }
381
382 /* search through the command line options for the processor */
383 static void
384 _findProcessor (int argc, char **argv)
385 {
386   while (argc--)
387     {
388       if (!strncmp (*argv, "-p", 2))
389         {
390           _setProcessor (*argv + 2);
391           return;
392         }
393       argv++;
394     }
395
396   /* no error if processor was not specified. */
397 }
398
399 /*-----------------------------------------------------------------*/
400 /* printVersionInfo - prints the version info        */
401 /*-----------------------------------------------------------------*/
402 void
403 printVersionInfo (void)
404 {
405   int i;
406
407   fprintf (stderr,
408            "SDCC : ");
409   for (i = 0; i < NUM_PORTS; i++) {
410     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
411 #ifdef DEFAULT_PORT
412         fprintf(stderr, "%s", (&DEFAULT_PORT == _ports[i])?"*":"");
413 #endif
414   }
415   
416   fprintf (stderr, " " SDCC_VERSION_STR
417 #ifdef SDCC_SUB_VERSION_STR
418            "/" SDCC_SUB_VERSION_STR
419 #endif
420            " (" __DATE__ ")"
421 #ifdef __CYGWIN__
422            " (CYGWIN)\n"
423 #elif defined __MINGW32__
424            " (MINGW32)\n"
425 #elif defined __DJGPP__
426            " (DJGPP)\n"
427 #elif defined(_MSC_VER)
428            " (MSVC)\n"
429 #elif defined(__BORLANDC__)
430            " (BORLANDC)\n"
431 #else
432            " (UNIX) \n"
433 #endif
434     );
435 }
436
437 static void
438 printOptions(const OPTION *optionsTable)
439 {
440   int i;
441   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++) 
442     {
443       fprintf(stdout, "  %c%c  %-20s  %s\n", 
444               optionsTable[i].shortOpt !=0 ? '-' : ' ',
445               optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
446               optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
447               optionsTable[i].help != NULL ? optionsTable[i].help : ""
448               );
449     }
450 }
451
452 /*-----------------------------------------------------------------*/
453 /* printUsage - prints command line syntax         */
454 /*-----------------------------------------------------------------*/
455 void
456 printUsage (void)
457 {
458     int i;
459     printVersionInfo();
460     fprintf (stdout,
461              "Usage : sdcc [options] filename\n"
462              "Options :-\n"
463              );
464
465     printOptions(optionsTable);
466
467     for (i = 0; i < NUM_PORTS; i++)
468       {
469         if (_ports[i]->poptions != NULL)
470           {
471             fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
472             printOptions (_ports[i]->poptions);
473           }
474       }
475
476     exit (0);
477 }
478
479 /*-----------------------------------------------------------------*/
480 /* setParseWithComma - separates string with comma to a set        */
481 /*-----------------------------------------------------------------*/
482 void
483 setParseWithComma (set **dest, char *src)
484 {
485   char *p;
486
487   /* skip the initial white spaces */
488   while (isspace(*src))
489     src++;
490
491   for (p = strtok(src, ","); p != NULL; p = strtok(NULL, ","))
492     addSet(dest, Safe_strdup(p));
493 }
494
495 /*-----------------------------------------------------------------*/
496 /* setDefaultOptions - sets the default options                    */
497 /*-----------------------------------------------------------------*/
498 static void
499 setDefaultOptions (void)
500 {
501   /* first the options part */
502   options.stack_loc = 0;        /* stack pointer initialised to 0 */
503   options.xstack_loc = 0;       /* xternal stack starts at 0 */
504   options.code_loc = 0;         /* code starts at 0 */
505   options.data_loc = 0;         /* JCF: By default let the linker locate data */
506   options.xdata_loc = 0;
507   options.idata_loc = 0x80;
508   options.nopeep = 0;
509   options.model = port->general.default_model;
510   options.nostdlib = 0;
511   options.nostdinc = 0;
512   options.verbose = 0;
513   options.shortis8bits = 0;
514
515   options.stack10bit=0;
516
517   /* now for the optimizations */
518   /* turn on the everything */
519   optimize.global_cse = 1;
520   optimize.label1 = 1;
521   optimize.label2 = 1;
522   optimize.label3 = 1;
523   optimize.label4 = 1;
524   optimize.loopInvariant = 1;
525   optimize.loopInduction = 1;
526
527   /* now for the ports */
528   port->setDefaultOptions ();
529 }
530
531 /*-----------------------------------------------------------------*/
532 /* processFile - determines the type of file from the extension    */
533 /*-----------------------------------------------------------------*/
534 static void
535 processFile (char *s)
536 {
537   char *fext = NULL;
538
539   /* get the file extension */
540   fext = s + strlen (s);
541   while ((fext != s) && *fext != '.')
542     fext--;
543
544   /* now if no '.' then we don't know what the file type is
545      so give a warning and return */
546   if (fext == s)
547     {
548       werror (W_UNKNOWN_FEXT, s);
549       return;
550     }
551
552   /* otherwise depending on the file type */
553   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0)
554     {
555       /* source file name : not if we already have a
556          source file */
557       if (fullSrcFileName)
558         {
559           werror (W_TOO_MANY_SRC, s);
560           return;
561         }
562
563       /* the only source file */
564       fullSrcFileName = s;
565       if (!(srcFile = fopen (fullSrcFileName, "r")))
566         {
567           werror (E_FILE_OPEN_ERR, s);
568           exit (1);
569         }
570
571       /* copy the file name into the buffer */
572       strncpyz (buffer, s, sizeof(buffer));
573
574       /* get rid of the "."-extension */
575
576       /* is there a dot at all? */
577       if (strrchr (buffer, '.') &&
578           /* is the dot in the filename, not in the path? */
579           (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
580         {
581         *strrchr (buffer, '.') = '\0';
582         }
583
584       /* get rid of any path information
585          for the module name; */
586       fext = buffer + strlen (buffer);
587 #if NATIVE_WIN32
588       /* do this by going backwards till we
589          get '\' or ':' or start of buffer */
590       while (fext != buffer &&
591              *(fext - 1) != DIR_SEPARATOR_CHAR &&
592              *(fext - 1) != ':')
593         {
594         fext--;
595         }
596 #else
597       /* do this by going backwards till we
598          get '/' or start of buffer */
599       while (fext != buffer &&
600              *(fext - 1) != DIR_SEPARATOR_CHAR)
601         {
602           fext--;
603         }
604 #endif
605       moduleName = Safe_strdup ( fext );
606       return;
607     }
608
609   /* if the extention is type .rel or .r or .REL or .R
610      addtional object file will be passed to the linker */
611   if (strcmp (fext, ".r") == 0 || strcmp (fext, ".rel") == 0 ||
612       strcmp (fext, ".R") == 0 || strcmp (fext, ".REL") == 0 ||
613       strcmp (fext, port->linker.rel_ext) == 0)
614     {
615       addSet(&relFilesSet, Safe_strdup(s));
616       return;
617     }
618
619   /* if .lib or .LIB */
620   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
621     {
622       addSet(&libFilesSet, Safe_strdup(s));
623       return;
624     }
625
626   werror (W_UNKNOWN_FEXT, s);
627
628 }
629
630 static void
631 _setModel (int model, const char *sz)
632 {
633   if (port->general.supported_models & model)
634     options.model = model;
635   else
636     werror (W_UNSUPPORTED_MODEL, sz, port->target);
637 }
638
639 /** Gets the string argument to this option.  If the option is '--opt'
640     then for input of '--optxyz' or '--opt xyz' returns xyz.
641 */
642 static char *
643 getStringArg(const char *szStart, char **argv, int *pi, int argc)
644 {
645   if (argv[*pi][strlen(szStart)])
646     {
647       return &argv[*pi][strlen(szStart)];
648     }
649   else
650     {
651       ++(*pi);
652       if (*pi >= argc)
653         {
654           werror (E_ARGUMENT_MISSING, szStart);
655           /* Die here rather than checking for errors later. */
656           exit(-1);
657         }
658       else
659         {
660           return argv[*pi];
661         }
662     }
663 }
664
665 /** Gets the integer argument to this option using the same rules as
666     getStringArg.
667 */
668 static int
669 getIntArg(const char *szStart, char **argv, int *pi, int argc)
670 {
671     return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
672 }
673
674 static void
675 verifyShortOption(const char *opt)
676 {
677   if (strlen(opt) != 2)
678     {
679       werror (W_EXCESS_SHORT_OPTIONS, opt);
680     }
681 }
682
683 static bool
684 tryHandleUnsupportedOpt(char **argv, int *pi)
685 {
686     if (argv[*pi][0] == '-') 
687         {
688             const char *longOpt = "";
689             char shortOpt = -1;
690             int i;
691
692             if (argv[*pi][1] == '-') 
693                 {
694                     /* Long option. */
695                     longOpt = argv[*pi];
696                 }
697             else 
698                 {
699                     shortOpt = argv[*pi][1];
700                 }
701             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
702                 {
703                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
704                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
705                         /* Found an unsupported opt. */
706                         char buffer[100];
707                         SNPRINTF(buffer, sizeof(buffer), 
708                                  "%s%c%c", 
709                                  longOpt ? longOpt : "", 
710                                  shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
711                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
712                         return 1;
713                     }
714                 }
715             /* Didn't find in the table */
716             return 0;
717         }
718     else 
719         {
720             /* Not an option, so can't be unsupported :) */
721             return 0;
722     }
723 }
724
725 static bool
726 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
727 {
728   int i;
729   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++)
730     {
731       if (optionsTable[i].shortOpt == shortOpt ||
732           (longOpt && optionsTable[i].longOpt && 
733            strcmp(optionsTable[i].longOpt, longOpt) == 0))
734         {
735
736           /* If it is a flag then we can handle it here */
737           if (optionsTable[i].pparameter != NULL) 
738             {
739               if (optionsTable[i].shortOpt == shortOpt)
740                 {
741                   verifyShortOption(argv[*pi]);
742                 }
743
744               (*optionsTable[i].pparameter)++;
745               return 1;
746             }
747           else {
748             /* Not a flag.  Handled manually later. */
749             return 0;
750           }
751         }
752     }
753   /* Didn't find in the table */
754   return 0;
755 }
756
757 static bool
758 tryHandleSimpleOpt(char **argv, int *pi)
759 {
760     if (argv[*pi][0] == '-') 
761         {
762             const char *longOpt = "";
763             char shortOpt = -1;
764
765             if (argv[*pi][1] == '-') 
766                 {
767                     /* Long option. */
768                     longOpt = argv[*pi];
769                 }
770             else 
771                 {
772                     shortOpt = argv[*pi][1];
773                 }
774
775             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
776               {
777                 return 1;
778               }
779             else if (port && port->poptions &&
780                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
781               {
782                 return 1;
783               }
784             else
785               {
786                 return 0;
787               }
788         }
789     else 
790         {
791             /* Not an option, so can't be handled. */
792             return 0;
793         }
794 }
795
796 /*-----------------------------------------------------------------*/
797 /* parseCmdLine - parses the command line and sets the options     */
798 /*-----------------------------------------------------------------*/
799 static int
800 parseCmdLine (int argc, char **argv)
801 {
802   int i;
803
804   /* go thru all whole command line */
805   for (i = 1; i < argc; i++)
806     {
807       if (i >= argc)
808         break;
809
810       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
811           {
812               continue;
813           }
814
815       if (tryHandleSimpleOpt(argv, &i) == TRUE)
816           {
817               continue;
818           }
819
820       /* options */
821       if (argv[i][0] == '-' && argv[i][1] == '-')
822         {
823           if (strcmp (argv[i], OPTION_HELP) == 0)
824             {
825               printUsage ();
826               exit (0);
827             }
828
829           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
830             {
831               options.stack10bit = 0;
832               continue;
833             }
834
835           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
836             {
837               options.out_fmt = 0;
838               continue;
839             }
840
841           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
842             {
843               _setModel (MODEL_LARGE, argv[i]);
844               continue;
845             }
846
847           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
848             {
849               _setModel (MODEL_MEDIUM, argv[i]);
850               continue;
851             }
852
853           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
854             {
855               _setModel (MODEL_SMALL, argv[i]);
856               continue;
857             }
858
859           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
860             {
861               _setModel (MODEL_FLAT24, argv[i]);
862               continue;
863             }
864
865           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
866             {
867               options.dump_rassgn =
868                 options.dump_pack =
869                 options.dump_range =
870                 options.dump_kill =
871                 options.dump_loop =
872                 options.dump_gcse =
873                 options.dump_raw = 1;
874               continue;
875             }
876
877           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
878             {
879                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
880                 continue;
881             }
882
883           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
884             {
885                 addSet(&libPathsSet, Safe_strdup(getStringArg(OPTION_LIB_PATH, argv, &i, argc)));
886                 continue;
887             }
888
889           if (strcmp (argv[i], OPTION_VERSION) == 0)
890             {
891               printVersionInfo ();
892               exit (0);
893               continue;
894             }
895
896           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
897             {
898                 setParseWithComma(&options.calleeSavesSet, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
899                 continue;
900             }
901
902           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
903             {
904                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
905                 continue;
906             }
907
908           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
909             {
910                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
911                 continue;
912             }
913
914           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
915             {
916                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
917                 continue;
918             }
919
920           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
921             {
922                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
923                 continue;
924             }
925
926           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
927             {
928                 options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
929                 options.xram_size_set = TRUE;
930                 continue;
931             }
932
933           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
934             {
935                 options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
936                 continue;
937             }
938
939           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
940             {
941                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
942                 continue;
943             }
944
945           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
946             {
947                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
948                 continue;
949             }
950
951           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
952             {
953                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
954                 continue;
955             }
956
957           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
958             {
959               optimize.global_cse = 0;
960               continue;
961             }
962
963           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
964             {
965               optimize.loopInvariant = 0;
966               continue;
967             }
968
969           if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
970             {
971               optimize.label4 = 0;
972               continue;
973             }
974
975           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
976             {
977               optimize.loopInduction = 0;
978               continue;
979             }
980
981           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
982             {
983               options.lessPedantic = 1;
984               setErrorLogLevel(ERROR_LEVEL_WARNING);
985               continue;
986             }
987
988           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
989             {
990               options.shortis8bits=1;
991               continue;
992             }
993
994           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
995             {
996                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
997                 continue;
998             }
999           
1000           if (!port->parseOption (&argc, argv, &i))
1001             {
1002               werror (W_UNKNOWN_OPTION, argv[i]);
1003             }
1004           else
1005             {
1006               continue;
1007             }
1008         }
1009
1010       /* if preceded by  '-' then option */
1011       if (*argv[i] == '-')
1012         {
1013           switch (argv[i][1])
1014             {
1015             case 'h':
1016               verifyShortOption(argv[i]);
1017
1018               printUsage ();
1019               exit (0);
1020               break;
1021
1022             case 'm':
1023               /* Used to select the port. But this has already been done. */
1024               break;
1025
1026             case 'p':
1027               /* Used to select the processor in port. But this has
1028                * already been done. */
1029               break;
1030
1031             case 'c':
1032               verifyShortOption(argv[i]);
1033
1034               options.cc_only = 1;
1035               break;
1036
1037             case 'L':
1038                 addSet(&libPathsSet, Safe_strdup(getStringArg("-L", argv, &i, argc)));
1039                 break;
1040
1041             case 'l':
1042                 addSet(&libFilesSet, Safe_strdup(getStringArg("-l", argv, &i, argc)));
1043                 break;
1044             
1045             case 'o':
1046               {
1047                 char *p;
1048
1049                 /* copy the file name into the buffer */
1050                 strncpyz(buffer, getStringArg("-o", argv, &i, argc), 
1051                          sizeof(buffer));
1052                 /* point to last character */
1053                 p = buffer + strlen (buffer) - 1;
1054                 if (*p == DIR_SEPARATOR_CHAR)
1055                   {
1056                     /* only output path specified */
1057                     dstPath = Safe_strdup (buffer);
1058                     fullDstFileName = NULL;
1059                   }
1060                 else
1061                   {
1062                     fullDstFileName = Safe_strdup (buffer);
1063
1064                     /* get rid of the "."-extension */
1065
1066                     /* is there a dot at all? */
1067                     if (strrchr (buffer, '.') &&
1068                         /* is the dot in the filename, not in the path? */
1069                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1070                       *strrchr (buffer, '.') = '\0';
1071
1072                     dstFileName = Safe_strdup (buffer);
1073
1074                     /* strip module name to get path */
1075                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1076                     if (p)
1077                       {
1078                         /* path with trailing / */
1079                         p[1] = '\0';
1080                         dstPath = Safe_strdup (buffer);
1081                       }
1082                   }
1083                 break;
1084               }
1085
1086             case 'W':
1087               /* pre-processer options */
1088               if (argv[i][2] == 'p')
1089                 {
1090                   setParseWithComma(&preArgvSet, getStringArg("-Wp", argv, &i, argc));
1091                 }
1092               /* linker options */
1093               else if (argv[i][2] == 'l')
1094                 {
1095                   setParseWithComma(&linkOptionsSet, getStringArg("-Wl", argv, &i, argc));
1096                 }
1097               /* assembler options */
1098               else if (argv[i][2] == 'a')
1099                 {
1100                   setParseWithComma(&asmOptionsSet, getStringArg("-Wa", argv, &i, argc));
1101                 }
1102               else
1103                 {
1104                   werror (W_UNKNOWN_OPTION, argv[i]);
1105                 }
1106               break;
1107
1108             case 'v':
1109               verifyShortOption(argv[i]);
1110
1111               printVersionInfo ();
1112               exit (0);
1113               break;
1114
1115               /* preprocessor options */
1116             case 'M':
1117               {
1118                 preProcOnly = 1;
1119                 addSet(&preArgvSet, Safe_strdup("-M"));
1120                 break;
1121               }
1122             case 'C':
1123               {
1124                 addSet(&preArgvSet, Safe_strdup("-C"));
1125                 break;
1126               }
1127
1128             case 'd':
1129             case 'D':
1130             case 'I':
1131             case 'A':
1132             case 'U':
1133               {
1134                 char sOpt = argv[i][1];
1135                 char *rest;
1136
1137                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1138                   {
1139                     i++;
1140                     if (i >= argc)
1141                       {
1142                           /* No argument. */
1143                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1144                           break;
1145                       }
1146                     else
1147                       {
1148                           rest = argv[i];
1149                       }
1150                   }
1151                 else
1152                   rest = &argv[i][2];
1153
1154                 if (sOpt == 'Y')
1155                   sOpt = 'I';
1156
1157                 SNPRINTF (buffer, sizeof(buffer),
1158                   ((sOpt == 'I') ? "-%c\"%s\"": "-%c%s"), sOpt, rest);
1159                 addSet(&preArgvSet, Safe_strdup(buffer));
1160               }
1161               break;
1162
1163             default:
1164               if (!port->parseOption (&argc, argv, &i))
1165                 werror (W_UNKNOWN_OPTION, argv[i]);
1166             }
1167           continue;
1168         }
1169
1170       if (!port->parseOption (&argc, argv, &i))
1171         {
1172            /* no option must be a filename */
1173            if (options.c1mode)
1174              {
1175                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1176              }
1177          else
1178              {
1179                 processFile (argv[i]);
1180              }
1181         }
1182     }
1183
1184   /* some sanity checks in c1 mode */
1185   if (options.c1mode)
1186     {
1187       const char *s;
1188
1189       if (fullSrcFileName)
1190         {
1191           fclose (srcFile);
1192           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1193         }
1194       fullSrcFileName = NULL;
1195       for (s = setFirstItem(relFilesSet); s != NULL; s = setNextItem(relFilesSet))
1196         {
1197           werror (W_NO_FILE_ARG_IN_C1, s);
1198         }
1199       for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1200         {
1201           werror (W_NO_FILE_ARG_IN_C1, s);
1202         }
1203       deleteSet(&relFilesSet);
1204       deleteSet(&libFilesSet);
1205
1206         if (options.cc_only || noAssemble || preProcOnly)
1207         {
1208           werror (W_ILLEGAL_OPT_COMBINATION);
1209         }
1210       options.cc_only = noAssemble = preProcOnly = 0;
1211       if (!dstFileName)
1212         {
1213           werror (E_NEED_OPT_O_IN_C1);
1214           exit (1);
1215         }
1216     }
1217   /* if no dstFileName given with -o, we've to find one: */
1218   if (!dstFileName)
1219     {
1220       const char *s;
1221
1222       /* use the modulename from the C-source */
1223       if (fullSrcFileName)
1224         {
1225           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1226
1227           dstFileName = Safe_alloc (bufSize);
1228           strncpyz (dstFileName, dstPath, bufSize);
1229           strncatz (dstFileName, moduleName, bufSize);
1230         }
1231       /* use the modulename from the first object file */
1232       else if ((s = peekSet(relFilesSet)) != NULL)
1233         {
1234           char *objectName;
1235           size_t bufSize;
1236
1237           strncpyz (buffer, s, sizeof(buffer));
1238           /* remove extension (it must be .rel) */
1239           *strrchr (buffer, '.') = '\0';
1240           /* remove path */
1241           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1242           if (objectName)
1243             {
1244               ++objectName;
1245             }
1246           else
1247             {
1248               objectName = buffer;
1249             }
1250           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1251           dstFileName = Safe_alloc (bufSize);
1252           strncpyz (dstFileName, dstPath, bufSize);
1253           strncatz (dstFileName, objectName, bufSize);
1254         }
1255       /* else no module given: help text is displayed */
1256     }
1257
1258   /* set up external stack location if not explicitly specified */
1259   if (!options.xstack_loc)
1260     options.xstack_loc = options.xdata_loc;
1261
1262   /* if debug option is set then open the cdbFile */
1263   if (options.debug && fullSrcFileName)
1264     {
1265       SNPRINTF (scratchFileName, sizeof(scratchFileName),
1266                 "%s.adb", dstFileName); /*JCF: Nov 30, 2002*/
1267       if(debugFile->openFile(scratchFileName))
1268         debugFile->writeModule(moduleName);
1269       else
1270         werror (E_FILE_OPEN_ERR, scratchFileName);
1271     }
1272   MSVC_style(options.vc_err_style);
1273   if(options.use_stdout) dup2(STDOUT_FILENO, STDERR_FILENO);
1274
1275   return 0;
1276 }
1277
1278 /*-----------------------------------------------------------------*/
1279 /* linkEdit : - calls the linkage editor  with options             */
1280 /*-----------------------------------------------------------------*/
1281 static void
1282 linkEdit (char **envp)
1283 {
1284   FILE *lnkfile;
1285   char *segName, *c;
1286   int system_ret;
1287   const char *s;
1288
1289   /* first we need to create the <filename>.lnk file */
1290   SNPRINTF (scratchFileName, sizeof(scratchFileName),
1291             "%s.lnk", dstFileName);
1292   if (!(lnkfile = fopen (scratchFileName, "w")))
1293     {
1294       werror (E_FILE_OPEN_ERR, scratchFileName);
1295       exit (1);
1296     }
1297
1298    if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
1299    {
1300           fprintf (lnkfile, "--\n-m\n-j\n-x\n-%c %s\n",
1301           (options.out_fmt ? 's' : 'i'), dstFileName);
1302    }
1303    else /*For all the other ports.  Including pics???*/
1304    {
1305           fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1306    }
1307
1308    if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1309    {
1310           /* if iram size specified */
1311           if (options.iram_size)
1312                 fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1313
1314           /* if xram size specified */
1315           if (options.xram_size_set)
1316                 fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1317
1318           /* if code size specified */
1319           if (options.code_size)
1320                 fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1321
1322           if (options.debug)
1323                 fprintf (lnkfile, "-z\n");
1324    }
1325
1326 #define WRITE_SEG_LOC(N, L) \
1327     segName = Safe_strdup(N); \
1328     c = strtok(segName, " \t"); \
1329     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1330     if (segName) { Safe_free(segName); }
1331
1332    if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1333    {
1334
1335           /* code segment start */
1336           WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1337
1338           /* data segment start. If zero, the linker chooses
1339       the best place for data*/
1340           if(options.data_loc){
1341                   WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1342           }
1343
1344           /* xdata start */
1345           WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1346
1347           /* indirect data */
1348           if (IDATA_NAME) {
1349                 WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1350           }
1351
1352           /* bit segment start */
1353           WRITE_SEG_LOC (BIT_NAME, 0);
1354
1355           /* stack start */
1356           if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1357                 WRITE_SEG_LOC ("SSEG", options.stack_loc);
1358           }
1359    }
1360    else /*For the z80, gbz80*/
1361    {
1362        WRITE_SEG_LOC ("_CODE", options.code_loc);
1363        WRITE_SEG_LOC ("_DATA", options.data_loc);
1364    }
1365   
1366   /* If the port has any special linker area declarations, get 'em */
1367   if (port->extraAreas.genExtraAreaLinkOptions)
1368   {
1369         port->extraAreas.genExtraAreaLinkOptions(lnkfile);
1370   }
1371
1372   /* add the extra linker options */
1373   fputStrSet(lnkfile, linkOptionsSet);
1374
1375   /* other library paths if specified */
1376   for (s = setFirstItem(libPathsSet); s != NULL; s = setNextItem(libPathsSet))
1377     fprintf (lnkfile, "-k %s\n", s);
1378   
1379   /* standard library path */
1380     if (!options.nostdlib)
1381     {
1382         if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1383         {
1384             switch (options.model)
1385             {
1386                 case MODEL_SMALL:
1387                     c = "small";
1388                     break;
1389                 case MODEL_LARGE:
1390                     c = "large";
1391                     break;
1392                 case MODEL_FLAT24:
1393                     /* c = "flat24"; */
1394                     if (TARGET_IS_DS390)
1395                     {
1396                         c = "ds390";
1397                     }
1398                     else if (TARGET_IS_DS400)
1399                     {
1400                         c = "ds400";
1401                     }
1402                     else
1403                     {
1404                         fprintf(stderr, 
1405                                 "Add support for your FLAT24 target in %s @ line %d\n",
1406                                 __FILE__, __LINE__);
1407                         exit(-1);
1408                     }
1409                         break;
1410                     case MODEL_PAGE0:
1411                         c = "xa51";
1412                         break;
1413                     default:
1414                         werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1415                         c = "unknown";
1416                         break;
1417                 }
1418         }
1419         else /*for the z80, gbz80*/
1420         {
1421             if (TARGET_IS_Z80)
1422                 c = "z80";
1423             else
1424                 c = "gbz80";
1425         }
1426         for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1427             mfprintf (lnkfile, getRuntimeVariables(), "-k %s{sep}%s\n", s, c);
1428
1429
1430       /* standard library files */
1431 #if !OPT_DISABLE_DS390
1432         if (options.model == MODEL_FLAT24)
1433         {
1434             if (TARGET_IS_DS390)
1435             {
1436                 fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1437             }
1438             else if (TARGET_IS_DS400)
1439             {
1440                 fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1441             }
1442             else
1443             {
1444                 fprintf(stderr, 
1445                     "Add support for your FLAT24 target in %s @ line %d\n",
1446                     __FILE__, __LINE__);
1447                 exit(-1);
1448             }
1449         }
1450 #endif
1451
1452 #if !OPT_DISABLE_XA51 
1453 #ifdef STD_XA51_LIB
1454         if (options.model == MODEL_PAGE0)
1455         {
1456             fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1457         }
1458 #endif
1459 #endif
1460         if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1461         { /*Why the z80 port is not using the standard libraries?*/
1462             fprintf (lnkfile, "-l %s\n", STD_LIB);
1463             fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1464             fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1465             fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1466         }
1467         else if (TARGET_IS_Z80)
1468         {
1469             fprintf (lnkfile, "-l z80\n");
1470         }
1471         else if (TARGET_IS_GBZ80)
1472         {
1473             fprintf (lnkfile, "-l gbz80\n");
1474         }
1475     }
1476
1477   /* additional libraries if any */
1478   for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1479     fprintf (lnkfile, "-l %s\n", s);
1480
1481   /* put in the object files */
1482   if (fullSrcFileName)
1483     fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
1484
1485   fputStrSet(lnkfile, relFilesSet);
1486
1487   /*For the z80 and gbz80 ports, try to find where crt0.o is...*/
1488   if (TARGET_IS_Z80 || TARGET_IS_GBZ80) /*For the z80, gbz80*/
1489   {
1490       char crt0path[PATH_MAX];
1491       FILE * crt0fp;
1492       for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1493       {
1494           sprintf (crt0path, "%s%s%s%scrt0.o",
1495              s, DIR_SEPARATOR_STRING, c, DIR_SEPARATOR_STRING);
1496           
1497           crt0fp=fopen(crt0path, "r");
1498           if(crt0fp!=NULL)/*Found it!*/
1499           {
1500               fclose(crt0fp);
1501               #ifdef __CYGWIN__
1502               {
1503                  /*The CYGWIN version of the z80-gbz80 linker is getting confused with
1504                  windows paths, so convert them to the CYGWIN format*/
1505                  char posix_path[PATH_MAX];
1506                  void cygwin_conv_to_full_posix_path(char * win_path, char * posix_path);
1507                  cygwin_conv_to_full_posix_path(crt0path, posix_path);
1508                  strcpy(crt0path, posix_path);
1509               }
1510               #endif
1511               fprintf (lnkfile, "%s\n", crt0path);
1512               break;
1513           }
1514       }
1515       if(s==NULL) fprintf (stderr, "Warning: couldn't find crt0.o\n");
1516   }
1517
1518   fprintf (lnkfile, "\n-e\n");
1519   fclose (lnkfile);
1520
1521   if (options.verbose)
1522     printf ("sdcc: Calling linker...\n");
1523
1524   /* build linker output filename */
1525
1526   /* -o option overrides default name? */
1527   if (fullDstFileName)
1528     {
1529       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1530     }
1531   else
1532     {
1533       /* the linked file gets the name of the first modul */
1534       if (fullSrcFileName)
1535         {
1536           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1537         }
1538       else
1539         {
1540           s = peekSet(relFilesSet);
1541
1542           assert(s);
1543
1544           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1545           /* strip ".rel" extension */
1546           *strrchr (scratchFileName, '.') = '\0';
1547         }
1548       strncatz (scratchFileName, 
1549                 options.out_fmt ? ".S19" : ".ihx",
1550                 sizeof(scratchFileName));
1551     }
1552
1553   if (port->linker.cmd)
1554     {
1555       char buffer2[PATH_MAX];
1556
1557         /* VR 030517 - gplink needs linker options to set the linker script,*/
1558         buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, linkOptionsSet);
1559
1560         buildCmdLine2 (buffer, sizeof(buffer), buffer2);
1561     }
1562   else
1563     {
1564       buildCmdLine2 (buffer, sizeof(buffer), port->linker.mcmd);
1565     }
1566
1567 /*  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer); */
1568
1569   system_ret = my_system (buffer);
1570   /* TODO: most linker don't have a -o parameter */
1571   /* -o option overrides default name? */
1572   if (fullDstFileName)
1573     {
1574       char *p, *q;
1575       /* the linked file gets the name of the first modul */
1576       if (fullSrcFileName)
1577         {
1578           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1579           p = strlen (scratchFileName) + scratchFileName;
1580         }
1581       else
1582         {
1583           s = peekSet(relFilesSet);
1584
1585           assert(s);
1586
1587           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1588           /* strip ".rel" extension */
1589           p = strrchr (scratchFileName, '.');
1590           if (p)
1591             {
1592               *p = 0;
1593             }
1594         }
1595       strncatz (scratchFileName,
1596                 options.out_fmt ? ".S19" : ".ihx",
1597                 sizeof(scratchFileName));
1598       rename (scratchFileName, fullDstFileName);
1599
1600       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1601       q = strrchr (buffer, '.');
1602       if (!q)
1603         {
1604           /* no extension: append new extensions */
1605           q = strlen (buffer) + buffer;
1606         }
1607
1608       *p = 0;
1609       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1610       *q = 0;
1611       strncatz(buffer, ".map", sizeof(buffer));
1612       rename (scratchFileName, buffer);
1613       *p = 0;
1614       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1615       *q = 0;
1616       strncatz(buffer, ".mem", sizeof(buffer));
1617       rename (scratchFileName, buffer);
1618     }
1619   if (system_ret)
1620     {
1621       exit (1);
1622     }
1623 }
1624
1625 /*-----------------------------------------------------------------*/
1626 /* assemble - spawns the assembler with arguments                  */
1627 /*-----------------------------------------------------------------*/
1628 static void
1629 assemble (char **envp)
1630 {
1631     /* build assembler output filename */
1632
1633     /* -o option overrides default name? */
1634     if (options.cc_only && fullDstFileName) {
1635         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1636     } else {
1637         /* the assembled file gets the name of the first modul */
1638         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1639         strncatz (scratchFileName, port->linker.rel_ext, 
1640                   sizeof(scratchFileName));
1641     }
1642
1643     if (port->assembler.do_assemble) {
1644         port->assembler.do_assemble(asmOptionsSet);
1645         return ;
1646     } else if (port->assembler.cmd) {
1647         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1648                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1649                       asmOptionsSet);
1650     } else {
1651         buildCmdLine2 (buffer, sizeof(buffer), port->assembler.mcmd);
1652     }
1653
1654     if (my_system (buffer)) {
1655         /* either system() or the assembler itself has reported an error
1656            perror ("Cannot exec assembler");
1657         */
1658         exit (1);
1659     }
1660     /* TODO: most assembler don't have a -o parameter */
1661     /* -o option overrides default name? */
1662     if (options.cc_only && fullDstFileName) {
1663         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1664         strncatz (scratchFileName, 
1665                   port->linker.rel_ext,
1666                   sizeof(scratchFileName));
1667         rename (scratchFileName, fullDstFileName);
1668     }
1669 }
1670
1671 /*-----------------------------------------------------------------*/
1672 /* preProcess - spawns the preprocessor with arguments       */
1673 /*-----------------------------------------------------------------*/
1674 static int
1675 preProcess (char **envp)
1676 {
1677   if (options.c1mode)
1678     {
1679       yyin = stdin;
1680     }
1681   else
1682     {
1683       const char *s;
1684       set *inclList = NULL;
1685
1686       /* if using external stack define the macro */
1687       if (options.useXstack)
1688         addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
1689
1690       /* set the macro for stack autos  */
1691       if (options.stackAuto)
1692         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_AUTO"));
1693
1694       /* set the macro for stack autos  */
1695       if (options.stack10bit)
1696         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_TENBIT"));
1697
1698       /* set the macro for no overlay  */
1699       if (options.noOverlay)
1700         addSet(&preArgvSet, Safe_strdup("-DSDCC_NOOVERLAY"));
1701
1702       /* set the macro for large model  */
1703       switch (options.model)
1704         {
1705         case MODEL_LARGE:
1706           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_LARGE"));
1707           break;
1708         case MODEL_SMALL:
1709           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_SMALL"));
1710           break;
1711         case MODEL_COMPACT:
1712           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_COMPACT"));
1713           break;
1714         case MODEL_MEDIUM:
1715           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_MEDIUM"));
1716           break;
1717         case MODEL_FLAT24:
1718           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_FLAT24"));
1719           break;
1720         case MODEL_PAGE0:
1721           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_PAGE0"));
1722           break;
1723         default:
1724           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1725           break;
1726         }
1727
1728       /* add port (processor information to processor */
1729       addSet(&preArgvSet, Safe_strdup("-DSDCC_{port}"));
1730       addSet(&preArgvSet, Safe_strdup("-D__{port}"));
1731
1732       /* standard include path */
1733       if (!options.nostdinc) {
1734         inclList = appendStrSet(includeDirsSet, "-I\"", "\"");
1735         mergeSets(&preArgvSet, inclList);
1736       }
1737
1738       setMainValue("cppextraopts", (s = joinStrSet(preArgvSet)));
1739       Safe_free((void *)s);
1740       if (inclList != NULL)
1741         deleteSet(&inclList);
1742
1743       if (preProcOnly && fullDstFileName)
1744         {
1745           /* -E and -o given */
1746           setMainValue ("cppoutfilename", fullDstFileName);
1747         }
1748       else
1749         {
1750           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1751           setMainValue ("cppoutfilename", NULL);
1752         }
1753
1754       if (options.verbose)
1755         printf ("sdcc: Calling preprocessor...\n");
1756
1757       buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
1758
1759       if (preProcOnly) {
1760         if (my_system (buffer)) {
1761           exit (1);
1762         }
1763
1764         exit (0);
1765       }
1766
1767       yyin = my_popen (buffer);
1768       if (yyin == NULL) {
1769           perror ("Preproc file not found");
1770           exit (1);
1771       }
1772       addSetHead (&pipeSet, yyin);
1773     }
1774
1775   return 0;
1776 }
1777
1778 /* Set bin paths */
1779 static void
1780 setBinPaths(const char *argv0)
1781 {
1782   char *p;
1783   char buf[PATH_MAX];
1784
1785   /*
1786    * Search logic:
1787    *
1788    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1789    * 2. - path(argv[0])
1790    * 3. - $PATH
1791    */
1792
1793   /* do it in reverse mode, so that addSetHead() can be used
1794      instead of slower addSet() */
1795
1796   if ((p = getBinPath(argv0)) != NULL)
1797     addSetHead(&binPathSet, Safe_strdup(p));
1798
1799   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1800     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1801     addSetHead(&binPathSet, Safe_strdup(buf));
1802   }
1803
1804   if (options.printSearchDirs) {
1805     printf("programs:\n");
1806     fputStrSet(stdout, binPathSet);
1807   }
1808 }
1809
1810 /* Set system include path */
1811 static void
1812 setIncludePath(void)
1813 {
1814   char *p;
1815
1816   /*
1817    * Search logic:
1818    *
1819    * 1. - $SDCC_INCLUDE
1820    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
1821    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
1822    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
1823    */
1824
1825   includeDirsSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX);
1826
1827   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
1828     addSetHead(&includeDirsSet, p);
1829
1830   if (options.printSearchDirs) {
1831     printf("includedir:\n");
1832     fputStrSet(stdout, includeDirsSet);
1833   }
1834 }
1835
1836 /* Set system lib path */
1837 static void
1838 setLibPath(void)
1839 {
1840   char *p;
1841
1842   /*
1843    * Search logic:
1844    *
1845    * 1. - $SDCC_LIB
1846    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
1847    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
1848    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
1849    */
1850
1851   libDirsSet = appendStrSet(dataDirsSet, NULL, LIB_DIR_SUFFIX);
1852
1853   if ((p = getenv(SDCC_LIB_NAME)) != NULL)
1854     addSetHead(&libDirsSet, p);
1855
1856   if (options.printSearchDirs) {
1857     printf("libdir:\n");
1858     fputStrSet(stdout, libDirsSet);
1859   }
1860 }
1861
1862 /* Set data path */
1863 static void
1864 setDataPaths(const char *argv0)
1865 {
1866   char *p;
1867   char buf[PATH_MAX];
1868
1869   /*
1870    * Search logic:
1871    *
1872    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
1873    * 2. - path(argv[0])/BIN2DATA_DIR
1874    * 3. - DATADIR (only on *nix)
1875    */
1876
1877   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1878     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
1879     addSet(&dataDirsSet, Safe_strdup(buf));
1880   }
1881
1882   if ((p = getBinPath(argv0)) != NULL) {
1883     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
1884     addSet(&dataDirsSet, Safe_strdup(buf));
1885   }
1886
1887 #ifdef _WIN32
1888   if (peekSet(dataDirsSet) == NULL) {
1889     /* this should never happen... */
1890     wassertl(0, "Can't get binary path");
1891   }
1892 #else
1893   addSet(&dataDirsSet, Safe_strdup(DATADIR));
1894 #endif
1895
1896   if (options.printSearchDirs) {
1897     printf("datadir:\n");
1898     fputStrSet(stdout, dataDirsSet);
1899   }
1900
1901   setIncludePath();
1902   setLibPath();
1903 }
1904
1905 static void
1906 initValues (void)
1907 {
1908   populateMainValues (_baseValues);
1909   setMainValue ("port", port->target);
1910   setMainValue ("objext", port->linker.rel_ext);
1911   setMainValue ("asmext", port->assembler.file_ext);
1912
1913   setMainValue ("dstfilename", dstFileName);
1914   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1915
1916   if (options.cc_only && fullDstFileName)
1917     /* compile + assemble and -o given: -o specifies name of object file */
1918     {
1919       setMainValue ("objdstfilename", fullDstFileName);
1920     }
1921   else
1922     {
1923       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1924     }
1925   if (fullDstFileName)
1926     /* if we're linking, -o gives the final file name */
1927     {
1928       setMainValue ("linkdstfilename", fullDstFileName);
1929     }
1930   else
1931     {
1932       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1933     }
1934
1935 }
1936
1937 static void
1938 sig_handler (int signal)
1939 {
1940   char *sig_string;
1941
1942   switch (signal)
1943     {
1944     case SIGABRT:
1945       sig_string = "SIGABRT";
1946       break;
1947     case SIGTERM:
1948       sig_string = "SIGTERM";
1949       break;
1950     case SIGINT:
1951       sig_string = "SIGINT";
1952       break;
1953     case SIGSEGV:
1954       sig_string = "SIGSEGV";
1955       break;
1956     default:
1957       sig_string = "Unknown?";
1958       break;
1959     }
1960   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1961   exit (1);
1962 }
1963
1964 /*
1965  * main routine
1966  * initialises and calls the parser
1967  */
1968
1969 int
1970 main (int argc, char **argv, char **envp)
1971 {
1972   /* turn all optimizations off by default */
1973   memset (&optimize, 0, sizeof (struct optimize));
1974
1975   /*printVersionInfo (); */
1976
1977   if (NUM_PORTS==0) {
1978     fprintf (stderr, "Build error: no ports are enabled.\n");
1979     exit (1);
1980   }
1981
1982   /* install atexit handler */
1983   atexit(rm_tmpfiles);
1984
1985   /* install signal handler;
1986      it's only purpuse is to call exit() to remove temp files */
1987   if (!getenv("SDCC_LEAVE_SIGNALS"))
1988     {
1989       signal (SIGABRT, sig_handler);
1990       signal (SIGTERM, sig_handler);
1991       signal (SIGINT , sig_handler);
1992       signal (SIGSEGV, sig_handler);
1993     }
1994
1995   /* Before parsing the command line options, do a
1996    * search for the port and processor and initialize
1997    * them if they're found. (We can't gurantee that these
1998    * will be the first options specified).
1999    */
2000
2001   _findPort (argc, argv);
2002
2003 #ifdef JAMIN_DS390
2004   if (strcmp(port->target, "mcs51") == 0) {
2005     printf("DS390 jammed in A\n");
2006           _setPort ("ds390");
2007     ds390_jammed = 1;
2008   }
2009 #endif
2010
2011   _findProcessor (argc, argv);
2012
2013   /* Initalise the port. */
2014   if (port->init)
2015     port->init ();
2016
2017   setDefaultOptions ();
2018 #ifdef JAMIN_DS390
2019   if (ds390_jammed) {
2020     options.model = MODEL_SMALL;
2021     options.stack10bit=0;
2022   }
2023 #endif
2024   parseCmdLine (argc, argv);
2025
2026   initValues ();
2027   setBinPaths(argv[0]);
2028   setDataPaths(argv[0]);
2029
2030   /* if no input then printUsage & exit */
2031   if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL) {
2032     if (!options.printSearchDirs)
2033       printUsage();
2034
2035     exit(0);
2036   }
2037
2038   /* initMem() is expensive, but
2039      initMem() must called before port->finaliseOptions ().
2040      And the z80 port needs port->finaliseOptions(),
2041      even if we're only linking. */
2042   initMem ();
2043   port->finaliseOptions ();
2044
2045   if (fullSrcFileName || options.c1mode)
2046     {
2047       preProcess (envp);
2048
2049       initSymt ();
2050       initiCode ();
2051       initCSupport ();
2052       initBuiltIns();
2053       initPeepHole ();
2054
2055       if (options.verbose)
2056         printf ("sdcc: Generating code...\n");
2057
2058       yyparse ();
2059
2060       pclose(yyin);
2061       deleteSetItem(&pipeSet, yyin);
2062
2063       if (fatalError) {
2064         exit (1);
2065       }
2066
2067       if (port->general.do_glue != NULL)
2068         (*port->general.do_glue)();
2069       else
2070         {
2071           /* this shouldn't happen */
2072           assert(FALSE);
2073           /* in case of NDEBUG */
2074           glue();
2075         }
2076
2077       if (!options.c1mode && !noAssemble)
2078         {
2079           if (options.verbose)
2080             printf ("sdcc: Calling assembler...\n");
2081           assemble (envp);
2082         }
2083     }
2084   closeDumpFiles();
2085
2086   if (options.debug && debugFile)
2087     debugFile->closeFile();
2088
2089   if (!options.cc_only &&
2090       !fatalError &&
2091       !noAssemble &&
2092       !options.c1mode &&
2093       (fullSrcFileName || peekSet(relFilesSet) != NULL))
2094     {
2095       if (port->linker.do_link)
2096         port->linker.do_link ();
2097       else
2098         linkEdit (envp);
2099     }
2100
2101   return 0;
2102 }