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