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