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