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