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