DS800C400 fun, improved ROM interface and tinibios
[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 #if !OPT_DISABLE_PIC
310 extern void picglue ();
311 #endif
312 #if !OPT_DISABLE_PIC16
313 extern void pic16glue();
314 #endif
315
316 /** Sets the port to the one given by the command line option.
317     @param    The name minus the option (eg 'mcs51')
318     @return     0 on success.
319 */
320 static void
321 _setPort (const char *name)
322 {
323   int i;
324   for (i = 0; i < NUM_PORTS; i++)
325     {
326       if (!strcmp (_ports[i]->target, name))
327         {
328           port = _ports[i];
329           return;
330         }
331     }
332   /* Error - didnt find */
333   werror (E_UNKNOWN_TARGET, name);
334   exit (1);
335 }
336
337 /* Override the default processor with the one specified 
338  * on the command line */
339 static void
340 _setProcessor (char *_processor)
341 {
342   port->processor = _processor;
343   fprintf(stderr,"Processor: %s\n",_processor);
344 }
345
346 static void
347 _validatePorts (void)
348 {
349   int i;
350   for (i = 0; i < NUM_PORTS; i++)
351     {
352       if (_ports[i]->magic != PORT_MAGIC)
353         {
354           /* Uncomment this line to debug which port is causing the problem
355            * (the target name is close to the beginning of the port struct 
356            * and probably can be accessed just fine). */
357           fprintf(stderr,"%s :",_ports[i]->target);
358           wassertl (0, "Port definition structure is incomplete");
359         }
360     }
361 }
362
363 /* search through the command line options for the port */
364 static void
365 _findPort (int argc, char **argv)
366 {
367   _validatePorts ();
368
369   while (argc--)
370     {
371       if (!strncmp (*argv, "-m", 2))
372         {
373           _setPort (*argv + 2);
374           return;
375         }
376       argv++;
377     }
378
379   /* Use the first in the list */
380 #if defined(DEFAULT_PORT)
381         /* VR - 13/5/2003 DEFAULT_PORT is defined in port.h */
382         port = &DEFAULT_PORT;
383 #else
384         port = _ports[0];
385 #endif
386
387 }
388
389 /* search through the command line options for the processor */
390 static void
391 _findProcessor (int argc, char **argv)
392 {
393   while (argc--)
394     {
395       if (!strncmp (*argv, "-p", 2))
396         {
397           _setProcessor (*argv + 2);
398           return;
399         }
400       argv++;
401     }
402
403   /* no error if processor was not specified. */
404 }
405
406 /*-----------------------------------------------------------------*/
407 /* printVersionInfo - prints the version info        */
408 /*-----------------------------------------------------------------*/
409 void
410 printVersionInfo ()
411 {
412   int i;
413
414   fprintf (stderr,
415            "SDCC : ");
416   for (i = 0; i < NUM_PORTS; i++) {
417     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
418 #ifdef DEFAULT_PORT
419         fprintf(stderr, "%s", (&DEFAULT_PORT == _ports[i])?"*":"");
420 #endif
421   }
422   
423   fprintf (stderr, " " SDCC_VERSION_STR
424 #ifdef SDCC_SUB_VERSION_STR
425            "/" SDCC_SUB_VERSION_STR
426 #endif
427            " (" __DATE__ ")"
428 #ifdef __CYGWIN__
429            " (CYGWIN)\n"
430 #elif defined __MINGW32__
431            " (MINGW32)\n"
432 #elif defined __DJGPP__
433            " (DJGPP)\n"
434 #elif defined(_MSC_VER)
435            " (MSVC)\n"
436 #elif defined(__BORLANDC__)
437            " (BORLANDC)\n"
438 #else
439            " (UNIX) \n"
440 #endif
441     );
442 }
443
444 static void
445 printOptions(const OPTION *optionsTable)
446 {
447   int i;
448   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++) 
449     {
450       fprintf(stdout, "  %c%c  %-20s  %s\n", 
451               optionsTable[i].shortOpt !=0 ? '-' : ' ',
452               optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
453               optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
454               optionsTable[i].help != NULL ? optionsTable[i].help : ""
455               );
456     }
457 }
458
459 /*-----------------------------------------------------------------*/
460 /* printUsage - prints command line syntax         */
461 /*-----------------------------------------------------------------*/
462 void
463 printUsage ()
464 {
465     int i;
466     printVersionInfo();
467     fprintf (stdout,
468              "Usage : sdcc [options] filename\n"
469              "Options :-\n"
470              );
471
472     printOptions(optionsTable);
473
474     for (i = 0; i < NUM_PORTS; i++)
475       {
476         if (_ports[i]->poptions != NULL)
477           {
478             fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
479             printOptions (_ports[i]->poptions);
480           }
481       }
482
483     exit (0);
484 }
485
486 /*-----------------------------------------------------------------*/
487 /* setParseWithComma - separates string with comma to a set        */
488 /*-----------------------------------------------------------------*/
489 void
490 setParseWithComma (set **dest, char *src)
491 {
492   char *p;
493
494   /* skip the initial white spaces */
495   while (isspace(*src))
496     src++;
497
498   for (p = strtok(src, ","); p != NULL; p = strtok(NULL, ","))
499     addSet(dest, Safe_strdup(p));
500 }
501
502 /*-----------------------------------------------------------------*/
503 /* setDefaultOptions - sets the default options                    */
504 /*-----------------------------------------------------------------*/
505 static void
506 setDefaultOptions (void)
507 {
508   /* first the options part */
509   options.stack_loc = 0;        /* stack pointer initialised to 0 */
510   options.xstack_loc = 0;       /* xternal stack starts at 0 */
511   options.code_loc = 0;         /* code starts at 0 */
512   options.data_loc = 0;         /* JCF: By default let the linker locate data */
513   options.xdata_loc = 0;
514   options.idata_loc = 0x80;
515   options.nopeep = 0;
516   options.model = port->general.default_model;
517   options.nostdlib = 0;
518   options.nostdinc = 0;
519   options.verbose = 0;
520   options.shortis8bits = 0;
521
522   options.stack10bit=0;
523
524   /* now for the optimizations */
525   /* turn on the everything */
526   optimize.global_cse = 1;
527   optimize.label1 = 1;
528   optimize.label2 = 1;
529   optimize.label3 = 1;
530   optimize.label4 = 1;
531   optimize.loopInvariant = 1;
532   optimize.loopInduction = 1;
533
534   /* now for the ports */
535   port->setDefaultOptions ();
536 }
537
538 /*-----------------------------------------------------------------*/
539 /* processFile - determines the type of file from the extension    */
540 /*-----------------------------------------------------------------*/
541 static void
542 processFile (char *s)
543 {
544   char *fext = NULL;
545
546   /* get the file extension */
547   fext = s + strlen (s);
548   while ((fext != s) && *fext != '.')
549     fext--;
550
551   /* now if no '.' then we don't know what the file type is
552      so give a warning and return */
553   if (fext == s)
554     {
555       werror (W_UNKNOWN_FEXT, s);
556       return;
557     }
558
559   /* otherwise depending on the file type */
560   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0)
561     {
562       /* source file name : not if we already have a
563          source file */
564       if (fullSrcFileName)
565         {
566           werror (W_TOO_MANY_SRC, s);
567           return;
568         }
569
570       /* the only source file */
571       fullSrcFileName = s;
572       if (!(srcFile = fopen (fullSrcFileName, "r")))
573         {
574           werror (E_FILE_OPEN_ERR, s);
575           exit (1);
576         }
577
578       /* copy the file name into the buffer */
579       strncpyz (buffer, s, sizeof(buffer));
580
581       /* get rid of the "."-extension */
582
583       /* is there a dot at all? */
584       if (strrchr (buffer, '.') &&
585           /* is the dot in the filename, not in the path? */
586           (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
587         {
588         *strrchr (buffer, '.') = '\0';
589         }
590
591       /* get rid of any path information
592          for the module name; */
593       fext = buffer + strlen (buffer);
594 #if NATIVE_WIN32
595       /* do this by going backwards till we
596          get '\' or ':' or start of buffer */
597       while (fext != buffer &&
598              *(fext - 1) != DIR_SEPARATOR_CHAR &&
599              *(fext - 1) != ':')
600         {
601         fext--;
602         }
603 #else
604       /* do this by going backwards till we
605          get '/' or start of buffer */
606       while (fext != buffer &&
607              *(fext - 1) != DIR_SEPARATOR_CHAR)
608         {
609           fext--;
610         }
611 #endif
612       moduleName = Safe_strdup ( fext );
613       return;
614     }
615
616   /* if the extention is type .rel or .r or .REL or .R
617      addtional object file will be passed to the linker */
618   if (strcmp (fext, ".r") == 0 || strcmp (fext, ".rel") == 0 ||
619       strcmp (fext, ".R") == 0 || strcmp (fext, ".REL") == 0 ||
620       strcmp (fext, port->linker.rel_ext) == 0)
621     {
622       addSet(&relFilesSet, Safe_strdup(s));
623       return;
624     }
625
626   /* if .lib or .LIB */
627   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
628     {
629       addSet(&libFilesSet, Safe_strdup(s));
630       return;
631     }
632
633   werror (W_UNKNOWN_FEXT, s);
634
635 }
636
637 static void
638 _setModel (int model, const char *sz)
639 {
640   if (port->general.supported_models & model)
641     options.model = model;
642   else
643     werror (W_UNSUPPORTED_MODEL, sz, port->target);
644 }
645
646 /** Gets the string argument to this option.  If the option is '--opt'
647     then for input of '--optxyz' or '--opt xyz' returns xyz.
648 */
649 static char *
650 getStringArg(const char *szStart, char **argv, int *pi, int argc)
651 {
652   if (argv[*pi][strlen(szStart)])
653     {
654       return &argv[*pi][strlen(szStart)];
655     }
656   else
657     {
658       ++(*pi);
659       if (*pi >= argc)
660         {
661           werror (E_ARGUMENT_MISSING, szStart);
662           /* Die here rather than checking for errors later. */
663           exit(-1);
664         }
665       else
666         {
667           return argv[*pi];
668         }
669     }
670 }
671
672 /** Gets the integer argument to this option using the same rules as
673     getStringArg.
674 */
675 static int
676 getIntArg(const char *szStart, char **argv, int *pi, int argc)
677 {
678     return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
679 }
680
681 static void
682 verifyShortOption(const char *opt)
683 {
684   if (strlen(opt) != 2)
685     {
686       werror (W_EXCESS_SHORT_OPTIONS, opt);
687     }
688 }
689
690 static bool
691 tryHandleUnsupportedOpt(char **argv, int *pi)
692 {
693     if (argv[*pi][0] == '-') 
694         {
695             const char *longOpt = "";
696             char shortOpt = -1;
697             int i;
698
699             if (argv[*pi][1] == '-') 
700                 {
701                     /* Long option. */
702                     longOpt = argv[*pi];
703                 }
704             else 
705                 {
706                     shortOpt = argv[*pi][1];
707                 }
708             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
709                 {
710                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
711                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
712                         /* Found an unsupported opt. */
713                         char buffer[100];
714                         SNPRINTF(buffer, sizeof(buffer), 
715                                  "%s%c%c", 
716                                  longOpt ? longOpt : "", 
717                                  shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
718                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
719                         return 1;
720                     }
721                 }
722             /* Didn't find in the table */
723             return 0;
724         }
725     else 
726         {
727             /* Not an option, so can't be unsupported :) */
728             return 0;
729     }
730 }
731
732 static bool
733 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
734 {
735   int i;
736   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++)
737     {
738       if (optionsTable[i].shortOpt == shortOpt ||
739           (longOpt && optionsTable[i].longOpt && 
740            strcmp(optionsTable[i].longOpt, longOpt) == 0))
741         {
742
743           /* If it is a flag then we can handle it here */
744           if (optionsTable[i].pparameter != NULL) 
745             {
746               if (optionsTable[i].shortOpt == shortOpt)
747                 {
748                   verifyShortOption(argv[*pi]);
749                 }
750
751               (*optionsTable[i].pparameter)++;
752               return 1;
753             }
754           else {
755             /* Not a flag.  Handled manually later. */
756             return 0;
757           }
758         }
759     }
760   /* Didn't find in the table */
761   return 0;
762 }
763
764 static bool
765 tryHandleSimpleOpt(char **argv, int *pi)
766 {
767     if (argv[*pi][0] == '-') 
768         {
769             const char *longOpt = "";
770             char shortOpt = -1;
771
772             if (argv[*pi][1] == '-') 
773                 {
774                     /* Long option. */
775                     longOpt = argv[*pi];
776                 }
777             else 
778                 {
779                     shortOpt = argv[*pi][1];
780                 }
781
782             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
783               {
784                 return 1;
785               }
786             else if (port && port->poptions &&
787                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
788               {
789                 return 1;
790               }
791             else
792               {
793                 return 0;
794               }
795         }
796     else 
797         {
798             /* Not an option, so can't be handled. */
799             return 0;
800         }
801 }
802
803 /*-----------------------------------------------------------------*/
804 /* parseCmdLine - parses the command line and sets the options     */
805 /*-----------------------------------------------------------------*/
806 static int
807 parseCmdLine (int argc, char **argv)
808 {
809   int i;
810
811   /* go thru all whole command line */
812   for (i = 1; i < argc; i++)
813     {
814       if (i >= argc)
815         break;
816
817       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
818           {
819               continue;
820           }
821
822       if (tryHandleSimpleOpt(argv, &i) == TRUE)
823           {
824               continue;
825           }
826
827       /* options */
828       if (argv[i][0] == '-' && argv[i][1] == '-')
829         {
830           if (strcmp (argv[i], OPTION_HELP) == 0)
831             {
832               printUsage ();
833               exit (0);
834             }
835
836           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
837             {
838               options.stack10bit = 0;
839               continue;
840             }
841
842           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
843             {
844               options.out_fmt = 0;
845               continue;
846             }
847
848           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
849             {
850               _setModel (MODEL_LARGE, argv[i]);
851               continue;
852             }
853
854           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
855             {
856               _setModel (MODEL_MEDIUM, argv[i]);
857               continue;
858             }
859
860           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
861             {
862               _setModel (MODEL_SMALL, argv[i]);
863               continue;
864             }
865
866           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
867             {
868               _setModel (MODEL_FLAT24, argv[i]);
869               continue;
870             }
871
872           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
873             {
874               options.dump_rassgn =
875                 options.dump_pack =
876                 options.dump_range =
877                 options.dump_kill =
878                 options.dump_loop =
879                 options.dump_gcse =
880                 options.dump_raw = 1;
881               continue;
882             }
883
884           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
885             {
886                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
887                 continue;
888             }
889
890           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
891             {
892                 addSet(&libPathsSet, Safe_strdup(getStringArg(OPTION_LIB_PATH, argv, &i, argc)));
893                 continue;
894             }
895
896           if (strcmp (argv[i], OPTION_VERSION) == 0)
897             {
898               printVersionInfo ();
899               exit (0);
900               continue;
901             }
902
903           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
904             {
905                 setParseWithComma(&options.calleeSavesSet, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
906                 continue;
907             }
908
909           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
910             {
911                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
912                 continue;
913             }
914
915           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
916             {
917                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
918                 continue;
919             }
920
921           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
922             {
923                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
924                 continue;
925             }
926
927           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
928             {
929                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
930                 continue;
931             }
932
933           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
934             {
935                 options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
936                 options.xram_size_set = TRUE;
937                 continue;
938             }
939
940           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
941             {
942                 options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
943                 continue;
944             }
945
946           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
947             {
948                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
949                 continue;
950             }
951
952           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
953             {
954                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
955                 continue;
956             }
957
958           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
959             {
960                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
961                 continue;
962             }
963
964           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
965             {
966               optimize.global_cse = 0;
967               continue;
968             }
969
970           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
971             {
972               optimize.loopInvariant = 0;
973               continue;
974             }
975
976           if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
977             {
978               optimize.label4 = 0;
979               continue;
980             }
981
982           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
983             {
984               optimize.loopInduction = 0;
985               continue;
986             }
987
988           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
989             {
990               options.lessPedantic = 1;
991               setErrorLogLevel(ERROR_LEVEL_WARNING);
992               continue;
993             }
994
995           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
996             {
997               options.shortis8bits=1;
998               continue;
999             }
1000
1001           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
1002             {
1003                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
1004                 continue;
1005             }
1006           
1007           if (!port->parseOption (&argc, argv, &i))
1008             {
1009               werror (W_UNKNOWN_OPTION, argv[i]);
1010             }
1011           else
1012             {
1013               continue;
1014             }
1015         }
1016
1017       /* if preceded by  '-' then option */
1018       if (*argv[i] == '-')
1019         {
1020           switch (argv[i][1])
1021             {
1022             case 'h':
1023               verifyShortOption(argv[i]);
1024
1025               printUsage ();
1026               exit (0);
1027               break;
1028
1029             case 'm':
1030               /* Used to select the port. But this has already been done. */
1031               break;
1032
1033             case 'p':
1034               /* Used to select the processor in port. But this has
1035                * already been done. */
1036               break;
1037
1038             case 'c':
1039               verifyShortOption(argv[i]);
1040
1041               options.cc_only = 1;
1042               break;
1043
1044             case 'L':
1045                 addSet(&libPathsSet, Safe_strdup(getStringArg("-L", argv, &i, argc)));
1046                 break;
1047
1048             case 'l':
1049                 addSet(&libFilesSet, Safe_strdup(getStringArg("-l", argv, &i, argc)));
1050                 break;
1051             
1052             case 'o':
1053               {
1054                 char *p;
1055
1056                 /* copy the file name into the buffer */
1057                 strncpyz(buffer, getStringArg("-o", argv, &i, argc), 
1058                          sizeof(buffer));
1059                 /* point to last character */
1060                 p = buffer + strlen (buffer) - 1;
1061                 if (*p == DIR_SEPARATOR_CHAR)
1062                   {
1063                     /* only output path specified */
1064                     dstPath = Safe_strdup (buffer);
1065                     fullDstFileName = NULL;
1066                   }
1067                 else
1068                   {
1069                     fullDstFileName = Safe_strdup (buffer);
1070
1071                     /* get rid of the "."-extension */
1072
1073                     /* is there a dot at all? */
1074                     if (strrchr (buffer, '.') &&
1075                         /* is the dot in the filename, not in the path? */
1076                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1077                       *strrchr (buffer, '.') = '\0';
1078
1079                     dstFileName = Safe_strdup (buffer);
1080
1081                     /* strip module name to get path */
1082                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1083                     if (p)
1084                       {
1085                         /* path with trailing / */
1086                         p[1] = '\0';
1087                         dstPath = Safe_strdup (buffer);
1088                       }
1089                   }
1090                 break;
1091               }
1092
1093             case 'W':
1094               /* pre-processer options */
1095               if (argv[i][2] == 'p')
1096                 {
1097                   setParseWithComma(&preArgvSet, getStringArg("-Wp", argv, &i, argc));
1098                 }
1099               /* linker options */
1100               else if (argv[i][2] == 'l')
1101                 {
1102                   setParseWithComma(&linkOptionsSet, getStringArg("-Wl", argv, &i, argc));
1103                 }
1104               /* assembler options */
1105               else if (argv[i][2] == 'a')
1106                 {
1107                   setParseWithComma(&asmOptionsSet, getStringArg("-Wa", argv, &i, argc));
1108                 }
1109               else
1110                 {
1111                   werror (W_UNKNOWN_OPTION, argv[i]);
1112                 }
1113               break;
1114
1115             case 'v':
1116               verifyShortOption(argv[i]);
1117
1118               printVersionInfo ();
1119               exit (0);
1120               break;
1121
1122               /* preprocessor options */
1123             case 'M':
1124               {
1125                 preProcOnly = 1;
1126                 addSet(&preArgvSet, Safe_strdup("-M"));
1127                 break;
1128               }
1129             case 'C':
1130               {
1131                 addSet(&preArgvSet, Safe_strdup("-C"));
1132                 break;
1133               }
1134
1135             case 'd':
1136             case 'D':
1137             case 'I':
1138             case 'A':
1139             case 'U':
1140               {
1141                 char sOpt = argv[i][1];
1142                 char *rest;
1143
1144                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1145                   {
1146                     i++;
1147                     if (i >= argc)
1148                       {
1149                           /* No argument. */
1150                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1151                           break;
1152                       }
1153                     else
1154                       {
1155                           rest = argv[i];
1156                       }
1157                   }
1158                 else
1159                   rest = &argv[i][2];
1160
1161                 if (sOpt == 'Y')
1162                   sOpt = 'I';
1163
1164                 SNPRINTF (buffer, sizeof(buffer),
1165                   ((sOpt == 'I') ? "-%c\"%s\"": "-%c%s"), sOpt, rest);
1166                 addSet(&preArgvSet, Safe_strdup(buffer));
1167               }
1168               break;
1169
1170             default:
1171               if (!port->parseOption (&argc, argv, &i))
1172                 werror (W_UNKNOWN_OPTION, argv[i]);
1173             }
1174           continue;
1175         }
1176
1177       if (!port->parseOption (&argc, argv, &i))
1178         {
1179            /* no option must be a filename */
1180            if (options.c1mode)
1181              {
1182                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1183              }
1184          else
1185              {
1186                 processFile (argv[i]);
1187              }
1188         }
1189     }
1190
1191   /* some sanity checks in c1 mode */
1192   if (options.c1mode)
1193     {
1194       const char *s;
1195
1196       if (fullSrcFileName)
1197         {
1198           fclose (srcFile);
1199           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1200         }
1201       fullSrcFileName = NULL;
1202       for (s = setFirstItem(relFilesSet); s != NULL; s = setNextItem(relFilesSet))
1203         {
1204           werror (W_NO_FILE_ARG_IN_C1, s);
1205         }
1206       for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1207         {
1208           werror (W_NO_FILE_ARG_IN_C1, s);
1209         }
1210       deleteSet(&relFilesSet);
1211       deleteSet(&libFilesSet);
1212
1213         if (options.cc_only || noAssemble || preProcOnly)
1214         {
1215           werror (W_ILLEGAL_OPT_COMBINATION);
1216         }
1217       options.cc_only = noAssemble = preProcOnly = 0;
1218       if (!dstFileName)
1219         {
1220           werror (E_NEED_OPT_O_IN_C1);
1221           exit (1);
1222         }
1223     }
1224   /* if no dstFileName given with -o, we've to find one: */
1225   if (!dstFileName)
1226     {
1227       const char *s;
1228
1229       /* use the modulename from the C-source */
1230       if (fullSrcFileName)
1231         {
1232           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1233
1234           dstFileName = Safe_alloc (bufSize);
1235           strncpyz (dstFileName, dstPath, bufSize);
1236           strncatz (dstFileName, moduleName, bufSize);
1237         }
1238       /* use the modulename from the first object file */
1239       else if ((s = peekSet(relFilesSet)) != NULL)
1240         {
1241           char *objectName;
1242           size_t bufSize;
1243
1244           strncpyz (buffer, s, sizeof(buffer));
1245           /* remove extension (it must be .rel) */
1246           *strrchr (buffer, '.') = '\0';
1247           /* remove path */
1248           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1249           if (objectName)
1250             {
1251               ++objectName;
1252             }
1253           else
1254             {
1255               objectName = buffer;
1256             }
1257           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1258           dstFileName = Safe_alloc (bufSize);
1259           strncpyz (dstFileName, dstPath, bufSize);
1260           strncatz (dstFileName, objectName, bufSize);
1261         }
1262       /* else no module given: help text is displayed */
1263     }
1264
1265   /* set up external stack location if not explicitly specified */
1266   if (!options.xstack_loc)
1267     options.xstack_loc = options.xdata_loc;
1268
1269   /* if debug option is set then open the cdbFile */
1270   if (options.debug && fullSrcFileName)
1271     {
1272       SNPRINTF (scratchFileName, sizeof(scratchFileName),
1273                 "%s.adb", dstFileName); /*JCF: Nov 30, 2002*/
1274       if(debugFile->openFile(scratchFileName))
1275         debugFile->writeModule(moduleName);
1276       else
1277         werror (E_FILE_OPEN_ERR, scratchFileName);
1278     }
1279   MSVC_style(options.vc_err_style);
1280   if(options.use_stdout) dup2(STDOUT_FILENO, STDERR_FILENO);
1281
1282   return 0;
1283 }
1284
1285 /*-----------------------------------------------------------------*/
1286 /* linkEdit : - calls the linkage editor  with options             */
1287 /*-----------------------------------------------------------------*/
1288 static void
1289 linkEdit (char **envp)
1290 {
1291   FILE *lnkfile;
1292   char *segName, *c;
1293   int system_ret;
1294   const char *s;
1295
1296   /* first we need to create the <filename>.lnk file */
1297   SNPRINTF (scratchFileName, sizeof(scratchFileName),
1298             "%s.lnk", dstFileName);
1299   if (!(lnkfile = fopen (scratchFileName, "w")))
1300     {
1301       werror (E_FILE_OPEN_ERR, scratchFileName);
1302       exit (1);
1303     }
1304
1305   /* now write the options.  JCF: added option 'y' */
1306   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1307
1308   /* if iram size specified */
1309   if (options.iram_size)
1310     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1311
1312   /* if xram size specified */
1313   if (options.xram_size_set)
1314     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1315
1316   /* if code size specified */
1317   if (options.code_size)
1318     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1319
1320   if (options.debug)
1321     fprintf (lnkfile, "-z\n");
1322
1323 #define WRITE_SEG_LOC(N, L) \
1324     segName = Safe_strdup(N); \
1325     c = strtok(segName, " \t"); \
1326     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1327     if (segName) { Safe_free(segName); }
1328
1329   /* code segment start */
1330   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1331
1332   /* data segment start */
1333   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1334           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1335   }
1336
1337   /* xdata start */
1338   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1339
1340   /* indirect data */
1341   if (IDATA_NAME) {
1342     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1343   }
1344
1345   /* bit segment start */
1346   WRITE_SEG_LOC (BIT_NAME, 0);
1347
1348   /* JCF: stack start */
1349   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1350         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1351   }
1352   
1353   /* If the port has any special linker area declarations, get 'em */
1354   if (port->extraAreas.genExtraAreaLinkOptions)
1355   {
1356         port->extraAreas.genExtraAreaLinkOptions(lnkfile);
1357   }
1358
1359   /* add the extra linker options */
1360   fputStrSet(lnkfile, linkOptionsSet);
1361
1362   /* other library paths if specified */
1363   for (s = setFirstItem(libPathsSet); s != NULL; s = setNextItem(libPathsSet))
1364     fprintf (lnkfile, "-k %s\n", s);
1365
1366   /* standard library path */
1367   if (!options.nostdlib)
1368     {
1369       switch (options.model)
1370         {
1371         case MODEL_SMALL:
1372           c = "small";
1373           break;
1374         case MODEL_LARGE:
1375           c = "large";
1376           break;
1377         case MODEL_FLAT24:
1378           /* c = "flat24"; */
1379             if (TARGET_IS_DS390)
1380             {
1381                 c = "ds390";
1382             }
1383             else if (TARGET_IS_DS400)
1384             {
1385                 c = "ds400";
1386             }
1387             else
1388             {
1389                 fprintf(stderr, 
1390                         "Add support for your FLAT24 target in %s @ line %d\n",
1391                         __FILE__, __LINE__);
1392                 exit(-1);
1393             }
1394           break;
1395         case MODEL_PAGE0:
1396           c = "xa51";
1397           break;
1398         default:
1399           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1400           c = "unknown";
1401           break;
1402         }
1403       for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1404         mfprintf (lnkfile, getRuntimeVariables(), "-k %s{sep}%s\n", s, c);
1405
1406       /* standard library files */
1407 #if !OPT_DISABLE_DS390
1408       if (options.model == MODEL_FLAT24)
1409         {
1410             if (TARGET_IS_DS390)
1411             {
1412                 fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1413             }
1414             else if (TARGET_IS_DS400)
1415             {
1416                 fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1417             }
1418             else
1419             {
1420                 fprintf(stderr, 
1421                         "Add support for your FLAT24 target in %s @ line %d\n",
1422                         __FILE__, __LINE__);
1423                 exit(-1);
1424             }
1425         }
1426 #endif
1427
1428 #if !OPT_DISABLE_XA51 
1429 #ifdef STD_XA51_LIB
1430       if (options.model == MODEL_PAGE0)
1431         {
1432           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1433         }
1434 #endif
1435 #endif
1436       fprintf (lnkfile, "-l %s\n", STD_LIB);
1437       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1438       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1439       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1440     }
1441
1442   /* additional libraries if any */
1443   for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1444     fprintf (lnkfile, "-l %s\n", s);
1445
1446   /* put in the object files */
1447   if (fullSrcFileName)
1448     fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
1449
1450   fputStrSet(lnkfile, relFilesSet);
1451
1452   fprintf (lnkfile, "\n-e\n");
1453   fclose (lnkfile);
1454
1455   if (options.verbose)
1456     printf ("sdcc: Calling linker...\n");
1457
1458   /* build linker output filename */
1459
1460   /* -o option overrides default name? */
1461   if (fullDstFileName)
1462     {
1463       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1464     }
1465   else
1466     {
1467       /* the linked file gets the name of the first modul */
1468       if (fullSrcFileName)
1469         {
1470           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1471         }
1472       else
1473         {
1474           s = peekSet(relFilesSet);
1475
1476           assert(s);
1477
1478           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1479           /* strip ".rel" extension */
1480           *strrchr (scratchFileName, '.') = '\0';
1481         }
1482       strncatz (scratchFileName, 
1483                 options.out_fmt ? ".S19" : ".ihx",
1484                 sizeof(scratchFileName));
1485     }
1486
1487   if (port->linker.cmd)
1488     {
1489       char buffer2[PATH_MAX];
1490
1491         /* VR 030517 - gplink needs linker options to set the linker script,*/
1492         buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, linkOptionsSet);
1493
1494         buildCmdLine2 (buffer, sizeof(buffer), buffer2);
1495     }
1496   else
1497     {
1498       buildCmdLine2 (buffer, sizeof(buffer), port->linker.mcmd);
1499     }
1500
1501 /*  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer); */
1502
1503   system_ret = my_system (buffer);
1504   /* TODO: most linker don't have a -o parameter */
1505   /* -o option overrides default name? */
1506   if (fullDstFileName)
1507     {
1508       char *p, *q;
1509       /* the linked file gets the name of the first modul */
1510       if (fullSrcFileName)
1511         {
1512           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1513           p = strlen (scratchFileName) + scratchFileName;
1514         }
1515       else
1516         {
1517           s = peekSet(relFilesSet);
1518
1519           assert(s);
1520
1521           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1522           /* strip ".rel" extension */
1523           p = strrchr (scratchFileName, '.');
1524           if (p)
1525             {
1526               *p = 0;
1527             }
1528         }
1529       strncatz (scratchFileName,
1530                 options.out_fmt ? ".S19" : ".ihx",
1531                 sizeof(scratchFileName));
1532       rename (scratchFileName, fullDstFileName);
1533
1534       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1535       q = strrchr (buffer, '.');
1536       if (!q)
1537         {
1538           /* no extension: append new extensions */
1539           q = strlen (buffer) + buffer;
1540         }
1541
1542       *p = 0;
1543       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1544       *q = 0;
1545       strncatz(buffer, ".map", sizeof(buffer));
1546       rename (scratchFileName, buffer);
1547       *p = 0;
1548       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1549       *q = 0;
1550       strncatz(buffer, ".mem", sizeof(buffer));
1551       rename (scratchFileName, buffer);
1552     }
1553   if (system_ret)
1554     {
1555       exit (1);
1556     }
1557 }
1558
1559 /*-----------------------------------------------------------------*/
1560 /* assemble - spawns the assembler with arguments                  */
1561 /*-----------------------------------------------------------------*/
1562 static void
1563 assemble (char **envp)
1564 {
1565     /* build assembler output filename */
1566
1567     /* -o option overrides default name? */
1568     if (options.cc_only && fullDstFileName) {
1569         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1570     } else {
1571         /* the assembled file gets the name of the first modul */
1572         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1573         strncatz (scratchFileName, port->linker.rel_ext, 
1574                   sizeof(scratchFileName));
1575     }
1576
1577     if (port->assembler.do_assemble) {
1578         port->assembler.do_assemble(asmOptionsSet);
1579         return ;
1580     } else if (port->assembler.cmd) {
1581         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1582                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1583                       asmOptionsSet);
1584     } else {
1585         buildCmdLine2 (buffer, sizeof(buffer), port->assembler.mcmd);
1586     }
1587
1588     if (my_system (buffer)) {
1589         /* either system() or the assembler itself has reported an error
1590            perror ("Cannot exec assembler");
1591         */
1592         exit (1);
1593     }
1594     /* TODO: most assembler don't have a -o parameter */
1595     /* -o option overrides default name? */
1596     if (options.cc_only && fullDstFileName) {
1597         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1598         strncatz (scratchFileName, 
1599                   port->linker.rel_ext,
1600                   sizeof(scratchFileName));
1601         rename (scratchFileName, fullDstFileName);
1602     }
1603 }
1604
1605 /*-----------------------------------------------------------------*/
1606 /* preProcess - spawns the preprocessor with arguments       */
1607 /*-----------------------------------------------------------------*/
1608 static int
1609 preProcess (char **envp)
1610 {
1611   if (options.c1mode)
1612     {
1613       yyin = stdin;
1614     }
1615   else
1616     {
1617       const char *s;
1618       set *inclList = NULL;
1619
1620       /* if using external stack define the macro */
1621       if (options.useXstack)
1622         addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
1623
1624       /* set the macro for stack autos  */
1625       if (options.stackAuto)
1626         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_AUTO"));
1627
1628       /* set the macro for stack autos  */
1629       if (options.stack10bit)
1630         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_TENBIT"));
1631
1632       /* set the macro for no overlay  */
1633       if (options.noOverlay)
1634         addSet(&preArgvSet, Safe_strdup("-DSDCC_NOOVERLAY"));
1635
1636       /* set the macro for large model  */
1637       switch (options.model)
1638         {
1639         case MODEL_LARGE:
1640           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_LARGE"));
1641           break;
1642         case MODEL_SMALL:
1643           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_SMALL"));
1644           break;
1645         case MODEL_COMPACT:
1646           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_COMPACT"));
1647           break;
1648         case MODEL_MEDIUM:
1649           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_MEDIUM"));
1650           break;
1651         case MODEL_FLAT24:
1652           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_FLAT24"));
1653           break;
1654         case MODEL_PAGE0:
1655           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_PAGE0"));
1656           break;
1657         default:
1658           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1659           break;
1660         }
1661
1662       /* add port (processor information to processor */
1663       addSet(&preArgvSet, Safe_strdup("-DSDCC_{port}"));
1664       addSet(&preArgvSet, Safe_strdup("-D__{port}"));
1665
1666       /* standard include path */
1667       if (!options.nostdinc) {
1668         inclList = appendStrSet(includeDirsSet, "-I\"", "\"");
1669         mergeSets(&preArgvSet, inclList);
1670       }
1671
1672       setMainValue("cppextraopts", (s = joinStrSet(preArgvSet)));
1673       Safe_free((void *)s);
1674       if (inclList != NULL)
1675         deleteSet(&inclList);
1676
1677       if (preProcOnly && fullDstFileName)
1678         {
1679           /* -E and -o given */
1680           setMainValue ("cppoutfilename", fullDstFileName);
1681         }
1682       else
1683         {
1684           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1685           setMainValue ("cppoutfilename", NULL);
1686         }
1687
1688       if (options.verbose)
1689         printf ("sdcc: Calling preprocessor...\n");
1690
1691       buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
1692
1693       if (preProcOnly) {
1694         if (my_system (buffer)) {
1695           exit (1);
1696         }
1697
1698         exit (0);
1699       }
1700
1701       yyin = my_popen (buffer);
1702       if (yyin == NULL) {
1703           perror ("Preproc file not found");
1704           exit (1);
1705       }
1706       addSetHead (&pipeSet, yyin);
1707     }
1708
1709   return 0;
1710 }
1711
1712 /* Set bin paths */
1713 static void
1714 setBinPaths(const char *argv0)
1715 {
1716   char *p;
1717   char buf[PATH_MAX];
1718
1719   /*
1720    * Search logic:
1721    *
1722    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1723    * 2. - path(argv[0])
1724    * 3. - $PATH
1725    */
1726
1727   /* do it in reverse mode, so that addSetHead() can be used
1728      instead of slower addSet() */
1729
1730   if ((p = getBinPath(argv0)) != NULL)
1731     addSetHead(&binPathSet, Safe_strdup(p));
1732
1733   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1734     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1735     addSetHead(&binPathSet, Safe_strdup(buf));
1736   }
1737
1738   if (options.printSearchDirs) {
1739     printf("programs:\n");
1740     fputStrSet(stdout, binPathSet);
1741   }
1742 }
1743
1744 /* Set system include path */
1745 static void
1746 setIncludePath(void)
1747 {
1748   char *p;
1749
1750   /*
1751    * Search logic:
1752    *
1753    * 1. - $SDCC_INCLUDE
1754    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
1755    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
1756    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
1757    */
1758
1759   includeDirsSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX);
1760
1761   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
1762     addSetHead(&includeDirsSet, p);
1763
1764   if (options.printSearchDirs) {
1765     printf("includedir:\n");
1766     fputStrSet(stdout, includeDirsSet);
1767   }
1768 }
1769
1770 /* Set system lib path */
1771 static void
1772 setLibPath(void)
1773 {
1774   char *p;
1775
1776   /*
1777    * Search logic:
1778    *
1779    * 1. - $SDCC_LIB
1780    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
1781    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
1782    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
1783    */
1784
1785   libDirsSet = appendStrSet(dataDirsSet, NULL, LIB_DIR_SUFFIX);
1786
1787   if ((p = getenv(SDCC_LIB_NAME)) != NULL)
1788     addSetHead(&libDirsSet, p);
1789
1790   if (options.printSearchDirs) {
1791     printf("libdir:\n");
1792     fputStrSet(stdout, libDirsSet);
1793   }
1794 }
1795
1796 /* Set data path */
1797 static void
1798 setDataPaths(const char *argv0)
1799 {
1800   char *p;
1801   char buf[PATH_MAX];
1802
1803   /*
1804    * Search logic:
1805    *
1806    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
1807    * 2. - path(argv[0])/BIN2DATA_DIR
1808    * 3. - DATADIR (only on *nix)
1809    */
1810
1811   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1812     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
1813     addSet(&dataDirsSet, Safe_strdup(buf));
1814   }
1815
1816   if ((p = getBinPath(argv0)) != NULL) {
1817     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
1818     addSet(&dataDirsSet, Safe_strdup(buf));
1819   }
1820
1821 #ifdef _WIN32
1822   if (peekSet(dataDirsSet) == NULL) {
1823     /* this should never happen... */
1824     wassertl(0, "Can't get binary path");
1825   }
1826 #else
1827   addSet(&dataDirsSet, Safe_strdup(DATADIR));
1828 #endif
1829
1830   if (options.printSearchDirs) {
1831     printf("datadir:\n");
1832     fputStrSet(stdout, dataDirsSet);
1833   }
1834
1835   setIncludePath();
1836   setLibPath();
1837 }
1838
1839 static void
1840 initValues (void)
1841 {
1842   populateMainValues (_baseValues);
1843   setMainValue ("port", port->target);
1844   setMainValue ("objext", port->linker.rel_ext);
1845   setMainValue ("asmext", port->assembler.file_ext);
1846
1847   setMainValue ("dstfilename", dstFileName);
1848   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1849
1850   if (options.cc_only && fullDstFileName)
1851     /* compile + assemble and -o given: -o specifies name of object file */
1852     {
1853       setMainValue ("objdstfilename", fullDstFileName);
1854     }
1855   else
1856     {
1857       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1858     }
1859   if (fullDstFileName)
1860     /* if we're linking, -o gives the final file name */
1861     {
1862       setMainValue ("linkdstfilename", fullDstFileName);
1863     }
1864   else
1865     {
1866       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1867     }
1868
1869 }
1870
1871 static void
1872 sig_handler (int signal)
1873 {
1874   char *sig_string;
1875
1876   switch (signal)
1877     {
1878     case SIGABRT:
1879       sig_string = "SIGABRT";
1880       break;
1881     case SIGTERM:
1882       sig_string = "SIGTERM";
1883       break;
1884     case SIGINT:
1885       sig_string = "SIGINT";
1886       break;
1887     case SIGSEGV:
1888       sig_string = "SIGSEGV";
1889       break;
1890     default:
1891       sig_string = "Unknown?";
1892       break;
1893     }
1894   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1895   exit (1);
1896 }
1897
1898 /*
1899  * main routine
1900  * initialises and calls the parser
1901  */
1902
1903 int
1904 main (int argc, char **argv, char **envp)
1905 {
1906   /* turn all optimizations off by default */
1907   memset (&optimize, 0, sizeof (struct optimize));
1908
1909   /*printVersionInfo (); */
1910
1911   if (NUM_PORTS==0) {
1912     fprintf (stderr, "Build error: no ports are enabled.\n");
1913     exit (1);
1914   }
1915
1916   /* install atexit handler */
1917   atexit(rm_tmpfiles);
1918
1919   /* install signal handler;
1920      it's only purpuse is to call exit() to remove temp files */
1921   if (!getenv("SDCC_LEAVE_SIGNALS"))
1922     {
1923       signal (SIGABRT, sig_handler);
1924       signal (SIGTERM, sig_handler);
1925       signal (SIGINT , sig_handler);
1926       signal (SIGSEGV, sig_handler);
1927     }
1928
1929   /* Before parsing the command line options, do a
1930    * search for the port and processor and initialize
1931    * them if they're found. (We can't gurantee that these
1932    * will be the first options specified).
1933    */
1934
1935   _findPort (argc, argv);
1936
1937 #ifdef JAMIN_DS390
1938   if (strcmp(port->target, "mcs51") == 0) {
1939     printf("DS390 jammed in A\n");
1940           _setPort ("ds390");
1941     ds390_jammed = 1;
1942   }
1943 #endif
1944
1945   _findProcessor (argc, argv);
1946
1947   /* Initalise the port. */
1948   if (port->init)
1949     port->init ();
1950
1951   setDefaultOptions ();
1952 #ifdef JAMIN_DS390
1953   if (ds390_jammed) {
1954     options.model = MODEL_SMALL;
1955     options.stack10bit=0;
1956   }
1957 #endif
1958   parseCmdLine (argc, argv);
1959
1960   initValues ();
1961   setBinPaths(argv[0]);
1962   setDataPaths(argv[0]);
1963
1964   /* if no input then printUsage & exit */
1965   if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL) {
1966     if (!options.printSearchDirs)
1967       printUsage();
1968
1969     exit(0);
1970   }
1971
1972   /* initMem() is expensive, but
1973      initMem() must called before port->finaliseOptions ().
1974      And the z80 port needs port->finaliseOptions(),
1975      even if we're only linking. */
1976   initMem ();
1977   port->finaliseOptions ();
1978
1979   if (fullSrcFileName || options.c1mode)
1980     {
1981       preProcess (envp);
1982
1983       initSymt ();
1984       initiCode ();
1985       initCSupport ();
1986       initBuiltIns();
1987       initPeepHole ();
1988
1989       if (options.verbose)
1990         printf ("sdcc: Generating code...\n");
1991
1992       yyparse ();
1993
1994       pclose(yyin);
1995       deleteSetItem(&pipeSet, yyin);
1996
1997       if (fatalError) {
1998         exit (1);
1999       }
2000
2001       if (TARGET_IS_PIC) {
2002         /* TSD PIC port hack - if the PIC port option is enabled
2003            and SDCC is used to generate PIC code, then we will
2004            generate .asm files in gpasm's format instead of SDCC's
2005            assembler's format
2006         */
2007 #if !OPT_DISABLE_PIC
2008         picglue ();
2009 #endif
2010
2011       } else
2012       if(TARGET_IS_PIC16) {
2013         /* PIC16 port misc improvements Vangelis Rokas - 6-May-2003
2014           Generate .asm files for gpasm (just like PIC target) but use
2015           pic16glue()
2016         */
2017       
2018 #if !OPT_DISABLE_PIC16
2019         pic16glue();
2020 #endif
2021       } else {
2022         glue ();
2023       }
2024
2025       if (!options.c1mode && !noAssemble)
2026         {
2027           if (options.verbose)
2028             printf ("sdcc: Calling assembler...\n");
2029           assemble (envp);
2030         }
2031     }
2032   closeDumpFiles();
2033
2034   if (options.debug && debugFile)
2035     debugFile->closeFile();
2036
2037   if (!options.cc_only &&
2038       !fatalError &&
2039       !noAssemble &&
2040       !options.c1mode &&
2041       (fullSrcFileName || peekSet(relFilesSet) != NULL))
2042     {
2043       if (port->linker.do_link)
2044         port->linker.do_link ();
2045       else
2046         linkEdit (envp);
2047     }
2048
2049   return 0;
2050 }