708ba0b5d09f87f8962237d24be9c5e4d326ed17
[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 /** Name of the environment variable checked for other instalations. */
45 #define SDCCDIR_NAME "SDCCDIR"
46
47 //REMOVE ME!!!
48 extern int yyparse ();
49
50 FILE *srcFile;                  /* source file          */
51 char *fullSrcFileName;          /* full name for the source file; */
52                                 /* can be NULL while c1mode or linking without compiling */
53 char *fullDstFileName;          /* full name for the output file; */
54                                 /* only given by -o, otherwise NULL */
55 size_t fullDstFileNameLen;      /* size of previous string. */
56 char *dstFileName;              /* destination file name without extension */
57 char *dstPath = "";             /* path for the output files; */
58                                 /* "" is equivalent with cwd */
59 char *moduleName;               /* module name is source file without path and extension */
60                                 /* can be NULL while linking without compiling */
61 /*
62  * in following definitions fixed length arrays are very dangerous!
63  * Sets should be used instead. See definition of asmOptions.
64  */
65 const char *preArgv[128];       /* pre-processor arguments  */
66 int currRegBank = 0;
67 int RegBankUsed[4]={1, 0, 0, 0}; /*JCF: Reg Bank 0 used by default*/
68 struct optimize optimize;
69 struct options options;
70 int preProcOnly = 0;
71 int noAssemble = 0;
72 set *asmOptions = NULL;         /* set of assembler options */
73 char *linkOptions[128];
74 char *libFiles[128];
75 int nlibFiles = 0;
76 char *libPaths[128];
77 int nlibPaths = 0;
78 char *relFiles[128];
79 int nrelFiles = 0;
80
81 /* uncomment JAMIN_DS390 to always override and use ds390 port
82   for mcs51 work.  This is temporary, for compatibility testing. */
83 /* #define JAMIN_DS390 */
84 #ifdef JAMIN_DS390
85 int ds390_jammed = 0;
86 #endif
87
88 // Globally accessible scratch buffer for file names.
89 char scratchFileName[PATH_MAX];
90 char buffer[PATH_MAX * 2];
91
92 #define OPTION_HELP     "-help"
93
94 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
95
96 #define OPTION_STACK_8BIT       "--stack-8bit"
97 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
98 #define OPTION_LARGE_MODEL      "--model-large"
99 #define OPTION_MEDIUM_MODEL     "--model-medium"
100 #define OPTION_SMALL_MODEL      "--model-small"
101 #define OPTION_FLAT24_MODEL     "--model-flat24"
102 #define OPTION_DUMP_ALL         "--dumpall"
103 #define OPTION_PEEP_FILE        "--peep-file"
104 #define OPTION_LIB_PATH         "--lib-path"
105 #define OPTION_XSTACK_LOC       "--xstack-loc"
106 #define OPTION_CALLEE_SAVES     "--callee-saves"
107 #define OPTION_STACK_LOC        "--stack-loc"
108 #define OPTION_XRAM_LOC         "--xram-loc"
109 #define OPTION_IRAM_SIZE        "--iram-size"
110 #define OPTION_VERSION          "--version"
111 #define OPTION_DATA_LOC         "--data-loc"
112 #define OPTION_CODE_LOC         "--code-loc"
113 #define OPTION_IDATA_LOC        "--idata-loc"
114 #define OPTION_NO_LABEL_OPT     "--nolabelopt"
115 #define OPTION_NO_LOOP_INV      "--noinvariant"
116 #define OPTION_NO_LOOP_IND      "--noinduction"
117 #define OPTION_LESS_PEDANTIC    "--lesspedantic"
118 #define OPTION_NO_GCSE          "--nogcse"
119 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
120 #define OPTION_TINI_LIBID       "--tini-libid"
121 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
122 #define OPTION_XRAM_SIZE        "--xram-size"
123 #define OPTION_CODE_SIZE        "--code-size"
124 #define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
125 #define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
126
127 static const OPTION
128 optionsTable[] = {
129     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
130     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
131     { 'd',  NULL,                   NULL, NULL },
132     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
133     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
134     { 'A',  NULL,                   NULL, NULL },
135     { 'U',  NULL,                   NULL, NULL },
136     { 'C',  NULL,                   NULL, "Preprocessor option" },
137     { 'M',  NULL,                   NULL, "Preprocessor option" },
138     { 'V',  NULL,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
139     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
140     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
141     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
142     { 'l',  NULL,                   NULL, "Include the given library in the link" },
143     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
144     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
145     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
146     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
147     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
148     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
149     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
150     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
151     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
152     { 0,    OPTION_NO_LABEL_OPT,    NULL, "Disable label optimisation" },
153     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
154     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
155     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
156     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
157     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
158     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
159     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
160     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
161     { 0,    "--dumploop",           &options.dump_loop, NULL },
162     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
163     { 0,    "--dumpliverange",      &options.dump_range, NULL },
164     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
165     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
166     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
167     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
168     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
169     { 0,    OPTION_XRAM_SIZE,       NULL, "<nnnn> External Ram size" },
170     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
171     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
172     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
173     { 0,    OPTION_CODE_SIZE,       NULL, "<nnnn> Code Segment size" },
174     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
175     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
176     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
177     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
178     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
179     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
180     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
181     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
182     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
183     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
184     { 0,    "--nooverlay",          &options.noOverlay, NULL },
185     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
186     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
187     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
188     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
189     { 0,    "--peep-asm",           &options.asmpeep, NULL },
190     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
191     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
192     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
193     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code." },
194     { 0,    "--help",               NULL, "Display this help" },
195     { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
196     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
197     { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
198     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
199     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
200     { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
201     { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
202     { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
203     { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
204     { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
205     { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
206     { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
207     { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
208     { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
209     { 0,    OPTION_NO_XINIT_OPT,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
210     { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
211     { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
212     /* End of options */
213     { 0,    NULL }
214 };
215
216 /** Table of all unsupported options and help text to display when one
217     is used.
218 */
219 typedef struct {
220     /** shortOpt as in OPTIONS. */
221     char shortOpt;
222     /** longOpt as in OPTIONS. */
223     const char *longOpt;
224     /** Message to display inside W_UNSUPPORTED_OPT when this option
225         is used. */
226     const char *message;
227 } UNSUPPORTEDOPT;
228
229 static const UNSUPPORTEDOPT 
230 unsupportedOptTable[] = {
231     { 'X',  NULL,       "use --xstack-loc instead" },
232     { 'x',  NULL,       "use --xstack instead" },
233     { 'i',  NULL,       "use --idata-loc instead" },
234     { 'r',  NULL,       "use --xdata-loc instead" },
235     { 's',  NULL,       "use --code-loc instead" },
236     { 'Y',  NULL,       "use -I instead" }
237 };
238
239 /** List of all default constant macros.
240  */
241 static const char *_baseValues[] = {
242   "cpp", "sdcpp",
243   "cppextraopts", "",
244   /* Path seperator character */
245   "sep", DIR_SEPARATOR_STRING,
246   NULL
247 };
248
249 static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} {fullsrcfilename} {cppoutfilename}";
250
251 PORT *port;
252
253 static PORT *_ports[] =
254 {
255 #if !OPT_DISABLE_MCS51
256   &mcs51_port,
257 #endif
258 #if !OPT_DISABLE_GBZ80
259   &gbz80_port,
260 #endif
261 #if !OPT_DISABLE_Z80
262   &z80_port,
263 #endif
264 #if !OPT_DISABLE_AVR
265   &avr_port,
266 #endif
267 #if !OPT_DISABLE_DS390
268   &ds390_port,
269 #endif
270 #if !OPT_DISABLE_PIC
271   &pic_port,
272 #endif
273 #if !OPT_DISABLE_TININative
274   &tininative_port,
275 #endif
276 #if !OPT_DISABLE_XA51
277   &xa51_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), "-%c%s", sOpt, rest);
1162                 addToList (preArgv, buffer);
1163               }
1164               break;
1165
1166             default:
1167               if (!port->parseOption (&argc, argv, &i))
1168                 werror (W_UNKNOWN_OPTION, argv[i]);
1169             }
1170           continue;
1171         }
1172
1173       if (!port->parseOption (&argc, argv, &i))
1174         {
1175            /* no option must be a filename */
1176            if (options.c1mode)
1177              {
1178                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1179              }
1180          else
1181              {
1182                 processFile (argv[i]);
1183              }
1184         }
1185     }
1186
1187   /* some sanity checks in c1 mode */
1188   if (options.c1mode)
1189     {
1190       int i;
1191
1192       if (fullSrcFileName)
1193         {
1194           fclose (srcFile);
1195           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1196         }
1197       fullSrcFileName = NULL;
1198       for (i = 0; i < nrelFiles; ++i)
1199         {
1200           werror (W_NO_FILE_ARG_IN_C1, relFiles[i]);
1201         }
1202       for (i = 0; i < nlibFiles; ++i)
1203         {
1204           werror (W_NO_FILE_ARG_IN_C1, libFiles[i]);
1205         }
1206       nrelFiles = nlibFiles = 0;
1207       if (options.cc_only || noAssemble || preProcOnly)
1208         {
1209           werror (W_ILLEGAL_OPT_COMBINATION);
1210         }
1211       options.cc_only = noAssemble = preProcOnly = 0;
1212       if (!dstFileName)
1213         {
1214           werror (E_NEED_OPT_O_IN_C1);
1215           exit (1);
1216         }
1217     }
1218   /* if no dstFileName given with -o, we've to find one: */
1219   if (!dstFileName)
1220     {
1221       /* use the modulename from the C-source */
1222       if (fullSrcFileName)
1223         {
1224           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1225
1226           dstFileName = Safe_alloc (bufSize);
1227           strncpyz (dstFileName, dstPath, bufSize);
1228           strncatz (dstFileName, moduleName, bufSize);
1229         }
1230       /* use the modulename from the first object file */
1231       else if (nrelFiles >= 1)
1232         {
1233           char *objectName;
1234           size_t bufSize;
1235
1236           strncpyz (buffer, relFiles[0], sizeof(buffer));
1237           /* remove extension (it must be .rel) */
1238           *strrchr (buffer, '.') = '\0';
1239           /* remove path */
1240           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1241           if (objectName)
1242             {
1243               ++objectName;
1244             }
1245           else
1246             {
1247               objectName = buffer;
1248             }
1249           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1250           dstFileName = Safe_alloc (bufSize);
1251           strncpyz (dstFileName, dstPath, bufSize);
1252           strncatz (dstFileName, objectName, bufSize);
1253         }
1254       /* else no module given: help text is displayed */
1255     }
1256
1257   /* set up external stack location if not explicitly specified */
1258   if (!options.xstack_loc)
1259     options.xstack_loc = options.xdata_loc;
1260
1261   /* if debug option is set then open the cdbFile */
1262   if (options.debug && fullSrcFileName)
1263     {
1264       SNPRINTF (scratchFileName, sizeof(scratchFileName), 
1265                 "%s.adb", dstFileName); //JCF: Nov 30, 2002
1266       if(debugFile->openFile(scratchFileName))
1267         debugFile->writeModule(moduleName);
1268       else
1269         werror (E_FILE_OPEN_ERR, scratchFileName);
1270     }
1271   return 0;
1272 }
1273
1274 /*-----------------------------------------------------------------*/
1275 /* linkEdit : - calls the linkage editor  with options             */
1276 /*-----------------------------------------------------------------*/
1277 static void
1278 linkEdit (char **envp)
1279 {
1280   FILE *lnkfile;
1281   char *segName, *c;
1282   int i, system_ret;
1283
1284   /* first we need to create the <filename>.lnk file */
1285   SNPRINTF (scratchFileName, sizeof(scratchFileName), 
1286             "%s.lnk", dstFileName);
1287   if (!(lnkfile = fopen (scratchFileName, "w")))
1288     {
1289       werror (E_FILE_OPEN_ERR, scratchFileName);
1290       exit (1);
1291     }
1292
1293   /* now write the options.  JCF: added option 'y' */
1294   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1295
1296   /* if iram size specified */
1297   if (options.iram_size)
1298     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1299
1300   /* if xram size specified */
1301   if (options.xram_size_set)
1302     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1303
1304   /* if code size specified */
1305   if (options.code_size)
1306     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1307
1308   if (options.debug)
1309     fprintf (lnkfile, "-z\n");
1310
1311 #define WRITE_SEG_LOC(N, L) \
1312     segName = Safe_strdup(N); \
1313     c = strtok(segName, " \t"); \
1314     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1315     if (segName) { Safe_free(segName); }
1316
1317   /* code segment start */
1318   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1319
1320   /* data segment start */
1321   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1322           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1323   }
1324
1325   /* xdata start */
1326   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1327
1328   /* indirect data */
1329   if (IDATA_NAME) {
1330     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1331   }
1332
1333   /* bit segment start */
1334   WRITE_SEG_LOC (BIT_NAME, 0);
1335
1336   /* JCF: stack start */
1337   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1338         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1339   }
1340
1341   /* add the extra linker options */
1342   for (i = 0; linkOptions[i]; i++)
1343     fprintf (lnkfile, "%s\n", linkOptions[i]);
1344
1345   /* other library paths if specified */
1346   for (i = 0; i < nlibPaths; i++)
1347     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1348
1349   /* standard library path */
1350   if (!options.nostdlib)
1351     {
1352       switch (options.model)
1353         {
1354         case MODEL_SMALL:
1355           c = "small";
1356           break;
1357         case MODEL_LARGE:
1358           c = "large";
1359           break;
1360         case MODEL_FLAT24:
1361           /* c = "flat24"; */
1362           c = "ds390";
1363           break;
1364         case MODEL_PAGE0:
1365           c = "xa51";
1366           break;
1367         default:
1368           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1369           c = "unknown";
1370           break;
1371         }
1372       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1373
1374       /* standard library files */
1375 #if !OPT_DISABLE_DS390
1376       if (options.model == MODEL_FLAT24)
1377         {
1378           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1379         }
1380 #endif
1381
1382 #if !OPT_DISABLE_XA51 
1383 #ifdef STD_XA51_LIB
1384       if (options.model == MODEL_PAGE0)
1385         {
1386           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1387         }
1388 #endif
1389 #endif
1390       fprintf (lnkfile, "-l %s\n", STD_LIB);
1391       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1392       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1393       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1394     }
1395
1396   /* additional libraries if any */
1397   for (i = 0; i < nlibFiles; i++)
1398     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1399
1400   /* put in the object files */
1401   if (fullSrcFileName)
1402     fprintf (lnkfile, "%s ", dstFileName);
1403
1404   for (i = 0; i < nrelFiles; i++)
1405     fprintf (lnkfile, "%s\n", relFiles[i]);
1406
1407   fprintf (lnkfile, "\n-e\n");
1408   fclose (lnkfile);
1409
1410   if (options.verbose)
1411     printf ("sdcc: Calling linker...\n");
1412
1413   /* build linker output filename */
1414
1415   /* -o option overrides default name? */
1416   if (fullDstFileName)
1417     {
1418       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1419     }
1420   else
1421     {
1422       /* the linked file gets the name of the first modul */
1423       if (fullSrcFileName)
1424         {
1425           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1426         }
1427       else
1428         {
1429           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1430           /* strip ".rel" extension */
1431           *strrchr (scratchFileName, '.') = '\0';
1432         }
1433       strncatz (scratchFileName, 
1434                 options.out_fmt ? ".S19" : ".ihx",
1435                 sizeof(scratchFileName));
1436     }
1437
1438   if (port->linker.cmd)
1439     {
1440       char buffer2[PATH_MAX];
1441       buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
1442       buildCmdLine2 (buffer, buffer2, sizeof(buffer));
1443     }
1444   else
1445     {
1446       buildCmdLine2 (buffer, port->linker.mcmd, sizeof(buffer));
1447     }
1448
1449   system_ret = my_system (buffer);
1450   /* TODO: most linker don't have a -o parameter */
1451   /* -o option overrides default name? */
1452   if (fullDstFileName)
1453     {
1454       char *p, *q;
1455       /* the linked file gets the name of the first modul */
1456       if (fullSrcFileName)
1457         {
1458           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1459           p = strlen (scratchFileName) + scratchFileName;
1460         }
1461       else
1462         {
1463           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1464           /* strip "rel" extension */
1465           p = strrchr (scratchFileName, '.');
1466           if (p)
1467             {
1468                 p++;
1469                 *p = 0;
1470             }
1471             
1472         }
1473       strncatz (scratchFileName,
1474                 options.out_fmt ? "S19" : "ihx",
1475                 sizeof(scratchFileName));
1476       rename (scratchFileName, fullDstFileName);
1477
1478       q = strrchr (fullDstFileName, '.');
1479       if (q)
1480         {
1481           /* point after the '.' of the extension */
1482           q++;
1483         }
1484       else
1485         {
1486           /* no extension: append new extensions */
1487           /* Don't we want to append a period here ? */
1488           q = strlen (fullDstFileName) + fullDstFileName;
1489         }
1490         
1491       *p = 0;   
1492       strncatz (scratchFileName, "map", sizeof(scratchFileName));
1493       *q = 0;
1494       strncatz(fullDstFileName, "map", fullDstFileNameLen);
1495       rename (scratchFileName, fullDstFileName);
1496       *p = 0;   
1497       strncatz (scratchFileName, "mem", sizeof(scratchFileName));
1498       *q = 0;
1499       strncatz(fullDstFileName, "mem", fullDstFileNameLen);     
1500       rename (scratchFileName, fullDstFileName);
1501     }
1502   if (system_ret)
1503     {
1504       exit (1);
1505     }
1506 }
1507
1508 /*-----------------------------------------------------------------*/
1509 /* assemble - spawns the assembler with arguments                  */
1510 /*-----------------------------------------------------------------*/
1511 static void
1512 assemble (char **envp)
1513 {
1514     /* build assembler output filename */
1515
1516     /* -o option overrides default name? */
1517     if (options.cc_only && fullDstFileName) {
1518         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1519     } else {
1520         /* the assembled file gets the name of the first modul */
1521         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1522         strncatz (scratchFileName, port->linker.rel_ext, 
1523                   sizeof(scratchFileName));
1524     }
1525
1526     if (port->assembler.do_assemble) {
1527         port->assembler.do_assemble(asmOptions);
1528         return ;
1529     } else if (port->assembler.cmd) {
1530         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1531                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1532                       asmOptions);
1533     } else {
1534         buildCmdLine2 (buffer, port->assembler.mcmd, sizeof(buffer));
1535     }
1536
1537     if (my_system (buffer)) {
1538         /* either system() or the assembler itself has reported an error
1539            perror ("Cannot exec assembler");
1540         */
1541         exit (1);
1542     }
1543     /* TODO: most assembler don't have a -o parameter */
1544     /* -o option overrides default name? */
1545     if (options.cc_only && fullDstFileName) {
1546         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1547         strncatz (scratchFileName, 
1548                   port->linker.rel_ext,
1549                   sizeof(scratchFileName));
1550         rename (scratchFileName, fullDstFileName);
1551     }
1552 }
1553
1554 /*-----------------------------------------------------------------*/
1555 /* preProcess - spawns the preprocessor with arguments       */
1556 /*-----------------------------------------------------------------*/
1557 static int
1558 preProcess (char **envp)
1559 {
1560   if (options.c1mode)
1561     {
1562       yyin = stdin;
1563     }
1564   else
1565     {
1566       /* if using external stack define the macro */
1567       if (options.useXstack)
1568         addToList (preArgv, "-DSDCC_USE_XSTACK");
1569
1570       /* set the macro for stack autos  */
1571       if (options.stackAuto)
1572         addToList (preArgv, "-DSDCC_STACK_AUTO");
1573
1574       /* set the macro for stack autos  */
1575       if (options.stack10bit)
1576         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1577
1578       /* set the macro for no overlay  */
1579       if (options.noOverlay)
1580         addToList (preArgv, "-DSDCC_NOOVERLAY");
1581
1582       /* set the macro for large model  */
1583       switch (options.model)
1584         {
1585         case MODEL_LARGE:
1586           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1587           break;
1588         case MODEL_SMALL:
1589           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1590           break;
1591         case MODEL_COMPACT:
1592           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1593           break;
1594         case MODEL_MEDIUM:
1595           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1596           break;
1597         case MODEL_FLAT24:
1598           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1599           break;
1600         case MODEL_PAGE0:
1601           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1602           break;
1603         default:
1604           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1605           break;
1606         }
1607
1608       /* add port (processor information to processor */
1609       addToList (preArgv, "-DSDCC_{port}");
1610       addToList (preArgv, "-D__{port}");
1611
1612       /* standard include path */
1613       if (!options.nostdinc) {
1614         addToList (preArgv, "-I{includedir}");
1615       }
1616
1617       setMainValue ("cppextraopts", join(preArgv));
1618
1619       if (preProcOnly && fullDstFileName)
1620         {
1621           /* -E and -o given */
1622           setMainValue ("cppoutfilename", fullDstFileName);
1623         }
1624       else
1625         {
1626           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1627           setMainValue ("cppoutfilename", NULL);
1628         }
1629
1630       if (options.verbose)
1631         printf ("sdcc: Calling preprocessor...\n");
1632
1633       buildCmdLine2 (buffer, _preCmd, sizeof(buffer));
1634
1635       if (preProcOnly) {
1636         if (my_system (buffer)) {
1637           exit (1);
1638         }
1639
1640         exit (0);
1641       }
1642
1643       yyin = my_popen (buffer);
1644       if (yyin == NULL) {
1645           perror ("Preproc file not found");
1646           exit (1);
1647       }
1648       addSetHead (&pipeSet, yyin);
1649     }
1650
1651   return 0;
1652 }
1653
1654 static bool
1655 _setPaths (const char *pprefix)
1656 {
1657   /* Logic:
1658       Given the prefix and how the directories were layed out at
1659       configure time, see if the library and include directories are
1660       where expected.  If so, set.
1661   */
1662   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1663   strncpyz (scratchFileName, pprefix, sizeof(scratchFileName));
1664   strncatz (scratchFileName, buffer, sizeof(scratchFileName));
1665
1666   if (pathExists (scratchFileName))
1667     {
1668       setMainValue ("includedir", scratchFileName);
1669     }
1670   else
1671     {
1672       return FALSE;
1673     }
1674
1675   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1676   strncpyz (scratchFileName, pprefix, sizeof(scratchFileName));
1677   strncatz (scratchFileName, buffer, sizeof(scratchFileName));
1678
1679   if (pathExists (scratchFileName))
1680     {
1681       setMainValue ("libdir", scratchFileName);
1682     }
1683   else
1684     {
1685       return FALSE;
1686     }
1687
1688   return TRUE;
1689 }
1690
1691 static void
1692 _discoverPaths (const char *argv0)
1693 {
1694   /* Logic:
1695       1.  Try the SDCCDIR environment variable.
1696       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1697       and library paths with respect to that.  Note that under win32
1698       argv[0] is always the full path to the program.
1699       3.  If (1) and (2) fail, fall back to the compile time defaults.
1700
1701       Detecting assumes the same layout as when configured.  If the
1702       directories have been further moved about then discovery will
1703       fail.
1704   */
1705
1706   /* Some input cases:
1707         "c:\fish\sdcc\bin\sdcc"
1708         "../bin/sdcc"
1709         "/home/fish/bin/sdcc"
1710
1711       Note that ./sdcc is explicitly not supported as there isn't
1712       enough information.
1713   */
1714   /* bindir is handled differently to the lib and include directories.
1715      It's rather unfortunate, but required due to the different
1716      install and development layouts.  Logic is different as well.
1717      Sigh.
1718    */
1719   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1720     {
1721       strncpyz (scratchFileName, argv0, sizeof(scratchFileName));
1722       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1723       setMainValue ("bindir", scratchFileName);
1724       addSet(&binPathSet, Safe_strdup (scratchFileName));
1725     }
1726   else if (getenv (SDCCDIR_NAME) != NULL)
1727     {
1728       getPathDifference (buffer, PREFIX, BINDIR);
1729       strncpyz (scratchFileName, getenv (SDCCDIR_NAME), sizeof(scratchFileName));
1730       strncatz (scratchFileName, buffer, sizeof(scratchFileName));
1731       setMainValue ("bindir", scratchFileName);
1732       addSet(&binPathSet, Safe_strdup (scratchFileName));
1733     }
1734   else
1735     {
1736       setMainValue ("bindir", BINDIR);
1737       addSet(&binPathSet, BINDIR);
1738     }
1739
1740   do
1741     {
1742       /* Case 1 */
1743       if (getenv (SDCCDIR_NAME) != NULL)
1744         {
1745           if (_setPaths (getenv (SDCCDIR_NAME)))
1746             {
1747               /* Successfully set. */
1748               break;
1749             }
1750           else
1751             {
1752               /* Include and lib weren't where expected. */
1753             }
1754         }
1755       /* Case 2 */
1756       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1757         {
1758           char *pbase = getPrefixFromBinPath (argv0);
1759
1760           if (pbase == NULL)
1761             {
1762               /* A bad path.  Skip. */
1763             }
1764           else
1765             {
1766               if (_setPaths (pbase))
1767                 {
1768                   /* Successfully set. */
1769                   break;
1770                 }
1771               else
1772                 {
1773                   /* Include and lib weren't where expected. */
1774                 }
1775             }
1776         }
1777       /* Case 3 */
1778       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1779       setMainValue ("libdir", SDCC_LIB_DIR);
1780     } while (0);
1781 }
1782
1783 static void
1784 initValues (void)
1785 {
1786   populateMainValues (_baseValues);
1787   setMainValue ("port", port->target);
1788   setMainValue ("objext", port->linker.rel_ext);
1789   setMainValue ("asmext", port->assembler.file_ext);
1790
1791   setMainValue ("dstfilename", dstFileName);
1792   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1793
1794   if (options.cc_only && fullDstFileName)
1795     /* compile + assemble and -o given: -o specifies name of object file */
1796     {
1797       setMainValue ("objdstfilename", fullDstFileName);
1798     }
1799   else
1800     {
1801       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1802     }
1803   if (fullDstFileName)
1804     /* if we're linking, -o gives the final file name */
1805     {
1806       setMainValue ("linkdstfilename", fullDstFileName);
1807     }
1808   else
1809     {
1810       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1811     }
1812
1813 }
1814
1815 static void
1816 sig_handler (int signal)
1817 {
1818   char *sig_string;
1819
1820   switch (signal)
1821     {
1822     case SIGABRT:
1823       sig_string = "SIGABRT";
1824       break;
1825     case SIGTERM:
1826       sig_string = "SIGTERM";
1827       break;
1828     case SIGINT:
1829       sig_string = "SIGINT";
1830       break;
1831     case SIGSEGV:
1832       sig_string = "SIGSEGV";
1833       break;
1834     default:
1835       sig_string = "Unknown?";
1836       break;
1837     }
1838   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1839   exit (1);
1840 }
1841
1842 /*
1843  * main routine
1844  * initialises and calls the parser
1845  */
1846
1847 int
1848 main (int argc, char **argv, char **envp)
1849 {
1850   /* turn all optimizations off by default */
1851   memset (&optimize, 0, sizeof (struct optimize));
1852
1853   /*printVersionInfo (); */
1854
1855   if (NUM_PORTS==0) {
1856     fprintf (stderr, "Build error: no ports are enabled.\n");
1857     exit (1);
1858   }
1859
1860   /* install atexit handler */
1861   atexit(rm_tmpfiles);
1862
1863   /* install signal handler;
1864      it's only purpuse is to call exit() to remove temp files */
1865   if (!getenv("SDCC_LEAVE_SIGNALS"))
1866     {
1867       signal (SIGABRT, sig_handler);
1868       signal (SIGTERM, sig_handler);
1869       signal (SIGINT , sig_handler);
1870       signal (SIGSEGV, sig_handler);
1871     }
1872
1873   /* Before parsing the command line options, do a
1874    * search for the port and processor and initialize
1875    * them if they're found. (We can't gurantee that these
1876    * will be the first options specified).
1877    */
1878
1879   _findPort (argc, argv);
1880
1881 #ifdef JAMIN_DS390
1882   if (strcmp(port->target, "mcs51") == 0) {
1883     printf("DS390 jammed in A\n");
1884           _setPort ("ds390");
1885     ds390_jammed = 1;
1886   }
1887 #endif
1888
1889   _findProcessor (argc, argv);
1890
1891   /* Initalise the port. */
1892   if (port->init)
1893     port->init ();
1894
1895   // Create a default exe search path from the path to the sdcc command
1896
1897
1898   setDefaultOptions ();
1899 #ifdef JAMIN_DS390
1900   if (ds390_jammed) {
1901     options.model = MODEL_SMALL;
1902     options.stack10bit=0;
1903   }
1904 #endif
1905   parseCmdLine (argc, argv);
1906
1907   /* if no input then printUsage & exit */
1908   if (!options.c1mode && !fullSrcFileName && !nrelFiles)
1909     {
1910       printUsage ();
1911       exit (0);
1912     }
1913
1914   initValues ();
1915   _discoverPaths (argv[0]);
1916
1917   /* initMem() is expensive, but
1918      initMem() must called before port->finaliseOptions ().
1919      And the z80 port needs port->finaliseOptions(),
1920      even if we're only linking. */
1921   initMem ();
1922   port->finaliseOptions ();
1923
1924   if (fullSrcFileName || options.c1mode)
1925     {
1926       preProcess (envp);
1927
1928       initSymt ();
1929       initiCode ();
1930       initCSupport ();
1931       initBuiltIns();
1932       initPeepHole ();
1933
1934       if (options.verbose)
1935         printf ("sdcc: Generating code...\n");
1936
1937       yyparse ();
1938
1939       pclose(yyin);
1940       deleteSetItem(&pipeSet, yyin);
1941
1942       if (fatalError) {
1943         exit (1);
1944       }
1945
1946       if (TARGET_IS_PIC) {
1947         /* TSD PIC port hack - if the PIC port option is enabled
1948            and SDCC is used to generate PIC code, then we will
1949            generate .asm files in gpasm's format instead of SDCC's
1950            assembler's format
1951         */
1952 #if !OPT_DISABLE_PIC
1953         picglue ();
1954 #endif
1955       }
1956       else {
1957         glue ();
1958       }
1959
1960       if (!options.c1mode && !noAssemble)
1961         {
1962           if (options.verbose)
1963             printf ("sdcc: Calling assembler...\n");
1964           assemble (envp);
1965         }
1966     }
1967   closeDumpFiles();
1968
1969   if (options.debug && debugFile)
1970     debugFile->closeFile();
1971
1972   if (!options.cc_only &&
1973       !fatalError &&
1974       !noAssemble &&
1975       !options.c1mode &&
1976       (fullSrcFileName || nrelFiles))
1977     {
1978       if (port->linker.do_link)
1979         port->linker.do_link ();
1980       else
1981         linkEdit (envp);
1982     }
1983
1984   return 0;
1985 }