* device/lib/z80/printf.c: Changed emitter to volatile to work
[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 static void
298 _validatePorts (void)
299 {
300   int i;
301   for (i = 0; i < NUM_PORTS; i++)
302     {
303       if (_ports[i]->magic != PORT_MAGIC)
304         {
305           /* Uncomment this line to debug which port is causing the problem
306            * (the target name is close to the beginning of the port struct 
307            * and probably can be accessed just fine). */
308           fprintf(stderr,"%s :",_ports[i]->target);
309           wassertl (0, "Port definition structure is incomplete");
310         }
311     }
312 }
313
314 /* search through the command line options for the port */
315 static void
316 _findPort (int argc, char **argv)
317 {
318   _validatePorts ();
319
320   while (argc--)
321     {
322       if (!strncmp (*argv, "-m", 2))
323         {
324           _setPort (*argv + 2);
325           return;
326         }
327       argv++;
328     }
329   /* Use the first in the list */
330   port = _ports[0];
331 }
332
333 /*-----------------------------------------------------------------*/
334 /* printVersionInfo - prints the version info        */
335 /*-----------------------------------------------------------------*/
336 void
337 printVersionInfo ()
338 {
339   int i;
340
341   fprintf (stderr,
342            "SDCC : ");
343   for (i = 0; i < NUM_PORTS; i++)
344     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
345
346   fprintf (stderr, " %s"
347 #ifdef SDCC_SUB_VERSION_STR
348            "/" SDCC_SUB_VERSION_STR
349 #endif
350            " (" __DATE__ ")"
351 #ifdef __CYGWIN__
352            " (CYGWIN)\n"
353 #else
354 #ifdef __DJGPP__
355            " (DJGPP) \n"
356 #else
357 #if defined(_MSC_VER)
358            " (WIN32) \n"
359 #else
360            " (UNIX) \n"
361 #endif
362 #endif
363 #endif
364
365            ,VersionString
366     );
367 }
368
369 static void
370 printOptions(const OPTION *optionsTable)
371 {
372   int i;
373   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++) 
374     {
375       fprintf(stdout, "  %c%c  %-20s  %s\n", 
376               optionsTable[i].shortOpt !=0 ? '-' : ' ',
377               optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
378               optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
379               optionsTable[i].help != NULL ? optionsTable[i].help : ""
380               );
381     }
382 }
383
384 /*-----------------------------------------------------------------*/
385 /* printUsage - prints command line syntax         */
386 /*-----------------------------------------------------------------*/
387 void
388 printUsage ()
389 {
390     int i;
391     printVersionInfo();
392     fprintf (stdout,
393              "Usage : sdcc [options] filename\n"
394              "Options :-\n"
395              );
396     
397     printOptions(optionsTable);
398
399     for (i = 0; i < NUM_PORTS; i++)
400       {
401         if (_ports[i]->poptions != NULL)
402           {
403             fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
404             printOptions (_ports[i]->poptions);
405           }
406       }
407
408     exit (0);
409 }
410
411 /*-----------------------------------------------------------------*/
412 /* parseWithComma - separates string with comma                    */
413 /*-----------------------------------------------------------------*/
414 void
415 parseWithComma (char **dest, char *src)
416 {
417   int i = 0;
418
419   strtok (src, "\r\n \t");
420   /* skip the initial white spaces */
421   while (isspace (*src))
422     src++;
423   dest[i++] = src;
424   while (*src)
425     {
426       if (*src == ',')
427         {
428           *src = '\0';
429           src++;
430           if (*src)
431             dest[i++] = src;
432           continue;
433         }
434       src++;
435     }
436 }
437
438 /*-----------------------------------------------------------------*/
439 /* setDefaultOptions - sets the default options                    */
440 /*-----------------------------------------------------------------*/
441 static void
442 setDefaultOptions ()
443 {
444   int i;
445
446   for (i = 0; i < 128; i++)
447     preArgv[i] = asmOptions[i] =
448       linkOptions[i] = relFiles[i] = libFiles[i] =
449       libPaths[i] = NULL;
450
451   /* first the options part */
452   options.stack_loc = 0;        /* stack pointer initialised to 0 */
453   options.xstack_loc = 0;       /* xternal stack starts at 0 */
454   options.code_loc = 0;         /* code starts at 0 */
455   options.data_loc = 0x0030;    /* data starts at 0x0030 */
456   options.xdata_loc = 0;
457   options.idata_loc = 0x80;
458   options.genericPtr = 1;       /* default on */
459   options.nopeep = 0;
460   options.model = port->general.default_model;
461   options.nostdlib = 0;
462   options.nostdinc = 0;
463   options.verbose = 0;
464   options.shortis8bits = 0;
465
466   options.stack10bit=0;
467
468   /* now for the optimizations */
469   /* turn on the everything */
470   optimize.global_cse = 1;
471   optimize.label1 = 1;
472   optimize.label2 = 1;
473   optimize.label3 = 1;
474   optimize.label4 = 1;
475   optimize.loopInvariant = 1;
476   optimize.loopInduction = 1;
477
478   /* now for the ports */
479   port->setDefaultOptions ();
480 }
481
482 /*-----------------------------------------------------------------*/
483 /* processFile - determines the type of file from the extension    */
484 /*-----------------------------------------------------------------*/
485 static void
486 processFile (char *s)
487 {
488   char *fext = NULL;
489
490   /* get the file extension */
491   fext = s + strlen (s);
492   while ((fext != s) && *fext != '.')
493     fext--;
494
495   /* now if no '.' then we don't know what the file type is
496      so give a warning and return */
497   if (fext == s)
498     {
499       werror (W_UNKNOWN_FEXT, s);
500       return;
501     }
502
503   /* otherwise depending on the file type */
504   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0 || options.c1mode)
505     {
506       /* source file name : not if we already have a
507          source file */
508       if (srcFileName)
509         {
510           werror (W_TOO_MANY_SRC, s);
511           return;
512         }
513
514       /* the only source file */
515       if (!(srcFile = fopen ((fullSrcFileName = s), "r")))
516         {
517           werror (E_FILE_OPEN_ERR, s);
518           exit (1);
519         }
520
521       /* copy the file name into the buffer */
522       strcpy (buffer, s);
523
524       /* get rid of the "."-extension */
525
526       /* is there a dot at all? */
527       if (strchr (buffer, '.') &&
528           /* is the dot in the filename, not in the path? */
529           (strrchr (buffer, '/' ) < strrchr (buffer, '.') ||
530            strrchr (buffer, '\\') < strrchr (buffer, '.')))
531         *strrchr (buffer, '.') = '\0';
532
533       srcFileName = Safe_alloc ( strlen (buffer) + 1);
534       strcpy (srcFileName, buffer);
535
536       /* get rid of any path information
537          for the module name; do this by going
538          backwards till we get to either '/' or '\' or ':'
539          or start of buffer */
540       fext = buffer + strlen (buffer);
541       while (fext != buffer &&
542              *(fext - 1) != '\\' &&
543              *(fext - 1) != '/' &&
544              *(fext - 1) != ':')
545         fext--;
546       moduleName = Safe_alloc ( strlen (fext) + 1);
547       strcpy (moduleName, fext);
548
549       return;
550     }
551
552   /* if the extention is type .rel or .r or .REL or .R
553      addtional object file will be passed to the linker */
554   if (strcmp (fext, ".r") == 0 || strcmp (fext, ".rel") == 0 ||
555       strcmp (fext, ".R") == 0 || strcmp (fext, ".REL") == 0 ||
556       strcmp (fext, port->linker.rel_ext) == 0)
557     {
558       relFiles[nrelFiles++] = s;
559       return;
560     }
561
562   /* if .lib or .LIB */
563   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
564     {
565       libFiles[nlibFiles++] = s;
566       return;
567     }
568
569   werror (W_UNKNOWN_FEXT, s);
570
571 }
572
573 static void
574 _processC1Arg (char *s)
575 {
576   if (srcFileName)
577     {
578       if (options.out_name)
579         {
580           werror (W_TOO_MANY_SRC, s);
581           return;
582         }
583       options.out_name = Safe_strdup (s);
584     }
585   else
586     {
587       processFile (s);
588     }
589 }
590
591 static void
592 _setModel (int model, const char *sz)
593 {
594   if (port->general.supported_models & model)
595     options.model = model;
596   else
597     werror (W_UNSUPPORTED_MODEL, sz, port->target);
598 }
599
600 static void
601 _setProcessor (char *_processor)
602 {
603   port->processor = _processor;
604   fprintf(stderr,"Processor: %s\n",_processor);
605 }
606
607 /** Gets the string argument to this option.  If the option is '--opt'
608     then for input of '--optxyz' or '--opt xyz' returns xyz.
609 */
610 static char *
611 getStringArg(const char *szStart, char **argv, int *pi, int argc)
612 {
613   if (argv[*pi][strlen(szStart)]) 
614     {
615       return &argv[*pi][strlen(szStart)];
616     }
617   else 
618     {
619       ++(*pi);
620       if (*pi >= argc) 
621         {
622           werror (E_ARGUMENT_MISSING, szStart);
623           /* Die here rather than checking for errors later. */
624           exit(-1);
625         }
626       else 
627         {
628           return argv[*pi];
629         }
630     }
631 }
632
633 /** Gets the integer argument to this option using the same rules as
634     getStringArg. 
635 */
636 static int
637 getIntArg(const char *szStart, char **argv, int *pi, int argc)
638 {
639     return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
640 }
641
642 static void
643 verifyShortOption(const char *opt)
644 {
645   if (strlen(opt) != 2)
646     {
647       werror (W_EXCESS_SHORT_OPTIONS, opt);
648     }
649 }
650
651 static bool
652 tryHandleUnsupportedOpt(char **argv, int *pi)
653 {
654     if (argv[*pi][0] == '-') 
655         {
656             const char *longOpt = "";
657             char shortOpt = -1;
658             int i;
659
660             if (argv[*pi][1] == '-') 
661                 {
662                     // Long option.
663                     longOpt = argv[*pi];
664                 }
665             else 
666                 {
667                     shortOpt = argv[*pi][1];
668                 }
669             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
670                 {
671                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
672                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
673                         // Found an unsupported opt.
674                         char buffer[100];
675                         sprintf(buffer, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
676                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
677                         return 1;
678                     }
679                 }
680             // Didn't find in the table
681             return 0;
682         }
683     else 
684         {
685             // Not an option, so can't be unsupported :)
686             return 0;
687     }
688 }
689
690 static bool
691 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
692 {
693   int i;
694   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++)
695     {
696       if (optionsTable[i].shortOpt == shortOpt ||
697           (longOpt && optionsTable[i].longOpt && 
698            strcmp(optionsTable[i].longOpt, longOpt) == 0))
699         {
700
701           // If it is a flag then we can handle it here
702           if (optionsTable[i].pparameter != NULL) 
703             {
704               if (optionsTable[i].shortOpt == shortOpt)
705                 {
706                   verifyShortOption(argv[*pi]);
707                 }
708
709               (*optionsTable[i].pparameter)++;
710               return 1;
711             }
712           else {
713             // Not a flag.  Handled manually later.
714             return 0;
715           }
716         }
717     }
718   // Didn't find in the table
719   return 0;
720 }
721
722 static bool
723 tryHandleSimpleOpt(char **argv, int *pi)
724 {
725     if (argv[*pi][0] == '-') 
726         {
727             const char *longOpt = "";
728             char shortOpt = -1;
729
730             if (argv[*pi][1] == '-') 
731                 {
732                     // Long option.
733                     longOpt = argv[*pi];
734                 }
735             else 
736                 {
737                     shortOpt = argv[*pi][1];
738                 }
739
740             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
741               {
742                 return 1;
743               }
744             else if (port && port->poptions &&
745                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
746               {
747                 return 1;
748               }
749             else
750               {
751                 return 0;
752               }
753         }
754     else 
755         {
756             // Not an option, so can't be handled.
757             return 0;
758         }
759 }
760
761 /*-----------------------------------------------------------------*/
762 /* parseCmdLine - parses the command line and sets the options     */
763 /*-----------------------------------------------------------------*/
764 int
765 parseCmdLine (int argc, char **argv)
766 {
767   int i;
768
769   /* go thru all whole command line */
770   for (i = 1; i < argc; i++)
771     {
772       if (i >= argc)
773         break;
774
775       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
776           {
777               continue;
778           }
779
780       if (tryHandleSimpleOpt(argv, &i) == TRUE)
781           {
782               continue;
783           }
784
785       /* options */
786       if (argv[i][0] == '-' && argv[i][1] == '-')
787         {
788           if (strcmp (argv[i], OPTION_HELP) == 0)
789             {
790               printUsage ();
791               exit (0);
792             }
793
794           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
795             {
796               options.stack10bit = 0;
797               continue;
798             }
799
800           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
801             {
802               options.out_fmt = 0;
803               continue;
804             }
805
806           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
807             {
808               _setModel (MODEL_LARGE, argv[i]);
809               continue;
810             }
811
812           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
813             {
814               _setModel (MODEL_MEDIUM, argv[i]);
815               continue;
816             }
817
818           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
819             {
820               _setModel (MODEL_SMALL, argv[i]);
821               continue;
822             }
823
824           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
825             {
826               _setModel (MODEL_FLAT24, argv[i]);
827               continue;
828             }
829
830           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
831             {
832               options.dump_rassgn =
833                 options.dump_pack =
834                 options.dump_range =
835                 options.dump_kill =
836                 options.dump_loop =
837                 options.dump_gcse =
838                 options.dump_raw = 1;
839               continue;
840             }
841
842           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
843             {
844                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
845                 continue;
846             }
847
848           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
849             {
850                 libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i, argc);
851                 continue;
852             }
853
854           if (strcmp (argv[i], OPTION_VERSION) == 0)
855             {
856               printVersionInfo ();
857               exit (0);
858               continue;
859             }
860
861           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
862             {
863                 parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
864                 continue;
865             }
866
867           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
868             {
869                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
870                 continue;
871             }
872
873           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
874             {
875                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
876                 continue;
877             }
878
879           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
880             {
881                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
882                 continue;
883             }
884
885           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
886             {
887                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
888                 continue;
889             }
890
891           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
892             {
893                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
894                 continue;
895             }
896
897           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
898             {
899                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
900                 continue;
901             }
902
903           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
904             {
905                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
906                 continue;
907             }
908
909           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
910             {
911               optimize.global_cse = 0;
912               continue;
913             }
914
915           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
916             {
917               optimize.loopInvariant = 0;
918               continue;
919             }
920
921           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
922             {
923               optimize.loopInduction = 0;
924               continue;
925             }
926
927           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
928             {
929               options.lessPedantic = 1;
930               setErrorLogLevel(ERROR_LEVEL_WARNING);
931               continue;
932             }
933
934           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
935             {
936               options.shortis8bits=1;
937               continue;
938             }
939
940           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
941             {
942                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
943                 continue;
944             }
945           
946           if (!port->parseOption (&argc, argv, &i))
947             {
948               werror (W_UNKNOWN_OPTION, argv[i]);
949             }
950           else
951             {
952               continue;
953             }
954         }
955
956       /* if preceded by  '-' then option */
957       if (*argv[i] == '-')
958         {
959           switch (argv[i][1])
960             {
961             case 'h':
962               verifyShortOption(argv[i]);
963
964               printUsage ();
965               exit (0);
966               break;
967
968             case 'm':
969               /* Used to select the port */
970               _setPort (argv[i] + 2);
971               break;
972
973             case 'p':
974               /* Used to select the processor in port */
975               _setProcessor (getStringArg("-p", argv, &i, argc));
976               break;
977
978             case 'c':
979               verifyShortOption(argv[i]);
980
981               options.cc_only = 1;
982               break;
983
984             case 'L':
985                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
986                 break;
987
988             case 'l':
989                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
990                 break;
991
992             case 'W':
993               /* pre-processer options */
994               if (argv[i][2] == 'p')
995                 {
996                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
997                 }
998               /* linker options */
999               else if (argv[i][2] == 'l')
1000                 {
1001                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1002                 }
1003               /* assembler options */
1004               else if (argv[i][2] == 'a')
1005                 {
1006                   parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
1007                 }
1008               else
1009                 {
1010                   werror (W_UNKNOWN_OPTION, argv[i]);
1011                 }
1012               break;
1013
1014             case 'v':
1015               verifyShortOption(argv[i]);
1016
1017               printVersionInfo ();
1018               exit (0);
1019               break;
1020
1021               /* preprocessor options */
1022             case 'M':
1023               {
1024                 preProcOnly = 1;
1025                 addToList (preArgv, "-M");
1026                 break;
1027               }
1028             case 'C':
1029               {
1030                 addToList (preArgv, "-C");
1031                 break;
1032               }
1033             case 'd':
1034             case 'D':
1035             case 'I':
1036             case 'A':
1037             case 'U':
1038               {
1039                 char sOpt = argv[i][1];
1040                 char *rest;
1041
1042                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1043                   {
1044                     i++;
1045                     if (i >= argc) 
1046                       {
1047                           /* No argument. */
1048                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1049                           break;
1050                       }
1051                     else 
1052                       {
1053                           rest = argv[i];
1054                       }
1055                   }
1056                 else
1057                   rest = &argv[i][2];
1058
1059                 if (sOpt == 'Y')
1060                   sOpt = 'I';
1061
1062                 sprintf (buffer, "-%c%s", sOpt, rest);
1063                 addToList (preArgv, buffer);
1064               }
1065               break;
1066
1067             default:
1068               if (!port->parseOption (&argc, argv, &i))
1069                 werror (W_UNKNOWN_OPTION, argv[i]);
1070             }
1071           continue;
1072         }
1073
1074       if (!port->parseOption (&argc, argv, &i))
1075         {
1076           /* no option must be a filename */
1077           if (options.c1mode)
1078             _processC1Arg (argv[i]);
1079           else
1080             processFile (argv[i]);
1081         }
1082     }
1083
1084   /* set up external stack location if not explicitly specified */
1085   if (!options.xstack_loc)
1086     options.xstack_loc = options.xdata_loc;
1087
1088   /* if debug option is set the open the cdbFile */
1089   if (options.debug && srcFileName)
1090     {
1091       sprintf (scratchFileName, "%s.cdb", srcFileName);
1092       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1093         werror (E_FILE_OPEN_ERR, scratchFileName);
1094       else
1095         {
1096           /* add a module record */
1097           fprintf (cdbFile, "M:%s\n", moduleName);
1098         }
1099     }
1100   return 0;
1101 }
1102
1103 /*-----------------------------------------------------------------*/
1104 /* linkEdit : - calls the linkage editor  with options             */
1105 /*-----------------------------------------------------------------*/
1106 static void
1107 linkEdit (char **envp)
1108 {
1109   FILE *lnkfile;
1110   char *segName, *c;
1111
1112   int i;
1113   if (!srcFileName)
1114     srcFileName = "temp";
1115
1116   /* first we need to create the <filename>.lnk file */
1117   sprintf (scratchFileName, "%s.lnk", srcFileName);
1118   if (!(lnkfile = fopen (scratchFileName, "w")))
1119     {
1120       werror (E_FILE_OPEN_ERR, scratchFileName);
1121       exit (1);
1122     }
1123
1124   /* now write the options */
1125   fprintf (lnkfile, "-mux%c\n", (options.out_fmt ? 's' : 'i'));
1126
1127   /* if iram size specified */
1128   if (options.iram_size)
1129     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1130
1131   if (options.debug)
1132     fprintf (lnkfile, "-z\n");
1133
1134 #define WRITE_SEG_LOC(N, L) \
1135     segName = Safe_strdup(N); \
1136     c = strtok(segName, " \t"); \
1137     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1138     if (segName) { Safe_free(segName); }
1139
1140   /* code segment start */
1141   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1142
1143   /* data segment start */
1144   WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1145
1146   /* xdata start */
1147   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1148
1149   /* indirect data */
1150   if (IDATA_NAME) {
1151     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1152   }
1153
1154   /* bit segment start */
1155   WRITE_SEG_LOC (BIT_NAME, 0);
1156
1157   /* add the extra linker options */
1158   for (i = 0; linkOptions[i]; i++)
1159     fprintf (lnkfile, "%s\n", linkOptions[i]);
1160
1161   /* other library paths if specified */
1162   for (i = 0; i < nlibPaths; i++)
1163     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1164
1165   /* standard library path */
1166   if (!options.nostdlib)
1167     {
1168       switch (options.model)
1169         {
1170         case MODEL_SMALL:
1171           c = "small";
1172           break;
1173         case MODEL_LARGE:
1174           c = "large";
1175           break;
1176         case MODEL_FLAT24:
1177           /* c = "flat24"; */
1178           c = "ds390";
1179           break;
1180         case MODEL_PAGE0:
1181           c = "xa51";
1182           break;
1183         default:
1184           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1185           c = "unknown";
1186           break;
1187         }
1188       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1189
1190       /* standard library files */
1191 #if !OPT_DISABLE_DS390
1192       if (options.model == MODEL_FLAT24)
1193         {
1194           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1195         }
1196 #endif
1197
1198 #if !OPT_DISABLE_XA51 
1199 #ifdef STD_XA51_LIB
1200       if (options.model == MODEL_PAGE0)
1201         {
1202           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1203         }
1204 #endif
1205 #endif
1206       fprintf (lnkfile, "-l %s\n", STD_LIB);
1207       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1208       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1209       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1210     }
1211
1212   /* additional libraries if any */
1213   for (i = 0; i < nlibFiles; i++)
1214     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1215
1216   /* put in the object files */
1217   if (strcmp (srcFileName, "temp"))
1218     fprintf (lnkfile, "%s ", srcFileName);
1219
1220   for (i = 0; i < nrelFiles; i++)
1221     fprintf (lnkfile, "%s\n", relFiles[i]);
1222
1223   fprintf (lnkfile, "\n-e\n");
1224   fclose (lnkfile);
1225
1226   if (options.verbose)
1227     printf ("sdcc: Calling linker...\n");
1228
1229   if (port->linker.cmd)
1230     {
1231       char buffer2[PATH_MAX];
1232       buildCmdLine (buffer2, port->linker.cmd, srcFileName, NULL, NULL, NULL);
1233       buildCmdLine2 (buffer, buffer2);
1234     }
1235   else
1236     {
1237       buildCmdLine2 (buffer, port->linker.mcmd);
1238     }
1239
1240   if (my_system (buffer))
1241     {
1242       exit (1);
1243     }
1244
1245   if (strcmp (srcFileName, "temp") == 0)
1246     {
1247       /* rename "temp.cdb" to "firstRelFile.cdb" */
1248       char *f = strtok (Safe_strdup (relFiles[0]), ".");
1249       f = strcat (f, ".cdb");
1250       rename ("temp.cdb", f);
1251       srcFileName = NULL;
1252     }
1253 }
1254
1255 /*-----------------------------------------------------------------*/
1256 /* assemble - spawns the assembler with arguments                  */
1257 /*-----------------------------------------------------------------*/
1258 static void
1259 assemble (char **envp)
1260 {
1261     if (port->assembler.do_assemble) {
1262         port->assembler.do_assemble(asmOptions);
1263         return ;
1264     } else if (port->assembler.cmd) {
1265         buildCmdLine (buffer, port->assembler.cmd, srcFileName, NULL,
1266                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1267                       asmOptions);
1268     } else {
1269         buildCmdLine2 (buffer, port->assembler.mcmd);
1270     }
1271
1272     if (my_system (buffer)) {
1273         /* either system() or the assembler itself has reported an error
1274            perror ("Cannot exec assembler");
1275         */
1276         exit (1);
1277     }
1278 }
1279
1280 /*-----------------------------------------------------------------*/
1281 /* preProcess - spawns the preprocessor with arguments       */
1282 /*-----------------------------------------------------------------*/
1283 static int
1284 preProcess (char **envp)
1285 {
1286   preOutName = NULL;
1287
1288   if (!options.c1mode)
1289     {
1290       /* if using external stack define the macro */
1291       if (options.useXstack)
1292         addToList (preArgv, "-DSDCC_USE_XSTACK");
1293
1294       /* set the macro for stack autos  */
1295       if (options.stackAuto)
1296         addToList (preArgv, "-DSDCC_STACK_AUTO");
1297
1298       /* set the macro for stack autos  */
1299       if (options.stack10bit)
1300         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1301
1302       /* set the macro for no overlay  */
1303       if (options.noOverlay)
1304         addToList (preArgv, "-DSDCC_NOOVERLAY");
1305
1306       /* set the macro for large model  */
1307       switch (options.model)
1308         {
1309         case MODEL_LARGE:
1310           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1311           break;
1312         case MODEL_SMALL:
1313           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1314           break;
1315         case MODEL_COMPACT:
1316           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1317           break;
1318         case MODEL_MEDIUM:
1319           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1320           break;
1321         case MODEL_FLAT24:
1322           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1323           break;
1324         case MODEL_PAGE0:
1325           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1326           break;
1327         default:
1328           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1329           break;
1330         }
1331
1332       /* add port (processor information to processor */
1333       addToList (preArgv, "-DSDCC_{port}");
1334       addToList (preArgv, "-D__{port}");
1335
1336       /* standard include path */
1337       if (!options.nostdinc) {
1338         addToList (preArgv, "-I{includedir}");
1339       }
1340
1341       setMainValue ("cppextraopts", join(preArgv));
1342       
1343       if (!preProcOnly)
1344           preOutName = Safe_strdup (tempfilename ());
1345
1346       /* Have to set cppoutfilename to something, even if just pre-processing. */
1347       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1348         
1349       if (options.verbose)
1350         printf ("sdcc: Calling preprocessor...\n");
1351
1352       buildCmdLine2 (buffer, _preCmd);
1353
1354       if (my_system (buffer))
1355         {
1356           // @FIX: Dario Vecchio 03-05-2001
1357           if (preOutName)
1358             {
1359               unlink (preOutName);
1360               Safe_free (preOutName);
1361             }
1362           // EndFix
1363           exit (1);
1364         }
1365
1366       if (preProcOnly)
1367       {
1368         exit (0);
1369       }
1370     }
1371   else
1372     {
1373       preOutName = fullSrcFileName;
1374     }
1375
1376   yyin = fopen (preOutName, "r");
1377   if (yyin == NULL)
1378     {
1379       perror ("Preproc file not found\n");
1380       exit (1);
1381     }
1382
1383   return 0;
1384 }
1385
1386 static bool
1387 _setPaths (const char *pprefix)
1388 {
1389   /* Logic:
1390       Given the prefix and how the directories were layed out at
1391       configure time, see if the library and include directories are
1392       where expected.  If so, set.
1393   */
1394   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1395   strcpy (scratchFileName, pprefix);
1396   strcat (scratchFileName, buffer);
1397
1398   if (pathExists (scratchFileName))
1399     {
1400       setMainValue ("includedir", scratchFileName);
1401     }
1402   else
1403     {
1404       return FALSE;
1405     }
1406
1407   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1408   strcpy (scratchFileName, pprefix);
1409   strcat (scratchFileName, buffer);
1410
1411   if (pathExists (scratchFileName))
1412     {
1413       setMainValue ("libdir", scratchFileName);
1414     }
1415   else
1416     {
1417       return FALSE;
1418     }
1419
1420   return TRUE;
1421 }
1422
1423 static void
1424 _discoverPaths (const char *argv0)
1425 {
1426   /* Logic:
1427       1.  Try the SDCCDIR environment variable.
1428       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1429       and library paths with respect to that.  Note that under win32
1430       argv[0] is always the full path to the program.
1431       3.  If (1) and (2) fail, fall back to the compile time defaults.
1432
1433       Detecting assumes the same layout as when configured.  If the
1434       directories have been further moved about then discovery will
1435       fail.
1436   */
1437
1438   /* Some input cases:
1439         "c:\fish\sdcc\bin\sdcc"
1440         "../bin/sdcc"
1441         "/home/fish/bin/sdcc"
1442
1443       Note that ./sdcc is explicitly not supported as there isn't
1444       enough information.
1445   */
1446   /* bindir is handled differently to the lib and include directories.
1447      It's rather unfortunate, but required due to the different
1448      install and development layouts.  Logic is different as well.
1449      Sigh.
1450    */
1451   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1452     {
1453       strcpy (scratchFileName, argv0);
1454       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1455       setMainValue ("bindir", scratchFileName);
1456       ExePathList[0] = Safe_strdup (scratchFileName);
1457     }
1458   else if (getenv (SDCCDIR_NAME) != NULL)
1459     {
1460       getPathDifference (buffer, PREFIX, BINDIR);
1461       strcpy (scratchFileName, getenv (SDCCDIR_NAME));
1462       strcat (scratchFileName, buffer);
1463       setMainValue ("bindir", scratchFileName);
1464       ExePathList[0] = Safe_strdup (scratchFileName);
1465     }
1466   else
1467     {
1468       setMainValue ("bindir", BINDIR);
1469       ExePathList[0] = BINDIR;
1470     }
1471
1472   do 
1473     {
1474       /* Case 1 */
1475       if (getenv (SDCCDIR_NAME) != NULL)
1476         {
1477           if (_setPaths (getenv (SDCCDIR_NAME)))
1478             {
1479               /* Successfully set. */
1480               break;
1481             }
1482           else
1483             {
1484               /* Include and lib weren't where expected. */
1485             }
1486         }
1487       /* Case 2 */
1488       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1489         {
1490           char *pbase = getPrefixFromBinPath (argv0);
1491
1492           if (pbase == NULL)
1493             {
1494               /* A bad path.  Skip. */
1495             }
1496           else
1497             {
1498               if (_setPaths (pbase))
1499                 {
1500                   /* Successfully set. */
1501                   break;
1502                 }
1503               else
1504                 {
1505                   /* Include and lib weren't where expected. */
1506                 }
1507             }
1508         }
1509       /* Case 3 */
1510       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1511       setMainValue ("libdir", SDCC_LIB_DIR);
1512     } while (0);
1513 }
1514
1515 static void
1516 initValues (void)
1517 {
1518   populateMainValues (_baseValues);
1519   setMainValue ("port", port->target);
1520   setMainValue ("objext", port->linker.rel_ext);
1521   setMainValue ("asmext", port->assembler.file_ext);
1522
1523   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1524   setMainValue ("srcfilename", srcFileName ? srcFileName : "srcfilename");
1525 }
1526
1527 /*
1528  * main routine
1529  * initialises and calls the parser
1530  */
1531
1532 int
1533 main (int argc, char **argv, char **envp)
1534 {
1535   /* turn all optimizations off by default */
1536   memset (&optimize, 0, sizeof (struct optimize));
1537
1538   /*printVersionInfo (); */
1539
1540   if (NUM_PORTS==0) {
1541     fprintf (stderr, "Build error: no ports are enabled.\n");
1542     exit (1);
1543   }
1544
1545   _findPort (argc, argv);
1546 #ifdef JAMIN_DS390
1547   if (strcmp(port->target, "mcs51") == 0) {
1548     printf("DS390 jammed in A\n");
1549           _setPort ("ds390");
1550     ds390_jammed = 1;
1551   }
1552 #endif
1553   /* Initalise the port. */
1554   if (port->init)
1555     port->init ();
1556
1557   // Create a default exe search path from the path to the sdcc command
1558
1559
1560   setDefaultOptions ();
1561 #ifdef JAMIN_DS390
1562   if (ds390_jammed) {
1563     options.model = MODEL_SMALL;
1564     options.stack10bit=0;
1565   }
1566 #endif
1567   parseCmdLine (argc, argv);
1568
1569   /* if no input then printUsage & exit */
1570   if ((!options.c1mode && !srcFileName && !nrelFiles) || 
1571       (options.c1mode && !srcFileName && !options.out_name))
1572     {
1573       printUsage ();
1574       exit (0);
1575     }
1576
1577   initValues ();
1578   _discoverPaths (argv[0]);
1579
1580   if (srcFileName)
1581     {
1582
1583       initMem ();
1584
1585       port->finaliseOptions ();
1586       preProcess (envp);
1587
1588       initSymt ();
1589       initiCode ();
1590       initCSupport ();
1591       initBuiltIns();
1592       initPeepHole ();
1593
1594       if (options.verbose)
1595         printf ("sdcc: Generating code...\n");
1596
1597       yyparse ();
1598
1599       if (!fatalError)
1600         {
1601           if (TARGET_IS_PIC) {
1602             /* TSD PIC port hack - if the PIC port option is enabled
1603                and SDCC is used to generate PIC code, then we will
1604                generate .asm files in gpasm's format instead of SDCC's
1605                assembler's format
1606             */
1607 #if !OPT_DISABLE_PIC
1608             picglue ();
1609 #endif
1610           } else {
1611             glue ();
1612           }
1613
1614           if (fatalError)
1615             {
1616               // @FIX: Dario Vecchio 03-05-2001
1617               if (preOutName)
1618                 {
1619                   if (yyin && yyin != stdin)
1620                     fclose (yyin);
1621                   unlink (preOutName);
1622                   Safe_free (preOutName);
1623                 }
1624               // EndFix
1625               return 1;
1626             }
1627           if (!options.c1mode && !noAssemble)
1628             {
1629               if (options.verbose)
1630                 printf ("sdcc: Calling assembler...\n");
1631               assemble (envp);
1632             }
1633         }
1634       else
1635         {
1636           // @FIX: Dario Vecchio 03-05-2001
1637           if (preOutName)
1638             {
1639               if (yyin && yyin != stdin)
1640                 fclose (yyin);
1641               unlink (preOutName);
1642               Safe_free (preOutName);
1643             }
1644           // EndFix
1645           #if defined (__MINGW32__) || defined (__CYGWIN__) || defined (_MSC_VER)
1646           rm_tmpfiles();
1647           #endif
1648           return 1;
1649         }
1650
1651     }
1652
1653   closeDumpFiles();
1654
1655   if (cdbFile)
1656     fclose (cdbFile);
1657
1658   if (preOutName && !options.c1mode)
1659     {
1660       unlink (preOutName);
1661       Safe_free (preOutName);
1662     }
1663
1664   if (!options.cc_only &&
1665       !fatalError &&
1666       !noAssemble &&
1667       !options.c1mode &&
1668       (srcFileName || nrelFiles))
1669     {
1670       if (port->linker.do_link)
1671         port->linker.do_link ();
1672       else
1673         linkEdit (envp);
1674     }
1675
1676   if (yyin && yyin != stdin)
1677     fclose (yyin);
1678
1679   return 0;
1680
1681 }