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