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