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