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