new option -o
[fw/sdcc] / src / SDCCmain.c
1 /*-------------------------------------------------------------------------
2   SDCCmain.c - main file
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include "common.h"
26 #include <ctype.h>
27 #include "newalloc.h"
28 #include "SDCCerr.h"
29 #include "BuildCmd.h"
30 #include "MySystem.h"
31 #include "SDCCmacro.h"
32 #include "SDCCutil.h"
33 #include "SDCCargs.h"
34
35 #if NATIVE_WIN32
36 #include <process.h>
37 #else
38 #include "spawn.h"
39 #endif
40
41 #if !defined(__BORLANDC__) && !defined(_MSC_VER)
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #endif
45
46 /** Name of the environment variable checked for other instalations. */
47 #define SDCCDIR_NAME "SDCCDIR"
48
49 //REMOVE ME!!!
50 extern int yyparse ();
51
52 FILE *srcFile;                  /* source file          */
53 FILE *cdbFile = NULL;           /* debugger information output file */
54 char *fullSrcFileName;          /* full name for the source file; */
55                                 /* can be NULL while linking without compiling */
56 char *fullDstFileName;          /* full name for the output file; */
57                                 /* only given by -o, otherwise NULL */
58 char *dstFileName;              /* destination file name without extension */
59 char *dstPath = "";             /* path for the output files; */
60                                 /* "" is equivalent with cwd */
61 char *moduleName;               /* module name is source file without path and extension */
62                                 /* can be NULL while linking without compiling */
63 const char *preArgv[128];       /* pre-processor arguments  */
64 int currRegBank = 0;
65 int RegBankUsed[4]={1, 0, 0, 0};        /*JCF: Reg Bank 0 used by default*/
66 struct optimize optimize;
67 struct options options;
68 char *VersionString = SDCC_VERSION_STR;
69 int preProcOnly = 0;
70 int noAssemble = 0;
71 char *linkOptions[128];
72 const char *asmOptions[128];
73 char *libFiles[128];
74 int nlibFiles = 0;
75 char *libPaths[128];
76 int nlibPaths = 0;
77 char *relFiles[128];
78 int nrelFiles = 0;
79 bool verboseExec = FALSE;
80 char *preOutName;
81 bool noXinitOpt = FALSE;
82
83 /* uncomment JAMIN_DS390 to always override and use ds390 port
84   for mcs51 work.  This is temporary, for compatibility testing. */
85 /* #define JAMIN_DS390 */
86 #ifdef JAMIN_DS390
87 int ds390_jammed = 0;
88 #endif
89
90 // Globally accessible scratch buffer for file names.
91 char scratchFileName[PATH_MAX];
92 char buffer[PATH_MAX];
93
94 // In MSC VC6 default search path for exe's to path for this
95
96 char DefaultExePath[128];
97
98 #define OPTION_HELP     "-help"
99
100 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
101
102 #define OPTION_STACK_8BIT       "--stack-8bit"
103 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
104 #define OPTION_LARGE_MODEL      "--model-large"
105 #define OPTION_MEDIUM_MODEL     "--model-medium"
106 #define OPTION_SMALL_MODEL      "--model-small"
107 #define OPTION_FLAT24_MODEL     "--model-flat24"
108 #define OPTION_DUMP_ALL         "--dumpall"
109 #define OPTION_PEEP_FILE        "--peep-file"
110 #define OPTION_LIB_PATH         "--lib-path"
111 #define OPTION_XSTACK_LOC       "--xstack-loc"
112 #define OPTION_CALLEE_SAVES     "--callee-saves"
113 #define OPTION_STACK_LOC        "--stack-loc"
114 #define OPTION_XRAM_LOC         "--xram-loc"
115 #define OPTION_IRAM_SIZE        "--iram-size"
116 #define OPTION_VERSION          "--version"
117 #define OPTION_DATA_LOC         "--data-loc"
118 #define OPTION_CODE_LOC         "--code-loc"
119 #define OPTION_IDATA_LOC        "--idata-loc"
120 #define OPTION_NO_LOOP_INV      "--noinvariant"
121 #define OPTION_NO_LOOP_IND      "--noinduction"
122 #define OPTION_LESS_PEDANTIC    "--lesspedantic"
123 #define OPTION_NO_GCSE          "--nogcse"
124 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
125 #define OPTION_TINI_LIBID       "--tini-libid"
126 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
127
128 static const OPTION 
129 optionsTable[] = {
130     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
131     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
132     { 'd',  NULL,                   NULL, NULL },
133     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
134     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
135     { 'A',  NULL,                   NULL, NULL },
136     { 'U',  NULL,                   NULL, NULL },
137     { 'C',  NULL,                   NULL, "Preprocessor option" },
138     { 'M',  NULL,                   NULL, "Preprocessor option" },
139     { 'V',  NULL,                   &verboseExec, "Execute verbosely.  Show sub commands as they are run" },
140     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
141     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
142     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
143     { 'l',  NULL,                   NULL, "Include the given library in the link" },
144     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
145     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
146     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
147     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
148     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
149     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
150     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
151     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
152     { 0,    "--generic",            &options.genericPtr, "All unqualified ptrs converted to '_generic'" },
153     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
154     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
155     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
156     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
157     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
158     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
159     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
160     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
161     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
162     { 0,    "--dumploop",           &options.dump_loop, NULL },
163     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
164     { 0,    "--dumpliverange",      &options.dump_range, NULL },
165     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
166     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
167     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
168     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
169     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
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_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
174     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
175     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
176     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
177     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
178     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
179     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
180     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
181     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
182     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
183     { 0,    "--nooverlay",          &options.noOverlay, NULL },
184     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
185     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
186     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
187     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
188     { 0,    "--peep-asm",           &options.asmpeep, NULL },
189     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
190     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
191     { 0,    "--stack-after-data",   &options.stackOnData, "initialize the stackpointer with the last byte use in DSEG" },
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     { 'a',  NULL,       "use --stack-auto instead." },
230     { 'g',  NULL,       "use --generic instead" },
231     { 'X',  NULL,       "use --xstack-loc instead" },
232     { 'x',  NULL,       "use --xstack instead" },
233     { 'i',  NULL,       "use --idata-loc instead" },
234     { 'r',  NULL,       "use --xdata-loc instead" },
235     { 's',  NULL,       "use --code-loc instead" },
236     { 'Y',  NULL,       "use -I instead" }
237 };
238
239 /** List of all default constant macros.
240  */
241 static const char *_baseValues[] = {
242   "cpp", "{bindir}{sep}sdcpp",
243   "cppextraopts", "",
244   /* Path seperator character */
245   "sep", DIR_SEPARATOR_STRING,
246   NULL
247 };
248
249 static const char *_preCmd = "{cpp} -nostdinc -Wall -lang-c++ -DSDCC=1 {cppextraopts} {fullsrcfilename} {cppoutfilename}";
250
251 PORT *port;
252
253 static PORT *_ports[] =
254 {
255 #if !OPT_DISABLE_MCS51
256   &mcs51_port,
257 #endif
258 #if !OPT_DISABLE_GBZ80
259   &gbz80_port,
260 #endif
261 #if !OPT_DISABLE_Z80
262   &z80_port,
263 #endif
264 #if !OPT_DISABLE_AVR
265   &avr_port,
266 #endif
267 #if !OPT_DISABLE_DS390
268   &ds390_port,
269 #endif
270 #if !OPT_DISABLE_PIC
271   &pic_port,
272 #endif
273 #if !OPT_DISABLE_TININative
274   &tininative_port,
275 #endif
276 #if !OPT_DISABLE_XA51
277   &xa51_port,
278 #endif
279 };
280
281 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
282
283 #if !OPT_DISABLE_PIC
284 extern void picglue ();
285 #endif
286
287 /** Sets the port to the one given by the command line option.
288     @param    The name minus the option (eg 'mcs51')
289     @return     0 on success.
290 */
291 static void
292 _setPort (const char *name)
293 {
294   int i;
295   for (i = 0; i < NUM_PORTS; i++)
296     {
297       if (!strcmp (_ports[i]->target, name))
298         {
299           port = _ports[i];
300           return;
301         }
302     }
303   /* Error - didnt find */
304   werror (E_UNKNOWN_TARGET, name);
305   exit (1);
306 }
307
308 /* Override the default processor with the one specified 
309  * on the command line */
310 static void
311 _setProcessor (char *_processor)
312 {
313   port->processor = _processor;
314   fprintf(stderr,"Processor: %s\n",_processor);
315 }
316
317 static void
318 _validatePorts (void)
319 {
320   int i;
321   for (i = 0; i < NUM_PORTS; i++)
322     {
323       if (_ports[i]->magic != PORT_MAGIC)
324         {
325           /* Uncomment this line to debug which port is causing the problem
326            * (the target name is close to the beginning of the port struct 
327            * and probably can be accessed just fine). */
328           fprintf(stderr,"%s :",_ports[i]->target);
329           wassertl (0, "Port definition structure is incomplete");
330         }
331     }
332 }
333
334 /* search through the command line options for the port */
335 static void
336 _findPort (int argc, char **argv)
337 {
338   _validatePorts ();
339
340   while (argc--)
341     {
342       if (!strncmp (*argv, "-m", 2))
343         {
344           _setPort (*argv + 2);
345           return;
346         }
347       argv++;
348     }
349   /* Use the first in the list */
350   port = _ports[0];
351 }
352
353 /* search through the command line options for the processor */
354 static void
355 _findProcessor (int argc, char **argv)
356 {
357   while (argc--)
358     {
359       if (!strncmp (*argv, "-p", 2))
360         {
361           _setProcessor (*argv + 2);
362           return;
363         }
364       argv++;
365     }
366
367   /* no error if processor was not specified. */
368 }
369
370 /*-----------------------------------------------------------------*/
371 /* printVersionInfo - prints the version info        */
372 /*-----------------------------------------------------------------*/
373 void
374 printVersionInfo ()
375 {
376   int i;
377
378   fprintf (stderr,
379            "SDCC : ");
380   for (i = 0; i < NUM_PORTS; i++)
381     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
382
383   fprintf (stderr, " %s"
384 #ifdef SDCC_SUB_VERSION_STR
385            "/" SDCC_SUB_VERSION_STR
386 #endif
387            " (" __DATE__ ")"
388 #ifdef __CYGWIN__
389            " (CYGWIN)\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.genericPtr = 1;       /* default on */
496   options.nopeep = 0;
497   options.model = port->general.default_model;
498   options.nostdlib = 0;
499   options.nostdinc = 0;
500   options.verbose = 0;
501   options.shortis8bits = 0;
502
503   options.stack10bit=0;
504
505   /* now for the optimizations */
506   /* turn on the everything */
507   optimize.global_cse = 1;
508   optimize.label1 = 1;
509   optimize.label2 = 1;
510   optimize.label3 = 1;
511   optimize.label4 = 1;
512   optimize.loopInvariant = 1;
513   optimize.loopInduction = 1;
514
515   /* now for the ports */
516   port->setDefaultOptions ();
517 }
518
519 /*-----------------------------------------------------------------*/
520 /* processFile - determines the type of file from the extension    */
521 /*-----------------------------------------------------------------*/
522 static void
523 processFile (char *s)
524 {
525   char *fext = NULL;
526
527   /* get the file extension */
528   fext = s + strlen (s);
529   while ((fext != s) && *fext != '.')
530     fext--;
531
532   /* now if no '.' then we don't know what the file type is
533      so give a warning and return */
534   if (fext == s)
535     {
536       werror (W_UNKNOWN_FEXT, s);
537       return;
538     }
539
540   /* otherwise depending on the file type */
541   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0 || options.c1mode)
542     {
543       /* source file name : not if we already have a
544          source file */
545       if (fullSrcFileName)
546         {
547           werror (W_TOO_MANY_SRC, s);
548           return;
549         }
550
551       /* the only source file */
552       if (!(srcFile = fopen ((fullSrcFileName = s), "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 _processC1Arg (char *s)
619 {
620   if (fullSrcFileName)
621     {
622       if (options.out_name)
623         {
624           werror (W_TOO_MANY_SRC, s);
625           return;
626         }
627       options.out_name = Safe_strdup (s);
628     }
629   else
630     {
631       processFile (s);
632     }
633 }
634
635 static void
636 _setModel (int model, const char *sz)
637 {
638   if (port->general.supported_models & model)
639     options.model = model;
640   else
641     werror (W_UNSUPPORTED_MODEL, sz, port->target);
642 }
643
644 /** Gets the string argument to this option.  If the option is '--opt'
645     then for input of '--optxyz' or '--opt xyz' returns xyz.
646 */
647 static char *
648 getStringArg(const char *szStart, char **argv, int *pi, int argc)
649 {
650   if (argv[*pi][strlen(szStart)]) 
651     {
652       return &argv[*pi][strlen(szStart)];
653     }
654   else 
655     {
656       ++(*pi);
657       if (*pi >= argc) 
658         {
659           werror (E_ARGUMENT_MISSING, szStart);
660           /* Die here rather than checking for errors later. */
661           exit(-1);
662         }
663       else 
664         {
665           return argv[*pi];
666         }
667     }
668 }
669
670 /** Gets the integer argument to this option using the same rules as
671     getStringArg. 
672 */
673 static int
674 getIntArg(const char *szStart, char **argv, int *pi, int argc)
675 {
676     return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
677 }
678
679 static void
680 verifyShortOption(const char *opt)
681 {
682   if (strlen(opt) != 2)
683     {
684       werror (W_EXCESS_SHORT_OPTIONS, opt);
685     }
686 }
687
688 static bool
689 tryHandleUnsupportedOpt(char **argv, int *pi)
690 {
691     if (argv[*pi][0] == '-') 
692         {
693             const char *longOpt = "";
694             char shortOpt = -1;
695             int i;
696
697             if (argv[*pi][1] == '-') 
698                 {
699                     // Long option.
700                     longOpt = argv[*pi];
701                 }
702             else 
703                 {
704                     shortOpt = argv[*pi][1];
705                 }
706             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
707                 {
708                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
709                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
710                         // Found an unsupported opt.
711                         char buffer[100];
712                         sprintf(buffer, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
713                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
714                         return 1;
715                     }
716                 }
717             // Didn't find in the table
718             return 0;
719         }
720     else 
721         {
722             // Not an option, so can't be unsupported :)
723             return 0;
724     }
725 }
726
727 static bool
728 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
729 {
730   int i;
731   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++)
732     {
733       if (optionsTable[i].shortOpt == shortOpt ||
734           (longOpt && optionsTable[i].longOpt && 
735            strcmp(optionsTable[i].longOpt, longOpt) == 0))
736         {
737
738           // If it is a flag then we can handle it here
739           if (optionsTable[i].pparameter != NULL) 
740             {
741               if (optionsTable[i].shortOpt == shortOpt)
742                 {
743                   verifyShortOption(argv[*pi]);
744                 }
745
746               (*optionsTable[i].pparameter)++;
747               return 1;
748             }
749           else {
750             // Not a flag.  Handled manually later.
751             return 0;
752           }
753         }
754     }
755   // Didn't find in the table
756   return 0;
757 }
758
759 static bool
760 tryHandleSimpleOpt(char **argv, int *pi)
761 {
762     if (argv[*pi][0] == '-') 
763         {
764             const char *longOpt = "";
765             char shortOpt = -1;
766
767             if (argv[*pi][1] == '-') 
768                 {
769                     // Long option.
770                     longOpt = argv[*pi];
771                 }
772             else 
773                 {
774                     shortOpt = argv[*pi][1];
775                 }
776
777             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
778               {
779                 return 1;
780               }
781             else if (port && port->poptions &&
782                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
783               {
784                 return 1;
785               }
786             else
787               {
788                 return 0;
789               }
790         }
791     else 
792         {
793             // Not an option, so can't be handled.
794             return 0;
795         }
796 }
797
798 /*-----------------------------------------------------------------*/
799 /* parseCmdLine - parses the command line and sets the options     */
800 /*-----------------------------------------------------------------*/
801 static int
802 parseCmdLine (int argc, char **argv)
803 {
804   int i;
805
806   /* go thru all whole command line */
807   for (i = 1; i < argc; i++)
808     {
809       if (i >= argc)
810         break;
811
812       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
813           {
814               continue;
815           }
816
817       if (tryHandleSimpleOpt(argv, &i) == TRUE)
818           {
819               continue;
820           }
821
822       /* options */
823       if (argv[i][0] == '-' && argv[i][1] == '-')
824         {
825           if (strcmp (argv[i], OPTION_HELP) == 0)
826             {
827               printUsage ();
828               exit (0);
829             }
830
831           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
832             {
833               options.stack10bit = 0;
834               continue;
835             }
836
837           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
838             {
839               options.out_fmt = 0;
840               continue;
841             }
842
843           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
844             {
845               _setModel (MODEL_LARGE, argv[i]);
846               continue;
847             }
848
849           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
850             {
851               _setModel (MODEL_MEDIUM, argv[i]);
852               continue;
853             }
854
855           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
856             {
857               _setModel (MODEL_SMALL, argv[i]);
858               continue;
859             }
860
861           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
862             {
863               _setModel (MODEL_FLAT24, argv[i]);
864               continue;
865             }
866
867           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
868             {
869               options.dump_rassgn =
870                 options.dump_pack =
871                 options.dump_range =
872                 options.dump_kill =
873                 options.dump_loop =
874                 options.dump_gcse =
875                 options.dump_raw = 1;
876               continue;
877             }
878
879           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
880             {
881                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
882                 continue;
883             }
884
885           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
886             {
887                 libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i, argc);
888                 continue;
889             }
890
891           if (strcmp (argv[i], OPTION_VERSION) == 0)
892             {
893               printVersionInfo ();
894               exit (0);
895               continue;
896             }
897
898           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
899             {
900                 parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
901                 continue;
902             }
903
904           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
905             {
906                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
907                 continue;
908             }
909
910           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
911             {
912                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
913                 continue;
914             }
915
916           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
917             {
918                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
919                 continue;
920             }
921
922           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
923             {
924                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
925                 continue;
926             }
927
928           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
929             {
930                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
931                 continue;
932             }
933
934           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
935             {
936                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
937                 continue;
938             }
939
940           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
941             {
942                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
943                 continue;
944             }
945
946           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
947             {
948               optimize.global_cse = 0;
949               continue;
950             }
951
952           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
953             {
954               optimize.loopInvariant = 0;
955               continue;
956             }
957
958           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
959             {
960               optimize.loopInduction = 0;
961               continue;
962             }
963
964           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
965             {
966               options.lessPedantic = 1;
967               setErrorLogLevel(ERROR_LEVEL_WARNING);
968               continue;
969             }
970
971           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
972             {
973               options.shortis8bits=1;
974               continue;
975             }
976
977           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
978             {
979                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
980                 continue;
981             }
982           
983           if (!port->parseOption (&argc, argv, &i))
984             {
985               werror (W_UNKNOWN_OPTION, argv[i]);
986             }
987           else
988             {
989               continue;
990             }
991         }
992
993       /* if preceded by  '-' then option */
994       if (*argv[i] == '-')
995         {
996           switch (argv[i][1])
997             {
998             case 'h':
999               verifyShortOption(argv[i]);
1000
1001               printUsage ();
1002               exit (0);
1003               break;
1004
1005             case 'm':
1006               /* Used to select the port. But this has already been done. */
1007               break;
1008
1009             case 'p':
1010               /* Used to select the processor in port. But this has
1011                * already been done. */
1012               break;
1013
1014             case 'c':
1015               verifyShortOption(argv[i]);
1016
1017               options.cc_only = 1;
1018               break;
1019
1020             case 'L':
1021                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
1022                 break;
1023
1024             case 'l':
1025                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
1026                 break;
1027             
1028             case 'o':
1029               {
1030                 char *p;
1031
1032                 /* copy the file name into the buffer */
1033                 strcpy (buffer, getStringArg("-o", argv, &i, argc));
1034                 /* point to last character */
1035                 p = buffer + strlen (buffer) - 1;
1036                 if (*p == DIR_SEPARATOR_CHAR)
1037                   {
1038                     /* only output path specified */
1039                     dstPath = Safe_strdup (buffer);
1040                     fullDstFileName = NULL;
1041                   }
1042                 else
1043                   {
1044                     fullDstFileName = Safe_strdup (buffer);
1045
1046                     /* get rid of the "."-extension */
1047
1048                     /* is there a dot at all? */
1049                     if (strrchr (buffer, '.') &&
1050                         /* is the dot in the filename, not in the path? */
1051                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1052                       *strrchr (buffer, '.') = '\0';
1053
1054                     dstFileName = Safe_strdup (buffer);
1055
1056                     /* strip module name to get path */
1057                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1058                     if (p)
1059                       {
1060                         /* path with trailing / */
1061                         p[1] = '\0';
1062                         dstPath = Safe_strdup (buffer);
1063                       }
1064                   }
1065                 break;
1066               }
1067
1068             case 'W':
1069               /* pre-processer options */
1070               if (argv[i][2] == 'p')
1071                 {
1072                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
1073                 }
1074               /* linker options */
1075               else if (argv[i][2] == 'l')
1076                 {
1077                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1078                 }
1079               /* assembler options */
1080               else if (argv[i][2] == 'a')
1081                 {
1082                   parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
1083                 }
1084               else
1085                 {
1086                   werror (W_UNKNOWN_OPTION, argv[i]);
1087                 }
1088               break;
1089
1090             case 'v':
1091               verifyShortOption(argv[i]);
1092
1093               printVersionInfo ();
1094               exit (0);
1095               break;
1096
1097               /* preprocessor options */
1098             case 'M':
1099               {
1100                 preProcOnly = 1;
1101                 addToList (preArgv, "-M");
1102                 break;
1103               }
1104             case 'C':
1105               {
1106                 addToList (preArgv, "-C");
1107                 break;
1108               }
1109             case 'd':
1110             case 'D':
1111             case 'I':
1112             case 'A':
1113             case 'U':
1114               {
1115                 char sOpt = argv[i][1];
1116                 char *rest;
1117
1118                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1119                   {
1120                     i++;
1121                     if (i >= argc) 
1122                       {
1123                           /* No argument. */
1124                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1125                           break;
1126                       }
1127                     else 
1128                       {
1129                           rest = argv[i];
1130                       }
1131                   }
1132                 else
1133                   rest = &argv[i][2];
1134
1135                 if (sOpt == 'Y')
1136                   sOpt = 'I';
1137
1138                 sprintf (buffer, "-%c%s", sOpt, rest);
1139                 addToList (preArgv, buffer);
1140               }
1141               break;
1142
1143             default:
1144               if (!port->parseOption (&argc, argv, &i))
1145                 werror (W_UNKNOWN_OPTION, argv[i]);
1146             }
1147           continue;
1148         }
1149
1150       if (!port->parseOption (&argc, argv, &i))
1151         {
1152           /* no option must be a filename */
1153           if (options.c1mode)
1154             _processC1Arg (argv[i]);
1155           else
1156             processFile (argv[i]);
1157         }
1158     }
1159
1160   /* if no dstFileName given with -o, we've to find one: */
1161   if (!dstFileName)
1162     {
1163       /* use the modulename from the C-source */
1164       if (fullSrcFileName)
1165         {
1166           dstFileName = Safe_alloc (strlen (dstPath) + strlen (moduleName) + 1);
1167           strcpy (dstFileName, dstPath);
1168           strcat (dstFileName, moduleName);
1169         }
1170       /* use the modulename from the first object file */
1171       else if (nrelFiles >= 1)
1172         {
1173           char *objectName;
1174
1175           strcpy (buffer, relFiles[0]);
1176           /* remove extension (it must be .rel) */
1177           *strrchr (buffer, '.') = '\0';
1178           /* remove path */
1179           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1180           if (objectName)
1181             {
1182               ++objectName;
1183             }
1184           else
1185             {
1186               objectName = buffer;
1187             }
1188           dstFileName = Safe_alloc (strlen (dstPath) + strlen (objectName) + 1);
1189           strcpy (dstFileName, dstPath);
1190           strcat (dstFileName, objectName);
1191         }
1192       /* else no module given: help text is displayed */
1193     }
1194
1195   /* set up external stack location if not explicitly specified */
1196   if (!options.xstack_loc)
1197     options.xstack_loc = options.xdata_loc;
1198
1199   /* if debug option is set the open the cdbFile */
1200   if (options.debug && fullSrcFileName)
1201     {
1202       sprintf (scratchFileName, "%s.adb", dstFileName); //JCF: Nov 30, 2002
1203       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1204         werror (E_FILE_OPEN_ERR, scratchFileName);
1205       else
1206         {
1207           /* add a module record */
1208           fprintf (cdbFile, "M:%s\n", moduleName);
1209         }
1210     }
1211   return 0;
1212 }
1213
1214 /*-----------------------------------------------------------------*/
1215 /* linkEdit : - calls the linkage editor  with options             */
1216 /*-----------------------------------------------------------------*/
1217 static void
1218 linkEdit (char **envp)
1219 {
1220   FILE *lnkfile;
1221   char *segName, *c;
1222   int i;
1223
1224   /* first we need to create the <filename>.lnk file */
1225   sprintf (scratchFileName, "%s.lnk", dstFileName);
1226   if (!(lnkfile = fopen (scratchFileName, "w")))
1227     {
1228       werror (E_FILE_OPEN_ERR, scratchFileName);
1229       exit (1);
1230     }
1231
1232   /* now write the options.  JCF: added option 'y' */
1233   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1234
1235   /* if iram size specified */
1236   if (options.iram_size)
1237     fprintf (lnkfile, "-a 0x%04x\n", options.iram_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) {
1269         WRITE_SEG_LOC ("SSEG", options.stack_loc & 0xff);
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   if (port->linker.cmd)
1345     {
1346       char buffer2[PATH_MAX];
1347       buildCmdLine (buffer2, port->linker.cmd, dstFileName, NULL, NULL, NULL);
1348       buildCmdLine2 (buffer, buffer2);
1349     }
1350   else
1351     {
1352       buildCmdLine2 (buffer, port->linker.mcmd);
1353     }
1354
1355   if (my_system (buffer))
1356     {
1357       exit (1);
1358     }
1359   /* -o option overrides default name? */
1360   if (fullDstFileName)
1361     {
1362       /* the linked file gets the name of the first modul */
1363       if (fullSrcFileName)
1364     {
1365           strcpy (scratchFileName, dstFileName);
1366         }
1367       else
1368         {
1369           strcpy (scratchFileName, relFiles[0]);
1370           /* strip ".rel" extension */
1371           *strrchr (scratchFileName, '.') = '\0';
1372         }
1373       strcat (scratchFileName, options.out_fmt ? ".S19" : ".ihx");
1374       rename (scratchFileName, fullDstFileName);
1375     }
1376 }
1377
1378 /*-----------------------------------------------------------------*/
1379 /* assemble - spawns the assembler with arguments                  */
1380 /*-----------------------------------------------------------------*/
1381 static void
1382 assemble (char **envp)
1383 {
1384     if (port->assembler.do_assemble) {
1385         port->assembler.do_assemble(asmOptions);
1386         return ;
1387     } else if (port->assembler.cmd) {
1388         buildCmdLine (buffer, port->assembler.cmd, dstFileName, NULL,
1389                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1390                       asmOptions);
1391     } else {
1392         buildCmdLine2 (buffer, port->assembler.mcmd);
1393     }
1394
1395     if (my_system (buffer)) {
1396         /* either system() or the assembler itself has reported an error
1397            perror ("Cannot exec assembler");
1398         */
1399         exit (1);
1400     }
1401     /* -o option overrides default name? */
1402     if (options.cc_only && fullDstFileName) {
1403         strcpy (scratchFileName, dstFileName);
1404         strcat (scratchFileName, ".rel");
1405         rename (scratchFileName, fullDstFileName);
1406     }
1407 }
1408
1409 /*-----------------------------------------------------------------*/
1410 /* preProcess - spawns the preprocessor with arguments       */
1411 /*-----------------------------------------------------------------*/
1412 static int
1413 preProcess (char **envp)
1414 {
1415   preOutName = NULL;
1416
1417   if (!options.c1mode)
1418     {
1419       /* if using external stack define the macro */
1420       if (options.useXstack)
1421         addToList (preArgv, "-DSDCC_USE_XSTACK");
1422
1423       /* set the macro for stack autos  */
1424       if (options.stackAuto)
1425         addToList (preArgv, "-DSDCC_STACK_AUTO");
1426
1427       /* set the macro for stack autos  */
1428       if (options.stack10bit)
1429         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1430
1431       /* set the macro for no overlay  */
1432       if (options.noOverlay)
1433         addToList (preArgv, "-DSDCC_NOOVERLAY");
1434
1435       /* set the macro for large model  */
1436       switch (options.model)
1437         {
1438         case MODEL_LARGE:
1439           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1440           break;
1441         case MODEL_SMALL:
1442           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1443           break;
1444         case MODEL_COMPACT:
1445           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1446           break;
1447         case MODEL_MEDIUM:
1448           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1449           break;
1450         case MODEL_FLAT24:
1451           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1452           break;
1453         case MODEL_PAGE0:
1454           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1455           break;
1456         default:
1457           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1458           break;
1459         }
1460
1461       /* add port (processor information to processor */
1462       addToList (preArgv, "-DSDCC_{port}");
1463       addToList (preArgv, "-D__{port}");
1464
1465       /* standard include path */
1466       if (!options.nostdinc) {
1467         addToList (preArgv, "-I{includedir}");
1468       }
1469
1470       setMainValue ("cppextraopts", join(preArgv));
1471       
1472       if (!preProcOnly)
1473           preOutName = Safe_strdup (tempfilename ());
1474
1475       /* Have to set cppoutfilename to something, even if just pre-processing. */
1476       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1477
1478       if (options.verbose)
1479         printf ("sdcc: Calling preprocessor...\n");
1480
1481       buildCmdLine2 (buffer, _preCmd);
1482
1483       if (my_system (buffer))
1484         {
1485           // @FIX: Dario Vecchio 03-05-2001
1486           if (preOutName)
1487             {
1488               unlink (preOutName);
1489               Safe_free (preOutName);
1490             }
1491           // EndFix
1492           exit (1);
1493         }
1494
1495       if (preProcOnly)
1496       {
1497         exit (0);
1498       }
1499     }
1500   else
1501     {
1502       preOutName = fullSrcFileName;
1503     }
1504
1505   yyin = fopen (preOutName, "r");
1506   if (yyin == NULL)
1507     {
1508       perror ("Preproc file not found\n");
1509       exit (1);
1510     }
1511
1512   return 0;
1513 }
1514
1515 static bool
1516 _setPaths (const char *pprefix)
1517 {
1518   /* Logic:
1519       Given the prefix and how the directories were layed out at
1520       configure time, see if the library and include directories are
1521       where expected.  If so, set.
1522   */
1523   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1524   strcpy (scratchFileName, pprefix);
1525   strcat (scratchFileName, buffer);
1526
1527   if (pathExists (scratchFileName))
1528     {
1529       setMainValue ("includedir", scratchFileName);
1530     }
1531   else
1532     {
1533       return FALSE;
1534     }
1535
1536   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1537   strcpy (scratchFileName, pprefix);
1538   strcat (scratchFileName, buffer);
1539
1540   if (pathExists (scratchFileName))
1541     {
1542       setMainValue ("libdir", scratchFileName);
1543     }
1544   else
1545     {
1546       return FALSE;
1547     }
1548
1549   return TRUE;
1550 }
1551
1552 static void
1553 _discoverPaths (const char *argv0)
1554 {
1555   /* Logic:
1556       1.  Try the SDCCDIR environment variable.
1557       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1558       and library paths with respect to that.  Note that under win32
1559       argv[0] is always the full path to the program.
1560       3.  If (1) and (2) fail, fall back to the compile time defaults.
1561
1562       Detecting assumes the same layout as when configured.  If the
1563       directories have been further moved about then discovery will
1564       fail.
1565   */
1566
1567   /* Some input cases:
1568         "c:\fish\sdcc\bin\sdcc"
1569         "../bin/sdcc"
1570         "/home/fish/bin/sdcc"
1571
1572       Note that ./sdcc is explicitly not supported as there isn't
1573       enough information.
1574   */
1575   /* bindir is handled differently to the lib and include directories.
1576      It's rather unfortunate, but required due to the different
1577      install and development layouts.  Logic is different as well.
1578      Sigh.
1579    */
1580   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1581     {
1582       strcpy (scratchFileName, argv0);
1583       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1584       setMainValue ("bindir", scratchFileName);
1585       ExePathList[0] = Safe_strdup (scratchFileName);
1586     }
1587   else if (getenv (SDCCDIR_NAME) != NULL)
1588     {
1589       getPathDifference (buffer, PREFIX, BINDIR);
1590       strcpy (scratchFileName, getenv (SDCCDIR_NAME));
1591       strcat (scratchFileName, buffer);
1592       setMainValue ("bindir", scratchFileName);
1593       ExePathList[0] = Safe_strdup (scratchFileName);
1594     }
1595   else
1596     {
1597       setMainValue ("bindir", BINDIR);
1598       ExePathList[0] = BINDIR;
1599     }
1600
1601   do 
1602     {
1603       /* Case 1 */
1604       if (getenv (SDCCDIR_NAME) != NULL)
1605         {
1606           if (_setPaths (getenv (SDCCDIR_NAME)))
1607             {
1608               /* Successfully set. */
1609               break;
1610             }
1611           else
1612             {
1613               /* Include and lib weren't where expected. */
1614             }
1615         }
1616       /* Case 2 */
1617       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1618         {
1619           char *pbase = getPrefixFromBinPath (argv0);
1620
1621           if (pbase == NULL)
1622             {
1623               /* A bad path.  Skip. */
1624             }
1625           else
1626             {
1627               if (_setPaths (pbase))
1628                 {
1629                   /* Successfully set. */
1630                   break;
1631                 }
1632               else
1633                 {
1634                   /* Include and lib weren't where expected. */
1635                 }
1636             }
1637         }
1638       /* Case 3 */
1639       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1640       setMainValue ("libdir", SDCC_LIB_DIR);
1641     } while (0);
1642 }
1643
1644 static void
1645 initValues (void)
1646 {
1647   populateMainValues (_baseValues);
1648   setMainValue ("port", port->target);
1649   setMainValue ("objext", port->linker.rel_ext);
1650   setMainValue ("asmext", port->assembler.file_ext);
1651
1652   setMainValue ("dstfilename", dstFileName);
1653   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1654   
1655   if (options.cc_only && fullDstFileName)
1656     /* compile + assemble and -o given: -o specifies name of object file */
1657     {
1658       setMainValue ("z80objdstfilename", fullDstFileName);
1659     }
1660   else
1661     {
1662       setMainValue ("z80objdstfilename", "{z80stdobjdstfilename}");
1663     }
1664   if (fullDstFileName)
1665     /* if we're linking, -o gives the final file name */
1666     {
1667       setMainValue ("z80linkdstfilename", fullDstFileName);
1668     }
1669   else
1670     {
1671       setMainValue ("z80linkdstfilename", "{z80stdlinkdstfilename}");
1672     }
1673
1674 }
1675
1676 /*
1677  * main routine
1678  * initialises and calls the parser
1679  */
1680
1681 int
1682 main (int argc, char **argv, char **envp)
1683 {
1684   /* turn all optimizations off by default */
1685   memset (&optimize, 0, sizeof (struct optimize));
1686
1687   /*printVersionInfo (); */
1688
1689   if (NUM_PORTS==0) {
1690     fprintf (stderr, "Build error: no ports are enabled.\n");
1691     exit (1);
1692   }
1693
1694   /* install atexit handler */
1695   atexit(rm_tmpfiles);
1696
1697   /* Before parsing the command line options, do a 
1698    * search for the port and processor and initialize
1699    * them if they're found. (We can't gurantee that these
1700    * will be the first options specified).
1701    */
1702
1703   _findPort (argc, argv);
1704
1705 #ifdef JAMIN_DS390
1706   if (strcmp(port->target, "mcs51") == 0) {
1707     printf("DS390 jammed in A\n");
1708           _setPort ("ds390");
1709     ds390_jammed = 1;
1710   }
1711 #endif
1712
1713   _findProcessor (argc, argv);
1714
1715   /* Initalise the port. */
1716   if (port->init)
1717     port->init ();
1718
1719   // Create a default exe search path from the path to the sdcc command
1720
1721
1722   setDefaultOptions ();
1723 #ifdef JAMIN_DS390
1724   if (ds390_jammed) {
1725     options.model = MODEL_SMALL;
1726     options.stack10bit=0;
1727   }
1728 #endif
1729   parseCmdLine (argc, argv);
1730
1731   /* if no input then printUsage & exit */
1732   if ((!options.c1mode && !fullSrcFileName && !nrelFiles) ||
1733       (options.c1mode && !fullSrcFileName && !options.out_name))
1734     {
1735       printUsage ();
1736       exit (0);
1737     }
1738
1739   initValues ();
1740   _discoverPaths (argv[0]);
1741
1742   if (fullSrcFileName)
1743     {
1744
1745       initMem ();
1746
1747       port->finaliseOptions ();
1748       preProcess (envp);
1749
1750       initSymt ();
1751       initiCode ();
1752       initCSupport ();
1753       initBuiltIns();
1754       initPeepHole ();
1755
1756       if (options.verbose)
1757         printf ("sdcc: Generating code...\n");
1758
1759       yyparse ();
1760
1761       if (fatalError) {
1762         // @FIX: Dario Vecchio 03-05-2001
1763         if (preOutName) {
1764           if (yyin && yyin != stdin)
1765             fclose (yyin);
1766           unlink (preOutName);
1767           Safe_free (preOutName);
1768         }
1769         // EndFix
1770         return 1;
1771       }
1772
1773       if (TARGET_IS_PIC) {
1774         /* TSD PIC port hack - if the PIC port option is enabled
1775            and SDCC is used to generate PIC code, then we will
1776            generate .asm files in gpasm's format instead of SDCC's
1777            assembler's format
1778         */
1779 #if !OPT_DISABLE_PIC
1780         picglue ();
1781 #endif
1782       }
1783       else {
1784         glue ();
1785       }
1786
1787       if (!options.c1mode && !noAssemble)
1788         {
1789           if (options.verbose)
1790             printf ("sdcc: Calling assembler...\n");
1791           assemble (envp);
1792         }
1793     }
1794
1795   closeDumpFiles();
1796
1797   if (cdbFile)
1798     fclose (cdbFile);
1799
1800   if (yyin && yyin != stdin)
1801     fclose (yyin);
1802
1803   if (preOutName && !options.c1mode)
1804     {
1805       unlink (preOutName);
1806       Safe_free (preOutName);
1807     }
1808
1809   if (!options.cc_only &&
1810       !fatalError &&
1811       !noAssemble &&
1812       !options.c1mode &&
1813       (fullSrcFileName || nrelFiles))
1814     {
1815       if (port->linker.do_link)
1816         port->linker.do_link ();
1817       else
1818         linkEdit (envp);
1819     }
1820
1821   return 0;
1822 }