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