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