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