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