* as/mcs51/lkarea.c: removed old K&R style,
[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 #ifdef _WIN32
26 #include <io.h>
27 #else
28 #include <unistd.h>
29 #endif
30
31 #include <signal.h>
32 #include "common.h"
33 #include <ctype.h>
34 #include "newalloc.h"
35 #include "SDCCerr.h"
36 #include "BuildCmd.h"
37 #include "MySystem.h"
38 #include "SDCCmacro.h"
39 #include "SDCCutil.h"
40 #include "SDCCdebug.h"
41 #include "SDCCargs.h"
42
43 #ifdef _WIN32
44 #include <process.h>
45 #else
46 #include <sys/stat.h>
47 #include <unistd.h>
48 #endif
49
50 /* REMOVE ME!!! */
51 extern int yyparse (void);
52
53 FILE *srcFile;                  /* source file          */
54 char *fullSrcFileName;          /* full name for the source file; */
55                                 /* can be NULL while c1mode or 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 *moduleNameBase;           /* module name base is source file without path and extension */
62                                 /* can be NULL while linking without compiling */
63 char *moduleName;               /* module name is same as module name base, but with all */
64                                 /* non-alphanumeric characters replaced with underscore */
65 int currRegBank = 0;
66 int RegBankUsed[4] = {1, 0, 0, 0}; /*JCF: Reg Bank 0 used by default*/
67 struct optimize optimize;
68 struct options options;
69 int preProcOnly = 0;
70 int noAssemble = 0;
71 set *preArgvSet = NULL;         /* pre-processor arguments  */
72 set *asmOptionsSet = NULL;      /* set of assembler options */
73 set *linkOptionsSet = NULL;     /* set of linker options */
74 set *libFilesSet = NULL;
75 set *libPathsSet = NULL;
76 set *relFilesSet = NULL;
77 set *dataDirsSet = NULL;        /* list of data search directories */
78 set *includeDirsSet = NULL;     /* list of include search directories */
79 set *userIncDirsSet = NULL;     /* list of user include directories */
80 set *libDirsSet = NULL;         /* list of lib search directories */
81
82 /* uncomment JAMIN_DS390 to always override and use ds390 port
83   for mcs51 work.  This is temporary, for compatibility testing. */
84 /* #define JAMIN_DS390 */
85 #ifdef JAMIN_DS390
86 int ds390_jammed = 0;
87 #endif
88
89 /* Globally accessible scratch buffer for file names. */
90 char scratchFileName[PATH_MAX];
91 char buffer[PATH_MAX * 2];
92
93 #define OPTION_HELP     "-help"
94
95 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
96
97 #define OPTION_STACK_8BIT       "--stack-8bit"
98 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
99 #define OPTION_LARGE_MODEL      "--model-large"
100 #define OPTION_MEDIUM_MODEL     "--model-medium"
101 #define OPTION_SMALL_MODEL      "--model-small"
102 #define OPTION_FLAT24_MODEL     "--model-flat24"
103 #define OPTION_DUMP_ALL         "--dumpall"
104 #define OPTION_PEEP_FILE        "--peep-file"
105 #define OPTION_LIB_PATH         "--lib-path"
106 #define OPTION_CALLEE_SAVES     "--callee-saves"
107 #define OPTION_STACK_LOC        "--stack-loc"
108 #define OPTION_XSTACK_LOC       "--xstack-loc"
109 #define OPTION_DATA_LOC         "--data-loc"
110 #define OPTION_IDATA_LOC        "--idata-loc"
111 #define OPTION_XRAM_LOC         "--xram-loc"
112 #define OPTION_CODE_LOC         "--code-loc"
113 #define OPTION_STACK_SIZE       "--stack-size"
114 #define OPTION_IRAM_SIZE        "--iram-size"
115 #define OPTION_XRAM_SIZE        "--xram-size"
116 #define OPTION_CODE_SIZE        "--code-size"
117 #define OPTION_VERSION          "--version"
118 #define OPTION_NO_LABEL_OPT     "--nolabelopt"
119 #define OPTION_NO_LOOP_INV      "--noinvariant"
120 #define OPTION_NO_LOOP_IND      "--noinduction"
121 #define OPTION_LESS_PEDANTIC    "--less-pedantic"
122 #define OPTION_DISABLE_WARNING  "--disable-warning"
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 #define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
128 #define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
129 #define OPTION_PRINT_SEARCH_DIRS "--print-search-dirs"
130 #define OPTION_MSVC_ERROR_STYLE "--vc"
131 #define OPTION_USE_STDOUT       "--use-stdout"
132 #define OPTION_PACK_IRAM        "--pack-iram"
133 #define OPTION_NO_PEEP_COMMENTS "--no-peep-comments"
134 #define OPTION_OPT_CODE_SPEED   "--opt-code-speed"
135 #define OPTION_OPT_CODE_SIZE    "--opt-code-size"
136
137 static const OPTION
138 optionsTable[] = {
139     { 0,    NULL,                   NULL, "General options" },
140     { 0,    "--help",               NULL, "Display this help" },
141     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
142     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
143     { 'V',  NULL,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
144     { 'd',  NULL,                   NULL, NULL },
145     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
146     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
147     { 'A',  NULL,                   NULL, NULL },
148     { 'U',  NULL,                   NULL, NULL },
149     { 'C',  NULL,                   NULL, "Preprocessor option" },
150     { 'M',  NULL,                   NULL, "Preprocessor option" },
151     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
152     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
153     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
154     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
155     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code." },
156     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
157     { 0,    OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
158     { 0,    OPTION_MSVC_ERROR_STYLE, &options.vc_err_style, "messages are compatible with Micro$oft visual studio"},
159     { 0,    OPTION_USE_STDOUT, &options.use_stdout, "send errors to stdout instead of stderr"},
160     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
161     { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
162     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
163     { 0,    OPTION_DISABLE_WARNING, NULL, "<nnnn> Disable specific warning" },
164     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
165     { 0,    "--cyclomatic",         &options.cyclomatic, "Display complexity of compiled functions" },
166
167     { 0,    NULL,                   NULL, "Code generation options"},    
168     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
169     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
170     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
171     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
172     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
173 #if !OPT_DISABLE_DS390
174     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
175     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
176     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
177 #endif
178     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
179     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
180     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
181     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the float support functions" },
182     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
183     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
184     { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
185     { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
186     { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
187     { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
188 #if !OPT_DISABLE_DS390
189     { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
190 #endif
191     { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
192 #if !OPT_DISABLE_TININative
193     { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
194 #endif
195 #if !OPT_DISABLE_DS390
196     { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
197 #endif
198 #if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51
199     { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
200 #endif
201     { 0,    OPTION_NO_XINIT_OPT,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
202     { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
203     { 0,    OPTION_NO_PEEP_COMMENTS, &options.noPeepComments, "don't include peephole optimizer comments"},
204 #if !OPT_DISABLE_Z80 || !OPT_DISABLE_GBZ80
205     { 0,    "--no-std-crt0", &options.no_std_crt0, "For the z80/gbz80 do not link default crt0.o"},
206 #endif
207     { 0,    OPTION_SHORT_IS_8BITS,  NULL, "Make short 8 bits (for old times sake)" },
208     
209     { 0,    NULL,                   NULL, "Optimization options"},
210     { 0,    "--nooverlay",          &options.noOverlay, "Disable overlaying leaf function auto variables" },
211     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
212     { 0,    OPTION_NO_LABEL_OPT,    NULL, "Disable label optimisation" },
213     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
214     { 0,    OPTION_NO_LOOP_IND,     NULL, "Disable loop variable induction" },
215     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
216     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
217     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
218     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
219     { 0,    "--peep-asm",           &options.asmpeep, "Enable peephole optimization on inline assembly" },
220     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peephole file" },
221     { 0,    OPTION_OPT_CODE_SPEED,  NULL, "Optimize for code speed rather than size" },
222     { 0,    OPTION_OPT_CODE_SIZE,   NULL, "Optimize for code size rather than speed" },
223         
224     { 0,    NULL,                   NULL, "Internal debugging options"},
225     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
226     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
227     { 0,    "--dumploop",           &options.dump_loop, NULL },
228     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
229     { 0,    "--dumpliverange",      &options.dump_range, NULL },
230     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
231     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
232     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
233     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
234     { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
235     
236     { 0,    NULL,                   NULL, "Linker options" },
237     { 'l',  NULL,                   NULL, "Include the given library in the link" },
238     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
239     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
240     { 0,    OPTION_OUT_FMT_IHX,     NULL, "Output in Intel hex format" },
241     { 0,    "--out-fmt-s19",        &options.out_fmt, "Output in S19 hex format" },
242     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
243     { 0,    OPTION_XRAM_SIZE,       NULL, "<nnnn> External Ram size" },
244     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
245     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
246     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
247     { 0,    OPTION_CODE_SIZE,       NULL, "<nnnn> Code Segment size" },
248     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
249     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
250     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
251 #if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51
252     { 0,    OPTION_STACK_SIZE,      NULL,"MCS51/DS390 - Tells the linker to allocate this space for stack"},
253     { 0,    OPTION_PACK_IRAM,       &options.pack_iram,"MCS51/DS390 - Tells the linker to pack variables in internal ram"},
254 #endif
255     
256     /* End of options */
257     { 0,    NULL }
258 };
259
260 /** Table of all unsupported options and help text to display when one
261     is used.
262 */
263 typedef struct {
264     /** shortOpt as in OPTIONS. */
265     char shortOpt;
266     /** longOpt as in OPTIONS. */
267     const char *longOpt;
268     /** Message to display inside W_UNSUPPORTED_OPT when this option
269         is used. */
270     const char *message;
271 } UNSUPPORTEDOPT;
272
273 static const UNSUPPORTEDOPT
274 unsupportedOptTable[] = {
275     { 'X',  NULL,       "use --xstack-loc instead" },
276     { 'x',  NULL,       "use --xstack instead" },
277     { 'i',  NULL,       "use --idata-loc instead" },
278     { 'r',  NULL,       "use --xdata-loc instead" },
279     { 's',  NULL,       "use --code-loc instead" },
280     { 'Y',  NULL,       "use -I instead" }
281 };
282
283 /** List of all default constant macros.
284  */
285 static const char *_baseValues[] = {
286   "cpp", "sdcpp",
287   "cppextraopts", "",
288   /* Path seperator character */
289   "sep", DIR_SEPARATOR_STRING,
290   NULL
291 };
292
293 static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
294
295 PORT *port;
296
297 static PORT *_ports[] =
298 {
299 #if !OPT_DISABLE_MCS51
300   &mcs51_port,
301 #endif
302 #if !OPT_DISABLE_GBZ80
303   &gbz80_port,
304 #endif
305 #if !OPT_DISABLE_Z80
306   &z80_port,
307 #endif
308 #if !OPT_DISABLE_AVR
309   &avr_port,
310 #endif
311 #if !OPT_DISABLE_DS390
312   &ds390_port,
313 #endif
314 #if !OPT_DISABLE_PIC16
315   &pic16_port,
316 #endif
317 #if !OPT_DISABLE_PIC
318   &pic_port,
319 #endif
320 #if !OPT_DISABLE_TININative
321   &tininative_port,
322 #endif
323 #if !OPT_DISABLE_XA51
324   &xa51_port,
325 #endif
326 #if !OPT_DISABLE_DS400
327   &ds400_port,
328 #endif
329 #if !OPT_DISABLE_HC08
330   &hc08_port,
331 #endif
332 };
333
334 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
335
336 /** Sets the port to the one given by the command line option.
337     @param    The name minus the option (eg 'mcs51')
338     @return     0 on success.
339 */
340 static void
341 _setPort (const char *name)
342 {
343   int i;
344   for (i = 0; i < NUM_PORTS; i++)
345     {
346       if (!strcmp (_ports[i]->target, name))
347         {
348           port = _ports[i];
349           return;
350         }
351     }
352   /* Error - didnt find */
353   werror (E_UNKNOWN_TARGET, name);
354   exit (1);
355 }
356
357 /* Override the default processor with the one specified
358  * on the command line */
359 static void
360 _setProcessor (char *_processor)
361 {
362   port->processor = _processor;
363   fprintf(stderr,"Processor: %s\n",_processor);
364 }
365
366 static void
367 _validatePorts (void)
368 {
369   int i;
370   for (i = 0; i < NUM_PORTS; i++)
371     {
372       if (_ports[i]->magic != PORT_MAGIC)
373         {
374           /* Uncomment this line to debug which port is causing the problem
375            * (the target name is close to the beginning of the port struct
376            * and probably can be accessed just fine). */
377           fprintf(stderr,"%s :",_ports[i]->target);
378           wassertl (0, "Port definition structure is incomplete");
379         }
380     }
381 }
382
383 /* search through the command line options for the port */
384 static void
385 _findPort (int argc, char **argv)
386 {
387   _validatePorts ();
388
389   while (argc--)
390     {
391       if (!strncmp (*argv, "-m", 2))
392         {
393           _setPort (*argv + 2);
394           return;
395         }
396       argv++;
397     }
398
399   /* Use the first in the list */
400         port = _ports[0];
401 }
402
403 /* search through the command line options for the processor */
404 static void
405 _findProcessor (int argc, char **argv)
406 {
407   while (argc--)
408     {
409       if (!strncmp (*argv, "-p", 2))
410         {
411           _setProcessor (*argv + 2);
412           return;
413         }
414       argv++;
415     }
416
417   /* no error if processor was not specified. */
418 }
419
420 /*-----------------------------------------------------------------*/
421 /* printVersionInfo - prints the version info        */
422 /*-----------------------------------------------------------------*/
423 void
424 printVersionInfo (void)
425 {
426   int i;
427
428   fprintf (stderr,
429            "SDCC : ");
430   for (i = 0; i < NUM_PORTS; i++)
431     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
432
433   fprintf (stderr, " " SDCC_VERSION_STR
434 #ifdef SDCC_SUB_VERSION_STR
435            "/" SDCC_SUB_VERSION_STR
436 #endif
437            " #%s (" __DATE__ ")"
438 #ifdef __CYGWIN__
439            " (CYGWIN)\n"
440 #elif defined __MINGW32__
441            " (MINGW32)\n"
442 #elif defined __DJGPP__
443            " (DJGPP)\n"
444 #elif defined(_MSC_VER)
445            " (MSVC)\n"
446 #elif defined(__BORLANDC__)
447            " (BORLANDC)\n"
448 #else
449            " (UNIX) \n"
450 #endif
451     , getBuildNumber() );
452 }
453
454 static void
455 printOptions(const OPTION *optionsTable)
456 {
457   int i;
458   for (i = 0;
459        optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL
460        || optionsTable[i].help != NULL;
461        i++)
462     {
463       if (!optionsTable[i].shortOpt && !optionsTable[i].longOpt
464           && optionsTable[i].help)
465         {
466           fprintf (stdout, "\n%s:\n", optionsTable[i].help);
467         }
468       else
469         {
470           fprintf(stdout, "  %c%c  %-20s  %s\n",
471                   optionsTable[i].shortOpt !=0 ? '-' : ' ',
472                   optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
473                   optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
474                   optionsTable[i].help != NULL ? optionsTable[i].help : ""
475                   );
476         }
477     }
478 }
479
480 /*-----------------------------------------------------------------*/
481 /* printUsage - prints command line syntax         */
482 /*-----------------------------------------------------------------*/
483 void
484 printUsage (void)
485 {
486     int i;
487     printVersionInfo();
488     fprintf (stdout,
489              "Usage : sdcc [options] filename\n"
490              "Options :-\n"
491              );
492
493     printOptions(optionsTable);
494
495     for (i = 0; i < NUM_PORTS; i++)
496       {
497         if (_ports[i]->poptions != NULL)
498           {
499             fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
500             printOptions (_ports[i]->poptions);
501           }
502       }
503
504     exit (0);
505 }
506
507 /*-----------------------------------------------------------------*/
508 /* setParseWithComma - separates string with comma to a set        */
509 /*-----------------------------------------------------------------*/
510 void
511 setParseWithComma (set **dest, char *src)
512 {
513   char *p;
514   int length;
515
516   /* skip the initial white spaces */
517   while (isspace(*src))
518     src++;
519
520   /* skip the trailing white spaces */
521   length = strlen(src);
522   while (length && isspace(src[length-1]))
523     src[--length] = '\0';
524
525   for (p = strtok(src, ","); p != NULL; p = strtok(NULL, ","))
526     addSet(dest, Safe_strdup(p));
527 }
528
529 /*-----------------------------------------------------------------*/
530 /* setDefaultOptions - sets the default options                    */
531 /*-----------------------------------------------------------------*/
532 static void
533 setDefaultOptions (void)
534 {
535   /* first the options part */
536   options.stack_loc = 0;        /* stack pointer initialised to 0 */
537   options.xstack_loc = 0;       /* xternal stack starts at 0 */
538   options.code_loc = 0;         /* code starts at 0 */
539   options.data_loc = 0;         /* JCF: By default let the linker locate data */
540   options.xdata_loc = 0;
541   options.idata_loc = 0x80;
542   options.nopeep = 0;
543   options.model = port->general.default_model;
544   options.nostdlib = 0;
545   options.nostdinc = 0;
546   options.verbose = 0;
547   options.shortis8bits = 0;
548
549   options.stack10bit=0;
550
551   /* now for the optimizations */
552   /* turn on the everything */
553   optimize.global_cse = 1;
554   optimize.label1 = 1;
555   optimize.label2 = 1;
556   optimize.label3 = 1;
557   optimize.label4 = 1;
558   optimize.loopInvariant = 1;
559   optimize.loopInduction = 1;
560
561   /* now for the ports */
562   port->setDefaultOptions ();
563 }
564
565 /*-----------------------------------------------------------------*/
566 /* processFile - determines the type of file from the extension    */
567 /*-----------------------------------------------------------------*/
568 static void
569 processFile (char *s)
570 {
571   char *fext = NULL;
572
573   /* get the file extension */
574   fext = s + strlen (s);
575   while ((fext != s) && *fext != '.')
576     fext--;
577
578   /* now if no '.' then we don't know what the file type is
579      so give a warning and return */
580   if (fext == s)
581     {
582       werror (W_UNKNOWN_FEXT, s);
583       return;
584     }
585
586   /* otherwise depending on the file type */
587   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0)
588     {
589       /* source file name : not if we already have a
590          source file */
591       if (fullSrcFileName)
592         {
593           werror (W_TOO_MANY_SRC, s);
594           return;
595         }
596
597       /* the only source file */
598       fullSrcFileName = s;
599       if (!(srcFile = fopen (fullSrcFileName, "r")))
600         {
601           werror (E_FILE_OPEN_ERR, s);
602           exit (1);
603         }
604
605       /* copy the file name into the buffer */
606       strncpyz (buffer, s, sizeof(buffer));
607
608       /* get rid of the "."-extension */
609
610       /* is there a dot at all? */
611       if (strrchr (buffer, '.') &&
612           /* is the dot in the filename, not in the path? */
613           (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
614         {
615         *strrchr (buffer, '.') = '\0';
616         }
617
618       /* get rid of any path information
619          for the module name; */
620       fext = buffer + strlen (buffer);
621 #if NATIVE_WIN32
622       /* do this by going backwards till we
623          get '\' or ':' or start of buffer */
624       while (fext != buffer &&
625              *(fext - 1) != DIR_SEPARATOR_CHAR &&
626              *(fext - 1) != ':')
627         {
628         fext--;
629         }
630 #else
631       /* do this by going backwards till we
632          get '/' or start of buffer */
633       while (fext != buffer &&
634              *(fext - 1) != DIR_SEPARATOR_CHAR)
635         {
636           fext--;
637         }
638 #endif
639       moduleNameBase = Safe_strdup ( fext );
640       moduleName = Safe_strdup ( fext );
641
642       for (fext = moduleName; *fext; fext++)
643         if (!isalnum (*fext))
644           *fext = '_';
645       return;
646     }
647
648   /* if the extention is type .rel or .r or .REL or .R
649      addtional object file will be passed to the linker */
650   if (strcmp (fext, ".r") == 0 || strcmp (fext, ".rel") == 0 ||
651       strcmp (fext, ".R") == 0 || strcmp (fext, ".REL") == 0 ||
652       strcmp (fext, port->linker.rel_ext) == 0)
653     {
654       addSet(&relFilesSet, Safe_strdup(s));
655       return;
656     }
657
658   /* if .lib or .LIB */
659   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
660     {
661       addSet(&libFilesSet, Safe_strdup(s));
662       return;
663     }
664
665   werror (W_UNKNOWN_FEXT, s);
666
667 }
668
669 static void
670 _setModel (int model, const char *sz)
671 {
672   if (port->general.supported_models & model)
673     options.model = model;
674   else
675     werror (W_UNSUPPORTED_MODEL, sz, port->target);
676 }
677
678 /** Gets the string argument to this option.  If the option is '--opt'
679     then for input of '--optxyz' or '--opt xyz' returns xyz.
680 */
681 char *
682 getStringArg(const char *szStart, char **argv, int *pi, int argc)
683 {
684   if (argv[*pi][strlen(szStart)])
685     {
686       return &argv[*pi][strlen(szStart)];
687     }
688   else
689     {
690       ++(*pi);
691       if (*pi >= argc)
692         {
693           werror (E_ARGUMENT_MISSING, szStart);
694           /* Die here rather than checking for errors later. */
695           exit(-1);
696         }
697       else
698         {
699           return argv[*pi];
700         }
701     }
702 }
703
704 /** Gets the integer argument to this option using the same rules as
705     getStringArg.
706 */
707 int
708 getIntArg(const char *szStart, char **argv, int *pi, int argc)
709 {
710   return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
711 }
712
713 static void
714 verifyShortOption(const char *opt)
715 {
716   if (strlen(opt) != 2)
717     {
718       werror (W_EXCESS_SHORT_OPTIONS, opt);
719     }
720 }
721
722 static bool
723 tryHandleUnsupportedOpt(char **argv, int *pi)
724 {
725     if (argv[*pi][0] == '-')
726         {
727             const char *longOpt = "";
728             char shortOpt = -1;
729             int i;
730
731             if (argv[*pi][1] == '-')
732                 {
733                     /* Long option. */
734                     longOpt = argv[*pi];
735                 }
736             else
737                 {
738                     shortOpt = argv[*pi][1];
739                 }
740             for (i = 0; i < LENGTH(unsupportedOptTable); i++)
741                 {
742                     if (unsupportedOptTable[i].shortOpt == shortOpt ||
743                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
744                         /* Found an unsupported opt. */
745                         char buffer[100];
746                         SNPRINTF(buffer, sizeof(buffer),
747                                  "%s%c%c",
748                                  longOpt ? longOpt : "",
749                                  shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
750                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
751                         return 1;
752                     }
753                 }
754             /* Didn't find in the table */
755             return 0;
756         }
757     else
758         {
759             /* Not an option, so can't be unsupported :) */
760             return 0;
761     }
762 }
763
764 static bool
765 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
766 {
767   int i;
768   for (i = 0;
769        optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL
770        || optionsTable[i].help != NULL;
771        i++)
772     {
773       if (optionsTable[i].shortOpt == shortOpt ||
774           (longOpt && optionsTable[i].longOpt &&
775            strcmp(optionsTable[i].longOpt, longOpt) == 0))
776         {
777
778           /* If it is a flag then we can handle it here */
779           if (optionsTable[i].pparameter != NULL)
780             {
781               if (optionsTable[i].shortOpt == shortOpt)
782                 {
783                   verifyShortOption(argv[*pi]);
784                 }
785
786               (*optionsTable[i].pparameter)++;
787               return 1;
788             }
789           else {
790             /* Not a flag.  Handled manually later. */
791             return 0;
792           }
793         }
794     }
795   /* Didn't find in the table */
796   return 0;
797 }
798
799 static bool
800 tryHandleSimpleOpt(char **argv, int *pi)
801 {
802     if (argv[*pi][0] == '-')
803         {
804             const char *longOpt = "";
805             char shortOpt = -1;
806
807             if (argv[*pi][1] == '-')
808                 {
809                     /* Long option. */
810                     longOpt = argv[*pi];
811                 }
812             else
813                 {
814                     shortOpt = argv[*pi][1];
815                 }
816
817             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
818               {
819                 return 1;
820               }
821             else if (port && port->poptions &&
822                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
823               {
824                 return 1;
825               }
826             else
827               {
828                 return 0;
829               }
830         }
831     else
832         {
833             /* Not an option, so can't be handled. */
834             return 0;
835         }
836 }
837
838 /*-----------------------------------------------------------------*/
839 /* parseCmdLine - parses the command line and sets the options     */
840 /*-----------------------------------------------------------------*/
841 static int
842 parseCmdLine (int argc, char **argv)
843 {
844   int i;
845
846   /* go thru all whole command line */
847   for (i = 1; i < argc; i++)
848     {
849       if (i >= argc)
850         break;
851
852       if (tryHandleUnsupportedOpt(argv, &i) == TRUE)
853         {
854           continue;
855         }
856
857       if (tryHandleSimpleOpt(argv, &i) == TRUE)
858         {
859           continue;
860         }
861
862       /* options */
863       if (argv[i][0] == '-' && argv[i][1] == '-')
864         {
865           if (strcmp (argv[i], OPTION_HELP) == 0)
866             {
867               printUsage ();
868               exit (0);
869             }
870
871           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
872             {
873               options.stack10bit = 0;
874               continue;
875             }
876
877           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
878             {
879               options.out_fmt = 0;
880               continue;
881             }
882
883           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
884             {
885               _setModel (MODEL_LARGE, argv[i]);
886               continue;
887             }
888
889           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
890             {
891               _setModel (MODEL_MEDIUM, argv[i]);
892               continue;
893             }
894
895           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
896             {
897               _setModel (MODEL_SMALL, argv[i]);
898               continue;
899             }
900
901           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
902             {
903               _setModel (MODEL_FLAT24, argv[i]);
904               continue;
905             }
906
907           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
908             {
909               options.dump_rassgn =
910                 options.dump_pack =
911                 options.dump_range =
912                 options.dump_kill =
913                 options.dump_loop =
914                 options.dump_gcse =
915                 options.dump_raw = 1;
916               continue;
917             }
918
919           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
920             {
921               options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
922               continue;
923             }
924
925           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
926             {
927               addSet(&libPathsSet, Safe_strdup(getStringArg(OPTION_LIB_PATH, argv, &i, argc)));
928               continue;
929             }
930
931           if (strcmp (argv[i], OPTION_VERSION) == 0)
932             {
933               printVersionInfo ();
934               exit (0);
935               continue;
936             }
937
938           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
939             {
940               setParseWithComma(&options.calleeSavesSet, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
941               continue;
942             }
943
944           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
945             {
946               options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
947               continue;
948             }
949
950           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
951             {
952               options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
953               continue;
954             }
955
956           if (strcmp (argv[i], OPTION_STACK_SIZE) == 0)
957             {
958               options.stack_size = getIntArg(OPTION_STACK_SIZE, argv, &i, argc);
959               continue;
960             }
961
962           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
963             {
964               options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
965               continue;
966             }
967
968           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
969             {
970               options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
971               continue;
972             }
973
974           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
975             {
976               options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
977               options.xram_size_set = TRUE;
978               continue;
979             }
980
981           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
982             {
983               options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
984               continue;
985             }
986
987           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
988             {
989               options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
990               continue;
991             }
992
993           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
994             {
995               options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
996               continue;
997             }
998
999           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
1000             {
1001               options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
1002               continue;
1003             }
1004
1005           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
1006             {
1007               optimize.global_cse = 0;
1008               continue;
1009             }
1010
1011           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
1012             {
1013               optimize.loopInvariant = 0;
1014               continue;
1015             }
1016
1017           if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
1018             {
1019               optimize.label4 = 0;
1020               continue;
1021             }
1022
1023           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
1024             {
1025               optimize.loopInduction = 0;
1026               continue;
1027             }
1028
1029           if (strcmp (argv[i], OPTION_OPT_CODE_SPEED) == 0)
1030             {
1031               optimize.codeSpeed = 1;
1032               optimize.codeSize = 0;
1033               continue;
1034             }
1035
1036           if (strcmp (argv[i], OPTION_OPT_CODE_SIZE) == 0)
1037             {
1038               optimize.codeSpeed = 0;
1039               optimize.codeSize = 1;
1040               continue;
1041             }
1042
1043           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0)
1044             {
1045               options.lessPedantic = 1;
1046               setErrorLogLevel(ERROR_LEVEL_WARNING);
1047               continue;
1048             }
1049
1050           if (strcmp (argv[i], OPTION_DISABLE_WARNING) == 0)
1051             {
1052               int w = getIntArg(OPTION_DISABLE_WARNING, argv, &i, argc);
1053               if (w < MAX_ERROR_WARNING)
1054                 {
1055                   setWarningDisabled(w);
1056                 }
1057               continue;
1058             }
1059
1060           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0)
1061             {
1062               options.shortis8bits=1;
1063               continue;
1064             }
1065
1066           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
1067             {
1068               options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
1069               continue;
1070             }
1071
1072           if (!port->parseOption (&argc, argv, &i))
1073             {
1074               werror (W_UNKNOWN_OPTION, argv[i]);
1075               continue;
1076             }
1077           else
1078             {
1079               continue;
1080             }
1081         }
1082
1083       /* if preceded by  '-' then option */
1084       if (*argv[i] == '-')
1085         {
1086           switch (argv[i][1])
1087             {
1088             case 'h':
1089               verifyShortOption(argv[i]);
1090
1091               printUsage ();
1092               exit (0);
1093               break;
1094
1095             case 'm':
1096               /* Used to select the port. But this has already been done. */
1097               break;
1098
1099             case 'p':
1100               /* Used to select the processor in port. But this has
1101                * already been done. */
1102               break;
1103
1104             case 'c':
1105               verifyShortOption(argv[i]);
1106
1107               options.cc_only = 1;
1108               break;
1109
1110             case 'L':
1111                 addSet(&libPathsSet, Safe_strdup(getStringArg("-L", argv, &i, argc)));
1112                 break;
1113
1114             case 'l':
1115                 addSet(&libFilesSet, Safe_strdup(getStringArg("-l", argv, &i, argc)));
1116                 break;
1117
1118             case 'o':
1119               {
1120                 char *p;
1121
1122                 /* copy the file name into the buffer */
1123                 strncpyz(buffer, getStringArg("-o", argv, &i, argc),
1124                          sizeof(buffer));
1125                 /* point to last character */
1126                 p = buffer + strlen (buffer) - 1;
1127                 if (*p == DIR_SEPARATOR_CHAR)
1128                   {
1129                     /* only output path specified */
1130                     dstPath = Safe_strdup (buffer);
1131                     fullDstFileName = NULL;
1132                   }
1133                 else
1134                   {
1135                     fullDstFileName = Safe_strdup (buffer);
1136
1137                     /* get rid of the "."-extension */
1138
1139                     /* is there a dot at all? */
1140                     if (strrchr (buffer, '.') &&
1141                         /* is the dot in the filename, not in the path? */
1142                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1143                       *strrchr (buffer, '.') = '\0';
1144
1145                     dstFileName = Safe_strdup (buffer);
1146
1147                     /* strip module name to get path */
1148                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1149                     if (p)
1150                       {
1151                         /* path with trailing / */
1152                         p[1] = '\0';
1153                         dstPath = Safe_strdup (buffer);
1154                       }
1155                   }
1156                 break;
1157               }
1158
1159             case 'W':
1160               /* pre-processer options */
1161               if (argv[i][2] == 'p')
1162                 {
1163                   setParseWithComma(&preArgvSet, getStringArg("-Wp", argv, &i, argc));
1164                 }
1165               /* linker options */
1166               else if (argv[i][2] == 'l')
1167                 {
1168                   setParseWithComma(&linkOptionsSet, getStringArg("-Wl", argv, &i, argc));
1169                 }
1170               /* assembler options */
1171               else if (argv[i][2] == 'a')
1172                 {
1173                   setParseWithComma(&asmOptionsSet, getStringArg("-Wa", argv, &i, argc));
1174                 }
1175               else
1176                 {
1177                   werror (W_UNKNOWN_OPTION, argv[i]);
1178                 }
1179               break;
1180
1181             case 'v':
1182               verifyShortOption(argv[i]);
1183
1184               printVersionInfo ();
1185               exit (0);
1186               break;
1187
1188               /* preprocessor options */
1189             case 'M':
1190               {
1191                 preProcOnly = 1;
1192                 if (argv[i][2] == 'M')
1193                   addSet(&preArgvSet, Safe_strdup("-MM"));
1194                 else
1195                   addSet(&preArgvSet, Safe_strdup("-M"));
1196                 break;
1197               }
1198             case 'C':
1199               {
1200                 addSet(&preArgvSet, Safe_strdup("-C"));
1201                 break;
1202               }
1203
1204             case 'd':
1205             case 'D':
1206             case 'I':
1207             case 'A':
1208             case 'U':
1209               {
1210                 char sOpt = argv[i][1];
1211                 char *rest;
1212
1213                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1214                   {
1215                     i++;
1216                     if (i >= argc)
1217                       {
1218                         /* No argument. */
1219                         werror(E_ARGUMENT_MISSING, argv[i-1]);
1220                         break;
1221                       }
1222                     else
1223                       {
1224                         rest = argv[i];
1225                       }
1226                   }
1227                 else
1228                   rest = &argv[i][2];
1229
1230                 if (sOpt == 'Y')
1231                   sOpt = 'I';
1232
1233                 SNPRINTF (buffer, sizeof(buffer),
1234                   ((sOpt == 'I') ? "-%c\"%s\"": "-%c%s"), sOpt, rest);
1235                 addSet(&preArgvSet, Safe_strdup(buffer));
1236                 if(sOpt == 'I') {
1237                   addSet(&includeDirsSet, Safe_strdup(rest));
1238                   addSet(&userIncDirsSet, Safe_strdup(rest));
1239                 }
1240               }
1241               break;
1242
1243             default:
1244               if (!port->parseOption (&argc, argv, &i))
1245                 werror (W_UNKNOWN_OPTION, argv[i]);
1246             }
1247           continue;
1248         }
1249
1250       if (!port->parseOption (&argc, argv, &i))
1251         {
1252           /* no option must be a filename */
1253           if (options.c1mode)
1254             {
1255               werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1256             }
1257           else
1258             {
1259               processFile (argv[i]);
1260             }
1261         }
1262     }
1263
1264   /* some sanity checks in c1 mode */
1265   if (options.c1mode)
1266     {
1267       const char *s;
1268
1269       if (fullSrcFileName)
1270         {
1271           fclose (srcFile);
1272           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1273         }
1274       fullSrcFileName = NULL;
1275       for (s = setFirstItem(relFilesSet); s != NULL; s = setNextItem(relFilesSet))
1276         {
1277           werror (W_NO_FILE_ARG_IN_C1, s);
1278         }
1279       for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1280         {
1281           werror (W_NO_FILE_ARG_IN_C1, s);
1282         }
1283       deleteSet(&relFilesSet);
1284       deleteSet(&libFilesSet);
1285
1286       if (options.cc_only || noAssemble || preProcOnly)
1287         {
1288           werror (W_ILLEGAL_OPT_COMBINATION);
1289         }
1290       options.cc_only = noAssemble = preProcOnly = 0;
1291       if (!dstFileName)
1292         {
1293           werror (E_NEED_OPT_O_IN_C1);
1294           exit (1);
1295         }
1296     }
1297   /* if no dstFileName given with -o, we've to find one: */
1298   if (!dstFileName)
1299     {
1300       const char *s;
1301
1302       /* use the modulename from the C-source */
1303       if (fullSrcFileName)
1304         {
1305           size_t bufSize = strlen (dstPath) + strlen (moduleNameBase) + 1;
1306
1307           dstFileName = Safe_alloc (bufSize);
1308           strncpyz (dstFileName, dstPath, bufSize);
1309           strncatz (dstFileName, moduleNameBase, bufSize);
1310         }
1311       /* use the modulename from the first object file */
1312       else if ((s = peekSet(relFilesSet)) != NULL)
1313         {
1314           char *objectName;
1315           size_t bufSize;
1316
1317           strncpyz (buffer, s, sizeof(buffer));
1318           /* remove extension (it must be .rel) */
1319           *strrchr (buffer, '.') = '\0';
1320           /* remove path */
1321           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1322           if (objectName)
1323             {
1324               ++objectName;
1325             }
1326           else
1327             {
1328               objectName = buffer;
1329             }
1330           bufSize = strlen (dstPath) + strlen (objectName) + 1;
1331           dstFileName = Safe_alloc (bufSize);
1332           strncpyz (dstFileName, dstPath, bufSize);
1333           strncatz (dstFileName, objectName, bufSize);
1334         }
1335       /* else no module given: help text is displayed */
1336     }
1337
1338   /* set int, long and float reentrancy based on stack-auto */
1339   if (options.stackAuto)
1340     {
1341       options.intlong_rent++;
1342       options.float_rent++;
1343     }
1344
1345   /* set up external stack location if not explicitly specified */
1346   if (!options.xstack_loc)
1347     options.xstack_loc = options.xdata_loc;
1348
1349   /* if debug option is set then open the cdbFile */
1350   if (options.debug && fullSrcFileName)
1351     {
1352       SNPRINTF (scratchFileName, sizeof(scratchFileName),
1353                 "%s.adb", dstFileName); /*JCF: Nov 30, 2002*/
1354       if(debugFile->openFile(scratchFileName))
1355         debugFile->writeModule(moduleName);
1356       else
1357         werror (E_FILE_OPEN_ERR, scratchFileName);
1358     }
1359   MSVC_style(options.vc_err_style);
1360   if(options.use_stdout) dup2(STDOUT_FILENO, STDERR_FILENO);
1361
1362   return 0;
1363 }
1364
1365 /*-----------------------------------------------------------------*/
1366 /* linkEdit : - calls the linkage editor  with options             */
1367 /*-----------------------------------------------------------------*/
1368 static void
1369 linkEdit (char **envp)
1370 {
1371   FILE *lnkfile;
1372   char *segName, *c;
1373   int system_ret;
1374   const char *s;
1375
1376
1377   if(port->linker.needLinkerScript)
1378     {
1379       char out_fmt;
1380
1381       switch (options.out_fmt)
1382         {
1383         case 0:
1384           out_fmt = 'i';        /* Intel hex */
1385           break;
1386         case 1:
1387           out_fmt = 's';        /* Motorola S19 */
1388           break;
1389         case 2:
1390           out_fmt = 't';        /* Elf */
1391           break;
1392         default:
1393           out_fmt = 'i';
1394         }
1395
1396       /* first we need to create the <filename>.lnk file */
1397       SNPRINTF (scratchFileName, sizeof(scratchFileName),
1398         "%s.lnk", dstFileName);
1399       if (!(lnkfile = fopen (scratchFileName, "w")))
1400         {
1401           werror (E_FILE_OPEN_ERR, scratchFileName);
1402           exit (1);
1403         }
1404
1405       if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
1406         {
1407           fprintf (lnkfile, "--\n-m\n-j\n-x\n-%c %s\n",
1408             out_fmt, dstFileName);
1409         }
1410       else /*For all the other ports.  Including pics???*/
1411         {
1412           fprintf (lnkfile, "-myux%c\n", out_fmt);
1413           if(options.pack_iram)
1414               fprintf (lnkfile, "-Y\n");
1415         }
1416
1417       if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1418         {
1419           /* if iram size specified */
1420           if (options.iram_size)
1421             fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1422
1423           /* if stack size specified*/
1424           if(options.stack_size)
1425               fprintf (lnkfile, "-A 0x%02x\n", options.stack_size);
1426
1427           /* if xram size specified */
1428           if (options.xram_size_set)
1429             fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1430
1431           /* if code size specified */
1432           if (options.code_size)
1433             fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1434
1435           if (options.debug)
1436             fprintf (lnkfile, "-z\n");
1437         }
1438
1439 #define WRITE_SEG_LOC(N, L) \
1440   segName = Safe_strdup(N); \
1441   c = strtok(segName, " \t"); \
1442   fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1443   if (segName) { Safe_free(segName); }
1444
1445       if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1446         {
1447
1448           /* code segment start */
1449           WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1450
1451           /* data segment start. If zero, the linker chooses
1452              the best place for data */
1453           if(options.data_loc)
1454             {
1455               WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1456             }
1457
1458           /* xdata segment start. If zero, the linker chooses
1459              the best place for xdata */
1460           if(options.xdata_loc)
1461             {
1462               WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1463             }
1464
1465           /* indirect data */
1466           if (IDATA_NAME)
1467             {
1468               WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1469             }
1470
1471           /* bit segment start */
1472           WRITE_SEG_LOC (BIT_NAME, 0);
1473
1474           /* stack start */
1475           if ( (options.stack_loc) && (options.stack_loc<0x100) )
1476             {
1477               WRITE_SEG_LOC ("SSEG", options.stack_loc);
1478             }
1479         }
1480       else /*For the z80, gbz80*/
1481         {
1482           WRITE_SEG_LOC ("_CODE", options.code_loc);
1483           WRITE_SEG_LOC ("_DATA", options.data_loc);
1484         }
1485
1486       /* If the port has any special linker area declarations, get 'em */
1487       if (port->extraAreas.genExtraAreaLinkOptions)
1488         {
1489           port->extraAreas.genExtraAreaLinkOptions(lnkfile);
1490         }
1491
1492       /* add the extra linker options */
1493       fputStrSet(lnkfile, linkOptionsSet);
1494
1495       /* command line defined library paths if specified */
1496       for (s = setFirstItem(libPathsSet); s != NULL; s = setNextItem(libPathsSet))
1497         fprintf (lnkfile, "-k %s\n", s);
1498
1499       /* standard library path */
1500       if (!options.nostdlib)
1501         {
1502           if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80 || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
1503             {
1504               switch (options.model)
1505                 {
1506                 case MODEL_SMALL:
1507                   c = "small";
1508                   break;
1509                 case MODEL_LARGE:
1510                   c = "large";
1511                   break;
1512                 case MODEL_FLAT24:
1513                   /* c = "flat24"; */
1514                   if (TARGET_IS_DS390)
1515                     {
1516                       c = "ds390";
1517                     }
1518                   else if (TARGET_IS_DS400)
1519                     {
1520                       c = "ds400";
1521                     }
1522                   else
1523                     {
1524                       fprintf(stderr,
1525                         "Add support for your FLAT24 target in %s @ line %d\n",
1526                         __FILE__, __LINE__);
1527                       exit(-1);
1528                     }
1529                   break;
1530                 case MODEL_PAGE0:
1531                   c = "xa51";
1532                   break;
1533                 default:
1534                   werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1535                   c = "unknown";
1536                   break;
1537                 }
1538             }
1539           else /*for the z80, gbz80*/
1540             {
1541               if (TARGET_IS_HC08)
1542                 c = "hc08";
1543               else if (TARGET_IS_Z80)
1544                 c = "z80";
1545               else
1546                 c = "gbz80";
1547             }
1548           for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1549             mfprintf (lnkfile, getRuntimeVariables(), "-k %s{sep}%s\n", s, c);
1550         }
1551
1552       /* command line defined library files if specified */
1553       for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1554         fprintf (lnkfile, "-l %s\n", s);
1555
1556       /* standard library files */
1557       if (!options.nostdlib)
1558         {
1559 #if !OPT_DISABLE_DS390
1560           if (options.model == MODEL_FLAT24)
1561             {
1562               if (TARGET_IS_DS390)
1563                 {
1564                   fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1565                 }
1566               else if (TARGET_IS_DS400)
1567                 {
1568                   fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1569                 }
1570               else
1571                 {
1572                   fprintf(stderr,
1573                     "Add support for your FLAT24 target in %s @ line %d\n",
1574                     __FILE__, __LINE__);
1575                   exit(-1);
1576                 }
1577               }
1578 #endif
1579
1580 #if !OPT_DISABLE_XA51
1581 #ifdef STD_XA51_LIB
1582           if (options.model == MODEL_PAGE0)
1583             {
1584               fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1585             }
1586 #endif
1587 #endif
1588           if (TARGET_IS_MCS51)
1589             {
1590               fprintf (lnkfile, "-l mcs51\n");
1591             }
1592           if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80
1593             || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
1594             { /*Why the z80 port is not using the standard libraries?*/
1595               fprintf (lnkfile, "-l %s\n", STD_LIB);
1596               fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1597               fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1598               fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1599             }
1600           else if (TARGET_IS_HC08)
1601             {
1602               fprintf (lnkfile, "-l hc08\n");
1603             }
1604           else if (TARGET_IS_Z80)
1605             {
1606               fprintf (lnkfile, "-l z80\n");
1607             }
1608           else if (TARGET_IS_GBZ80)
1609             {
1610               fprintf (lnkfile, "-l gbz80\n");
1611             }
1612         }
1613
1614       /*For the z80 and gbz80 ports, try to find where crt0.o is...
1615       It is very important for this file to be first on the linking proccess
1616       so the areas are set in the correct order, expecially _GSINIT*/
1617       if ((TARGET_IS_Z80 || TARGET_IS_GBZ80) &&
1618         !options.no_std_crt0 && !options.nostdlib) /*For the z80, gbz80*/
1619         {
1620           char crt0path[PATH_MAX];
1621           FILE * crt0fp;
1622           for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1623             {
1624               sprintf (crt0path, "%s%s%s%scrt0.o",
1625                 s, DIR_SEPARATOR_STRING, c, DIR_SEPARATOR_STRING);
1626
1627               crt0fp=fopen(crt0path, "r");
1628               if(crt0fp!=NULL)/*Found it!*/
1629                 {
1630                   fclose(crt0fp);
1631                   #ifdef __CYGWIN__
1632                   {
1633                     /*The CYGWIN version of the z80-gbz80 linker is getting confused with
1634                     windows paths, so convert them to the CYGWIN format*/
1635                     char posix_path[PATH_MAX];
1636                     void cygwin_conv_to_full_posix_path(char * win_path, char * posix_path);
1637                     cygwin_conv_to_full_posix_path(crt0path, posix_path);
1638                     strcpy(crt0path, posix_path);
1639                   }
1640                   #endif
1641                   fprintf (lnkfile, "%s\n", crt0path);
1642                   break;
1643                 }
1644             }
1645           if(s==NULL) fprintf (stderr, "Warning: couldn't find crt0.o\n");
1646         }
1647
1648       /* put in the object files */
1649       if (fullSrcFileName)
1650         fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
1651
1652       fputStrSet(lnkfile, relFilesSet);
1653
1654       fprintf (lnkfile, "\n-e\n");
1655       fclose (lnkfile);
1656     } /* if(port->linker.needLinkerScript) */
1657
1658   if (options.verbose)
1659     printf ("sdcc: Calling linker...\n");
1660
1661   /* build linker output filename */
1662
1663   /* -o option overrides default name? */
1664   if (fullDstFileName)
1665     {
1666       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1667     }
1668   else
1669     {
1670       /* the linked file gets the name of the first modul */
1671       if (fullSrcFileName)
1672         {
1673           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1674         }
1675       else
1676         {
1677           s = peekSet(relFilesSet);
1678
1679           assert(s);
1680
1681           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1682           /* strip ".rel" extension */
1683           *strrchr (scratchFileName, '.') = '\0';
1684         }
1685       strncatz (scratchFileName,
1686         options.out_fmt ? ".S19" : ".ihx",
1687         sizeof(scratchFileName));
1688     }
1689
1690   if (port->linker.cmd)
1691     {
1692       char buffer2[PATH_MAX];
1693       char buffer3[PATH_MAX];
1694       set *tempSet=NULL, *libSet=NULL;
1695
1696       strcpy(buffer3, dstFileName);
1697       if(TARGET_IS_PIC16) {
1698
1699          /* use $l to set the linker include directories */
1700          tempSet = appendStrSet(libDirsSet, "-I\"", "\"");
1701          mergeSets(&linkOptionsSet, tempSet);
1702
1703          tempSet = appendStrSet(libPathsSet, "-I\"", "\"");
1704          mergeSets(&linkOptionsSet, tempSet);
1705
1706          /* use $3 for libraries from command line --> libSet */
1707          mergeSets(&libSet, libFilesSet);
1708
1709          tempSet = appendStrSet(relFilesSet, "", "");
1710          mergeSets(&libSet, tempSet);
1711 //         libSet = reverseSet(libSet);
1712
1713         if(fullSrcFileName) {
1714 //              strcpy(buffer3, strrchr(fullSrcFileName, DIR_SEPARATOR_CHAR)+1);
1715                 /* if it didn't work, revert to old behaviour */
1716                 if(!strlen(buffer3))strcpy(buffer3, dstFileName);
1717                 strcat(buffer3, port->linker.rel_ext);
1718
1719         } else strcpy(buffer3, "");
1720       }
1721
1722       buildCmdLine (buffer2, port->linker.cmd, buffer3, scratchFileName, (libSet?joinStrSet(libSet):NULL), linkOptionsSet);
1723
1724       buildCmdLine2 (buffer, sizeof(buffer), buffer2);
1725     }
1726   else
1727     {
1728       buildCmdLine2 (buffer, sizeof(buffer), port->linker.mcmd);
1729     }
1730
1731   /*  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer); */
1732
1733   system_ret = my_system (buffer);
1734   /* TODO: most linker don't have a -o parameter */
1735   /* -o option overrides default name? */
1736   if (fullDstFileName)
1737     {
1738       char *p, *q;
1739       /* the linked file gets the name of the first modul */
1740       if (fullSrcFileName)
1741         {
1742           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1743           p = strlen (scratchFileName) + scratchFileName;
1744         }
1745       else
1746         {
1747           s = peekSet(relFilesSet);
1748
1749           assert(s);
1750
1751           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1752           /* strip ".rel" extension */
1753           p = strrchr (scratchFileName, '.');
1754           if (p)
1755             {
1756               *p = 0;
1757             }
1758         }
1759       strncatz (scratchFileName,
1760         options.out_fmt ? ".S19" : ".ihx",
1761         sizeof(scratchFileName));
1762       if (strcmp (fullDstFileName, scratchFileName))
1763         unlink (fullDstFileName);
1764       rename (scratchFileName, fullDstFileName);
1765
1766       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1767       q = strrchr (buffer, '.');
1768       if (!q)
1769         {
1770           /* no extension: append new extensions */
1771           q = strlen (buffer) + buffer;
1772         }
1773
1774       *p = 0;
1775       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1776       *q = 0;
1777       strncatz(buffer, ".map", sizeof(buffer));
1778       if (strcmp (scratchFileName, buffer))
1779         unlink (buffer);
1780       rename (scratchFileName, buffer);
1781       *p = 0;
1782       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1783       *q = 0;
1784       strncatz(buffer, ".mem", sizeof(buffer));
1785       if (strcmp (scratchFileName, buffer))
1786         unlink (buffer);
1787       rename (scratchFileName, buffer);
1788       if (options.debug)
1789         {
1790           *p = 0;
1791           strncatz (scratchFileName, ".cdb", sizeof(scratchFileName));
1792           *q = 0;
1793           strncatz(buffer, ".cdb", sizeof(buffer));
1794           if (strcmp (scratchFileName, buffer))
1795             unlink (buffer);
1796           rename (scratchFileName, buffer);
1797           /* and the OMF file without extension: */
1798           *p = 0;
1799           *q = 0;
1800           if (strcmp (scratchFileName, buffer))
1801             unlink (buffer);
1802           rename (scratchFileName, buffer);
1803         }
1804     }
1805   if (system_ret)
1806     {
1807       exit (1);
1808     }
1809 }
1810
1811 /*-----------------------------------------------------------------*/
1812 /* assemble - spawns the assembler with arguments                  */
1813 /*-----------------------------------------------------------------*/
1814 static void
1815 assemble (char **envp)
1816 {
1817     /* build assembler output filename */
1818
1819     /* -o option overrides default name? */
1820     if (options.cc_only && fullDstFileName) {
1821         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1822     } else {
1823         /* the assembled file gets the name of the first modul */
1824         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1825         strncatz (scratchFileName, port->linker.rel_ext,
1826                   sizeof(scratchFileName));
1827     }
1828
1829     if (port->assembler.do_assemble) {
1830         port->assembler.do_assemble(asmOptionsSet);
1831         return ;
1832     } else if (port->assembler.cmd) {
1833         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1834                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1835                       asmOptionsSet);
1836     } else {
1837         buildCmdLine2 (buffer, sizeof(buffer), port->assembler.mcmd);
1838     }
1839
1840     if (my_system (buffer)) {
1841         /* either system() or the assembler itself has reported an error
1842            perror ("Cannot exec assembler");
1843         */
1844         exit (1);
1845     }
1846     /* TODO: most assembler don't have a -o parameter */
1847     /* -o option overrides default name? */
1848     if (options.cc_only && fullDstFileName) {
1849         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1850         strncatz (scratchFileName,
1851                   port->linker.rel_ext,
1852                   sizeof(scratchFileName));
1853         if (strcmp (scratchFileName, fullDstFileName))
1854           unlink (fullDstFileName);
1855         rename (scratchFileName, fullDstFileName);
1856     }
1857 }
1858
1859 /*-----------------------------------------------------------------*/
1860 /* preProcess - spawns the preprocessor with arguments       */
1861 /*-----------------------------------------------------------------*/
1862 static int
1863 preProcess (char **envp)
1864 {
1865   if (options.c1mode)
1866     {
1867       yyin = stdin;
1868     }
1869   else
1870     {
1871       const char *s;
1872       set *inclList = NULL;
1873
1874       /* if using external stack define the macro */
1875       if (options.useXstack)
1876         addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
1877
1878       /* set the macro for stack autos  */
1879       if (options.stackAuto)
1880         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_AUTO"));
1881
1882       /* set the macro for stack autos  */
1883       if (options.stack10bit)
1884         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_TENBIT"));
1885
1886       /* set the macro for no overlay  */
1887       if (options.noOverlay)
1888         addSet(&preArgvSet, Safe_strdup("-DSDCC_NOOVERLAY"));
1889
1890       /* set the macro for large model  */
1891       switch (options.model)
1892         {
1893         case MODEL_LARGE:
1894           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_LARGE"));
1895           break;
1896         case MODEL_SMALL:
1897           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_SMALL"));
1898           break;
1899         case MODEL_COMPACT:
1900           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_COMPACT"));
1901           break;
1902         case MODEL_MEDIUM:
1903           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_MEDIUM"));
1904           break;
1905         case MODEL_FLAT24:
1906           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_FLAT24"));
1907           break;
1908         case MODEL_PAGE0:
1909           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_PAGE0"));
1910           break;
1911         default:
1912           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1913           break;
1914         }
1915
1916       /* add port (processor information to processor */
1917       addSet(&preArgvSet, Safe_strdup("-DSDCC_{port}"));
1918       addSet(&preArgvSet, Safe_strdup("-D__{port}"));
1919
1920       /* standard include path */
1921       if (!options.nostdinc) {
1922         inclList = appendStrSet(includeDirsSet, "-I\"", "\"");
1923         mergeSets(&preArgvSet, inclList);
1924       }
1925
1926       setMainValue("cppextraopts", (s = joinStrSet(preArgvSet)));
1927       Safe_free((void *)s);
1928       if (inclList != NULL)
1929         deleteSet(&inclList);
1930
1931       if (preProcOnly && fullDstFileName)
1932         {
1933           /* -E and -o given */
1934           setMainValue ("cppoutfilename", fullDstFileName);
1935         }
1936       else
1937         {
1938           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1939           setMainValue ("cppoutfilename", NULL);
1940         }
1941
1942       if (options.verbose)
1943         printf ("sdcc: Calling preprocessor...\n");
1944
1945       buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
1946
1947       if (preProcOnly) {
1948         if (my_system (buffer)) {
1949           exit (1);
1950         }
1951
1952         exit (0);
1953       }
1954
1955       yyin = my_popen (buffer);
1956       if (yyin == NULL) {
1957           perror ("Preproc file not found");
1958           exit (1);
1959       }
1960       addSetHead (&pipeSet, yyin);
1961     }
1962
1963   return 0;
1964 }
1965
1966 /* Set bin paths */
1967 static void
1968 setBinPaths(const char *argv0)
1969 {
1970   char *p;
1971   char buf[PATH_MAX];
1972
1973   /*
1974    * Search logic:
1975    *
1976    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1977    * 2. - path(argv[0])
1978    * 3. - $PATH
1979    */
1980
1981   /* do it in reverse mode, so that addSetHead() can be used
1982      instead of slower addSet() */
1983
1984   if ((p = getBinPath(argv0)) != NULL)
1985     addSetHead(&binPathSet, Safe_strdup(p));
1986
1987   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1988     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1989     addSetHead(&binPathSet, Safe_strdup(buf));
1990   }
1991
1992 #if 0
1993   if (options.printSearchDirs) {
1994     printf("programs:\n");
1995     fputStrSet(stdout, binPathSet);
1996   }
1997 #endif
1998 }
1999
2000 /* Set system include path */
2001 static void
2002 setIncludePath(void)
2003 {
2004   char *p;
2005
2006   /*
2007    * Search logic:
2008    *
2009    * 1. - $SDCC_INCLUDE
2010    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
2011    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
2012    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
2013    */
2014
2015   includeDirsSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX);
2016
2017   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
2018     addSetHead(&includeDirsSet, p);
2019
2020 #if 0
2021   if (options.printSearchDirs) {
2022     printf("includedir:\n");
2023     fputStrSet(stdout, includeDirsSet);
2024   }
2025 #endif
2026 }
2027
2028 /* Set system lib path */
2029 static void
2030 setLibPath(void)
2031 {
2032   char *p;
2033
2034   /*
2035    * Search logic:
2036    *
2037    * 1. - $SDCC_LIB
2038    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
2039    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
2040    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
2041    */
2042
2043   libDirsSet = appendStrSet(dataDirsSet, NULL, LIB_DIR_SUFFIX);
2044
2045   if ((p = getenv(SDCC_LIB_NAME)) != NULL)
2046     addSetHead(&libDirsSet, p);
2047
2048 #if 0
2049   if (options.printSearchDirs) {
2050     printf("libdir:\n");
2051     fputStrSet(stdout, libDirsSet);
2052   }
2053 #endif
2054 }
2055
2056 /* Set data path */
2057 static void
2058 setDataPaths(const char *argv0)
2059 {
2060   char *p;
2061   char buf[PATH_MAX];
2062
2063   /*
2064    * Search logic:
2065    *
2066    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
2067    * 2. - path(argv[0])/BIN2DATA_DIR
2068    * 3. - DATADIR (only on *nix)
2069    */
2070
2071   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
2072     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
2073     addSet(&dataDirsSet, Safe_strdup(buf));
2074   }
2075
2076   if ((p = getBinPath(argv0)) != NULL) {
2077     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
2078     addSet(&dataDirsSet, Safe_strdup(buf));
2079   }
2080
2081 #ifdef _WIN32
2082   if (peekSet(dataDirsSet) == NULL) {
2083     /* this should never happen... */
2084     wassertl(0, "Can't get binary path");
2085   }
2086 #else
2087   addSet(&dataDirsSet, Safe_strdup(DATADIR));
2088 #endif
2089
2090 #if 0
2091   if (options.printSearchDirs) {
2092     printf("datadir:\n");
2093     fputStrSet(stdout, dataDirsSet);
2094   }
2095 #endif
2096
2097   setIncludePath();
2098   setLibPath();
2099 }
2100
2101 static void
2102 initValues (void)
2103 {
2104   populateMainValues (_baseValues);
2105   setMainValue ("port", port->target);
2106   setMainValue ("objext", port->linker.rel_ext);
2107   setMainValue ("asmext", port->assembler.file_ext);
2108
2109   setMainValue ("dstfilename", dstFileName);
2110   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
2111
2112   if (options.cc_only && fullDstFileName)
2113     /* compile + assemble and -o given: -o specifies name of object file */
2114     {
2115       setMainValue ("objdstfilename", fullDstFileName);
2116     }
2117   else
2118     {
2119       setMainValue ("objdstfilename", "{stdobjdstfilename}");
2120     }
2121   if (fullDstFileName)
2122     /* if we're linking, -o gives the final file name */
2123     {
2124       setMainValue ("linkdstfilename", fullDstFileName);
2125     }
2126   else
2127     {
2128       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
2129     }
2130
2131 }
2132
2133 static void doPrintSearchDirs(void)
2134 {
2135     printf("programs:\n");
2136     fputStrSet(stdout, binPathSet);
2137
2138     printf("datadir:\n");
2139     fputStrSet(stdout, dataDirsSet);
2140
2141     printf("includedir:\n");
2142     fputStrSet(stdout, includeDirsSet);
2143
2144     printf("libdir:\n");
2145     fputStrSet(stdout, libDirsSet);
2146     fputStrSet(stdout, libPathsSet);
2147 }
2148
2149
2150 static void
2151 sig_handler (int signal)
2152 {
2153   char *sig_string;
2154
2155   switch (signal)
2156     {
2157     case SIGABRT:
2158       sig_string = "SIGABRT";
2159       break;
2160     case SIGTERM:
2161       sig_string = "SIGTERM";
2162       break;
2163     case SIGINT:
2164       sig_string = "SIGINT";
2165       break;
2166     case SIGSEGV:
2167       sig_string = "SIGSEGV";
2168       break;
2169     default:
2170       sig_string = "Unknown?";
2171       break;
2172     }
2173   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
2174   exit (1);
2175 }
2176
2177 /*
2178  * main routine
2179  * initialises and calls the parser
2180  */
2181
2182 int
2183 main (int argc, char **argv, char **envp)
2184 {
2185   /* turn all optimizations off by default */
2186   memset (&optimize, 0, sizeof (struct optimize));
2187
2188   /*printVersionInfo (); */
2189
2190   if (NUM_PORTS==0) {
2191     fprintf (stderr, "Build error: no ports are enabled.\n");
2192     exit (1);
2193   }
2194
2195   /* install atexit handler */
2196   atexit(rm_tmpfiles);
2197
2198   /* install signal handler;
2199      it's only purpuse is to call exit() to remove temp files */
2200   if (!getenv("SDCC_LEAVE_SIGNALS"))
2201     {
2202       signal (SIGABRT, sig_handler);
2203       signal (SIGTERM, sig_handler);
2204       signal (SIGINT , sig_handler);
2205       signal (SIGSEGV, sig_handler);
2206     }
2207
2208   /* Before parsing the command line options, do a
2209    * search for the port and processor and initialize
2210    * them if they're found. (We can't gurantee that these
2211    * will be the first options specified).
2212    */
2213
2214   _findPort (argc, argv);
2215
2216 #ifdef JAMIN_DS390
2217   if (strcmp(port->target, "mcs51") == 0) {
2218     printf("DS390 jammed in A\n");
2219           _setPort ("ds390");
2220     ds390_jammed = 1;
2221   }
2222 #endif
2223
2224   _findProcessor (argc, argv);
2225
2226   /* Initalise the port. */
2227   if (port->init)
2228     port->init ();
2229
2230   setDefaultOptions ();
2231 #ifdef JAMIN_DS390
2232   if (ds390_jammed) {
2233     options.model = MODEL_SMALL;
2234     options.stack10bit=0;
2235   }
2236 #endif
2237   parseCmdLine (argc, argv);
2238
2239   initValues ();
2240
2241   setBinPaths(argv[0]);
2242   setDataPaths(argv[0]);
2243
2244   if(port->initPaths)
2245         port->initPaths();
2246
2247   if(options.printSearchDirs)
2248         doPrintSearchDirs();
2249
2250   /* if no input then printUsage & exit */
2251   if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL) {
2252     if (!options.printSearchDirs)
2253       printUsage();
2254
2255     exit(0);
2256   }
2257
2258   /* initMem() is expensive, but
2259      initMem() must called before port->finaliseOptions ().
2260      And the z80 port needs port->finaliseOptions(),
2261      even if we're only linking. */
2262   initMem ();
2263   port->finaliseOptions ();
2264
2265   if (fullSrcFileName || options.c1mode)
2266     {
2267       preProcess (envp);
2268
2269       initSymt ();
2270       initiCode ();
2271       initCSupport ();
2272       initBuiltIns();
2273       initPeepHole ();
2274
2275       if (options.verbose)
2276         printf ("sdcc: Generating code...\n");
2277
2278       yyparse ();
2279
2280       if (pclose(yyin))
2281         fatalError = 1;
2282       deleteSetItem(&pipeSet, yyin);
2283
2284       if (fatalError) {
2285         exit (1);
2286       }
2287
2288       if (port->general.do_glue != NULL)
2289         (*port->general.do_glue)();
2290       else
2291         {
2292           /* this shouldn't happen */
2293           assert(FALSE);
2294           /* in case of NDEBUG */
2295           glue();
2296         }
2297
2298       if (fatalError) {
2299         exit (1);
2300       }
2301
2302       if (!options.c1mode && !noAssemble)
2303         {
2304           if (options.verbose)
2305             printf ("sdcc: Calling assembler...\n");
2306           assemble (envp);
2307         }
2308     }
2309   closeDumpFiles();
2310
2311   if (options.debug && debugFile)
2312     debugFile->closeFile();
2313
2314   if (!options.cc_only &&
2315       !fatalError &&
2316       !noAssemble &&
2317       !options.c1mode &&
2318       (fullSrcFileName || peekSet(relFilesSet) != NULL))
2319     {
2320       if (port->linker.do_link)
2321         port->linker.do_link ();
2322       else
2323         linkEdit (envp);
2324     }
2325
2326   return 0;
2327 }