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