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