* as/mcs51/lkmem.c: rflag is for DS390
[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                                 /* can be NULL while linking without compiling */
56 char *fullDstFileName;          /* full name for the output file; */
57                                 /* only given by -o, otherwise NULL */
58 char *dstFileName;              /* destination file name without extension */
59 char *dstPath = "";             /* path for the output files; */
60                                 /* "" is equivalent with cwd */
61 char *moduleName;               /* module name is source file without path and extension */
62                                 /* can be NULL while linking without compiling */
63 const char *preArgv[128];       /* pre-processor arguments  */
64 int currRegBank = 0;
65 int RegBankUsed[4]={1, 0, 0, 0};        /*JCF: Reg Bank 0 used by default*/
66 struct optimize optimize;
67 struct options options;
68 char *VersionString = SDCC_VERSION_STR;
69 int preProcOnly = 0;
70 int noAssemble = 0;
71 char *linkOptions[128];
72 const char *asmOptions[128];
73 char *libFiles[128];
74 int nlibFiles = 0;
75 char *libPaths[128];
76 int nlibPaths = 0;
77 char *relFiles[128];
78 int nrelFiles = 0;
79 bool verboseExec = FALSE;
80 char *preOutName;
81 bool noXinitOpt = FALSE;
82
83 /* uncomment JAMIN_DS390 to always override and use ds390 port
84   for mcs51 work.  This is temporary, for compatibility testing. */
85 /* #define JAMIN_DS390 */
86 #ifdef JAMIN_DS390
87 int ds390_jammed = 0;
88 #endif
89
90 // Globally accessible scratch buffer for file names.
91 char scratchFileName[PATH_MAX];
92 char buffer[PATH_MAX];
93
94 // In MSC VC6 default search path for exe's to path for this
95
96 char DefaultExePath[128];
97
98 #define OPTION_HELP     "-help"
99
100 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
101
102 #define OPTION_STACK_8BIT       "--stack-8bit"
103 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
104 #define OPTION_LARGE_MODEL      "--model-large"
105 #define OPTION_MEDIUM_MODEL     "--model-medium"
106 #define OPTION_SMALL_MODEL      "--model-small"
107 #define OPTION_FLAT24_MODEL     "--model-flat24"
108 #define OPTION_DUMP_ALL         "--dumpall"
109 #define OPTION_PEEP_FILE        "--peep-file"
110 #define OPTION_LIB_PATH         "--lib-path"
111 #define OPTION_XSTACK_LOC       "--xstack-loc"
112 #define OPTION_CALLEE_SAVES     "--callee-saves"
113 #define OPTION_STACK_LOC        "--stack-loc"
114 #define OPTION_XRAM_LOC         "--xram-loc"
115 #define OPTION_IRAM_SIZE        "--iram-size"
116 #define OPTION_VERSION          "--version"
117 #define OPTION_DATA_LOC         "--data-loc"
118 #define OPTION_CODE_LOC         "--code-loc"
119 #define OPTION_IDATA_LOC        "--idata-loc"
120 #define OPTION_NO_LOOP_INV      "--noinvariant"
121 #define OPTION_NO_LOOP_IND      "--noinduction"
122 #define OPTION_LESS_PEDANTIC    "--lesspedantic"
123 #define OPTION_NO_GCSE          "--nogcse"
124 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
125 #define OPTION_TINI_LIBID       "--tini-libid"
126 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
127
128 static const OPTION 
129 optionsTable[] = {
130     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
131     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
132     { 'd',  NULL,                   NULL, NULL },
133     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
134     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
135     { 'A',  NULL,                   NULL, NULL },
136     { 'U',  NULL,                   NULL, NULL },
137     { 'C',  NULL,                   NULL, "Preprocessor option" },
138     { 'M',  NULL,                   NULL, "Preprocessor option" },
139     { 'V',  NULL,                   &verboseExec, "Execute verbosely.  Show sub commands as they are run" },
140     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
141     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
142     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
143     { 'l',  NULL,                   NULL, "Include the given library in the link" },
144     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
145     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
146     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
147     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
148     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
149     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
150     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
151     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
152     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
153     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
154     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
155     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
156     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
157     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
158     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
159     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
160     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
161     { 0,    "--dumploop",           &options.dump_loop, NULL },
162     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
163     { 0,    "--dumpliverange",      &options.dump_range, NULL },
164     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
165     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
166     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
167     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
168     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
169     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
170     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
171     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
172     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
173     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
174     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
175     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
176     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
177     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
178     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
179     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
180     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
181     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
182     { 0,    "--nooverlay",          &options.noOverlay, NULL },
183     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
184     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
185     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
186     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
187     { 0,    "--peep-asm",           &options.asmpeep, NULL },
188     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
189     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
190     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
191     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The input is preprocessed code, the output is assembly code." },
192     { 0,    "--help",               NULL, "Display this help" },
193     { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
194     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
195     { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
196     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
197     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
198     { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
199     { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
200     { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
201     { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
202     { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
203     { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
204     { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
205     { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
206     { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
207     { 0,    OPTION_NO_XINIT_OPT,    &noXinitOpt, "don't memcpy initialized xram from code"},
208     /* End of options */
209     { 0,    NULL }
210 };
211
212 /** Table of all unsupported options and help text to display when one
213     is used.
214 */
215 typedef struct {
216     /** shortOpt as in OPTIONS. */
217     char shortOpt;
218     /** longOpt as in OPTIONS. */
219     const char *longOpt;
220     /** Message to display inside W_UNSUPPORTED_OPT when this option
221         is used. */
222     const char *message;
223 } UNSUPPORTEDOPT;
224
225 static const UNSUPPORTEDOPT 
226 unsupportedOptTable[] = {
227     { 'X',  NULL,       "use --xstack-loc instead" },
228     { 'x',  NULL,       "use --xstack instead" },
229     { 'i',  NULL,       "use --idata-loc instead" },
230     { 'r',  NULL,       "use --xdata-loc instead" },
231     { 's',  NULL,       "use --code-loc instead" },
232     { 'Y',  NULL,       "use -I instead" }
233 };
234
235 /** List of all default constant macros.
236  */
237 static const char *_baseValues[] = {
238   "cpp", "{bindir}{sep}sdcpp",
239   "cppextraopts", "",
240   /* Path seperator character */
241   "sep", DIR_SEPARATOR_STRING,
242   NULL
243 };
244
245 static const char *_preCmd = "{cpp} -nostdinc -Wall -lang-c++ -DSDCC=1 {cppextraopts} {fullsrcfilename} {cppoutfilename}";
246
247 PORT *port;
248
249 static PORT *_ports[] =
250 {
251 #if !OPT_DISABLE_MCS51
252   &mcs51_port,
253 #endif
254 #if !OPT_DISABLE_GBZ80
255   &gbz80_port,
256 #endif
257 #if !OPT_DISABLE_Z80
258   &z80_port,
259 #endif
260 #if !OPT_DISABLE_AVR
261   &avr_port,
262 #endif
263 #if !OPT_DISABLE_DS390
264   &ds390_port,
265 #endif
266 #if !OPT_DISABLE_PIC
267   &pic_port,
268 #endif
269 #if !OPT_DISABLE_TININative
270   &tininative_port,
271 #endif
272 #if !OPT_DISABLE_XA51
273   &xa51_port,
274 #endif
275 };
276
277 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
278
279 #if !OPT_DISABLE_PIC
280 extern void picglue ();
281 #endif
282
283 /** Sets the port to the one given by the command line option.
284     @param    The name minus the option (eg 'mcs51')
285     @return     0 on success.
286 */
287 static void
288 _setPort (const char *name)
289 {
290   int i;
291   for (i = 0; i < NUM_PORTS; i++)
292     {
293       if (!strcmp (_ports[i]->target, name))
294         {
295           port = _ports[i];
296           return;
297         }
298     }
299   /* Error - didnt find */
300   werror (E_UNKNOWN_TARGET, name);
301   exit (1);
302 }
303
304 /* Override the default processor with the one specified 
305  * on the command line */
306 static void
307 _setProcessor (char *_processor)
308 {
309   port->processor = _processor;
310   fprintf(stderr,"Processor: %s\n",_processor);
311 }
312
313 static void
314 _validatePorts (void)
315 {
316   int i;
317   for (i = 0; i < NUM_PORTS; i++)
318     {
319       if (_ports[i]->magic != PORT_MAGIC)
320         {
321           /* Uncomment this line to debug which port is causing the problem
322            * (the target name is close to the beginning of the port struct 
323            * and probably can be accessed just fine). */
324           fprintf(stderr,"%s :",_ports[i]->target);
325           wassertl (0, "Port definition structure is incomplete");
326         }
327     }
328 }
329
330 /* search through the command line options for the port */
331 static void
332 _findPort (int argc, char **argv)
333 {
334   _validatePorts ();
335
336   while (argc--)
337     {
338       if (!strncmp (*argv, "-m", 2))
339         {
340           _setPort (*argv + 2);
341           return;
342         }
343       argv++;
344     }
345   /* Use the first in the list */
346   port = _ports[0];
347 }
348
349 /* search through the command line options for the processor */
350 static void
351 _findProcessor (int argc, char **argv)
352 {
353   while (argc--)
354     {
355       if (!strncmp (*argv, "-p", 2))
356         {
357           _setProcessor (*argv + 2);
358           return;
359         }
360       argv++;
361     }
362
363   /* no error if processor was not specified. */
364 }
365
366 /*-----------------------------------------------------------------*/
367 /* printVersionInfo - prints the version info        */
368 /*-----------------------------------------------------------------*/
369 void
370 printVersionInfo ()
371 {
372   int i;
373
374   fprintf (stderr,
375            "SDCC : ");
376   for (i = 0; i < NUM_PORTS; i++)
377     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
378
379   fprintf (stderr, " %s"
380 #ifdef SDCC_SUB_VERSION_STR
381            "/" SDCC_SUB_VERSION_STR
382 #endif
383            " (" __DATE__ ")"
384 #ifdef __CYGWIN__
385            " (CYGWIN)\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;
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   if (my_system (buffer))
1354     {
1355       exit (1);
1356     }
1357   /* TODO: most linker don't have a -o parameter */
1358   /* -o option overrides default name? */
1359   if (fullDstFileName)
1360     {
1361       char *p, *q;
1362       /* the linked file gets the name of the first modul */
1363       if (fullSrcFileName)
1364         {
1365           strcpy (scratchFileName, dstFileName);
1366           p = strlen (scratchFileName) + scratchFileName;
1367         }
1368       else
1369         {
1370           strcpy (scratchFileName, relFiles[0]);
1371           /* strip "rel" extension */
1372           p = strrchr (scratchFileName, '.') + 1;
1373         }
1374       strcpy (p, options.out_fmt ? "S19" : "ihx");
1375       rename (scratchFileName, fullDstFileName);
1376
1377       q = strrchr (fullDstFileName, '.');
1378       if (q)
1379         {
1380           /* point after the '.' of the extension */
1381           q++;
1382         }
1383       else
1384         {
1385           /* no extension: append new extensions */
1386           q = strlen (fullDstFileName) + fullDstFileName;
1387         }
1388       strcpy (p, "map");
1389       strcpy (q, "map");
1390       rename (scratchFileName, fullDstFileName);
1391       strcpy (p, "mem");
1392       strcpy (q, "mem");
1393       rename (scratchFileName, fullDstFileName);
1394     }
1395 }
1396
1397 /*-----------------------------------------------------------------*/
1398 /* assemble - spawns the assembler with arguments                  */
1399 /*-----------------------------------------------------------------*/
1400 static void
1401 assemble (char **envp)
1402 {
1403     /* build assembler output filename */
1404
1405     /* -o option overrides default name? */
1406     if (options.cc_only && fullDstFileName) {
1407         strcpy (scratchFileName, fullDstFileName);
1408     } else {
1409         /* the assembled file gets the name of the first modul */
1410         strcpy (scratchFileName, dstFileName);
1411         strcat (scratchFileName, port->linker.rel_ext);
1412     }
1413
1414     if (port->assembler.do_assemble) {
1415         port->assembler.do_assemble(asmOptions);
1416         return ;
1417     } else if (port->assembler.cmd) {
1418         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1419                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1420                       asmOptions);
1421     } else {
1422         buildCmdLine2 (buffer, port->assembler.mcmd);
1423     }
1424
1425     if (my_system (buffer)) {
1426         /* either system() or the assembler itself has reported an error
1427            perror ("Cannot exec assembler");
1428         */
1429         exit (1);
1430     }
1431     /* TODO: most assembler don't have a -o parameter */
1432     /* -o option overrides default name? */
1433     if (options.cc_only && fullDstFileName) {
1434         strcpy (scratchFileName, dstFileName);
1435         strcat (scratchFileName, port->linker.rel_ext);
1436         rename (scratchFileName, fullDstFileName);
1437     }
1438 }
1439
1440 /*-----------------------------------------------------------------*/
1441 /* preProcess - spawns the preprocessor with arguments       */
1442 /*-----------------------------------------------------------------*/
1443 static int
1444 preProcess (char **envp)
1445 {
1446   preOutName = NULL;
1447
1448   if (!options.c1mode)
1449     {
1450       /* if using external stack define the macro */
1451       if (options.useXstack)
1452         addToList (preArgv, "-DSDCC_USE_XSTACK");
1453
1454       /* set the macro for stack autos  */
1455       if (options.stackAuto)
1456         addToList (preArgv, "-DSDCC_STACK_AUTO");
1457
1458       /* set the macro for stack autos  */
1459       if (options.stack10bit)
1460         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1461
1462       /* set the macro for no overlay  */
1463       if (options.noOverlay)
1464         addToList (preArgv, "-DSDCC_NOOVERLAY");
1465
1466       /* set the macro for large model  */
1467       switch (options.model)
1468         {
1469         case MODEL_LARGE:
1470           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1471           break;
1472         case MODEL_SMALL:
1473           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1474           break;
1475         case MODEL_COMPACT:
1476           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1477           break;
1478         case MODEL_MEDIUM:
1479           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1480           break;
1481         case MODEL_FLAT24:
1482           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1483           break;
1484         case MODEL_PAGE0:
1485           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1486           break;
1487         default:
1488           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1489           break;
1490         }
1491
1492       /* add port (processor information to processor */
1493       addToList (preArgv, "-DSDCC_{port}");
1494       addToList (preArgv, "-D__{port}");
1495
1496       /* standard include path */
1497       if (!options.nostdinc) {
1498         addToList (preArgv, "-I{includedir}");
1499       }
1500
1501       setMainValue ("cppextraopts", join(preArgv));
1502
1503       if (preProcOnly)
1504         {
1505           if (fullDstFileName)
1506               preOutName = Safe_strdup (fullDstFileName);
1507         }
1508       else
1509           preOutName = Safe_strdup (tempfilename ());
1510
1511       /* Have to set cppoutfilename to something, even if just pre-processing. */
1512       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1513
1514       if (options.verbose)
1515         printf ("sdcc: Calling preprocessor...\n");
1516
1517       buildCmdLine2 (buffer, _preCmd);
1518
1519       if (my_system (buffer))
1520         {
1521           // @FIX: Dario Vecchio 03-05-2001
1522           if (preOutName)
1523             {
1524               unlink (preOutName);
1525               Safe_free (preOutName);
1526             }
1527           // EndFix
1528           exit (1);
1529         }
1530
1531       if (preProcOnly)
1532       {
1533         exit (0);
1534       }
1535     }
1536   else
1537     {
1538       preOutName = fullSrcFileName;
1539     }
1540
1541   yyin = fopen (preOutName, "r");
1542   if (yyin == NULL)
1543     {
1544       perror ("Preproc file not found\n");
1545       exit (1);
1546     }
1547
1548   return 0;
1549 }
1550
1551 static bool
1552 _setPaths (const char *pprefix)
1553 {
1554   /* Logic:
1555       Given the prefix and how the directories were layed out at
1556       configure time, see if the library and include directories are
1557       where expected.  If so, set.
1558   */
1559   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1560   strcpy (scratchFileName, pprefix);
1561   strcat (scratchFileName, buffer);
1562
1563   if (pathExists (scratchFileName))
1564     {
1565       setMainValue ("includedir", scratchFileName);
1566     }
1567   else
1568     {
1569       return FALSE;
1570     }
1571
1572   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1573   strcpy (scratchFileName, pprefix);
1574   strcat (scratchFileName, buffer);
1575
1576   if (pathExists (scratchFileName))
1577     {
1578       setMainValue ("libdir", scratchFileName);
1579     }
1580   else
1581     {
1582       return FALSE;
1583     }
1584
1585   return TRUE;
1586 }
1587
1588 static void
1589 _discoverPaths (const char *argv0)
1590 {
1591   /* Logic:
1592       1.  Try the SDCCDIR environment variable.
1593       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1594       and library paths with respect to that.  Note that under win32
1595       argv[0] is always the full path to the program.
1596       3.  If (1) and (2) fail, fall back to the compile time defaults.
1597
1598       Detecting assumes the same layout as when configured.  If the
1599       directories have been further moved about then discovery will
1600       fail.
1601   */
1602
1603   /* Some input cases:
1604         "c:\fish\sdcc\bin\sdcc"
1605         "../bin/sdcc"
1606         "/home/fish/bin/sdcc"
1607
1608       Note that ./sdcc is explicitly not supported as there isn't
1609       enough information.
1610   */
1611   /* bindir is handled differently to the lib and include directories.
1612      It's rather unfortunate, but required due to the different
1613      install and development layouts.  Logic is different as well.
1614      Sigh.
1615    */
1616   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1617     {
1618       strcpy (scratchFileName, argv0);
1619       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1620       setMainValue ("bindir", scratchFileName);
1621       ExePathList[0] = Safe_strdup (scratchFileName);
1622     }
1623   else if (getenv (SDCCDIR_NAME) != NULL)
1624     {
1625       getPathDifference (buffer, PREFIX, BINDIR);
1626       strcpy (scratchFileName, getenv (SDCCDIR_NAME));
1627       strcat (scratchFileName, buffer);
1628       setMainValue ("bindir", scratchFileName);
1629       ExePathList[0] = Safe_strdup (scratchFileName);
1630     }
1631   else
1632     {
1633       setMainValue ("bindir", BINDIR);
1634       ExePathList[0] = BINDIR;
1635     }
1636
1637   do 
1638     {
1639       /* Case 1 */
1640       if (getenv (SDCCDIR_NAME) != NULL)
1641         {
1642           if (_setPaths (getenv (SDCCDIR_NAME)))
1643             {
1644               /* Successfully set. */
1645               break;
1646             }
1647           else
1648             {
1649               /* Include and lib weren't where expected. */
1650             }
1651         }
1652       /* Case 2 */
1653       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1654         {
1655           char *pbase = getPrefixFromBinPath (argv0);
1656
1657           if (pbase == NULL)
1658             {
1659               /* A bad path.  Skip. */
1660             }
1661           else
1662             {
1663               if (_setPaths (pbase))
1664                 {
1665                   /* Successfully set. */
1666                   break;
1667                 }
1668               else
1669                 {
1670                   /* Include and lib weren't where expected. */
1671                 }
1672             }
1673         }
1674       /* Case 3 */
1675       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1676       setMainValue ("libdir", SDCC_LIB_DIR);
1677     } while (0);
1678 }
1679
1680 static void
1681 initValues (void)
1682 {
1683   populateMainValues (_baseValues);
1684   setMainValue ("port", port->target);
1685   setMainValue ("objext", port->linker.rel_ext);
1686   setMainValue ("asmext", port->assembler.file_ext);
1687
1688   setMainValue ("dstfilename", dstFileName);
1689   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1690   
1691   if (options.cc_only && fullDstFileName)
1692     /* compile + assemble and -o given: -o specifies name of object file */
1693     {
1694       setMainValue ("objdstfilename", fullDstFileName);
1695     }
1696   else
1697     {
1698       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1699     }
1700   if (fullDstFileName)
1701     /* if we're linking, -o gives the final file name */
1702     {
1703       setMainValue ("linkdstfilename", fullDstFileName);
1704     }
1705   else
1706     {
1707       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1708     }
1709
1710 }
1711
1712 /*
1713  * main routine
1714  * initialises and calls the parser
1715  */
1716
1717 int
1718 main (int argc, char **argv, char **envp)
1719 {
1720   /* turn all optimizations off by default */
1721   memset (&optimize, 0, sizeof (struct optimize));
1722
1723   /*printVersionInfo (); */
1724
1725   if (NUM_PORTS==0) {
1726     fprintf (stderr, "Build error: no ports are enabled.\n");
1727     exit (1);
1728   }
1729
1730   /* install atexit handler */
1731   atexit(rm_tmpfiles);
1732
1733   /* Before parsing the command line options, do a 
1734    * search for the port and processor and initialize
1735    * them if they're found. (We can't gurantee that these
1736    * will be the first options specified).
1737    */
1738
1739   _findPort (argc, argv);
1740
1741 #ifdef JAMIN_DS390
1742   if (strcmp(port->target, "mcs51") == 0) {
1743     printf("DS390 jammed in A\n");
1744           _setPort ("ds390");
1745     ds390_jammed = 1;
1746   }
1747 #endif
1748
1749   _findProcessor (argc, argv);
1750
1751   /* Initalise the port. */
1752   if (port->init)
1753     port->init ();
1754
1755   // Create a default exe search path from the path to the sdcc command
1756
1757
1758   setDefaultOptions ();
1759 #ifdef JAMIN_DS390
1760   if (ds390_jammed) {
1761     options.model = MODEL_SMALL;
1762     options.stack10bit=0;
1763   }
1764 #endif
1765   parseCmdLine (argc, argv);
1766
1767   /* if no input then printUsage & exit */
1768   if ((!options.c1mode && !fullSrcFileName && !nrelFiles) ||
1769       (options.c1mode && !fullSrcFileName))
1770     {
1771       printUsage ();
1772       exit (0);
1773     }
1774
1775   initValues ();
1776   _discoverPaths (argv[0]);
1777
1778   /* initMem() is expensive, but
1779      initMem() must called before port->finaliseOptions ().
1780      And the z80 port needs port->finaliseOptions(),
1781      even if we're only linking. */
1782   initMem ();
1783   port->finaliseOptions ();
1784
1785   if (fullSrcFileName)
1786     {
1787       preProcess (envp);
1788
1789       initSymt ();
1790       initiCode ();
1791       initCSupport ();
1792       initBuiltIns();
1793       initPeepHole ();
1794
1795       if (options.verbose)
1796         printf ("sdcc: Generating code...\n");
1797
1798       yyparse ();
1799
1800       if (fatalError) {
1801         // @FIX: Dario Vecchio 03-05-2001
1802         if (preOutName) {
1803           if (yyin && yyin != stdin)
1804             fclose (yyin);
1805           unlink (preOutName);
1806           Safe_free (preOutName);
1807         }
1808         // EndFix
1809         return 1;
1810       }
1811
1812       if (TARGET_IS_PIC) {
1813         /* TSD PIC port hack - if the PIC port option is enabled
1814            and SDCC is used to generate PIC code, then we will
1815            generate .asm files in gpasm's format instead of SDCC's
1816            assembler's format
1817         */
1818 #if !OPT_DISABLE_PIC
1819         picglue ();
1820 #endif
1821       }
1822       else {
1823         glue ();
1824       }
1825
1826       if (!options.c1mode && !noAssemble)
1827         {
1828           if (options.verbose)
1829             printf ("sdcc: Calling assembler...\n");
1830           assemble (envp);
1831         }
1832     }
1833
1834   closeDumpFiles();
1835
1836   if (cdbFile)
1837     fclose (cdbFile);
1838
1839   if (yyin && yyin != stdin)
1840     fclose (yyin);
1841
1842   if (preOutName && !options.c1mode)
1843     {
1844       unlink (preOutName);
1845       Safe_free (preOutName);
1846     }
1847
1848   if (!options.cc_only &&
1849       !fatalError &&
1850       !noAssemble &&
1851       !options.c1mode &&
1852       (fullSrcFileName || nrelFiles))
1853     {
1854       if (port->linker.do_link)
1855         port->linker.do_link ();
1856       else
1857         linkEdit (envp);
1858     }
1859
1860   return 0;
1861 }