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