Hopefully --vc works now
[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   MSVC_style(options.vc_err_style);
1300   return 0;
1301 }
1302
1303 /*-----------------------------------------------------------------*/
1304 /* linkEdit : - calls the linkage editor  with options             */
1305 /*-----------------------------------------------------------------*/
1306 static void
1307 linkEdit (char **envp)
1308 {
1309   FILE *lnkfile;
1310   char *segName, *c;
1311   int i, system_ret;
1312
1313   /* first we need to create the <filename>.lnk file */
1314   SNPRINTF (scratchFileName, sizeof(scratchFileName),
1315             "%s.lnk", dstFileName);
1316   if (!(lnkfile = fopen (scratchFileName, "w")))
1317     {
1318       werror (E_FILE_OPEN_ERR, scratchFileName);
1319       exit (1);
1320     }
1321
1322   /* now write the options.  JCF: added option 'y' */
1323   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1324
1325   /* if iram size specified */
1326   if (options.iram_size)
1327     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1328
1329   /* if xram size specified */
1330   if (options.xram_size_set)
1331     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1332
1333   /* if code size specified */
1334   if (options.code_size)
1335     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1336
1337   if (options.debug)
1338     fprintf (lnkfile, "-z\n");
1339
1340 #define WRITE_SEG_LOC(N, L) \
1341     segName = Safe_strdup(N); \
1342     c = strtok(segName, " \t"); \
1343     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1344     if (segName) { Safe_free(segName); }
1345
1346   /* code segment start */
1347   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1348
1349   /* data segment start */
1350   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1351           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1352   }
1353
1354   /* xdata start */
1355   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1356
1357   /* indirect data */
1358   if (IDATA_NAME) {
1359     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1360   }
1361
1362   /* bit segment start */
1363   WRITE_SEG_LOC (BIT_NAME, 0);
1364
1365   /* JCF: stack start */
1366   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1367         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1368   }
1369
1370   /* add the extra linker options */
1371   for (i = 0; i<elementsInSet(linkOptions); i++)
1372     fprintf (lnkfile, "%s\n", (char *)indexSet(linkOptions, i));
1373   
1374   /* other library paths if specified */
1375   for (i = 0; i < nlibPaths; i++)
1376     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1377
1378   /* standard library path */
1379   if (!options.nostdlib)
1380     {
1381       switch (options.model)
1382         {
1383         case MODEL_SMALL:
1384           c = "small";
1385           break;
1386         case MODEL_LARGE:
1387           c = "large";
1388           break;
1389         case MODEL_FLAT24:
1390           /* c = "flat24"; */
1391             if (TARGET_IS_DS390)
1392             {
1393                 c = "ds390";
1394             }
1395             else if (TARGET_IS_DS400)
1396             {
1397                 c = "ds400";
1398             }
1399             else
1400             {
1401                 fprintf(stderr, 
1402                         "Add support for your FLAT24 target in %s @ line %d\n",
1403                         __FILE__, __LINE__);
1404                 exit(-1);
1405             }
1406           break;
1407         case MODEL_PAGE0:
1408           c = "xa51";
1409           break;
1410         default:
1411           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1412           c = "unknown";
1413           break;
1414         }
1415       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1416
1417       /* standard library files */
1418 #if !OPT_DISABLE_DS390
1419       if (options.model == MODEL_FLAT24)
1420         {
1421             if (TARGET_IS_DS390)
1422             {
1423                 fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1424             }
1425             else if (TARGET_IS_DS400)
1426             {
1427                 fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1428             }
1429             else
1430             {
1431                 fprintf(stderr, 
1432                         "Add support for your FLAT24 target in %s @ line %d\n",
1433                         __FILE__, __LINE__);
1434                 exit(-1);
1435             }
1436         }
1437 #endif
1438
1439 #if !OPT_DISABLE_XA51 
1440 #ifdef STD_XA51_LIB
1441       if (options.model == MODEL_PAGE0)
1442         {
1443           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1444         }
1445 #endif
1446 #endif
1447       fprintf (lnkfile, "-l %s\n", STD_LIB);
1448       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1449       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1450       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1451     }
1452
1453   /* additional libraries if any */
1454   for (i = 0; i < nlibFiles; i++)
1455     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1456
1457   /* put in the object files */
1458   if (fullSrcFileName)
1459     fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
1460
1461   for (i = 0; i < nrelFiles; i++)
1462     fprintf (lnkfile, "%s\n", relFiles[i]);
1463
1464   fprintf (lnkfile, "\n-e\n");
1465   fclose (lnkfile);
1466
1467   if (options.verbose)
1468     printf ("sdcc: Calling linker...\n");
1469
1470   /* build linker output filename */
1471
1472   /* -o option overrides default name? */
1473   if (fullDstFileName)
1474     {
1475       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1476     }
1477   else
1478     {
1479       /* the linked file gets the name of the first modul */
1480       if (fullSrcFileName)
1481         {
1482           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1483         }
1484       else
1485         {
1486           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1487           /* strip ".rel" extension */
1488           *strrchr (scratchFileName, '.') = '\0';
1489         }
1490       strncatz (scratchFileName, 
1491                 options.out_fmt ? ".S19" : ".ihx",
1492                 sizeof(scratchFileName));
1493     }
1494
1495   if (port->linker.cmd)
1496     {
1497       char buffer2[PATH_MAX];
1498
1499         /* VR 030517 - gplink needs linker options to set the linker script,*/
1500         buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, linkOptions);
1501
1502         buildCmdLine2 (buffer, buffer2, sizeof(buffer));
1503     }
1504   else
1505     {
1506       buildCmdLine2 (buffer, port->linker.mcmd, sizeof(buffer));
1507     }
1508
1509 //  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer);
1510
1511   system_ret = my_system (buffer);
1512   /* TODO: most linker don't have a -o parameter */
1513   /* -o option overrides default name? */
1514   if (fullDstFileName)
1515     {
1516       char *p, *q;
1517       /* the linked file gets the name of the first modul */
1518       if (fullSrcFileName)
1519         {
1520           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1521           p = strlen (scratchFileName) + scratchFileName;
1522         }
1523       else
1524         {
1525           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1526           /* strip ".rel" extension */
1527           p = strrchr (scratchFileName, '.');
1528           if (p)
1529             {
1530               *p = 0;
1531             }
1532         }
1533       strncatz (scratchFileName,
1534                 options.out_fmt ? ".S19" : ".ihx",
1535                 sizeof(scratchFileName));
1536       rename (scratchFileName, fullDstFileName);
1537
1538       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1539       q = strrchr (buffer, '.');
1540       if (!q)
1541         {
1542           /* no extension: append new extensions */
1543           q = strlen (buffer) + buffer;
1544         }
1545
1546       *p = 0;
1547       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1548       *q = 0;
1549       strncatz(buffer, ".map", sizeof(buffer));
1550       rename (scratchFileName, buffer);
1551       *p = 0;
1552       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1553       *q = 0;
1554       strncatz(buffer, ".mem", sizeof(buffer));
1555       rename (scratchFileName, buffer);
1556     }
1557   if (system_ret)
1558     {
1559       exit (1);
1560     }
1561 }
1562
1563 /*-----------------------------------------------------------------*/
1564 /* assemble - spawns the assembler with arguments                  */
1565 /*-----------------------------------------------------------------*/
1566 static void
1567 assemble (char **envp)
1568 {
1569     /* build assembler output filename */
1570
1571     /* -o option overrides default name? */
1572     if (options.cc_only && fullDstFileName) {
1573         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1574     } else {
1575         /* the assembled file gets the name of the first modul */
1576         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1577         strncatz (scratchFileName, port->linker.rel_ext, 
1578                   sizeof(scratchFileName));
1579     }
1580
1581     if (port->assembler.do_assemble) {
1582         port->assembler.do_assemble(asmOptions);
1583         return ;
1584     } else if (port->assembler.cmd) {
1585         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1586                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1587                       asmOptions);
1588     } else {
1589         buildCmdLine2 (buffer, port->assembler.mcmd, sizeof(buffer));
1590     }
1591
1592     if (my_system (buffer)) {
1593         /* either system() or the assembler itself has reported an error
1594            perror ("Cannot exec assembler");
1595         */
1596         exit (1);
1597     }
1598     /* TODO: most assembler don't have a -o parameter */
1599     /* -o option overrides default name? */
1600     if (options.cc_only && fullDstFileName) {
1601         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1602         strncatz (scratchFileName, 
1603                   port->linker.rel_ext,
1604                   sizeof(scratchFileName));
1605         rename (scratchFileName, fullDstFileName);
1606     }
1607 }
1608
1609 /*-----------------------------------------------------------------*/
1610 /* preProcess - spawns the preprocessor with arguments       */
1611 /*-----------------------------------------------------------------*/
1612 static int
1613 preProcess (char **envp)
1614 {
1615   if (options.c1mode)
1616     {
1617       yyin = stdin;
1618     }
1619   else
1620     {
1621       /* if using external stack define the macro */
1622       if (options.useXstack)
1623         addToList (preArgv, "-DSDCC_USE_XSTACK");
1624
1625       /* set the macro for stack autos  */
1626       if (options.stackAuto)
1627         addToList (preArgv, "-DSDCC_STACK_AUTO");
1628
1629       /* set the macro for stack autos  */
1630       if (options.stack10bit)
1631         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1632
1633       /* set the macro for no overlay  */
1634       if (options.noOverlay)
1635         addToList (preArgv, "-DSDCC_NOOVERLAY");
1636
1637       /* set the macro for large model  */
1638       switch (options.model)
1639         {
1640         case MODEL_LARGE:
1641           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1642           break;
1643         case MODEL_SMALL:
1644           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1645           break;
1646         case MODEL_COMPACT:
1647           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1648           break;
1649         case MODEL_MEDIUM:
1650           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1651           break;
1652         case MODEL_FLAT24:
1653           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1654           break;
1655         case MODEL_PAGE0:
1656           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1657           break;
1658         default:
1659           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1660           break;
1661         }
1662
1663       /* add port (processor information to processor */
1664       addToList (preArgv, "-DSDCC_{port}");
1665       addToList (preArgv, "-D__{port}");
1666
1667       /* standard include path */
1668       if (!options.nostdinc) {
1669         addToList (preArgv, "-I\"{includedir}\"");
1670       }
1671
1672       setMainValue ("cppextraopts", join(preArgv));
1673
1674       if (preProcOnly && fullDstFileName)
1675         {
1676           /* -E and -o given */
1677           setMainValue ("cppoutfilename", fullDstFileName);
1678         }
1679       else
1680         {
1681           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1682           setMainValue ("cppoutfilename", NULL);
1683         }
1684
1685       if (options.verbose)
1686         printf ("sdcc: Calling preprocessor...\n");
1687
1688       buildCmdLine2 (buffer, _preCmd, sizeof(buffer));
1689
1690       if (preProcOnly) {
1691         if (my_system (buffer)) {
1692           exit (1);
1693         }
1694
1695         exit (0);
1696       }
1697
1698       yyin = my_popen (buffer);
1699       if (yyin == NULL) {
1700           perror ("Preproc file not found");
1701           exit (1);
1702       }
1703       addSetHead (&pipeSet, yyin);
1704     }
1705
1706   return 0;
1707 }
1708
1709 /* Set bin paths */
1710 static void
1711 setBinPaths(const char *argv0)
1712 {
1713   char *p;
1714   char buf[PATH_MAX];
1715
1716   /*
1717    * Search logic:
1718    *
1719    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1720    * 2. - path(argv[0])
1721    * 3. - $PATH
1722    */
1723
1724   /* do it in reverse mode, so that addSetHead() can be used
1725      instead of slower addSet() */
1726
1727   if ((p = getBinPath(argv0)) != NULL)
1728     addSetHead(&binPathSet, Safe_strdup(p));
1729
1730   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1731     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1732     addSetHead(&binPathSet, Safe_strdup(buf));
1733   }
1734
1735   if (options.printSearchDirs) {
1736     printf("programs: ");
1737     if (NULL != (p = (char *)setFirstItem(binPathSet))) {
1738       printf("%s", p);
1739       while (NULL != (p = (char *)setNextItem(binPathSet)))
1740         printf(":%s", p);
1741     }
1742     putchar('\n');
1743   }
1744 }
1745
1746 /* Set system include path */
1747 static void
1748 setIncludePath(const char *datadir)
1749 {
1750   char *p;
1751   char buf[PATH_MAX];
1752
1753   /*
1754    * Search logic:
1755    *
1756    * 1. - $SDCC_INCLUDE
1757    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
1758    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
1759    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
1760    */
1761
1762   if ((p = getenv(SDCC_INCLUDE_NAME)) == NULL) {
1763     SNPRINTF(buf, sizeof buf, "%s" INCLUDE_DIR_SUFFIX, datadir);
1764     p = buf;
1765   }
1766
1767   if (options.printSearchDirs)
1768     printf("includedir: %s\n", p);
1769
1770   setMainValue ("includedir", p);
1771 }
1772
1773 /* Set system lib path */
1774 static void
1775 setLibPath(const char *datadir)
1776 {
1777   char *p;
1778   char buf[PATH_MAX];
1779
1780   /*
1781    * Search logic:
1782    *
1783    * 1. - $SDCC_LIB
1784    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
1785    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
1786    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
1787    */
1788
1789   if ((p = getenv(SDCC_LIB_NAME)) == NULL) {
1790     SNPRINTF(buf, sizeof buf, "%s" LIB_DIR_SUFFIX, datadir);
1791     p = buf;
1792   }
1793
1794   if (options.printSearchDirs)
1795     printf("libdir: %s\n", p);
1796
1797   setMainValue ("libdir", p);
1798 }
1799
1800 /* Set data path */
1801 static void
1802 setDataPaths(const char *argv0)
1803 {
1804   char *p;
1805   char buf[PATH_MAX];
1806
1807   /*
1808    * Search logic:
1809    *
1810    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
1811    * 2. - path(argv[0])/BIN2DATA_DIR
1812    * 3. - DATADIR (only on *nix)
1813    */
1814
1815   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1816     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
1817     p = buf;
1818   }
1819   else if ((p = getBinPath(argv0)) != NULL) {
1820     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
1821     p = buf;
1822   }
1823 #ifdef _WIN32
1824   else {
1825     /* this should never happen... */
1826     wassertl(0, "Can't get binary path");
1827     p = ".";
1828   }
1829 #else
1830   if (!pathExists(p))
1831     p = DATADIR; /* last resort */
1832 #endif
1833
1834   if (options.printSearchDirs)
1835     printf("datadir: %s\n", p);
1836
1837   setIncludePath(p);
1838   setLibPath(p);
1839
1840   setMainValue ("datadir", p);
1841 }
1842
1843 static void
1844 initValues (void)
1845 {
1846   populateMainValues (_baseValues);
1847   setMainValue ("port", port->target);
1848   setMainValue ("objext", port->linker.rel_ext);
1849   setMainValue ("asmext", port->assembler.file_ext);
1850
1851   setMainValue ("dstfilename", dstFileName);
1852   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1853
1854   if (options.cc_only && fullDstFileName)
1855     /* compile + assemble and -o given: -o specifies name of object file */
1856     {
1857       setMainValue ("objdstfilename", fullDstFileName);
1858     }
1859   else
1860     {
1861       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1862     }
1863   if (fullDstFileName)
1864     /* if we're linking, -o gives the final file name */
1865     {
1866       setMainValue ("linkdstfilename", fullDstFileName);
1867     }
1868   else
1869     {
1870       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1871     }
1872
1873 }
1874
1875 static void
1876 sig_handler (int signal)
1877 {
1878   char *sig_string;
1879
1880   switch (signal)
1881     {
1882     case SIGABRT:
1883       sig_string = "SIGABRT";
1884       break;
1885     case SIGTERM:
1886       sig_string = "SIGTERM";
1887       break;
1888     case SIGINT:
1889       sig_string = "SIGINT";
1890       break;
1891     case SIGSEGV:
1892       sig_string = "SIGSEGV";
1893       break;
1894     default:
1895       sig_string = "Unknown?";
1896       break;
1897     }
1898   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1899   exit (1);
1900 }
1901
1902 /*
1903  * main routine
1904  * initialises and calls the parser
1905  */
1906
1907 int
1908 main (int argc, char **argv, char **envp)
1909 {
1910   /* turn all optimizations off by default */
1911   memset (&optimize, 0, sizeof (struct optimize));
1912
1913   /*printVersionInfo (); */
1914
1915   if (NUM_PORTS==0) {
1916     fprintf (stderr, "Build error: no ports are enabled.\n");
1917     exit (1);
1918   }
1919
1920   /* install atexit handler */
1921   atexit(rm_tmpfiles);
1922
1923   /* install signal handler;
1924      it's only purpuse is to call exit() to remove temp files */
1925   if (!getenv("SDCC_LEAVE_SIGNALS"))
1926     {
1927       signal (SIGABRT, sig_handler);
1928       signal (SIGTERM, sig_handler);
1929       signal (SIGINT , sig_handler);
1930       signal (SIGSEGV, sig_handler);
1931     }
1932
1933   /* Before parsing the command line options, do a
1934    * search for the port and processor and initialize
1935    * them if they're found. (We can't gurantee that these
1936    * will be the first options specified).
1937    */
1938
1939   _findPort (argc, argv);
1940
1941 #ifdef JAMIN_DS390
1942   if (strcmp(port->target, "mcs51") == 0) {
1943     printf("DS390 jammed in A\n");
1944           _setPort ("ds390");
1945     ds390_jammed = 1;
1946   }
1947 #endif
1948
1949   _findProcessor (argc, argv);
1950
1951   /* Initalise the port. */
1952   if (port->init)
1953     port->init ();
1954
1955   setDefaultOptions ();
1956 #ifdef JAMIN_DS390
1957   if (ds390_jammed) {
1958     options.model = MODEL_SMALL;
1959     options.stack10bit=0;
1960   }
1961 #endif
1962   parseCmdLine (argc, argv);
1963
1964   initValues ();
1965   setBinPaths(argv[0]);
1966   setDataPaths(argv[0]);
1967
1968   /* if no input then printUsage & exit */
1969   if (!options.c1mode && !fullSrcFileName && !nrelFiles) {
1970     if (!options.printSearchDirs)
1971       printUsage();
1972
1973     exit(0);
1974   }
1975
1976   /* initMem() is expensive, but
1977      initMem() must called before port->finaliseOptions ().
1978      And the z80 port needs port->finaliseOptions(),
1979      even if we're only linking. */
1980   initMem ();
1981   port->finaliseOptions ();
1982
1983   if (fullSrcFileName || options.c1mode)
1984     {
1985       preProcess (envp);
1986
1987       initSymt ();
1988       initiCode ();
1989       initCSupport ();
1990       initBuiltIns();
1991       initPeepHole ();
1992
1993       if (options.verbose)
1994         printf ("sdcc: Generating code...\n");
1995
1996       yyparse ();
1997
1998       pclose(yyin);
1999       deleteSetItem(&pipeSet, yyin);
2000
2001       if (fatalError) {
2002         exit (1);
2003       }
2004
2005       if (TARGET_IS_PIC) {
2006         /* TSD PIC port hack - if the PIC port option is enabled
2007            and SDCC is used to generate PIC code, then we will
2008            generate .asm files in gpasm's format instead of SDCC's
2009            assembler's format
2010         */
2011 #if !OPT_DISABLE_PIC
2012         picglue ();
2013 #endif
2014
2015       } else
2016       if(TARGET_IS_PIC16) {
2017         /* PIC16 port misc improvements Vangelis Rokas - 6-May-2003
2018           Generate .asm files for gpasm (just like PIC target) but use
2019           pic16glue()
2020         */
2021       
2022 #if !OPT_DISABLE_PIC16
2023         pic16glue();
2024 #endif
2025       } else {
2026         glue ();
2027       }
2028
2029       if (!options.c1mode && !noAssemble)
2030         {
2031           if (options.verbose)
2032             printf ("sdcc: Calling assembler...\n");
2033           assemble (envp);
2034         }
2035     }
2036   closeDumpFiles();
2037
2038   if (options.debug && debugFile)
2039     debugFile->closeFile();
2040
2041   if (!options.cc_only &&
2042       !fatalError &&
2043       !noAssemble &&
2044       !options.c1mode &&
2045       (fullSrcFileName || nrelFiles))
2046     {
2047       if (port->linker.do_link)
2048         port->linker.do_link ();
2049       else
2050         linkEdit (envp);
2051     }
2052
2053   return 0;
2054 }