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