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