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