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