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