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