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