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