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