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