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