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