buffer overflow caught: preOutCmd could exceed PATH_MAX (observed on Cygwin building...
[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 #else
395 #  ifdef __DJGPP__
396            " (DJGPP) \n"
397 #  else
398 #    if defined(_MSC_VER)
399            " (WIN32) \n"
400 #    else
401            " (UNIX) \n"
402 #    endif
403 #  endif
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_LOOP_IND) == 0)
961             {
962               optimize.loopInduction = 0;
963               continue;
964             }
965
966           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
967             {
968               options.lessPedantic = 1;
969               setErrorLogLevel(ERROR_LEVEL_WARNING);
970               continue;
971             }
972
973           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
974             {
975               options.shortis8bits=1;
976               continue;
977             }
978
979           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
980             {
981                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
982                 continue;
983             }
984           
985           if (!port->parseOption (&argc, argv, &i))
986             {
987               werror (W_UNKNOWN_OPTION, argv[i]);
988             }
989           else
990             {
991               continue;
992             }
993         }
994
995       /* if preceded by  '-' then option */
996       if (*argv[i] == '-')
997         {
998           switch (argv[i][1])
999             {
1000             case 'h':
1001               verifyShortOption(argv[i]);
1002
1003               printUsage ();
1004               exit (0);
1005               break;
1006
1007             case 'm':
1008               /* Used to select the port. But this has already been done. */
1009               break;
1010
1011             case 'p':
1012               /* Used to select the processor in port. But this has
1013                * already been done. */
1014               break;
1015
1016             case 'c':
1017               verifyShortOption(argv[i]);
1018
1019               options.cc_only = 1;
1020               break;
1021
1022             case 'L':
1023                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
1024                 break;
1025
1026             case 'l':
1027                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
1028                 break;
1029             
1030             case 'o':
1031               {
1032                 char *p;
1033
1034                 /* copy the file name into the buffer */
1035                 strncpyz(buffer, getStringArg("-o", argv, &i, argc), 
1036                          sizeof(buffer));
1037                 /* point to last character */
1038                 p = buffer + strlen (buffer) - 1;
1039                 if (*p == DIR_SEPARATOR_CHAR)
1040                   {
1041                     /* only output path specified */
1042                     dstPath = Safe_strdup (buffer);
1043                     fullDstFileName = NULL;
1044                   }
1045                 else
1046                   {
1047                     fullDstFileName = Safe_strdup (buffer);
1048                     fullDstFileNameLen = strlen(fullDstFileName) + 1;
1049
1050                     /* get rid of the "."-extension */
1051
1052                     /* is there a dot at all? */
1053                     if (strrchr (buffer, '.') &&
1054                         /* is the dot in the filename, not in the path? */
1055                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1056                       *strrchr (buffer, '.') = '\0';
1057
1058                     dstFileName = Safe_strdup (buffer);
1059
1060                     /* strip module name to get path */
1061                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1062                     if (p)
1063                       {
1064                         /* path with trailing / */
1065                         p[1] = '\0';
1066                         dstPath = Safe_strdup (buffer);
1067                       }
1068                   }
1069                 break;
1070               }
1071
1072             case 'W':
1073               /* pre-processer options */
1074               if (argv[i][2] == 'p')
1075                 {
1076                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
1077                 }
1078               /* linker options */
1079               else if (argv[i][2] == 'l')
1080                 {
1081                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1082                 }
1083               /* assembler options */
1084               else if (argv[i][2] == 'a')
1085                 {
1086                   parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
1087                 }
1088               else
1089                 {
1090                   werror (W_UNKNOWN_OPTION, argv[i]);
1091                 }
1092               break;
1093
1094             case 'v':
1095               verifyShortOption(argv[i]);
1096
1097               printVersionInfo ();
1098               exit (0);
1099               break;
1100
1101               /* preprocessor options */
1102             case 'M':
1103               {
1104                 preProcOnly = 1;
1105                 addToList (preArgv, "-M");
1106                 break;
1107               }
1108             case 'C':
1109               {
1110                 addToList (preArgv, "-C");
1111                 break;
1112               }
1113             case 'd':
1114             case 'D':
1115             case 'I':
1116             case 'A':
1117             case 'U':
1118               {
1119                 char sOpt = argv[i][1];
1120                 char *rest;
1121
1122                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1123                   {
1124                     i++;
1125                     if (i >= argc)
1126                       {
1127                           /* No argument. */
1128                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1129                           break;
1130                       }
1131                     else
1132                       {
1133                           rest = argv[i];
1134                       }
1135                   }
1136                 else
1137                   rest = &argv[i][2];
1138
1139                 if (sOpt == 'Y')
1140                   sOpt = 'I';
1141
1142                 SNPRINTF (buffer, sizeof(buffer), "-%c%s", sOpt, rest);
1143                 addToList (preArgv, buffer);
1144               }
1145               break;
1146
1147             default:
1148               if (!port->parseOption (&argc, argv, &i))
1149                 werror (W_UNKNOWN_OPTION, argv[i]);
1150             }
1151           continue;
1152         }
1153
1154       if (!port->parseOption (&argc, argv, &i))
1155         {
1156            /* no option must be a filename */
1157            if (options.c1mode)
1158              {
1159                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1160              }
1161          else
1162              {
1163                 processFile (argv[i]);
1164              }
1165         }
1166     }
1167
1168   /* some sanity checks in c1 mode */
1169   if (options.c1mode)
1170     {
1171       int i;
1172
1173       if (fullSrcFileName)
1174         {
1175           fclose (srcFile);
1176           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1177         }
1178       fullSrcFileName = NULL;
1179       for (i = 0; i < nrelFiles; ++i)
1180         {
1181           werror (W_NO_FILE_ARG_IN_C1, relFiles[i]);
1182         }
1183       for (i = 0; i < nlibFiles; ++i)
1184         {
1185           werror (W_NO_FILE_ARG_IN_C1, libFiles[i]);
1186         }
1187       nrelFiles = nlibFiles = 0;
1188       if (options.cc_only || noAssemble || preProcOnly)
1189         {
1190           werror (W_ILLEGAL_OPT_COMBINATION);
1191         }
1192       options.cc_only = noAssemble = preProcOnly = 0;
1193       if (!dstFileName)
1194         {
1195           werror (E_NEED_OPT_O_IN_C1);
1196           exit (1);
1197         }
1198     }
1199   /* if no dstFileName given with -o, we've to find one: */
1200   if (!dstFileName)
1201     {
1202       /* use the modulename from the C-source */
1203       if (fullSrcFileName)
1204         {
1205           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1206
1207           dstFileName = Safe_alloc (bufSize);
1208           strncpyz (dstFileName, dstPath, bufSize);
1209           strncatz (dstFileName, moduleName, bufSize);
1210         }
1211       /* use the modulename from the first object file */
1212       else if (nrelFiles >= 1)
1213         {
1214           char *objectName;
1215           size_t bufSize;
1216
1217           strncpyz (buffer, relFiles[0], sizeof(buffer));
1218           /* remove extension (it must be .rel) */
1219           *strrchr (buffer, '.') = '\0';
1220           /* remove path */
1221           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1222           if (objectName)
1223             {
1224               ++objectName;
1225             }
1226           else
1227             {
1228               objectName = buffer;
1229             }
1230           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1231           dstFileName = Safe_alloc (bufSize);
1232           strncpyz (dstFileName, dstPath, bufSize);
1233           strncatz (dstFileName, objectName, bufSize);
1234         }
1235       /* else no module given: help text is displayed */
1236     }
1237
1238   /* set up external stack location if not explicitly specified */
1239   if (!options.xstack_loc)
1240     options.xstack_loc = options.xdata_loc;
1241
1242   /* if debug option is set the open the cdbFile */
1243   if (options.debug && fullSrcFileName)
1244     {
1245       SNPRINTF (scratchFileName, sizeof(scratchFileName), 
1246                 "%s.adb", dstFileName); //JCF: Nov 30, 2002
1247       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1248         werror (E_FILE_OPEN_ERR, scratchFileName);
1249       else
1250         {
1251           /* add a module record */
1252           fprintf (cdbFile, "M:%s\n", moduleName);
1253         }
1254     }
1255   return 0;
1256 }
1257
1258 /*-----------------------------------------------------------------*/
1259 /* linkEdit : - calls the linkage editor  with options             */
1260 /*-----------------------------------------------------------------*/
1261 static void
1262 linkEdit (char **envp)
1263 {
1264   FILE *lnkfile;
1265   char *segName, *c;
1266   int i, system_ret;
1267
1268   /* first we need to create the <filename>.lnk file */
1269   SNPRINTF (scratchFileName, sizeof(scratchFileName), 
1270             "%s.lnk", dstFileName);
1271   if (!(lnkfile = fopen (scratchFileName, "w")))
1272     {
1273       werror (E_FILE_OPEN_ERR, scratchFileName);
1274       exit (1);
1275     }
1276
1277   /* now write the options.  JCF: added option 'y' */
1278   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1279
1280   /* if iram size specified */
1281   if (options.iram_size)
1282     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1283
1284   /* if xram size specified */
1285   if (options.xram_size_set)
1286     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1287
1288   /* if code size specified */
1289   if (options.code_size)
1290     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1291
1292   if (options.debug)
1293     fprintf (lnkfile, "-z\n");
1294
1295 #define WRITE_SEG_LOC(N, L) \
1296     segName = Safe_strdup(N); \
1297     c = strtok(segName, " \t"); \
1298     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1299     if (segName) { Safe_free(segName); }
1300
1301   /* code segment start */
1302   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1303
1304   /* data segment start */
1305   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1306           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1307   }
1308
1309   /* xdata start */
1310   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1311
1312   /* indirect data */
1313   if (IDATA_NAME) {
1314     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1315   }
1316
1317   /* bit segment start */
1318   WRITE_SEG_LOC (BIT_NAME, 0);
1319
1320   /* JCF: stack start */
1321   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1322         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1323   }
1324
1325   /* add the extra linker options */
1326   for (i = 0; linkOptions[i]; i++)
1327     fprintf (lnkfile, "%s\n", linkOptions[i]);
1328
1329   /* other library paths if specified */
1330   for (i = 0; i < nlibPaths; i++)
1331     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1332
1333   /* standard library path */
1334   if (!options.nostdlib)
1335     {
1336       switch (options.model)
1337         {
1338         case MODEL_SMALL:
1339           c = "small";
1340           break;
1341         case MODEL_LARGE:
1342           c = "large";
1343           break;
1344         case MODEL_FLAT24:
1345           /* c = "flat24"; */
1346           c = "ds390";
1347           break;
1348         case MODEL_PAGE0:
1349           c = "xa51";
1350           break;
1351         default:
1352           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1353           c = "unknown";
1354           break;
1355         }
1356       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1357
1358       /* standard library files */
1359 #if !OPT_DISABLE_DS390
1360       if (options.model == MODEL_FLAT24)
1361         {
1362           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1363         }
1364 #endif
1365
1366 #if !OPT_DISABLE_XA51 
1367 #ifdef STD_XA51_LIB
1368       if (options.model == MODEL_PAGE0)
1369         {
1370           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1371         }
1372 #endif
1373 #endif
1374       fprintf (lnkfile, "-l %s\n", STD_LIB);
1375       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1376       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1377       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1378     }
1379
1380   /* additional libraries if any */
1381   for (i = 0; i < nlibFiles; i++)
1382     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1383
1384   /* put in the object files */
1385   if (fullSrcFileName)
1386     fprintf (lnkfile, "%s ", dstFileName);
1387
1388   for (i = 0; i < nrelFiles; i++)
1389     fprintf (lnkfile, "%s\n", relFiles[i]);
1390
1391   fprintf (lnkfile, "\n-e\n");
1392   fclose (lnkfile);
1393
1394   if (options.verbose)
1395     printf ("sdcc: Calling linker...\n");
1396
1397   /* build linker output filename */
1398
1399   /* -o option overrides default name? */
1400   if (fullDstFileName)
1401     {
1402       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1403     }
1404   else
1405     {
1406       /* the linked file gets the name of the first modul */
1407       if (fullSrcFileName)
1408         {
1409           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1410         }
1411       else
1412         {
1413           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1414           /* strip ".rel" extension */
1415           *strrchr (scratchFileName, '.') = '\0';
1416         }
1417       strncatz (scratchFileName, 
1418                 options.out_fmt ? ".S19" : ".ihx",
1419                 sizeof(scratchFileName));
1420     }
1421
1422   if (port->linker.cmd)
1423     {
1424       char buffer2[PATH_MAX];
1425       buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
1426       buildCmdLine2 (buffer, buffer2, sizeof(buffer));
1427     }
1428   else
1429     {
1430       buildCmdLine2 (buffer, port->linker.mcmd, sizeof(buffer));
1431     }
1432
1433   system_ret = my_system (buffer);
1434   /* TODO: most linker don't have a -o parameter */
1435   /* -o option overrides default name? */
1436   if (fullDstFileName)
1437     {
1438       char *p, *q;
1439       /* the linked file gets the name of the first modul */
1440       if (fullSrcFileName)
1441         {
1442           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1443           p = strlen (scratchFileName) + scratchFileName;
1444         }
1445       else
1446         {
1447           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1448           /* strip "rel" extension */
1449           p = strrchr (scratchFileName, '.');
1450           if (p)
1451             {
1452                 p++;
1453                 *p = 0;
1454             }
1455             
1456         }
1457       strncatz (scratchFileName,
1458                 options.out_fmt ? "S19" : "ihx",
1459                 sizeof(scratchFileName));
1460       rename (scratchFileName, fullDstFileName);
1461
1462       q = strrchr (fullDstFileName, '.');
1463       if (q)
1464         {
1465           /* point after the '.' of the extension */
1466           q++;
1467         }
1468       else
1469         {
1470           /* no extension: append new extensions */
1471           /* Don't we want to append a period here ? */
1472           q = strlen (fullDstFileName) + fullDstFileName;
1473         }
1474         
1475       *p = 0;   
1476       strncatz (scratchFileName, "map", sizeof(scratchFileName));
1477       *q = 0;
1478       strncatz(fullDstFileName, "map", fullDstFileNameLen);
1479       rename (scratchFileName, fullDstFileName);
1480       *p = 0;   
1481       strncatz (scratchFileName, "mem", sizeof(scratchFileName));
1482       *q = 0;
1483       strncatz(fullDstFileName, "mem", fullDstFileNameLen);     
1484       rename (scratchFileName, fullDstFileName);
1485     }
1486   if (system_ret)
1487     {
1488       exit (1);
1489     }
1490 }
1491
1492 /*-----------------------------------------------------------------*/
1493 /* assemble - spawns the assembler with arguments                  */
1494 /*-----------------------------------------------------------------*/
1495 static void
1496 assemble (char **envp)
1497 {
1498     /* build assembler output filename */
1499
1500     /* -o option overrides default name? */
1501     if (options.cc_only && fullDstFileName) {
1502         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1503     } else {
1504         /* the assembled file gets the name of the first modul */
1505         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1506         strncatz (scratchFileName, port->linker.rel_ext, 
1507                   sizeof(scratchFileName));
1508     }
1509
1510     if (port->assembler.do_assemble) {
1511         port->assembler.do_assemble(asmOptions);
1512         return ;
1513     } else if (port->assembler.cmd) {
1514         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1515                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1516                       asmOptions);
1517     } else {
1518         buildCmdLine2 (buffer, port->assembler.mcmd, sizeof(buffer));
1519     }
1520
1521     if (my_system (buffer)) {
1522         /* either system() or the assembler itself has reported an error
1523            perror ("Cannot exec assembler");
1524         */
1525         exit (1);
1526     }
1527     /* TODO: most assembler don't have a -o parameter */
1528     /* -o option overrides default name? */
1529     if (options.cc_only && fullDstFileName) {
1530         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1531         strncatz (scratchFileName, 
1532                   port->linker.rel_ext,
1533                   sizeof(scratchFileName));
1534         rename (scratchFileName, fullDstFileName);
1535     }
1536 }
1537
1538 /*-----------------------------------------------------------------*/
1539 /* preProcess - spawns the preprocessor with arguments       */
1540 /*-----------------------------------------------------------------*/
1541 static int
1542 preProcess (char **envp)
1543 {
1544   if (options.c1mode)
1545     {
1546       yyin = stdin;
1547     }
1548   else
1549     {
1550       /* if using external stack define the macro */
1551       if (options.useXstack)
1552         addToList (preArgv, "-DSDCC_USE_XSTACK");
1553
1554       /* set the macro for stack autos  */
1555       if (options.stackAuto)
1556         addToList (preArgv, "-DSDCC_STACK_AUTO");
1557
1558       /* set the macro for stack autos  */
1559       if (options.stack10bit)
1560         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1561
1562       /* set the macro for no overlay  */
1563       if (options.noOverlay)
1564         addToList (preArgv, "-DSDCC_NOOVERLAY");
1565
1566       /* set the macro for large model  */
1567       switch (options.model)
1568         {
1569         case MODEL_LARGE:
1570           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1571           break;
1572         case MODEL_SMALL:
1573           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1574           break;
1575         case MODEL_COMPACT:
1576           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1577           break;
1578         case MODEL_MEDIUM:
1579           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1580           break;
1581         case MODEL_FLAT24:
1582           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1583           break;
1584         case MODEL_PAGE0:
1585           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1586           break;
1587         default:
1588           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1589           break;
1590         }
1591
1592       /* add port (processor information to processor */
1593       addToList (preArgv, "-DSDCC_{port}");
1594       addToList (preArgv, "-D__{port}");
1595
1596       /* standard include path */
1597       if (!options.nostdinc) {
1598         addToList (preArgv, "-I{includedir}");
1599       }
1600
1601       setMainValue ("cppextraopts", join(preArgv));
1602
1603       if (preProcOnly)
1604         {
1605           if (fullDstFileName)
1606             {
1607               preOutName = Safe_strdup (fullDstFileName);
1608             }
1609         }
1610       else
1611           preOutName = Safe_strdup (tempfilename ());
1612
1613       /* Have to set cppoutfilename to something, even if just pre-processing. */
1614       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1615       addSetHead (&tmpfileNameSet, preOutName);
1616
1617       if (options.verbose)
1618         printf ("sdcc: Calling preprocessor...\n");
1619
1620       buildCmdLine2 (buffer, _preCmd, sizeof(buffer));
1621
1622       if (my_system (buffer))
1623         {
1624           exit (1);
1625         }
1626       if (preProcOnly)
1627         {
1628           exit (0);
1629         }
1630       yyin = fopen (preOutName, "r");
1631       if (yyin == NULL)
1632         {
1633           perror ("Preproc file not found\n");
1634           exit (1);
1635         }
1636       addSetHead (&tmpfileSet, yyin);
1637     }
1638
1639   return 0;
1640 }
1641
1642 static bool
1643 _setPaths (const char *pprefix)
1644 {
1645   /* Logic:
1646       Given the prefix and how the directories were layed out at
1647       configure time, see if the library and include directories are
1648       where expected.  If so, set.
1649   */
1650   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1651   strncpyz (scratchFileName, pprefix, sizeof(scratchFileName));
1652   strncatz (scratchFileName, buffer, sizeof(scratchFileName));
1653
1654   if (pathExists (scratchFileName))
1655     {
1656       setMainValue ("includedir", scratchFileName);
1657     }
1658   else
1659     {
1660       return FALSE;
1661     }
1662
1663   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1664   strncpyz (scratchFileName, pprefix, sizeof(scratchFileName));
1665   strncatz (scratchFileName, buffer, sizeof(scratchFileName));
1666
1667   if (pathExists (scratchFileName))
1668     {
1669       setMainValue ("libdir", scratchFileName);
1670     }
1671   else
1672     {
1673       return FALSE;
1674     }
1675
1676   return TRUE;
1677 }
1678
1679 static void
1680 _discoverPaths (const char *argv0)
1681 {
1682   /* Logic:
1683       1.  Try the SDCCDIR environment variable.
1684       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1685       and library paths with respect to that.  Note that under win32
1686       argv[0] is always the full path to the program.
1687       3.  If (1) and (2) fail, fall back to the compile time defaults.
1688
1689       Detecting assumes the same layout as when configured.  If the
1690       directories have been further moved about then discovery will
1691       fail.
1692   */
1693
1694   /* Some input cases:
1695         "c:\fish\sdcc\bin\sdcc"
1696         "../bin/sdcc"
1697         "/home/fish/bin/sdcc"
1698
1699       Note that ./sdcc is explicitly not supported as there isn't
1700       enough information.
1701   */
1702   /* bindir is handled differently to the lib and include directories.
1703      It's rather unfortunate, but required due to the different
1704      install and development layouts.  Logic is different as well.
1705      Sigh.
1706    */
1707   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1708     {
1709       strncpyz (scratchFileName, argv0, sizeof(scratchFileName));
1710       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1711       setMainValue ("bindir", scratchFileName);
1712       ExePathList[0] = Safe_strdup (scratchFileName);
1713     }
1714   else if (getenv (SDCCDIR_NAME) != NULL)
1715     {
1716       getPathDifference (buffer, PREFIX, BINDIR);
1717       strncpyz (scratchFileName, getenv (SDCCDIR_NAME), sizeof(scratchFileName));
1718       strncatz (scratchFileName, buffer, sizeof(scratchFileName));
1719       setMainValue ("bindir", scratchFileName);
1720       ExePathList[0] = Safe_strdup (scratchFileName);
1721     }
1722   else
1723     {
1724       setMainValue ("bindir", BINDIR);
1725       ExePathList[0] = BINDIR;
1726     }
1727
1728   do
1729     {
1730       /* Case 1 */
1731       if (getenv (SDCCDIR_NAME) != NULL)
1732         {
1733           if (_setPaths (getenv (SDCCDIR_NAME)))
1734             {
1735               /* Successfully set. */
1736               break;
1737             }
1738           else
1739             {
1740               /* Include and lib weren't where expected. */
1741             }
1742         }
1743       /* Case 2 */
1744       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1745         {
1746           char *pbase = getPrefixFromBinPath (argv0);
1747
1748           if (pbase == NULL)
1749             {
1750               /* A bad path.  Skip. */
1751             }
1752           else
1753             {
1754               if (_setPaths (pbase))
1755                 {
1756                   /* Successfully set. */
1757                   break;
1758                 }
1759               else
1760                 {
1761                   /* Include and lib weren't where expected. */
1762                 }
1763             }
1764         }
1765       /* Case 3 */
1766       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1767       setMainValue ("libdir", SDCC_LIB_DIR);
1768     } while (0);
1769 }
1770
1771 static void
1772 initValues (void)
1773 {
1774   populateMainValues (_baseValues);
1775   setMainValue ("port", port->target);
1776   setMainValue ("objext", port->linker.rel_ext);
1777   setMainValue ("asmext", port->assembler.file_ext);
1778
1779   setMainValue ("dstfilename", dstFileName);
1780   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1781
1782   if (options.cc_only && fullDstFileName)
1783     /* compile + assemble and -o given: -o specifies name of object file */
1784     {
1785       setMainValue ("objdstfilename", fullDstFileName);
1786     }
1787   else
1788     {
1789       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1790     }
1791   if (fullDstFileName)
1792     /* if we're linking, -o gives the final file name */
1793     {
1794       setMainValue ("linkdstfilename", fullDstFileName);
1795     }
1796   else
1797     {
1798       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1799     }
1800
1801 }
1802
1803 static void
1804 sig_handler (int signal)
1805 {
1806   char *sig_string;
1807
1808   switch (signal)
1809     {
1810     case SIGABRT:
1811       sig_string = "SIGABRT";
1812       break;
1813     case SIGTERM:
1814       sig_string = "SIGTERM";
1815       break;
1816     case SIGINT:
1817       sig_string = "SIGINT";
1818       break;
1819     case SIGSEGV:
1820       sig_string = "SIGSEGV";
1821       break;
1822     default:
1823       sig_string = "Unknown?";
1824       break;
1825     }
1826   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1827   exit (1);
1828 }
1829
1830 /*
1831  * main routine
1832  * initialises and calls the parser
1833  */
1834
1835 int
1836 main (int argc, char **argv, char **envp)
1837 {
1838   /* turn all optimizations off by default */
1839   memset (&optimize, 0, sizeof (struct optimize));
1840
1841   /*printVersionInfo (); */
1842
1843   if (NUM_PORTS==0) {
1844     fprintf (stderr, "Build error: no ports are enabled.\n");
1845     exit (1);
1846   }
1847
1848   /* install atexit handler */
1849   atexit(rm_tmpfiles);
1850
1851   /* install signal handler;
1852      it's only purpuse is to call exit() to remove temp files */
1853   if (!getenv("SDCC_LEAVE_SIGNALS"))
1854     {
1855       signal (SIGABRT, sig_handler);
1856       signal (SIGTERM, sig_handler);
1857       signal (SIGINT , sig_handler);
1858       signal (SIGSEGV, sig_handler);
1859     }
1860
1861   /* Before parsing the command line options, do a
1862    * search for the port and processor and initialize
1863    * them if they're found. (We can't gurantee that these
1864    * will be the first options specified).
1865    */
1866
1867   _findPort (argc, argv);
1868
1869 #ifdef JAMIN_DS390
1870   if (strcmp(port->target, "mcs51") == 0) {
1871     printf("DS390 jammed in A\n");
1872           _setPort ("ds390");
1873     ds390_jammed = 1;
1874   }
1875 #endif
1876
1877   _findProcessor (argc, argv);
1878
1879   /* Initalise the port. */
1880   if (port->init)
1881     port->init ();
1882
1883   // Create a default exe search path from the path to the sdcc command
1884
1885
1886   setDefaultOptions ();
1887 #ifdef JAMIN_DS390
1888   if (ds390_jammed) {
1889     options.model = MODEL_SMALL;
1890     options.stack10bit=0;
1891   }
1892 #endif
1893   parseCmdLine (argc, argv);
1894
1895   /* if no input then printUsage & exit */
1896   if (!options.c1mode && !fullSrcFileName && !nrelFiles)
1897     {
1898       printUsage ();
1899       exit (0);
1900     }
1901
1902   initValues ();
1903   _discoverPaths (argv[0]);
1904
1905   /* initMem() is expensive, but
1906      initMem() must called before port->finaliseOptions ().
1907      And the z80 port needs port->finaliseOptions(),
1908      even if we're only linking. */
1909   initMem ();
1910   port->finaliseOptions ();
1911
1912   if (fullSrcFileName || options.c1mode)
1913     {
1914       preProcess (envp);
1915
1916       initSymt ();
1917       initiCode ();
1918       initCSupport ();
1919       initBuiltIns();
1920       initPeepHole ();
1921
1922       if (options.verbose)
1923         printf ("sdcc: Generating code...\n");
1924
1925       yyparse ();
1926       if (fatalError) {
1927         exit (1);
1928       }
1929
1930       if (TARGET_IS_PIC) {
1931         /* TSD PIC port hack - if the PIC port option is enabled
1932            and SDCC is used to generate PIC code, then we will
1933            generate .asm files in gpasm's format instead of SDCC's
1934            assembler's format
1935         */
1936 #if !OPT_DISABLE_PIC
1937         picglue ();
1938 #endif
1939       }
1940       else {
1941         glue ();
1942       }
1943
1944       if (!options.c1mode && !noAssemble)
1945         {
1946           if (options.verbose)
1947             printf ("sdcc: Calling assembler...\n");
1948           assemble (envp);
1949         }
1950     }
1951   closeDumpFiles();
1952
1953   if (cdbFile)
1954     fclose (cdbFile);
1955
1956   if (!options.cc_only &&
1957       !fatalError &&
1958       !noAssemble &&
1959       !options.c1mode &&
1960       (fullSrcFileName || nrelFiles))
1961     {
1962       if (port->linker.do_link)
1963         port->linker.do_link ();
1964       else
1965         linkEdit (envp);
1966     }
1967
1968   return 0;
1969 }