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