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