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