virtualization of glue() function: each port has it's own glue function,
[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   /* now write the options.  JCF: added option 'y' */
1299   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1300
1301   /* if iram size specified */
1302   if (options.iram_size)
1303     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1304
1305   /* if xram size specified */
1306   if (options.xram_size_set)
1307     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1308
1309   /* if code size specified */
1310   if (options.code_size)
1311     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1312
1313   if (options.debug)
1314     fprintf (lnkfile, "-z\n");
1315
1316 #define WRITE_SEG_LOC(N, L) \
1317     segName = Safe_strdup(N); \
1318     c = strtok(segName, " \t"); \
1319     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1320     if (segName) { Safe_free(segName); }
1321
1322   /* code segment start */
1323   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1324
1325   /* data segment start */
1326   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1327           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1328   }
1329
1330   /* xdata start */
1331   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1332
1333   /* indirect data */
1334   if (IDATA_NAME) {
1335     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1336   }
1337
1338   /* bit segment start */
1339   WRITE_SEG_LOC (BIT_NAME, 0);
1340
1341   /* JCF: stack start */
1342   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1343         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1344   }
1345   
1346   /* If the port has any special linker area declarations, get 'em */
1347   if (port->extraAreas.genExtraAreaLinkOptions)
1348   {
1349         port->extraAreas.genExtraAreaLinkOptions(lnkfile);
1350   }
1351
1352   /* add the extra linker options */
1353   fputStrSet(lnkfile, linkOptionsSet);
1354
1355   /* other library paths if specified */
1356   for (s = setFirstItem(libPathsSet); s != NULL; s = setNextItem(libPathsSet))
1357     fprintf (lnkfile, "-k %s\n", s);
1358
1359   /* standard library path */
1360   if (!options.nostdlib)
1361     {
1362       switch (options.model)
1363         {
1364         case MODEL_SMALL:
1365           c = "small";
1366           break;
1367         case MODEL_LARGE:
1368           c = "large";
1369           break;
1370         case MODEL_FLAT24:
1371           /* c = "flat24"; */
1372             if (TARGET_IS_DS390)
1373             {
1374                 c = "ds390";
1375             }
1376             else if (TARGET_IS_DS400)
1377             {
1378                 c = "ds400";
1379             }
1380             else
1381             {
1382                 fprintf(stderr, 
1383                         "Add support for your FLAT24 target in %s @ line %d\n",
1384                         __FILE__, __LINE__);
1385                 exit(-1);
1386             }
1387           break;
1388         case MODEL_PAGE0:
1389           c = "xa51";
1390           break;
1391         default:
1392           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1393           c = "unknown";
1394           break;
1395         }
1396       for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1397         mfprintf (lnkfile, getRuntimeVariables(), "-k %s{sep}%s\n", s, c);
1398
1399       /* standard library files */
1400 #if !OPT_DISABLE_DS390
1401       if (options.model == MODEL_FLAT24)
1402         {
1403             if (TARGET_IS_DS390)
1404             {
1405                 fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1406             }
1407             else if (TARGET_IS_DS400)
1408             {
1409                 fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1410             }
1411             else
1412             {
1413                 fprintf(stderr, 
1414                         "Add support for your FLAT24 target in %s @ line %d\n",
1415                         __FILE__, __LINE__);
1416                 exit(-1);
1417             }
1418         }
1419 #endif
1420
1421 #if !OPT_DISABLE_XA51 
1422 #ifdef STD_XA51_LIB
1423       if (options.model == MODEL_PAGE0)
1424         {
1425           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1426         }
1427 #endif
1428 #endif
1429       fprintf (lnkfile, "-l %s\n", STD_LIB);
1430       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1431       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1432       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1433     }
1434
1435   /* additional libraries if any */
1436   for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1437     fprintf (lnkfile, "-l %s\n", s);
1438
1439   /* put in the object files */
1440   if (fullSrcFileName)
1441     fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
1442
1443   fputStrSet(lnkfile, relFilesSet);
1444
1445   fprintf (lnkfile, "\n-e\n");
1446   fclose (lnkfile);
1447
1448   if (options.verbose)
1449     printf ("sdcc: Calling linker...\n");
1450
1451   /* build linker output filename */
1452
1453   /* -o option overrides default name? */
1454   if (fullDstFileName)
1455     {
1456       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1457     }
1458   else
1459     {
1460       /* the linked file gets the name of the first modul */
1461       if (fullSrcFileName)
1462         {
1463           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1464         }
1465       else
1466         {
1467           s = peekSet(relFilesSet);
1468
1469           assert(s);
1470
1471           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1472           /* strip ".rel" extension */
1473           *strrchr (scratchFileName, '.') = '\0';
1474         }
1475       strncatz (scratchFileName, 
1476                 options.out_fmt ? ".S19" : ".ihx",
1477                 sizeof(scratchFileName));
1478     }
1479
1480   if (port->linker.cmd)
1481     {
1482       char buffer2[PATH_MAX];
1483
1484         /* VR 030517 - gplink needs linker options to set the linker script,*/
1485         buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, linkOptionsSet);
1486
1487         buildCmdLine2 (buffer, sizeof(buffer), buffer2);
1488     }
1489   else
1490     {
1491       buildCmdLine2 (buffer, sizeof(buffer), port->linker.mcmd);
1492     }
1493
1494 /*  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer); */
1495
1496   system_ret = my_system (buffer);
1497   /* TODO: most linker don't have a -o parameter */
1498   /* -o option overrides default name? */
1499   if (fullDstFileName)
1500     {
1501       char *p, *q;
1502       /* the linked file gets the name of the first modul */
1503       if (fullSrcFileName)
1504         {
1505           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1506           p = strlen (scratchFileName) + scratchFileName;
1507         }
1508       else
1509         {
1510           s = peekSet(relFilesSet);
1511
1512           assert(s);
1513
1514           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1515           /* strip ".rel" extension */
1516           p = strrchr (scratchFileName, '.');
1517           if (p)
1518             {
1519               *p = 0;
1520             }
1521         }
1522       strncatz (scratchFileName,
1523                 options.out_fmt ? ".S19" : ".ihx",
1524                 sizeof(scratchFileName));
1525       rename (scratchFileName, fullDstFileName);
1526
1527       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1528       q = strrchr (buffer, '.');
1529       if (!q)
1530         {
1531           /* no extension: append new extensions */
1532           q = strlen (buffer) + buffer;
1533         }
1534
1535       *p = 0;
1536       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1537       *q = 0;
1538       strncatz(buffer, ".map", sizeof(buffer));
1539       rename (scratchFileName, buffer);
1540       *p = 0;
1541       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1542       *q = 0;
1543       strncatz(buffer, ".mem", sizeof(buffer));
1544       rename (scratchFileName, buffer);
1545     }
1546   if (system_ret)
1547     {
1548       exit (1);
1549     }
1550 }
1551
1552 /*-----------------------------------------------------------------*/
1553 /* assemble - spawns the assembler with arguments                  */
1554 /*-----------------------------------------------------------------*/
1555 static void
1556 assemble (char **envp)
1557 {
1558     /* build assembler output filename */
1559
1560     /* -o option overrides default name? */
1561     if (options.cc_only && fullDstFileName) {
1562         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1563     } else {
1564         /* the assembled file gets the name of the first modul */
1565         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1566         strncatz (scratchFileName, port->linker.rel_ext, 
1567                   sizeof(scratchFileName));
1568     }
1569
1570     if (port->assembler.do_assemble) {
1571         port->assembler.do_assemble(asmOptionsSet);
1572         return ;
1573     } else if (port->assembler.cmd) {
1574         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1575                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1576                       asmOptionsSet);
1577     } else {
1578         buildCmdLine2 (buffer, sizeof(buffer), port->assembler.mcmd);
1579     }
1580
1581     if (my_system (buffer)) {
1582         /* either system() or the assembler itself has reported an error
1583            perror ("Cannot exec assembler");
1584         */
1585         exit (1);
1586     }
1587     /* TODO: most assembler don't have a -o parameter */
1588     /* -o option overrides default name? */
1589     if (options.cc_only && fullDstFileName) {
1590         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1591         strncatz (scratchFileName, 
1592                   port->linker.rel_ext,
1593                   sizeof(scratchFileName));
1594         rename (scratchFileName, fullDstFileName);
1595     }
1596 }
1597
1598 /*-----------------------------------------------------------------*/
1599 /* preProcess - spawns the preprocessor with arguments       */
1600 /*-----------------------------------------------------------------*/
1601 static int
1602 preProcess (char **envp)
1603 {
1604   if (options.c1mode)
1605     {
1606       yyin = stdin;
1607     }
1608   else
1609     {
1610       const char *s;
1611       set *inclList = NULL;
1612
1613       /* if using external stack define the macro */
1614       if (options.useXstack)
1615         addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
1616
1617       /* set the macro for stack autos  */
1618       if (options.stackAuto)
1619         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_AUTO"));
1620
1621       /* set the macro for stack autos  */
1622       if (options.stack10bit)
1623         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_TENBIT"));
1624
1625       /* set the macro for no overlay  */
1626       if (options.noOverlay)
1627         addSet(&preArgvSet, Safe_strdup("-DSDCC_NOOVERLAY"));
1628
1629       /* set the macro for large model  */
1630       switch (options.model)
1631         {
1632         case MODEL_LARGE:
1633           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_LARGE"));
1634           break;
1635         case MODEL_SMALL:
1636           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_SMALL"));
1637           break;
1638         case MODEL_COMPACT:
1639           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_COMPACT"));
1640           break;
1641         case MODEL_MEDIUM:
1642           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_MEDIUM"));
1643           break;
1644         case MODEL_FLAT24:
1645           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_FLAT24"));
1646           break;
1647         case MODEL_PAGE0:
1648           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_PAGE0"));
1649           break;
1650         default:
1651           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1652           break;
1653         }
1654
1655       /* add port (processor information to processor */
1656       addSet(&preArgvSet, Safe_strdup("-DSDCC_{port}"));
1657       addSet(&preArgvSet, Safe_strdup("-D__{port}"));
1658
1659       /* standard include path */
1660       if (!options.nostdinc) {
1661         inclList = appendStrSet(includeDirsSet, "-I\"", "\"");
1662         mergeSets(&preArgvSet, inclList);
1663       }
1664
1665       setMainValue("cppextraopts", (s = joinStrSet(preArgvSet)));
1666       Safe_free((void *)s);
1667       if (inclList != NULL)
1668         deleteSet(&inclList);
1669
1670       if (preProcOnly && fullDstFileName)
1671         {
1672           /* -E and -o given */
1673           setMainValue ("cppoutfilename", fullDstFileName);
1674         }
1675       else
1676         {
1677           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1678           setMainValue ("cppoutfilename", NULL);
1679         }
1680
1681       if (options.verbose)
1682         printf ("sdcc: Calling preprocessor...\n");
1683
1684       buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
1685
1686       if (preProcOnly) {
1687         if (my_system (buffer)) {
1688           exit (1);
1689         }
1690
1691         exit (0);
1692       }
1693
1694       yyin = my_popen (buffer);
1695       if (yyin == NULL) {
1696           perror ("Preproc file not found");
1697           exit (1);
1698       }
1699       addSetHead (&pipeSet, yyin);
1700     }
1701
1702   return 0;
1703 }
1704
1705 /* Set bin paths */
1706 static void
1707 setBinPaths(const char *argv0)
1708 {
1709   char *p;
1710   char buf[PATH_MAX];
1711
1712   /*
1713    * Search logic:
1714    *
1715    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1716    * 2. - path(argv[0])
1717    * 3. - $PATH
1718    */
1719
1720   /* do it in reverse mode, so that addSetHead() can be used
1721      instead of slower addSet() */
1722
1723   if ((p = getBinPath(argv0)) != NULL)
1724     addSetHead(&binPathSet, Safe_strdup(p));
1725
1726   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1727     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1728     addSetHead(&binPathSet, Safe_strdup(buf));
1729   }
1730
1731   if (options.printSearchDirs) {
1732     printf("programs:\n");
1733     fputStrSet(stdout, binPathSet);
1734   }
1735 }
1736
1737 /* Set system include path */
1738 static void
1739 setIncludePath(void)
1740 {
1741   char *p;
1742
1743   /*
1744    * Search logic:
1745    *
1746    * 1. - $SDCC_INCLUDE
1747    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
1748    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
1749    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
1750    */
1751
1752   includeDirsSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX);
1753
1754   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
1755     addSetHead(&includeDirsSet, p);
1756
1757   if (options.printSearchDirs) {
1758     printf("includedir:\n");
1759     fputStrSet(stdout, includeDirsSet);
1760   }
1761 }
1762
1763 /* Set system lib path */
1764 static void
1765 setLibPath(void)
1766 {
1767   char *p;
1768
1769   /*
1770    * Search logic:
1771    *
1772    * 1. - $SDCC_LIB
1773    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
1774    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
1775    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
1776    */
1777
1778   libDirsSet = appendStrSet(dataDirsSet, NULL, LIB_DIR_SUFFIX);
1779
1780   if ((p = getenv(SDCC_LIB_NAME)) != NULL)
1781     addSetHead(&libDirsSet, p);
1782
1783   if (options.printSearchDirs) {
1784     printf("libdir:\n");
1785     fputStrSet(stdout, libDirsSet);
1786   }
1787 }
1788
1789 /* Set data path */
1790 static void
1791 setDataPaths(const char *argv0)
1792 {
1793   char *p;
1794   char buf[PATH_MAX];
1795
1796   /*
1797    * Search logic:
1798    *
1799    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
1800    * 2. - path(argv[0])/BIN2DATA_DIR
1801    * 3. - DATADIR (only on *nix)
1802    */
1803
1804   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1805     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
1806     addSet(&dataDirsSet, Safe_strdup(buf));
1807   }
1808
1809   if ((p = getBinPath(argv0)) != NULL) {
1810     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
1811     addSet(&dataDirsSet, Safe_strdup(buf));
1812   }
1813
1814 #ifdef _WIN32
1815   if (peekSet(dataDirsSet) == NULL) {
1816     /* this should never happen... */
1817     wassertl(0, "Can't get binary path");
1818   }
1819 #else
1820   addSet(&dataDirsSet, Safe_strdup(DATADIR));
1821 #endif
1822
1823   if (options.printSearchDirs) {
1824     printf("datadir:\n");
1825     fputStrSet(stdout, dataDirsSet);
1826   }
1827
1828   setIncludePath();
1829   setLibPath();
1830 }
1831
1832 static void
1833 initValues (void)
1834 {
1835   populateMainValues (_baseValues);
1836   setMainValue ("port", port->target);
1837   setMainValue ("objext", port->linker.rel_ext);
1838   setMainValue ("asmext", port->assembler.file_ext);
1839
1840   setMainValue ("dstfilename", dstFileName);
1841   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1842
1843   if (options.cc_only && fullDstFileName)
1844     /* compile + assemble and -o given: -o specifies name of object file */
1845     {
1846       setMainValue ("objdstfilename", fullDstFileName);
1847     }
1848   else
1849     {
1850       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1851     }
1852   if (fullDstFileName)
1853     /* if we're linking, -o gives the final file name */
1854     {
1855       setMainValue ("linkdstfilename", fullDstFileName);
1856     }
1857   else
1858     {
1859       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1860     }
1861
1862 }
1863
1864 static void
1865 sig_handler (int signal)
1866 {
1867   char *sig_string;
1868
1869   switch (signal)
1870     {
1871     case SIGABRT:
1872       sig_string = "SIGABRT";
1873       break;
1874     case SIGTERM:
1875       sig_string = "SIGTERM";
1876       break;
1877     case SIGINT:
1878       sig_string = "SIGINT";
1879       break;
1880     case SIGSEGV:
1881       sig_string = "SIGSEGV";
1882       break;
1883     default:
1884       sig_string = "Unknown?";
1885       break;
1886     }
1887   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1888   exit (1);
1889 }
1890
1891 /*
1892  * main routine
1893  * initialises and calls the parser
1894  */
1895
1896 int
1897 main (int argc, char **argv, char **envp)
1898 {
1899   /* turn all optimizations off by default */
1900   memset (&optimize, 0, sizeof (struct optimize));
1901
1902   /*printVersionInfo (); */
1903
1904   if (NUM_PORTS==0) {
1905     fprintf (stderr, "Build error: no ports are enabled.\n");
1906     exit (1);
1907   }
1908
1909   /* install atexit handler */
1910   atexit(rm_tmpfiles);
1911
1912   /* install signal handler;
1913      it's only purpuse is to call exit() to remove temp files */
1914   if (!getenv("SDCC_LEAVE_SIGNALS"))
1915     {
1916       signal (SIGABRT, sig_handler);
1917       signal (SIGTERM, sig_handler);
1918       signal (SIGINT , sig_handler);
1919       signal (SIGSEGV, sig_handler);
1920     }
1921
1922   /* Before parsing the command line options, do a
1923    * search for the port and processor and initialize
1924    * them if they're found. (We can't gurantee that these
1925    * will be the first options specified).
1926    */
1927
1928   _findPort (argc, argv);
1929
1930 #ifdef JAMIN_DS390
1931   if (strcmp(port->target, "mcs51") == 0) {
1932     printf("DS390 jammed in A\n");
1933           _setPort ("ds390");
1934     ds390_jammed = 1;
1935   }
1936 #endif
1937
1938   _findProcessor (argc, argv);
1939
1940   /* Initalise the port. */
1941   if (port->init)
1942     port->init ();
1943
1944   setDefaultOptions ();
1945 #ifdef JAMIN_DS390
1946   if (ds390_jammed) {
1947     options.model = MODEL_SMALL;
1948     options.stack10bit=0;
1949   }
1950 #endif
1951   parseCmdLine (argc, argv);
1952
1953   initValues ();
1954   setBinPaths(argv[0]);
1955   setDataPaths(argv[0]);
1956
1957   /* if no input then printUsage & exit */
1958   if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL) {
1959     if (!options.printSearchDirs)
1960       printUsage();
1961
1962     exit(0);
1963   }
1964
1965   /* initMem() is expensive, but
1966      initMem() must called before port->finaliseOptions ().
1967      And the z80 port needs port->finaliseOptions(),
1968      even if we're only linking. */
1969   initMem ();
1970   port->finaliseOptions ();
1971
1972   if (fullSrcFileName || options.c1mode)
1973     {
1974       preProcess (envp);
1975
1976       initSymt ();
1977       initiCode ();
1978       initCSupport ();
1979       initBuiltIns();
1980       initPeepHole ();
1981
1982       if (options.verbose)
1983         printf ("sdcc: Generating code...\n");
1984
1985       yyparse ();
1986
1987       pclose(yyin);
1988       deleteSetItem(&pipeSet, yyin);
1989
1990       if (fatalError) {
1991         exit (1);
1992       }
1993
1994       if (port->general.do_glue != NULL)
1995         (*port->general.do_glue)();
1996       else
1997         {
1998           /* this shouldn't happen */
1999           assert(FALSE);
2000           /* in case of NDEBUG */
2001           glue();
2002         }
2003
2004       if (!options.c1mode && !noAssemble)
2005         {
2006           if (options.verbose)
2007             printf ("sdcc: Calling assembler...\n");
2008           assemble (envp);
2009         }
2010     }
2011   closeDumpFiles();
2012
2013   if (options.debug && debugFile)
2014     debugFile->closeFile();
2015
2016   if (!options.cc_only &&
2017       !fatalError &&
2018       !noAssemble &&
2019       !options.c1mode &&
2020       (fullSrcFileName || peekSet(relFilesSet) != NULL))
2021     {
2022       if (port->linker.do_link)
2023         port->linker.do_link ();
2024       else
2025         linkEdit (envp);
2026     }
2027
2028   return 0;
2029 }