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