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