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