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