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