1d544f7bc9b8777cd38d7e782b8ad12f357c66b5
[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 -std=c99 -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                 options.xram_size_set = TRUE;
914                 continue;
915             }
916
917           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
918             {
919                 options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
920                 continue;
921             }
922
923           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
924             {
925                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
926                 continue;
927             }
928
929           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
930             {
931                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
932                 continue;
933             }
934
935           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
936             {
937                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
938                 continue;
939             }
940
941           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
942             {
943               optimize.global_cse = 0;
944               continue;
945             }
946
947           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
948             {
949               optimize.loopInvariant = 0;
950               continue;
951             }
952
953           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
954             {
955               optimize.loopInduction = 0;
956               continue;
957             }
958
959           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
960             {
961               options.lessPedantic = 1;
962               setErrorLogLevel(ERROR_LEVEL_WARNING);
963               continue;
964             }
965
966           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
967             {
968               options.shortis8bits=1;
969               continue;
970             }
971
972           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
973             {
974                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
975                 continue;
976             }
977           
978           if (!port->parseOption (&argc, argv, &i))
979             {
980               werror (W_UNKNOWN_OPTION, argv[i]);
981             }
982           else
983             {
984               continue;
985             }
986         }
987
988       /* if preceded by  '-' then option */
989       if (*argv[i] == '-')
990         {
991           switch (argv[i][1])
992             {
993             case 'h':
994               verifyShortOption(argv[i]);
995
996               printUsage ();
997               exit (0);
998               break;
999
1000             case 'm':
1001               /* Used to select the port. But this has already been done. */
1002               break;
1003
1004             case 'p':
1005               /* Used to select the processor in port. But this has
1006                * already been done. */
1007               break;
1008
1009             case 'c':
1010               verifyShortOption(argv[i]);
1011
1012               options.cc_only = 1;
1013               break;
1014
1015             case 'L':
1016                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
1017                 break;
1018
1019             case 'l':
1020                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
1021                 break;
1022             
1023             case 'o':
1024               {
1025                 char *p;
1026
1027                 /* copy the file name into the buffer */
1028                 strcpy (buffer, getStringArg("-o", argv, &i, argc));
1029                 /* point to last character */
1030                 p = buffer + strlen (buffer) - 1;
1031                 if (*p == DIR_SEPARATOR_CHAR)
1032                   {
1033                     /* only output path specified */
1034                     dstPath = Safe_strdup (buffer);
1035                     fullDstFileName = NULL;
1036                   }
1037                 else
1038                   {
1039                     fullDstFileName = Safe_strdup (buffer);
1040
1041                     /* get rid of the "."-extension */
1042
1043                     /* is there a dot at all? */
1044                     if (strrchr (buffer, '.') &&
1045                         /* is the dot in the filename, not in the path? */
1046                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1047                       *strrchr (buffer, '.') = '\0';
1048
1049                     dstFileName = Safe_strdup (buffer);
1050
1051                     /* strip module name to get path */
1052                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1053                     if (p)
1054                       {
1055                         /* path with trailing / */
1056                         p[1] = '\0';
1057                         dstPath = Safe_strdup (buffer);
1058                       }
1059                   }
1060                 break;
1061               }
1062
1063             case 'W':
1064               /* pre-processer options */
1065               if (argv[i][2] == 'p')
1066                 {
1067                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
1068                 }
1069               /* linker options */
1070               else if (argv[i][2] == 'l')
1071                 {
1072                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1073                 }
1074               /* assembler options */
1075               else if (argv[i][2] == 'a')
1076                 {
1077                   parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
1078                 }
1079               else
1080                 {
1081                   werror (W_UNKNOWN_OPTION, argv[i]);
1082                 }
1083               break;
1084
1085             case 'v':
1086               verifyShortOption(argv[i]);
1087
1088               printVersionInfo ();
1089               exit (0);
1090               break;
1091
1092               /* preprocessor options */
1093             case 'M':
1094               {
1095                 preProcOnly = 1;
1096                 addToList (preArgv, "-M");
1097                 break;
1098               }
1099             case 'C':
1100               {
1101                 addToList (preArgv, "-C");
1102                 break;
1103               }
1104             case 'd':
1105             case 'D':
1106             case 'I':
1107             case 'A':
1108             case 'U':
1109               {
1110                 char sOpt = argv[i][1];
1111                 char *rest;
1112
1113                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1114                   {
1115                     i++;
1116                     if (i >= argc)
1117                       {
1118                           /* No argument. */
1119                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1120                           break;
1121                       }
1122                     else
1123                       {
1124                           rest = argv[i];
1125                       }
1126                   }
1127                 else
1128                   rest = &argv[i][2];
1129
1130                 if (sOpt == 'Y')
1131                   sOpt = 'I';
1132
1133                 sprintf (buffer, "-%c%s", sOpt, rest);
1134                 addToList (preArgv, buffer);
1135               }
1136               break;
1137
1138             default:
1139               if (!port->parseOption (&argc, argv, &i))
1140                 werror (W_UNKNOWN_OPTION, argv[i]);
1141             }
1142           continue;
1143         }
1144
1145       if (!port->parseOption (&argc, argv, &i))
1146         {
1147           /* no option must be a filename */
1148            processFile (argv[i]);
1149         }
1150     }
1151
1152   /* if no dstFileName given with -o, we've to find one: */
1153   if (!dstFileName)
1154     {
1155       /* use the modulename from the C-source */
1156       if (fullSrcFileName)
1157         {
1158           dstFileName = Safe_alloc (strlen (dstPath) + strlen (moduleName) + 1);
1159           strcpy (dstFileName, dstPath);
1160           strcat (dstFileName, moduleName);
1161         }
1162       /* use the modulename from the first object file */
1163       else if (nrelFiles >= 1)
1164         {
1165           char *objectName;
1166
1167           strcpy (buffer, relFiles[0]);
1168           /* remove extension (it must be .rel) */
1169           *strrchr (buffer, '.') = '\0';
1170           /* remove path */
1171           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1172           if (objectName)
1173             {
1174               ++objectName;
1175             }
1176           else
1177             {
1178               objectName = buffer;
1179             }
1180           dstFileName = Safe_alloc (strlen (dstPath) + strlen (objectName) + 1);
1181           strcpy (dstFileName, dstPath);
1182           strcat (dstFileName, objectName);
1183         }
1184       /* else no module given: help text is displayed */
1185     }
1186
1187   /* set up external stack location if not explicitly specified */
1188   if (!options.xstack_loc)
1189     options.xstack_loc = options.xdata_loc;
1190
1191   /* if debug option is set the open the cdbFile */
1192   if (options.debug && fullSrcFileName)
1193     {
1194       sprintf (scratchFileName, "%s.adb", dstFileName); //JCF: Nov 30, 2002
1195       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1196         werror (E_FILE_OPEN_ERR, scratchFileName);
1197       else
1198         {
1199           /* add a module record */
1200           fprintf (cdbFile, "M:%s\n", moduleName);
1201         }
1202     }
1203   return 0;
1204 }
1205
1206 /*-----------------------------------------------------------------*/
1207 /* linkEdit : - calls the linkage editor  with options             */
1208 /*-----------------------------------------------------------------*/
1209 static void
1210 linkEdit (char **envp)
1211 {
1212   FILE *lnkfile;
1213   char *segName, *c;
1214   int i, system_ret;
1215
1216   /* first we need to create the <filename>.lnk file */
1217   sprintf (scratchFileName, "%s.lnk", dstFileName);
1218   if (!(lnkfile = fopen (scratchFileName, "w")))
1219     {
1220       werror (E_FILE_OPEN_ERR, scratchFileName);
1221       exit (1);
1222     }
1223
1224   /* now write the options.  JCF: added option 'y' */
1225   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1226
1227   /* if iram size specified */
1228   if (options.iram_size)
1229     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1230
1231   /* if xram size specified */
1232   if (options.xram_size_set)
1233     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1234
1235   /* if code size specified */
1236   if (options.code_size)
1237     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1238
1239   if (options.debug)
1240     fprintf (lnkfile, "-z\n");
1241
1242 #define WRITE_SEG_LOC(N, L) \
1243     segName = Safe_strdup(N); \
1244     c = strtok(segName, " \t"); \
1245     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1246     if (segName) { Safe_free(segName); }
1247
1248   /* code segment start */
1249   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1250
1251   /* data segment start */
1252   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1253           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1254   }
1255
1256   /* xdata start */
1257   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1258
1259   /* indirect data */
1260   if (IDATA_NAME) {
1261     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1262   }
1263
1264   /* bit segment start */
1265   WRITE_SEG_LOC (BIT_NAME, 0);
1266
1267   /* JCF: stack start */
1268   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1269         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1270   }
1271
1272   /* add the extra linker options */
1273   for (i = 0; linkOptions[i]; i++)
1274     fprintf (lnkfile, "%s\n", linkOptions[i]);
1275
1276   /* other library paths if specified */
1277   for (i = 0; i < nlibPaths; i++)
1278     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1279
1280   /* standard library path */
1281   if (!options.nostdlib)
1282     {
1283       switch (options.model)
1284         {
1285         case MODEL_SMALL:
1286           c = "small";
1287           break;
1288         case MODEL_LARGE:
1289           c = "large";
1290           break;
1291         case MODEL_FLAT24:
1292           /* c = "flat24"; */
1293           c = "ds390";
1294           break;
1295         case MODEL_PAGE0:
1296           c = "xa51";
1297           break;
1298         default:
1299           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1300           c = "unknown";
1301           break;
1302         }
1303       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1304
1305       /* standard library files */
1306 #if !OPT_DISABLE_DS390
1307       if (options.model == MODEL_FLAT24)
1308         {
1309           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1310         }
1311 #endif
1312
1313 #if !OPT_DISABLE_XA51 
1314 #ifdef STD_XA51_LIB
1315       if (options.model == MODEL_PAGE0)
1316         {
1317           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1318         }
1319 #endif
1320 #endif
1321       fprintf (lnkfile, "-l %s\n", STD_LIB);
1322       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1323       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1324       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1325     }
1326
1327   /* additional libraries if any */
1328   for (i = 0; i < nlibFiles; i++)
1329     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1330
1331   /* put in the object files */
1332   if (fullSrcFileName)
1333     fprintf (lnkfile, "%s ", dstFileName);
1334
1335   for (i = 0; i < nrelFiles; i++)
1336     fprintf (lnkfile, "%s\n", relFiles[i]);
1337
1338   fprintf (lnkfile, "\n-e\n");
1339   fclose (lnkfile);
1340
1341   if (options.verbose)
1342     printf ("sdcc: Calling linker...\n");
1343
1344   /* build linker output filename */
1345
1346   /* -o option overrides default name? */
1347   if (fullDstFileName)
1348     {
1349       strcpy (scratchFileName, fullDstFileName);
1350     }
1351   else
1352     {
1353       /* the linked file gets the name of the first modul */
1354       if (fullSrcFileName)
1355         {
1356           strcpy (scratchFileName, dstFileName);
1357         }
1358       else
1359         {
1360           strcpy (scratchFileName, relFiles[0]);
1361           /* strip ".rel" extension */
1362           *strrchr (scratchFileName, '.') = '\0';
1363         }
1364       strcat (scratchFileName, options.out_fmt ? ".S19" : ".ihx");
1365     }
1366
1367   if (port->linker.cmd)
1368     {
1369       char buffer2[PATH_MAX];
1370       buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
1371       buildCmdLine2 (buffer, buffer2);
1372     }
1373   else
1374     {
1375       buildCmdLine2 (buffer, port->linker.mcmd);
1376     }
1377
1378   system_ret = my_system (buffer);
1379   /* TODO: most linker don't have a -o parameter */
1380   /* -o option overrides default name? */
1381   if (fullDstFileName)
1382     {
1383       char *p, *q;
1384       /* the linked file gets the name of the first modul */
1385       if (fullSrcFileName)
1386         {
1387           strcpy (scratchFileName, dstFileName);
1388           p = strlen (scratchFileName) + scratchFileName;
1389         }
1390       else
1391         {
1392           strcpy (scratchFileName, relFiles[0]);
1393           /* strip "rel" extension */
1394           p = strrchr (scratchFileName, '.') + 1;
1395         }
1396       strcpy (p, options.out_fmt ? "S19" : "ihx");
1397       rename (scratchFileName, fullDstFileName);
1398
1399       q = strrchr (fullDstFileName, '.');
1400       if (q)
1401         {
1402           /* point after the '.' of the extension */
1403           q++;
1404         }
1405       else
1406         {
1407           /* no extension: append new extensions */
1408           q = strlen (fullDstFileName) + fullDstFileName;
1409         }
1410       strcpy (p, "map");
1411       strcpy (q, "map");
1412       rename (scratchFileName, fullDstFileName);
1413       strcpy (p, "mem");
1414       strcpy (q, "mem");
1415       rename (scratchFileName, fullDstFileName);
1416     }
1417   if (system_ret)
1418     {
1419       exit (1);
1420     }
1421 }
1422
1423 /*-----------------------------------------------------------------*/
1424 /* assemble - spawns the assembler with arguments                  */
1425 /*-----------------------------------------------------------------*/
1426 static void
1427 assemble (char **envp)
1428 {
1429     /* build assembler output filename */
1430
1431     /* -o option overrides default name? */
1432     if (options.cc_only && fullDstFileName) {
1433         strcpy (scratchFileName, fullDstFileName);
1434     } else {
1435         /* the assembled file gets the name of the first modul */
1436         strcpy (scratchFileName, dstFileName);
1437         strcat (scratchFileName, port->linker.rel_ext);
1438     }
1439
1440     if (port->assembler.do_assemble) {
1441         port->assembler.do_assemble(asmOptions);
1442         return ;
1443     } else if (port->assembler.cmd) {
1444         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1445                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1446                       asmOptions);
1447     } else {
1448         buildCmdLine2 (buffer, port->assembler.mcmd);
1449     }
1450
1451     if (my_system (buffer)) {
1452         /* either system() or the assembler itself has reported an error
1453            perror ("Cannot exec assembler");
1454         */
1455         exit (1);
1456     }
1457     /* TODO: most assembler don't have a -o parameter */
1458     /* -o option overrides default name? */
1459     if (options.cc_only && fullDstFileName) {
1460         strcpy (scratchFileName, dstFileName);
1461         strcat (scratchFileName, port->linker.rel_ext);
1462         rename (scratchFileName, fullDstFileName);
1463     }
1464 }
1465
1466 /*-----------------------------------------------------------------*/
1467 /* preProcess - spawns the preprocessor with arguments       */
1468 /*-----------------------------------------------------------------*/
1469 static int
1470 preProcess (char **envp)
1471 {
1472   preOutName = NULL;
1473
1474   if (!options.c1mode)
1475     {
1476       /* if using external stack define the macro */
1477       if (options.useXstack)
1478         addToList (preArgv, "-DSDCC_USE_XSTACK");
1479
1480       /* set the macro for stack autos  */
1481       if (options.stackAuto)
1482         addToList (preArgv, "-DSDCC_STACK_AUTO");
1483
1484       /* set the macro for stack autos  */
1485       if (options.stack10bit)
1486         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1487
1488       /* set the macro for no overlay  */
1489       if (options.noOverlay)
1490         addToList (preArgv, "-DSDCC_NOOVERLAY");
1491
1492       /* set the macro for large model  */
1493       switch (options.model)
1494         {
1495         case MODEL_LARGE:
1496           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1497           break;
1498         case MODEL_SMALL:
1499           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1500           break;
1501         case MODEL_COMPACT:
1502           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1503           break;
1504         case MODEL_MEDIUM:
1505           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1506           break;
1507         case MODEL_FLAT24:
1508           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1509           break;
1510         case MODEL_PAGE0:
1511           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1512           break;
1513         default:
1514           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1515           break;
1516         }
1517
1518       /* add port (processor information to processor */
1519       addToList (preArgv, "-DSDCC_{port}");
1520       addToList (preArgv, "-D__{port}");
1521
1522       /* standard include path */
1523       if (!options.nostdinc) {
1524         addToList (preArgv, "-I{includedir}");
1525       }
1526
1527       setMainValue ("cppextraopts", join(preArgv));
1528
1529       if (preProcOnly)
1530         {
1531           if (fullDstFileName)
1532               preOutName = Safe_strdup (fullDstFileName);
1533         }
1534       else
1535           preOutName = Safe_strdup (tempfilename ());
1536
1537       /* Have to set cppoutfilename to something, even if just pre-processing. */
1538       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1539
1540       if (options.verbose)
1541         printf ("sdcc: Calling preprocessor...\n");
1542
1543       buildCmdLine2 (buffer, _preCmd);
1544
1545       if (my_system (buffer))
1546         {
1547           // @FIX: Dario Vecchio 03-05-2001
1548           if (preOutName)
1549             {
1550               unlink (preOutName);
1551               Safe_free (preOutName);
1552             }
1553           // EndFix
1554           exit (1);
1555         }
1556
1557       if (preProcOnly)
1558       {
1559         exit (0);
1560       }
1561     }
1562   else
1563     {
1564       preOutName = fullSrcFileName;
1565     }
1566
1567   yyin = fopen (preOutName, "r");
1568   if (yyin == NULL)
1569     {
1570       perror ("Preproc file not found\n");
1571       exit (1);
1572     }
1573
1574   return 0;
1575 }
1576
1577 static bool
1578 _setPaths (const char *pprefix)
1579 {
1580   /* Logic:
1581       Given the prefix and how the directories were layed out at
1582       configure time, see if the library and include directories are
1583       where expected.  If so, set.
1584   */
1585   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1586   strcpy (scratchFileName, pprefix);
1587   strcat (scratchFileName, buffer);
1588
1589   if (pathExists (scratchFileName))
1590     {
1591       setMainValue ("includedir", scratchFileName);
1592     }
1593   else
1594     {
1595       return FALSE;
1596     }
1597
1598   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1599   strcpy (scratchFileName, pprefix);
1600   strcat (scratchFileName, buffer);
1601
1602   if (pathExists (scratchFileName))
1603     {
1604       setMainValue ("libdir", scratchFileName);
1605     }
1606   else
1607     {
1608       return FALSE;
1609     }
1610
1611   return TRUE;
1612 }
1613
1614 static void
1615 _discoverPaths (const char *argv0)
1616 {
1617   /* Logic:
1618       1.  Try the SDCCDIR environment variable.
1619       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1620       and library paths with respect to that.  Note that under win32
1621       argv[0] is always the full path to the program.
1622       3.  If (1) and (2) fail, fall back to the compile time defaults.
1623
1624       Detecting assumes the same layout as when configured.  If the
1625       directories have been further moved about then discovery will
1626       fail.
1627   */
1628
1629   /* Some input cases:
1630         "c:\fish\sdcc\bin\sdcc"
1631         "../bin/sdcc"
1632         "/home/fish/bin/sdcc"
1633
1634       Note that ./sdcc is explicitly not supported as there isn't
1635       enough information.
1636   */
1637   /* bindir is handled differently to the lib and include directories.
1638      It's rather unfortunate, but required due to the different
1639      install and development layouts.  Logic is different as well.
1640      Sigh.
1641    */
1642   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1643     {
1644       strcpy (scratchFileName, argv0);
1645       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1646       setMainValue ("bindir", scratchFileName);
1647       ExePathList[0] = Safe_strdup (scratchFileName);
1648     }
1649   else if (getenv (SDCCDIR_NAME) != NULL)
1650     {
1651       getPathDifference (buffer, PREFIX, BINDIR);
1652       strcpy (scratchFileName, getenv (SDCCDIR_NAME));
1653       strcat (scratchFileName, buffer);
1654       setMainValue ("bindir", scratchFileName);
1655       ExePathList[0] = Safe_strdup (scratchFileName);
1656     }
1657   else
1658     {
1659       setMainValue ("bindir", BINDIR);
1660       ExePathList[0] = BINDIR;
1661     }
1662
1663   do 
1664     {
1665       /* Case 1 */
1666       if (getenv (SDCCDIR_NAME) != NULL)
1667         {
1668           if (_setPaths (getenv (SDCCDIR_NAME)))
1669             {
1670               /* Successfully set. */
1671               break;
1672             }
1673           else
1674             {
1675               /* Include and lib weren't where expected. */
1676             }
1677         }
1678       /* Case 2 */
1679       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1680         {
1681           char *pbase = getPrefixFromBinPath (argv0);
1682
1683           if (pbase == NULL)
1684             {
1685               /* A bad path.  Skip. */
1686             }
1687           else
1688             {
1689               if (_setPaths (pbase))
1690                 {
1691                   /* Successfully set. */
1692                   break;
1693                 }
1694               else
1695                 {
1696                   /* Include and lib weren't where expected. */
1697                 }
1698             }
1699         }
1700       /* Case 3 */
1701       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1702       setMainValue ("libdir", SDCC_LIB_DIR);
1703     } while (0);
1704 }
1705
1706 static void
1707 initValues (void)
1708 {
1709   populateMainValues (_baseValues);
1710   setMainValue ("port", port->target);
1711   setMainValue ("objext", port->linker.rel_ext);
1712   setMainValue ("asmext", port->assembler.file_ext);
1713
1714   setMainValue ("dstfilename", dstFileName);
1715   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1716   
1717   if (options.cc_only && fullDstFileName)
1718     /* compile + assemble and -o given: -o specifies name of object file */
1719     {
1720       setMainValue ("objdstfilename", fullDstFileName);
1721     }
1722   else
1723     {
1724       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1725     }
1726   if (fullDstFileName)
1727     /* if we're linking, -o gives the final file name */
1728     {
1729       setMainValue ("linkdstfilename", fullDstFileName);
1730     }
1731   else
1732     {
1733       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1734     }
1735
1736 }
1737
1738 /*
1739  * main routine
1740  * initialises and calls the parser
1741  */
1742
1743 int
1744 main (int argc, char **argv, char **envp)
1745 {
1746   /* turn all optimizations off by default */
1747   memset (&optimize, 0, sizeof (struct optimize));
1748
1749   /*printVersionInfo (); */
1750
1751   if (NUM_PORTS==0) {
1752     fprintf (stderr, "Build error: no ports are enabled.\n");
1753     exit (1);
1754   }
1755
1756   /* install atexit handler */
1757   atexit(rm_tmpfiles);
1758
1759   /* Before parsing the command line options, do a 
1760    * search for the port and processor and initialize
1761    * them if they're found. (We can't gurantee that these
1762    * will be the first options specified).
1763    */
1764
1765   _findPort (argc, argv);
1766
1767 #ifdef JAMIN_DS390
1768   if (strcmp(port->target, "mcs51") == 0) {
1769     printf("DS390 jammed in A\n");
1770           _setPort ("ds390");
1771     ds390_jammed = 1;
1772   }
1773 #endif
1774
1775   _findProcessor (argc, argv);
1776
1777   /* Initalise the port. */
1778   if (port->init)
1779     port->init ();
1780
1781   // Create a default exe search path from the path to the sdcc command
1782
1783
1784   setDefaultOptions ();
1785 #ifdef JAMIN_DS390
1786   if (ds390_jammed) {
1787     options.model = MODEL_SMALL;
1788     options.stack10bit=0;
1789   }
1790 #endif
1791   parseCmdLine (argc, argv);
1792
1793   /* if no input then printUsage & exit */
1794   if ((!options.c1mode && !fullSrcFileName && !nrelFiles) ||
1795       (options.c1mode && !fullSrcFileName))
1796     {
1797       printUsage ();
1798       exit (0);
1799     }
1800
1801   initValues ();
1802   _discoverPaths (argv[0]);
1803
1804   /* initMem() is expensive, but
1805      initMem() must called before port->finaliseOptions ().
1806      And the z80 port needs port->finaliseOptions(),
1807      even if we're only linking. */
1808   initMem ();
1809   port->finaliseOptions ();
1810
1811   if (fullSrcFileName)
1812     {
1813       preProcess (envp);
1814
1815       initSymt ();
1816       initiCode ();
1817       initCSupport ();
1818       initBuiltIns();
1819       initPeepHole ();
1820
1821       if (options.verbose)
1822         printf ("sdcc: Generating code...\n");
1823
1824       yyparse ();
1825
1826       if (fatalError) {
1827         // @FIX: Dario Vecchio 03-05-2001
1828         if (preOutName) {
1829           if (yyin && yyin != stdin)
1830             fclose (yyin);
1831           unlink (preOutName);
1832           Safe_free (preOutName);
1833         }
1834         // EndFix
1835         return 1;
1836       }
1837
1838       if (TARGET_IS_PIC) {
1839         /* TSD PIC port hack - if the PIC port option is enabled
1840            and SDCC is used to generate PIC code, then we will
1841            generate .asm files in gpasm's format instead of SDCC's
1842            assembler's format
1843         */
1844 #if !OPT_DISABLE_PIC
1845         picglue ();
1846 #endif
1847       }
1848       else {
1849         glue ();
1850       }
1851
1852       if (!options.c1mode && !noAssemble)
1853         {
1854           if (options.verbose)
1855             printf ("sdcc: Calling assembler...\n");
1856           assemble (envp);
1857         }
1858     }
1859
1860   closeDumpFiles();
1861
1862   if (cdbFile)
1863     fclose (cdbFile);
1864
1865   if (yyin && yyin != stdin)
1866     fclose (yyin);
1867
1868   if (preOutName && !options.c1mode)
1869     {
1870       unlink (preOutName);
1871       Safe_free (preOutName);
1872     }
1873
1874   if (!options.cc_only &&
1875       !fatalError &&
1876       !noAssemble &&
1877       !options.c1mode &&
1878       (fullSrcFileName || nrelFiles))
1879     {
1880       if (port->linker.do_link)
1881         port->linker.do_link ();
1882       else
1883         linkEdit (envp);
1884     }
1885
1886   return 0;
1887 }