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