e6f0f3ba9b94a58e8b5c51371fc7c175921cbf55
[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 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 static char *preOutName;
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];
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_LOOP_INV      "--noinvariant"
118 #define OPTION_NO_LOOP_IND      "--noinduction"
119 #define OPTION_LESS_PEDANTIC    "--lesspedantic"
120 #define OPTION_NO_GCSE          "--nogcse"
121 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
122 #define OPTION_TINI_LIBID       "--tini-libid"
123 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
124 #define OPTION_XRAM_SIZE        "--xram-size"
125 #define OPTION_CODE_SIZE        "--code-size"
126 #define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
127 #define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
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,                   &options.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 standard 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,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
211     { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
212     { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
213     /* End of options */
214     { 0,    NULL }
215 };
216
217 /** Table of all unsupported options and help text to display when one
218     is used.
219 */
220 typedef struct {
221     /** shortOpt as in OPTIONS. */
222     char shortOpt;
223     /** longOpt as in OPTIONS. */
224     const char *longOpt;
225     /** Message to display inside W_UNSUPPORTED_OPT when this option
226         is used. */
227     const char *message;
228 } UNSUPPORTEDOPT;
229
230 static const UNSUPPORTEDOPT 
231 unsupportedOptTable[] = {
232     { 'X',  NULL,       "use --xstack-loc instead" },
233     { 'x',  NULL,       "use --xstack instead" },
234     { 'i',  NULL,       "use --idata-loc instead" },
235     { 'r',  NULL,       "use --xdata-loc instead" },
236     { 's',  NULL,       "use --code-loc instead" },
237     { 'Y',  NULL,       "use -I instead" }
238 };
239
240 /** List of all default constant macros.
241  */
242 static const char *_baseValues[] = {
243   "cpp", "{bindir}{sep}sdcpp",
244   "cppextraopts", "",
245   /* Path seperator character */
246   "sep", DIR_SEPARATOR_STRING,
247   NULL
248 };
249
250 static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} {fullsrcfilename} {cppoutfilename}";
251
252 PORT *port;
253
254 static PORT *_ports[] =
255 {
256 #if !OPT_DISABLE_MCS51
257   &mcs51_port,
258 #endif
259 #if !OPT_DISABLE_GBZ80
260   &gbz80_port,
261 #endif
262 #if !OPT_DISABLE_Z80
263   &z80_port,
264 #endif
265 #if !OPT_DISABLE_AVR
266   &avr_port,
267 #endif
268 #if !OPT_DISABLE_DS390
269   &ds390_port,
270 #endif
271 #if !OPT_DISABLE_PIC
272   &pic_port,
273 #endif
274 #if !OPT_DISABLE_TININative
275   &tininative_port,
276 #endif
277 #if !OPT_DISABLE_XA51
278   &xa51_port,
279 #endif
280 };
281
282 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
283
284 #if !OPT_DISABLE_PIC
285 extern void picglue ();
286 #endif
287
288 /** Sets the port to the one given by the command line option.
289     @param    The name minus the option (eg 'mcs51')
290     @return     0 on success.
291 */
292 static void
293 _setPort (const char *name)
294 {
295   int i;
296   for (i = 0; i < NUM_PORTS; i++)
297     {
298       if (!strcmp (_ports[i]->target, name))
299         {
300           port = _ports[i];
301           return;
302         }
303     }
304   /* Error - didnt find */
305   werror (E_UNKNOWN_TARGET, name);
306   exit (1);
307 }
308
309 /* Override the default processor with the one specified 
310  * on the command line */
311 static void
312 _setProcessor (char *_processor)
313 {
314   port->processor = _processor;
315   fprintf(stderr,"Processor: %s\n",_processor);
316 }
317
318 static void
319 _validatePorts (void)
320 {
321   int i;
322   for (i = 0; i < NUM_PORTS; i++)
323     {
324       if (_ports[i]->magic != PORT_MAGIC)
325         {
326           /* Uncomment this line to debug which port is causing the problem
327            * (the target name is close to the beginning of the port struct 
328            * and probably can be accessed just fine). */
329           fprintf(stderr,"%s :",_ports[i]->target);
330           wassertl (0, "Port definition structure is incomplete");
331         }
332     }
333 }
334
335 /* search through the command line options for the port */
336 static void
337 _findPort (int argc, char **argv)
338 {
339   _validatePorts ();
340
341   while (argc--)
342     {
343       if (!strncmp (*argv, "-m", 2))
344         {
345           _setPort (*argv + 2);
346           return;
347         }
348       argv++;
349     }
350   /* Use the first in the list */
351   port = _ports[0];
352 }
353
354 /* search through the command line options for the processor */
355 static void
356 _findProcessor (int argc, char **argv)
357 {
358   while (argc--)
359     {
360       if (!strncmp (*argv, "-p", 2))
361         {
362           _setProcessor (*argv + 2);
363           return;
364         }
365       argv++;
366     }
367
368   /* no error if processor was not specified. */
369 }
370
371 /*-----------------------------------------------------------------*/
372 /* printVersionInfo - prints the version info        */
373 /*-----------------------------------------------------------------*/
374 void
375 printVersionInfo ()
376 {
377   int i;
378
379   fprintf (stderr,
380            "SDCC : ");
381   for (i = 0; i < NUM_PORTS; i++)
382     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
383
384   fprintf (stderr, " %s"
385 #ifdef SDCC_SUB_VERSION_STR
386            "/" SDCC_SUB_VERSION_STR
387 #endif
388            " (" __DATE__ ")"
389 #ifdef __CYGWIN__
390            " (CYGWIN)\n"
391 #elif defined __MINGW32__
392            " (MINGW32) \n"
393 #else
394 #  ifdef __DJGPP__
395            " (DJGPP) \n"
396 #  else
397 #    if defined(_MSC_VER)
398            " (WIN32) \n"
399 #    else
400            " (UNIX) \n"
401 #    endif
402 #  endif
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       strcpy (buffer, s);
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                         sprintf(buffer, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
698                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
699                         return 1;
700                     }
701                 }
702             // Didn't find in the table
703             return 0;
704         }
705     else 
706         {
707             // Not an option, so can't be unsupported :)
708             return 0;
709     }
710 }
711
712 static bool
713 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
714 {
715   int i;
716   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++)
717     {
718       if (optionsTable[i].shortOpt == shortOpt ||
719           (longOpt && optionsTable[i].longOpt && 
720            strcmp(optionsTable[i].longOpt, longOpt) == 0))
721         {
722
723           // If it is a flag then we can handle it here
724           if (optionsTable[i].pparameter != NULL) 
725             {
726               if (optionsTable[i].shortOpt == shortOpt)
727                 {
728                   verifyShortOption(argv[*pi]);
729                 }
730
731               (*optionsTable[i].pparameter)++;
732               return 1;
733             }
734           else {
735             // Not a flag.  Handled manually later.
736             return 0;
737           }
738         }
739     }
740   // Didn't find in the table
741   return 0;
742 }
743
744 static bool
745 tryHandleSimpleOpt(char **argv, int *pi)
746 {
747     if (argv[*pi][0] == '-') 
748         {
749             const char *longOpt = "";
750             char shortOpt = -1;
751
752             if (argv[*pi][1] == '-') 
753                 {
754                     // Long option.
755                     longOpt = argv[*pi];
756                 }
757             else 
758                 {
759                     shortOpt = argv[*pi][1];
760                 }
761
762             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
763               {
764                 return 1;
765               }
766             else if (port && port->poptions &&
767                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
768               {
769                 return 1;
770               }
771             else
772               {
773                 return 0;
774               }
775         }
776     else 
777         {
778             // Not an option, so can't be handled.
779             return 0;
780         }
781 }
782
783 /*-----------------------------------------------------------------*/
784 /* parseCmdLine - parses the command line and sets the options     */
785 /*-----------------------------------------------------------------*/
786 static int
787 parseCmdLine (int argc, char **argv)
788 {
789   int i;
790
791   /* go thru all whole command line */
792   for (i = 1; i < argc; i++)
793     {
794       if (i >= argc)
795         break;
796
797       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
798           {
799               continue;
800           }
801
802       if (tryHandleSimpleOpt(argv, &i) == TRUE)
803           {
804               continue;
805           }
806
807       /* options */
808       if (argv[i][0] == '-' && argv[i][1] == '-')
809         {
810           if (strcmp (argv[i], OPTION_HELP) == 0)
811             {
812               printUsage ();
813               exit (0);
814             }
815
816           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
817             {
818               options.stack10bit = 0;
819               continue;
820             }
821
822           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
823             {
824               options.out_fmt = 0;
825               continue;
826             }
827
828           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
829             {
830               _setModel (MODEL_LARGE, argv[i]);
831               continue;
832             }
833
834           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
835             {
836               _setModel (MODEL_MEDIUM, argv[i]);
837               continue;
838             }
839
840           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
841             {
842               _setModel (MODEL_SMALL, argv[i]);
843               continue;
844             }
845
846           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
847             {
848               _setModel (MODEL_FLAT24, argv[i]);
849               continue;
850             }
851
852           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
853             {
854               options.dump_rassgn =
855                 options.dump_pack =
856                 options.dump_range =
857                 options.dump_kill =
858                 options.dump_loop =
859                 options.dump_gcse =
860                 options.dump_raw = 1;
861               continue;
862             }
863
864           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
865             {
866                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
867                 continue;
868             }
869
870           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
871             {
872                 libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i, argc);
873                 continue;
874             }
875
876           if (strcmp (argv[i], OPTION_VERSION) == 0)
877             {
878               printVersionInfo ();
879               exit (0);
880               continue;
881             }
882
883           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
884             {
885                 parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
886                 continue;
887             }
888
889           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
890             {
891                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
892                 continue;
893             }
894
895           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
896             {
897                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
898                 continue;
899             }
900
901           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
902             {
903                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
904                 continue;
905             }
906
907           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
908             {
909                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
910                 continue;
911             }
912
913           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
914             {
915                 options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
916                 options.xram_size_set = TRUE;
917                 continue;
918             }
919
920           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
921             {
922                 options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
923                 continue;
924             }
925
926           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
927             {
928                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
929                 continue;
930             }
931
932           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
933             {
934                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
935                 continue;
936             }
937
938           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
939             {
940                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
941                 continue;
942             }
943
944           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
945             {
946               optimize.global_cse = 0;
947               continue;
948             }
949
950           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
951             {
952               optimize.loopInvariant = 0;
953               continue;
954             }
955
956           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
957             {
958               optimize.loopInduction = 0;
959               continue;
960             }
961
962           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
963             {
964               options.lessPedantic = 1;
965               setErrorLogLevel(ERROR_LEVEL_WARNING);
966               continue;
967             }
968
969           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
970             {
971               options.shortis8bits=1;
972               continue;
973             }
974
975           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
976             {
977                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
978                 continue;
979             }
980           
981           if (!port->parseOption (&argc, argv, &i))
982             {
983               werror (W_UNKNOWN_OPTION, argv[i]);
984             }
985           else
986             {
987               continue;
988             }
989         }
990
991       /* if preceded by  '-' then option */
992       if (*argv[i] == '-')
993         {
994           switch (argv[i][1])
995             {
996             case 'h':
997               verifyShortOption(argv[i]);
998
999               printUsage ();
1000               exit (0);
1001               break;
1002
1003             case 'm':
1004               /* Used to select the port. But this has already been done. */
1005               break;
1006
1007             case 'p':
1008               /* Used to select the processor in port. But this has
1009                * already been done. */
1010               break;
1011
1012             case 'c':
1013               verifyShortOption(argv[i]);
1014
1015               options.cc_only = 1;
1016               break;
1017
1018             case 'L':
1019                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
1020                 break;
1021
1022             case 'l':
1023                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
1024                 break;
1025             
1026             case 'o':
1027               {
1028                 char *p;
1029
1030                 /* copy the file name into the buffer */
1031                 strcpy (buffer, getStringArg("-o", argv, &i, argc));
1032                 /* point to last character */
1033                 p = buffer + strlen (buffer) - 1;
1034                 if (*p == DIR_SEPARATOR_CHAR)
1035                   {
1036                     /* only output path specified */
1037                     dstPath = Safe_strdup (buffer);
1038                     fullDstFileName = NULL;
1039                   }
1040                 else
1041                   {
1042                     fullDstFileName = Safe_strdup (buffer);
1043
1044                     /* get rid of the "."-extension */
1045
1046                     /* is there a dot at all? */
1047                     if (strrchr (buffer, '.') &&
1048                         /* is the dot in the filename, not in the path? */
1049                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1050                       *strrchr (buffer, '.') = '\0';
1051
1052                     dstFileName = Safe_strdup (buffer);
1053
1054                     /* strip module name to get path */
1055                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1056                     if (p)
1057                       {
1058                         /* path with trailing / */
1059                         p[1] = '\0';
1060                         dstPath = Safe_strdup (buffer);
1061                       }
1062                   }
1063                 break;
1064               }
1065
1066             case 'W':
1067               /* pre-processer options */
1068               if (argv[i][2] == 'p')
1069                 {
1070                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
1071                 }
1072               /* linker options */
1073               else if (argv[i][2] == 'l')
1074                 {
1075                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1076                 }
1077               /* assembler options */
1078               else if (argv[i][2] == 'a')
1079                 {
1080                   parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
1081                 }
1082               else
1083                 {
1084                   werror (W_UNKNOWN_OPTION, argv[i]);
1085                 }
1086               break;
1087
1088             case 'v':
1089               verifyShortOption(argv[i]);
1090
1091               printVersionInfo ();
1092               exit (0);
1093               break;
1094
1095               /* preprocessor options */
1096             case 'M':
1097               {
1098                 preProcOnly = 1;
1099                 addToList (preArgv, "-M");
1100                 break;
1101               }
1102             case 'C':
1103               {
1104                 addToList (preArgv, "-C");
1105                 break;
1106               }
1107             case 'd':
1108             case 'D':
1109             case 'I':
1110             case 'A':
1111             case 'U':
1112               {
1113                 char sOpt = argv[i][1];
1114                 char *rest;
1115
1116                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1117                   {
1118                     i++;
1119                     if (i >= argc)
1120                       {
1121                           /* No argument. */
1122                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1123                           break;
1124                       }
1125                     else
1126                       {
1127                           rest = argv[i];
1128                       }
1129                   }
1130                 else
1131                   rest = &argv[i][2];
1132
1133                 if (sOpt == 'Y')
1134                   sOpt = 'I';
1135
1136                 sprintf (buffer, "-%c%s", sOpt, rest);
1137                 addToList (preArgv, buffer);
1138               }
1139               break;
1140
1141             default:
1142               if (!port->parseOption (&argc, argv, &i))
1143                 werror (W_UNKNOWN_OPTION, argv[i]);
1144             }
1145           continue;
1146         }
1147
1148       if (!port->parseOption (&argc, argv, &i))
1149         {
1150            /* no option must be a filename */
1151            if (options.c1mode)
1152              {
1153                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1154              }
1155          else
1156              {
1157                 processFile (argv[i]);
1158              }
1159         }
1160     }
1161
1162   /* some sanity checks in c1 mode */
1163   if (options.c1mode)
1164     {
1165       int i;
1166
1167       if (fullSrcFileName)
1168         {
1169           fclose (srcFile);
1170           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1171         }
1172       fullSrcFileName = NULL;
1173       for (i = 0; i < nrelFiles; ++i)
1174         {
1175           werror (W_NO_FILE_ARG_IN_C1, relFiles[i]);
1176         }
1177       for (i = 0; i < nlibFiles; ++i)
1178         {
1179           werror (W_NO_FILE_ARG_IN_C1, libFiles[i]);
1180         }
1181       nrelFiles = nlibFiles = 0;
1182       if (options.cc_only || noAssemble || preProcOnly)
1183         {
1184           werror (W_ILLEGAL_OPT_COMBINATION);
1185         }
1186       options.cc_only = noAssemble = preProcOnly = 0;
1187       if (!dstFileName)
1188         {
1189           werror (E_NEED_OPT_O_IN_C1);
1190           exit (1);
1191         }
1192     }
1193   /* if no dstFileName given with -o, we've to find one: */
1194   if (!dstFileName)
1195     {
1196       /* use the modulename from the C-source */
1197       if (fullSrcFileName)
1198         {
1199           dstFileName = Safe_alloc (strlen (dstPath) + strlen (moduleName) + 1);
1200           strcpy (dstFileName, dstPath);
1201           strcat (dstFileName, moduleName);
1202         }
1203       /* use the modulename from the first object file */
1204       else if (nrelFiles >= 1)
1205         {
1206           char *objectName;
1207
1208           strcpy (buffer, relFiles[0]);
1209           /* remove extension (it must be .rel) */
1210           *strrchr (buffer, '.') = '\0';
1211           /* remove path */
1212           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1213           if (objectName)
1214             {
1215               ++objectName;
1216             }
1217           else
1218             {
1219               objectName = buffer;
1220             }
1221           dstFileName = Safe_alloc (strlen (dstPath) + strlen (objectName) + 1);
1222           strcpy (dstFileName, dstPath);
1223           strcat (dstFileName, objectName);
1224         }
1225       /* else no module given: help text is displayed */
1226     }
1227
1228   /* set up external stack location if not explicitly specified */
1229   if (!options.xstack_loc)
1230     options.xstack_loc = options.xdata_loc;
1231
1232   /* if debug option is set the open the cdbFile */
1233   if (options.debug && fullSrcFileName)
1234     {
1235       sprintf (scratchFileName, "%s.adb", dstFileName); //JCF: Nov 30, 2002
1236       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1237         werror (E_FILE_OPEN_ERR, scratchFileName);
1238       else
1239         {
1240           /* add a module record */
1241           fprintf (cdbFile, "M:%s\n", moduleName);
1242         }
1243     }
1244   return 0;
1245 }
1246
1247 /*-----------------------------------------------------------------*/
1248 /* linkEdit : - calls the linkage editor  with options             */
1249 /*-----------------------------------------------------------------*/
1250 static void
1251 linkEdit (char **envp)
1252 {
1253   FILE *lnkfile;
1254   char *segName, *c;
1255   int i, system_ret;
1256
1257   /* first we need to create the <filename>.lnk file */
1258   sprintf (scratchFileName, "%s.lnk", dstFileName);
1259   if (!(lnkfile = fopen (scratchFileName, "w")))
1260     {
1261       werror (E_FILE_OPEN_ERR, scratchFileName);
1262       exit (1);
1263     }
1264
1265   /* now write the options.  JCF: added option 'y' */
1266   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1267
1268   /* if iram size specified */
1269   if (options.iram_size)
1270     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1271
1272   /* if xram size specified */
1273   if (options.xram_size_set)
1274     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1275
1276   /* if code size specified */
1277   if (options.code_size)
1278     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1279
1280   if (options.debug)
1281     fprintf (lnkfile, "-z\n");
1282
1283 #define WRITE_SEG_LOC(N, L) \
1284     segName = Safe_strdup(N); \
1285     c = strtok(segName, " \t"); \
1286     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1287     if (segName) { Safe_free(segName); }
1288
1289   /* code segment start */
1290   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1291
1292   /* data segment start */
1293   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1294           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1295   }
1296
1297   /* xdata start */
1298   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1299
1300   /* indirect data */
1301   if (IDATA_NAME) {
1302     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1303   }
1304
1305   /* bit segment start */
1306   WRITE_SEG_LOC (BIT_NAME, 0);
1307
1308   /* JCF: stack start */
1309   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1310         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1311   }
1312
1313   /* add the extra linker options */
1314   for (i = 0; linkOptions[i]; i++)
1315     fprintf (lnkfile, "%s\n", linkOptions[i]);
1316
1317   /* other library paths if specified */
1318   for (i = 0; i < nlibPaths; i++)
1319     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1320
1321   /* standard library path */
1322   if (!options.nostdlib)
1323     {
1324       switch (options.model)
1325         {
1326         case MODEL_SMALL:
1327           c = "small";
1328           break;
1329         case MODEL_LARGE:
1330           c = "large";
1331           break;
1332         case MODEL_FLAT24:
1333           /* c = "flat24"; */
1334           c = "ds390";
1335           break;
1336         case MODEL_PAGE0:
1337           c = "xa51";
1338           break;
1339         default:
1340           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1341           c = "unknown";
1342           break;
1343         }
1344       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1345
1346       /* standard library files */
1347 #if !OPT_DISABLE_DS390
1348       if (options.model == MODEL_FLAT24)
1349         {
1350           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1351         }
1352 #endif
1353
1354 #if !OPT_DISABLE_XA51 
1355 #ifdef STD_XA51_LIB
1356       if (options.model == MODEL_PAGE0)
1357         {
1358           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1359         }
1360 #endif
1361 #endif
1362       fprintf (lnkfile, "-l %s\n", STD_LIB);
1363       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1364       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1365       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1366     }
1367
1368   /* additional libraries if any */
1369   for (i = 0; i < nlibFiles; i++)
1370     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1371
1372   /* put in the object files */
1373   if (fullSrcFileName)
1374     fprintf (lnkfile, "%s ", dstFileName);
1375
1376   for (i = 0; i < nrelFiles; i++)
1377     fprintf (lnkfile, "%s\n", relFiles[i]);
1378
1379   fprintf (lnkfile, "\n-e\n");
1380   fclose (lnkfile);
1381
1382   if (options.verbose)
1383     printf ("sdcc: Calling linker...\n");
1384
1385   /* build linker output filename */
1386
1387   /* -o option overrides default name? */
1388   if (fullDstFileName)
1389     {
1390       strcpy (scratchFileName, fullDstFileName);
1391     }
1392   else
1393     {
1394       /* the linked file gets the name of the first modul */
1395       if (fullSrcFileName)
1396         {
1397           strcpy (scratchFileName, dstFileName);
1398         }
1399       else
1400         {
1401           strcpy (scratchFileName, relFiles[0]);
1402           /* strip ".rel" extension */
1403           *strrchr (scratchFileName, '.') = '\0';
1404         }
1405       strcat (scratchFileName, options.out_fmt ? ".S19" : ".ihx");
1406     }
1407
1408   if (port->linker.cmd)
1409     {
1410       char buffer2[PATH_MAX];
1411       buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
1412       buildCmdLine2 (buffer, buffer2);
1413     }
1414   else
1415     {
1416       buildCmdLine2 (buffer, port->linker.mcmd);
1417     }
1418
1419   system_ret = my_system (buffer);
1420   /* TODO: most linker don't have a -o parameter */
1421   /* -o option overrides default name? */
1422   if (fullDstFileName)
1423     {
1424       char *p, *q;
1425       /* the linked file gets the name of the first modul */
1426       if (fullSrcFileName)
1427         {
1428           strcpy (scratchFileName, dstFileName);
1429           p = strlen (scratchFileName) + scratchFileName;
1430         }
1431       else
1432         {
1433           strcpy (scratchFileName, relFiles[0]);
1434           /* strip "rel" extension */
1435           p = strrchr (scratchFileName, '.') + 1;
1436         }
1437       strcpy (p, options.out_fmt ? "S19" : "ihx");
1438       rename (scratchFileName, fullDstFileName);
1439
1440       q = strrchr (fullDstFileName, '.');
1441       if (q)
1442         {
1443           /* point after the '.' of the extension */
1444           q++;
1445         }
1446       else
1447         {
1448           /* no extension: append new extensions */
1449           q = strlen (fullDstFileName) + fullDstFileName;
1450         }
1451       strcpy (p, "map");
1452       strcpy (q, "map");
1453       rename (scratchFileName, fullDstFileName);
1454       strcpy (p, "mem");
1455       strcpy (q, "mem");
1456       rename (scratchFileName, fullDstFileName);
1457     }
1458   if (system_ret)
1459     {
1460       exit (1);
1461     }
1462 }
1463
1464 /*-----------------------------------------------------------------*/
1465 /* assemble - spawns the assembler with arguments                  */
1466 /*-----------------------------------------------------------------*/
1467 static void
1468 assemble (char **envp)
1469 {
1470     /* build assembler output filename */
1471
1472     /* -o option overrides default name? */
1473     if (options.cc_only && fullDstFileName) {
1474         strcpy (scratchFileName, fullDstFileName);
1475     } else {
1476         /* the assembled file gets the name of the first modul */
1477         strcpy (scratchFileName, dstFileName);
1478         strcat (scratchFileName, port->linker.rel_ext);
1479     }
1480
1481     if (port->assembler.do_assemble) {
1482         port->assembler.do_assemble(asmOptions);
1483         return ;
1484     } else if (port->assembler.cmd) {
1485         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1486                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1487                       asmOptions);
1488     } else {
1489         buildCmdLine2 (buffer, port->assembler.mcmd);
1490     }
1491
1492     if (my_system (buffer)) {
1493         /* either system() or the assembler itself has reported an error
1494            perror ("Cannot exec assembler");
1495         */
1496         exit (1);
1497     }
1498     /* TODO: most assembler don't have a -o parameter */
1499     /* -o option overrides default name? */
1500     if (options.cc_only && fullDstFileName) {
1501         strcpy (scratchFileName, dstFileName);
1502         strcat (scratchFileName, port->linker.rel_ext);
1503         rename (scratchFileName, fullDstFileName);
1504     }
1505 }
1506
1507 /*-----------------------------------------------------------------*/
1508 /* preProcess - spawns the preprocessor with arguments       */
1509 /*-----------------------------------------------------------------*/
1510 static int
1511 preProcess (char **envp)
1512 {
1513   if (options.c1mode)
1514     {
1515       yyin = stdin;
1516     }
1517   else
1518     {
1519       /* if using external stack define the macro */
1520       if (options.useXstack)
1521         addToList (preArgv, "-DSDCC_USE_XSTACK");
1522
1523       /* set the macro for stack autos  */
1524       if (options.stackAuto)
1525         addToList (preArgv, "-DSDCC_STACK_AUTO");
1526
1527       /* set the macro for stack autos  */
1528       if (options.stack10bit)
1529         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1530
1531       /* set the macro for no overlay  */
1532       if (options.noOverlay)
1533         addToList (preArgv, "-DSDCC_NOOVERLAY");
1534
1535       /* set the macro for large model  */
1536       switch (options.model)
1537         {
1538         case MODEL_LARGE:
1539           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1540           break;
1541         case MODEL_SMALL:
1542           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1543           break;
1544         case MODEL_COMPACT:
1545           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1546           break;
1547         case MODEL_MEDIUM:
1548           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1549           break;
1550         case MODEL_FLAT24:
1551           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1552           break;
1553         case MODEL_PAGE0:
1554           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1555           break;
1556         default:
1557           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1558           break;
1559         }
1560
1561       /* add port (processor information to processor */
1562       addToList (preArgv, "-DSDCC_{port}");
1563       addToList (preArgv, "-D__{port}");
1564
1565       /* standard include path */
1566       if (!options.nostdinc) {
1567         addToList (preArgv, "-I{includedir}");
1568       }
1569
1570       setMainValue ("cppextraopts", join(preArgv));
1571
1572       if (preProcOnly)
1573         {
1574           if (fullDstFileName)
1575             {
1576               preOutName = Safe_strdup (fullDstFileName);
1577             }
1578         }
1579       else
1580           preOutName = Safe_strdup (tempfilename ());
1581
1582       /* Have to set cppoutfilename to something, even if just pre-processing. */
1583       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1584       addSetHead (&tmpfileNameSet, preOutName);
1585
1586       if (options.verbose)
1587         printf ("sdcc: Calling preprocessor...\n");
1588
1589       buildCmdLine2 (buffer, _preCmd);
1590
1591       if (my_system (buffer))
1592         {
1593           exit (1);
1594         }
1595       if (preProcOnly)
1596         {
1597           exit (0);
1598         }
1599       yyin = fopen (preOutName, "r");
1600       if (yyin == NULL)
1601         {
1602           perror ("Preproc file not found\n");
1603           exit (1);
1604         }
1605       addSetHead (&tmpfileSet, yyin);
1606     }
1607
1608   return 0;
1609 }
1610
1611 static bool
1612 _setPaths (const char *pprefix)
1613 {
1614   /* Logic:
1615       Given the prefix and how the directories were layed out at
1616       configure time, see if the library and include directories are
1617       where expected.  If so, set.
1618   */
1619   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1620   strcpy (scratchFileName, pprefix);
1621   strcat (scratchFileName, buffer);
1622
1623   if (pathExists (scratchFileName))
1624     {
1625       setMainValue ("includedir", scratchFileName);
1626     }
1627   else
1628     {
1629       return FALSE;
1630     }
1631
1632   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1633   strcpy (scratchFileName, pprefix);
1634   strcat (scratchFileName, buffer);
1635
1636   if (pathExists (scratchFileName))
1637     {
1638       setMainValue ("libdir", scratchFileName);
1639     }
1640   else
1641     {
1642       return FALSE;
1643     }
1644
1645   return TRUE;
1646 }
1647
1648 static void
1649 _discoverPaths (const char *argv0)
1650 {
1651   /* Logic:
1652       1.  Try the SDCCDIR environment variable.
1653       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1654       and library paths with respect to that.  Note that under win32
1655       argv[0] is always the full path to the program.
1656       3.  If (1) and (2) fail, fall back to the compile time defaults.
1657
1658       Detecting assumes the same layout as when configured.  If the
1659       directories have been further moved about then discovery will
1660       fail.
1661   */
1662
1663   /* Some input cases:
1664         "c:\fish\sdcc\bin\sdcc"
1665         "../bin/sdcc"
1666         "/home/fish/bin/sdcc"
1667
1668       Note that ./sdcc is explicitly not supported as there isn't
1669       enough information.
1670   */
1671   /* bindir is handled differently to the lib and include directories.
1672      It's rather unfortunate, but required due to the different
1673      install and development layouts.  Logic is different as well.
1674      Sigh.
1675    */
1676   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1677     {
1678       strcpy (scratchFileName, argv0);
1679       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1680       setMainValue ("bindir", scratchFileName);
1681       ExePathList[0] = Safe_strdup (scratchFileName);
1682     }
1683   else if (getenv (SDCCDIR_NAME) != NULL)
1684     {
1685       getPathDifference (buffer, PREFIX, BINDIR);
1686       strcpy (scratchFileName, getenv (SDCCDIR_NAME));
1687       strcat (scratchFileName, buffer);
1688       setMainValue ("bindir", scratchFileName);
1689       ExePathList[0] = Safe_strdup (scratchFileName);
1690     }
1691   else
1692     {
1693       setMainValue ("bindir", BINDIR);
1694       ExePathList[0] = BINDIR;
1695     }
1696
1697   do
1698     {
1699       /* Case 1 */
1700       if (getenv (SDCCDIR_NAME) != NULL)
1701         {
1702           if (_setPaths (getenv (SDCCDIR_NAME)))
1703             {
1704               /* Successfully set. */
1705               break;
1706             }
1707           else
1708             {
1709               /* Include and lib weren't where expected. */
1710             }
1711         }
1712       /* Case 2 */
1713       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1714         {
1715           char *pbase = getPrefixFromBinPath (argv0);
1716
1717           if (pbase == NULL)
1718             {
1719               /* A bad path.  Skip. */
1720             }
1721           else
1722             {
1723               if (_setPaths (pbase))
1724                 {
1725                   /* Successfully set. */
1726                   break;
1727                 }
1728               else
1729                 {
1730                   /* Include and lib weren't where expected. */
1731                 }
1732             }
1733         }
1734       /* Case 3 */
1735       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1736       setMainValue ("libdir", SDCC_LIB_DIR);
1737     } while (0);
1738 }
1739
1740 static void
1741 initValues (void)
1742 {
1743   populateMainValues (_baseValues);
1744   setMainValue ("port", port->target);
1745   setMainValue ("objext", port->linker.rel_ext);
1746   setMainValue ("asmext", port->assembler.file_ext);
1747
1748   setMainValue ("dstfilename", dstFileName);
1749   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1750
1751   if (options.cc_only && fullDstFileName)
1752     /* compile + assemble and -o given: -o specifies name of object file */
1753     {
1754       setMainValue ("objdstfilename", fullDstFileName);
1755     }
1756   else
1757     {
1758       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1759     }
1760   if (fullDstFileName)
1761     /* if we're linking, -o gives the final file name */
1762     {
1763       setMainValue ("linkdstfilename", fullDstFileName);
1764     }
1765   else
1766     {
1767       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1768     }
1769
1770 }
1771
1772 static void
1773 sig_handler (int signal)
1774 {
1775   char *sig_string;
1776
1777   switch (signal)
1778     {
1779     case SIGABRT:
1780       sig_string = "SIGABRT";
1781       break;
1782     case SIGTERM:
1783       sig_string = "SIGTERM";
1784       break;
1785     case SIGINT:
1786       sig_string = "SIGINT";
1787       break;
1788     case SIGSEGV:
1789       sig_string = "SIGSEGV";
1790       break;
1791     default:
1792       sig_string = "Unknown?";
1793       break;
1794     }
1795   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1796   exit (1);
1797 }
1798
1799 /*
1800  * main routine
1801  * initialises and calls the parser
1802  */
1803
1804 int
1805 main (int argc, char **argv, char **envp)
1806 {
1807   /* turn all optimizations off by default */
1808   memset (&optimize, 0, sizeof (struct optimize));
1809
1810   /*printVersionInfo (); */
1811
1812   if (NUM_PORTS==0) {
1813     fprintf (stderr, "Build error: no ports are enabled.\n");
1814     exit (1);
1815   }
1816
1817   /* install atexit handler */
1818   atexit(rm_tmpfiles);
1819
1820   /* install signal handler;
1821      it's only purpuse is to call exit() to remove temp files */
1822   if (!getenv("SDCC_LEAVE_SIGNALS"))
1823     {
1824       signal (SIGABRT, sig_handler);
1825       signal (SIGTERM, sig_handler);
1826       signal (SIGINT , sig_handler);
1827       signal (SIGSEGV, sig_handler);
1828     }
1829
1830   /* Before parsing the command line options, do a
1831    * search for the port and processor and initialize
1832    * them if they're found. (We can't gurantee that these
1833    * will be the first options specified).
1834    */
1835
1836   _findPort (argc, argv);
1837
1838 #ifdef JAMIN_DS390
1839   if (strcmp(port->target, "mcs51") == 0) {
1840     printf("DS390 jammed in A\n");
1841           _setPort ("ds390");
1842     ds390_jammed = 1;
1843   }
1844 #endif
1845
1846   _findProcessor (argc, argv);
1847
1848   /* Initalise the port. */
1849   if (port->init)
1850     port->init ();
1851
1852   // Create a default exe search path from the path to the sdcc command
1853
1854
1855   setDefaultOptions ();
1856 #ifdef JAMIN_DS390
1857   if (ds390_jammed) {
1858     options.model = MODEL_SMALL;
1859     options.stack10bit=0;
1860   }
1861 #endif
1862   parseCmdLine (argc, argv);
1863
1864   /* if no input then printUsage & exit */
1865   if (!options.c1mode && !fullSrcFileName && !nrelFiles)
1866     {
1867       printUsage ();
1868       exit (0);
1869     }
1870
1871   initValues ();
1872   _discoverPaths (argv[0]);
1873
1874   /* initMem() is expensive, but
1875      initMem() must called before port->finaliseOptions ().
1876      And the z80 port needs port->finaliseOptions(),
1877      even if we're only linking. */
1878   initMem ();
1879   port->finaliseOptions ();
1880
1881   if (fullSrcFileName || options.c1mode)
1882     {
1883       preProcess (envp);
1884
1885       initSymt ();
1886       initiCode ();
1887       initCSupport ();
1888       initBuiltIns();
1889       initPeepHole ();
1890
1891       if (options.verbose)
1892         printf ("sdcc: Generating code...\n");
1893
1894       yyparse ();
1895       if (fatalError) {
1896         exit (1);
1897       }
1898
1899       if (TARGET_IS_PIC) {
1900         /* TSD PIC port hack - if the PIC port option is enabled
1901            and SDCC is used to generate PIC code, then we will
1902            generate .asm files in gpasm's format instead of SDCC's
1903            assembler's format
1904         */
1905 #if !OPT_DISABLE_PIC
1906         picglue ();
1907 #endif
1908       }
1909       else {
1910         glue ();
1911       }
1912
1913       if (!options.c1mode && !noAssemble)
1914         {
1915           if (options.verbose)
1916             printf ("sdcc: Calling assembler...\n");
1917           assemble (envp);
1918         }
1919     }
1920   closeDumpFiles();
1921
1922   if (cdbFile)
1923     fclose (cdbFile);
1924
1925   if (!options.cc_only &&
1926       !fatalError &&
1927       !noAssemble &&
1928       !options.c1mode &&
1929       (fullSrcFileName || nrelFiles))
1930     {
1931       if (port->linker.do_link)
1932         port->linker.do_link ();
1933       else
1934         linkEdit (envp);
1935     }
1936
1937   return 0;
1938 }