Buffer overflow hunt: removing strcpy, strcat, sprintf
[fw/sdcc] / src / SDCCmain.c
1 /*-------------------------------------------------------------------------
2   SDCCmain.c - main file
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include <signal.h>
26 #include "common.h"
27 #include <ctype.h>
28 #include "newalloc.h"
29 #include "SDCCerr.h"
30 #include "BuildCmd.h"
31 #include "MySystem.h"
32 #include "SDCCmacro.h"
33 #include "SDCCutil.h"
34 #include "SDCCargs.h"
35
36 #if NATIVE_WIN32
37 #include <process.h>
38 #endif
39
40 #if !defined(__BORLANDC__) && !defined(_MSC_VER)
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #endif
44
45 /** Name of the environment variable checked for other instalations. */
46 #define SDCCDIR_NAME "SDCCDIR"
47
48 //REMOVE ME!!!
49 extern int yyparse ();
50
51 FILE *srcFile;                  /* source file          */
52 FILE *cdbFile = NULL;           /* debugger information output file */
53 char *fullSrcFileName;          /* full name for the source file; */
54                                 /* can be NULL while c1mode or linking without compiling */
55 char *fullDstFileName;          /* full name for the output file; */
56                                 /* only given by -o, otherwise NULL */
57 size_t fullDstFileNameLen;      /* size of previous string. */
58 char *dstFileName;              /* destination file name without extension */
59 char *dstPath = "";             /* path for the output files; */
60                                 /* "" is equivalent with cwd */
61 char *moduleName;               /* module name is source file without path and extension */
62                                 /* can be NULL while linking without compiling */
63 const char *preArgv[128];       /* pre-processor arguments  */
64 int currRegBank = 0;
65 int RegBankUsed[4]={1, 0, 0, 0};        /*JCF: Reg Bank 0 used by default*/
66 struct optimize optimize;
67 struct options options;
68 char *VersionString = SDCC_VERSION_STR;
69 int preProcOnly = 0;
70 int noAssemble = 0;
71 char *linkOptions[128];
72 const char *asmOptions[128];
73 char *libFiles[128];
74 int nlibFiles = 0;
75 char *libPaths[128];
76 int nlibPaths = 0;
77 char *relFiles[128];
78 int nrelFiles = 0;
79 static 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,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
142     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
143     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
144     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
145     { 'l',  NULL,                   NULL, "Include the given library in the link" },
146     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
147     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
148     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
149     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
150     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
151     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
152     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
153     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
154     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
155     { 0,    OPTION_NO_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 standard 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)
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       strncpyz (buffer, s, PATH_MAX);
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                 strncpyz(buffer, getStringArg("-o", argv, &i, argc), PATH_MAX);
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                     fullDstFileNameLen = strlen(fullDstFileName) + 1;
1045
1046                     /* get rid of the "."-extension */
1047
1048                     /* is there a dot at all? */
1049                     if (strrchr (buffer, '.') &&
1050                         /* is the dot in the filename, not in the path? */
1051                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1052                       *strrchr (buffer, '.') = '\0';
1053
1054                     dstFileName = Safe_strdup (buffer);
1055
1056                     /* strip module name to get path */
1057                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1058                     if (p)
1059                       {
1060                         /* path with trailing / */
1061                         p[1] = '\0';
1062                         dstPath = Safe_strdup (buffer);
1063                       }
1064                   }
1065                 break;
1066               }
1067
1068             case 'W':
1069               /* pre-processer options */
1070               if (argv[i][2] == 'p')
1071                 {
1072                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
1073                 }
1074               /* linker options */
1075               else if (argv[i][2] == 'l')
1076                 {
1077                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1078                 }
1079               /* assembler options */
1080               else if (argv[i][2] == 'a')
1081                 {
1082                   parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
1083                 }
1084               else
1085                 {
1086                   werror (W_UNKNOWN_OPTION, argv[i]);
1087                 }
1088               break;
1089
1090             case 'v':
1091               verifyShortOption(argv[i]);
1092
1093               printVersionInfo ();
1094               exit (0);
1095               break;
1096
1097               /* preprocessor options */
1098             case 'M':
1099               {
1100                 preProcOnly = 1;
1101                 addToList (preArgv, "-M");
1102                 break;
1103               }
1104             case 'C':
1105               {
1106                 addToList (preArgv, "-C");
1107                 break;
1108               }
1109             case 'd':
1110             case 'D':
1111             case 'I':
1112             case 'A':
1113             case 'U':
1114               {
1115                 char sOpt = argv[i][1];
1116                 char *rest;
1117
1118                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1119                   {
1120                     i++;
1121                     if (i >= argc)
1122                       {
1123                           /* No argument. */
1124                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1125                           break;
1126                       }
1127                     else
1128                       {
1129                           rest = argv[i];
1130                       }
1131                   }
1132                 else
1133                   rest = &argv[i][2];
1134
1135                 if (sOpt == 'Y')
1136                   sOpt = 'I';
1137
1138                 sprintf (buffer, "-%c%s", sOpt, rest);
1139                 addToList (preArgv, buffer);
1140               }
1141               break;
1142
1143             default:
1144               if (!port->parseOption (&argc, argv, &i))
1145                 werror (W_UNKNOWN_OPTION, argv[i]);
1146             }
1147           continue;
1148         }
1149
1150       if (!port->parseOption (&argc, argv, &i))
1151         {
1152            /* no option must be a filename */
1153            if (options.c1mode)
1154              {
1155                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1156              }
1157          else
1158              {
1159                 processFile (argv[i]);
1160              }
1161         }
1162     }
1163
1164   /* some sanity checks in c1 mode */
1165   if (options.c1mode)
1166     {
1167       int i;
1168
1169       if (fullSrcFileName)
1170         {
1171           fclose (srcFile);
1172           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1173         }
1174       fullSrcFileName = NULL;
1175       for (i = 0; i < nrelFiles; ++i)
1176         {
1177           werror (W_NO_FILE_ARG_IN_C1, relFiles[i]);
1178         }
1179       for (i = 0; i < nlibFiles; ++i)
1180         {
1181           werror (W_NO_FILE_ARG_IN_C1, libFiles[i]);
1182         }
1183       nrelFiles = nlibFiles = 0;
1184       if (options.cc_only || noAssemble || preProcOnly)
1185         {
1186           werror (W_ILLEGAL_OPT_COMBINATION);
1187         }
1188       options.cc_only = noAssemble = preProcOnly = 0;
1189       if (!dstFileName)
1190         {
1191           werror (E_NEED_OPT_O_IN_C1);
1192           exit (1);
1193         }
1194     }
1195   /* if no dstFileName given with -o, we've to find one: */
1196   if (!dstFileName)
1197     {
1198       /* use the modulename from the C-source */
1199       if (fullSrcFileName)
1200         {
1201           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1202
1203           dstFileName = Safe_alloc (bufSize);
1204           strncpyz (dstFileName, dstPath, bufSize);
1205           strncatz (dstFileName, moduleName, bufSize);
1206         }
1207       /* use the modulename from the first object file */
1208       else if (nrelFiles >= 1)
1209         {
1210           char *objectName;
1211           size_t bufSize;
1212
1213           strncpyz (buffer, relFiles[0], PATH_MAX);
1214           /* remove extension (it must be .rel) */
1215           *strrchr (buffer, '.') = '\0';
1216           /* remove path */
1217           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1218           if (objectName)
1219             {
1220               ++objectName;
1221             }
1222           else
1223             {
1224               objectName = buffer;
1225             }
1226           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1227           dstFileName = Safe_alloc (bufSize);
1228           strncpyz (dstFileName, dstPath, bufSize);
1229           strncatz (dstFileName, objectName, bufSize);
1230         }
1231       /* else no module given: help text is displayed */
1232     }
1233
1234   /* set up external stack location if not explicitly specified */
1235   if (!options.xstack_loc)
1236     options.xstack_loc = options.xdata_loc;
1237
1238   /* if debug option is set the open the cdbFile */
1239   if (options.debug && fullSrcFileName)
1240     {
1241       sprintf (scratchFileName, "%s.adb", dstFileName); //JCF: Nov 30, 2002
1242       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1243         werror (E_FILE_OPEN_ERR, scratchFileName);
1244       else
1245         {
1246           /* add a module record */
1247           fprintf (cdbFile, "M:%s\n", moduleName);
1248         }
1249     }
1250   return 0;
1251 }
1252
1253 /*-----------------------------------------------------------------*/
1254 /* linkEdit : - calls the linkage editor  with options             */
1255 /*-----------------------------------------------------------------*/
1256 static void
1257 linkEdit (char **envp)
1258 {
1259   FILE *lnkfile;
1260   char *segName, *c;
1261   int i, system_ret;
1262
1263   /* first we need to create the <filename>.lnk file */
1264   sprintf (scratchFileName, "%s.lnk", dstFileName);
1265   if (!(lnkfile = fopen (scratchFileName, "w")))
1266     {
1267       werror (E_FILE_OPEN_ERR, scratchFileName);
1268       exit (1);
1269     }
1270
1271   /* now write the options.  JCF: added option 'y' */
1272   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1273
1274   /* if iram size specified */
1275   if (options.iram_size)
1276     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1277
1278   /* if xram size specified */
1279   if (options.xram_size_set)
1280     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1281
1282   /* if code size specified */
1283   if (options.code_size)
1284     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1285
1286   if (options.debug)
1287     fprintf (lnkfile, "-z\n");
1288
1289 #define WRITE_SEG_LOC(N, L) \
1290     segName = Safe_strdup(N); \
1291     c = strtok(segName, " \t"); \
1292     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1293     if (segName) { Safe_free(segName); }
1294
1295   /* code segment start */
1296   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1297
1298   /* data segment start */
1299   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1300           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1301   }
1302
1303   /* xdata start */
1304   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1305
1306   /* indirect data */
1307   if (IDATA_NAME) {
1308     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1309   }
1310
1311   /* bit segment start */
1312   WRITE_SEG_LOC (BIT_NAME, 0);
1313
1314   /* JCF: stack start */
1315   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1316         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1317   }
1318
1319   /* add the extra linker options */
1320   for (i = 0; linkOptions[i]; i++)
1321     fprintf (lnkfile, "%s\n", linkOptions[i]);
1322
1323   /* other library paths if specified */
1324   for (i = 0; i < nlibPaths; i++)
1325     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1326
1327   /* standard library path */
1328   if (!options.nostdlib)
1329     {
1330       switch (options.model)
1331         {
1332         case MODEL_SMALL:
1333           c = "small";
1334           break;
1335         case MODEL_LARGE:
1336           c = "large";
1337           break;
1338         case MODEL_FLAT24:
1339           /* c = "flat24"; */
1340           c = "ds390";
1341           break;
1342         case MODEL_PAGE0:
1343           c = "xa51";
1344           break;
1345         default:
1346           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1347           c = "unknown";
1348           break;
1349         }
1350       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1351
1352       /* standard library files */
1353 #if !OPT_DISABLE_DS390
1354       if (options.model == MODEL_FLAT24)
1355         {
1356           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1357         }
1358 #endif
1359
1360 #if !OPT_DISABLE_XA51 
1361 #ifdef STD_XA51_LIB
1362       if (options.model == MODEL_PAGE0)
1363         {
1364           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1365         }
1366 #endif
1367 #endif
1368       fprintf (lnkfile, "-l %s\n", STD_LIB);
1369       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1370       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1371       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1372     }
1373
1374   /* additional libraries if any */
1375   for (i = 0; i < nlibFiles; i++)
1376     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1377
1378   /* put in the object files */
1379   if (fullSrcFileName)
1380     fprintf (lnkfile, "%s ", dstFileName);
1381
1382   for (i = 0; i < nrelFiles; i++)
1383     fprintf (lnkfile, "%s\n", relFiles[i]);
1384
1385   fprintf (lnkfile, "\n-e\n");
1386   fclose (lnkfile);
1387
1388   if (options.verbose)
1389     printf ("sdcc: Calling linker...\n");
1390
1391   /* build linker output filename */
1392
1393   /* -o option overrides default name? */
1394   if (fullDstFileName)
1395     {
1396       strncpyz (scratchFileName, fullDstFileName, PATH_MAX);
1397     }
1398   else
1399     {
1400       /* the linked file gets the name of the first modul */
1401       if (fullSrcFileName)
1402         {
1403           strncpyz (scratchFileName, dstFileName, PATH_MAX);
1404         }
1405       else
1406         {
1407           strncpyz (scratchFileName, relFiles[0], PATH_MAX);
1408           /* strip ".rel" extension */
1409           *strrchr (scratchFileName, '.') = '\0';
1410         }
1411       strncatz (scratchFileName, options.out_fmt ? ".S19" : ".ihx", PATH_MAX);
1412     }
1413
1414   if (port->linker.cmd)
1415     {
1416       char buffer2[PATH_MAX];
1417       buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
1418       buildCmdLine2 (buffer, buffer2, PATH_MAX);
1419     }
1420   else
1421     {
1422       buildCmdLine2 (buffer, port->linker.mcmd, PATH_MAX);
1423     }
1424
1425   system_ret = my_system (buffer);
1426   /* TODO: most linker don't have a -o parameter */
1427   /* -o option overrides default name? */
1428   if (fullDstFileName)
1429     {
1430       char *p, *q;
1431       /* the linked file gets the name of the first modul */
1432       if (fullSrcFileName)
1433         {
1434           strncpyz (scratchFileName, dstFileName, PATH_MAX);
1435           p = strlen (scratchFileName) + scratchFileName;
1436         }
1437       else
1438         {
1439           strncpyz (scratchFileName, relFiles[0], PATH_MAX);
1440           /* strip "rel" extension */
1441           p = strrchr (scratchFileName, '.');
1442           if (p)
1443             {
1444                 p++;
1445                 *p = 0;
1446             }
1447             
1448         }
1449       strncatz (scratchFileName, options.out_fmt ? "S19" : "ihx", PATH_MAX);
1450       rename (scratchFileName, fullDstFileName);
1451
1452       q = strrchr (fullDstFileName, '.');
1453       if (q)
1454         {
1455           /* point after the '.' of the extension */
1456           q++;
1457         }
1458       else
1459         {
1460           /* no extension: append new extensions */
1461           /* Don't we want to append a period here ? */
1462           q = strlen (fullDstFileName) + fullDstFileName;
1463         }
1464         
1465       *p = 0;   
1466       strncatz (scratchFileName, "map", PATH_MAX);
1467       *q = 0;
1468       strncatz(fullDstFileName, "map", PATH_MAX);
1469       rename (scratchFileName, fullDstFileName);
1470       *p = 0;   
1471       strncatz (scratchFileName, "mem", PATH_MAX);
1472       *q = 0;
1473       strncatz(fullDstFileName, "mem", PATH_MAX);       
1474       rename (scratchFileName, fullDstFileName);
1475     }
1476   if (system_ret)
1477     {
1478       exit (1);
1479     }
1480 }
1481
1482 /*-----------------------------------------------------------------*/
1483 /* assemble - spawns the assembler with arguments                  */
1484 /*-----------------------------------------------------------------*/
1485 static void
1486 assemble (char **envp)
1487 {
1488     /* build assembler output filename */
1489
1490     /* -o option overrides default name? */
1491     if (options.cc_only && fullDstFileName) {
1492         strncpyz (scratchFileName, fullDstFileName, PATH_MAX);
1493     } else {
1494         /* the assembled file gets the name of the first modul */
1495         strncpyz (scratchFileName, dstFileName, PATH_MAX);
1496         strncatz (scratchFileName, port->linker.rel_ext, PATH_MAX);
1497     }
1498
1499     if (port->assembler.do_assemble) {
1500         port->assembler.do_assemble(asmOptions);
1501         return ;
1502     } else if (port->assembler.cmd) {
1503         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1504                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1505                       asmOptions);
1506     } else {
1507         buildCmdLine2 (buffer, port->assembler.mcmd, PATH_MAX);
1508     }
1509
1510     if (my_system (buffer)) {
1511         /* either system() or the assembler itself has reported an error
1512            perror ("Cannot exec assembler");
1513         */
1514         exit (1);
1515     }
1516     /* TODO: most assembler don't have a -o parameter */
1517     /* -o option overrides default name? */
1518     if (options.cc_only && fullDstFileName) {
1519         strncpyz (scratchFileName, dstFileName, PATH_MAX);
1520         strncatz (scratchFileName, port->linker.rel_ext, PATH_MAX);
1521         rename (scratchFileName, fullDstFileName);
1522     }
1523 }
1524
1525 /*-----------------------------------------------------------------*/
1526 /* preProcess - spawns the preprocessor with arguments       */
1527 /*-----------------------------------------------------------------*/
1528 static int
1529 preProcess (char **envp)
1530 {
1531   if (options.c1mode)
1532     {
1533       yyin = stdin;
1534     }
1535   else
1536     {
1537       /* if using external stack define the macro */
1538       if (options.useXstack)
1539         addToList (preArgv, "-DSDCC_USE_XSTACK");
1540
1541       /* set the macro for stack autos  */
1542       if (options.stackAuto)
1543         addToList (preArgv, "-DSDCC_STACK_AUTO");
1544
1545       /* set the macro for stack autos  */
1546       if (options.stack10bit)
1547         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1548
1549       /* set the macro for no overlay  */
1550       if (options.noOverlay)
1551         addToList (preArgv, "-DSDCC_NOOVERLAY");
1552
1553       /* set the macro for large model  */
1554       switch (options.model)
1555         {
1556         case MODEL_LARGE:
1557           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1558           break;
1559         case MODEL_SMALL:
1560           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1561           break;
1562         case MODEL_COMPACT:
1563           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1564           break;
1565         case MODEL_MEDIUM:
1566           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1567           break;
1568         case MODEL_FLAT24:
1569           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1570           break;
1571         case MODEL_PAGE0:
1572           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1573           break;
1574         default:
1575           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1576           break;
1577         }
1578
1579       /* add port (processor information to processor */
1580       addToList (preArgv, "-DSDCC_{port}");
1581       addToList (preArgv, "-D__{port}");
1582
1583       /* standard include path */
1584       if (!options.nostdinc) {
1585         addToList (preArgv, "-I{includedir}");
1586       }
1587
1588       setMainValue ("cppextraopts", join(preArgv));
1589
1590       if (preProcOnly)
1591         {
1592           if (fullDstFileName)
1593             {
1594               preOutName = Safe_strdup (fullDstFileName);
1595             }
1596         }
1597       else
1598           preOutName = Safe_strdup (tempfilename ());
1599
1600       /* Have to set cppoutfilename to something, even if just pre-processing. */
1601       setMainValue ("cppoutfilename", preOutName ? preOutName : "");
1602       addSetHead (&tmpfileNameSet, preOutName);
1603
1604       if (options.verbose)
1605         printf ("sdcc: Calling preprocessor...\n");
1606
1607       buildCmdLine2 (buffer, _preCmd, PATH_MAX);
1608
1609       if (my_system (buffer))
1610         {
1611           exit (1);
1612         }
1613       if (preProcOnly)
1614         {
1615           exit (0);
1616         }
1617       yyin = fopen (preOutName, "r");
1618       if (yyin == NULL)
1619         {
1620           perror ("Preproc file not found\n");
1621           exit (1);
1622         }
1623       addSetHead (&tmpfileSet, yyin);
1624     }
1625
1626   return 0;
1627 }
1628
1629 static bool
1630 _setPaths (const char *pprefix)
1631 {
1632   /* Logic:
1633       Given the prefix and how the directories were layed out at
1634       configure time, see if the library and include directories are
1635       where expected.  If so, set.
1636   */
1637   getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
1638   strncpyz (scratchFileName, pprefix, PATH_MAX);
1639   strncatz (scratchFileName, buffer, PATH_MAX);
1640
1641   if (pathExists (scratchFileName))
1642     {
1643       setMainValue ("includedir", scratchFileName);
1644     }
1645   else
1646     {
1647       return FALSE;
1648     }
1649
1650   getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
1651   strncpyz (scratchFileName, pprefix, PATH_MAX);
1652   strncatz (scratchFileName, buffer, PATH_MAX);
1653
1654   if (pathExists (scratchFileName))
1655     {
1656       setMainValue ("libdir", scratchFileName);
1657     }
1658   else
1659     {
1660       return FALSE;
1661     }
1662
1663   return TRUE;
1664 }
1665
1666 static void
1667 _discoverPaths (const char *argv0)
1668 {
1669   /* Logic:
1670       1.  Try the SDCCDIR environment variable.
1671       2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
1672       and library paths with respect to that.  Note that under win32
1673       argv[0] is always the full path to the program.
1674       3.  If (1) and (2) fail, fall back to the compile time defaults.
1675
1676       Detecting assumes the same layout as when configured.  If the
1677       directories have been further moved about then discovery will
1678       fail.
1679   */
1680
1681   /* Some input cases:
1682         "c:\fish\sdcc\bin\sdcc"
1683         "../bin/sdcc"
1684         "/home/fish/bin/sdcc"
1685
1686       Note that ./sdcc is explicitly not supported as there isn't
1687       enough information.
1688   */
1689   /* bindir is handled differently to the lib and include directories.
1690      It's rather unfortunate, but required due to the different
1691      install and development layouts.  Logic is different as well.
1692      Sigh.
1693    */
1694   if (strchr (argv0, DIR_SEPARATOR_CHAR))
1695     {
1696       strncpyz (scratchFileName, argv0, PATH_MAX);
1697       *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
1698       setMainValue ("bindir", scratchFileName);
1699       ExePathList[0] = Safe_strdup (scratchFileName);
1700     }
1701   else if (getenv (SDCCDIR_NAME) != NULL)
1702     {
1703       getPathDifference (buffer, PREFIX, BINDIR);
1704       strncpyz (scratchFileName, getenv (SDCCDIR_NAME), PATH_MAX);
1705       strncatz (scratchFileName, buffer, PATH_MAX);
1706       setMainValue ("bindir", scratchFileName);
1707       ExePathList[0] = Safe_strdup (scratchFileName);
1708     }
1709   else
1710     {
1711       setMainValue ("bindir", BINDIR);
1712       ExePathList[0] = BINDIR;
1713     }
1714
1715   do
1716     {
1717       /* Case 1 */
1718       if (getenv (SDCCDIR_NAME) != NULL)
1719         {
1720           if (_setPaths (getenv (SDCCDIR_NAME)))
1721             {
1722               /* Successfully set. */
1723               break;
1724             }
1725           else
1726             {
1727               /* Include and lib weren't where expected. */
1728             }
1729         }
1730       /* Case 2 */
1731       if (strchr (argv0, DIR_SEPARATOR_CHAR))
1732         {
1733           char *pbase = getPrefixFromBinPath (argv0);
1734
1735           if (pbase == NULL)
1736             {
1737               /* A bad path.  Skip. */
1738             }
1739           else
1740             {
1741               if (_setPaths (pbase))
1742                 {
1743                   /* Successfully set. */
1744                   break;
1745                 }
1746               else
1747                 {
1748                   /* Include and lib weren't where expected. */
1749                 }
1750             }
1751         }
1752       /* Case 3 */
1753       setMainValue ("includedir", SDCC_INCLUDE_DIR);
1754       setMainValue ("libdir", SDCC_LIB_DIR);
1755     } while (0);
1756 }
1757
1758 static void
1759 initValues (void)
1760 {
1761   populateMainValues (_baseValues);
1762   setMainValue ("port", port->target);
1763   setMainValue ("objext", port->linker.rel_ext);
1764   setMainValue ("asmext", port->assembler.file_ext);
1765
1766   setMainValue ("dstfilename", dstFileName);
1767   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1768
1769   if (options.cc_only && fullDstFileName)
1770     /* compile + assemble and -o given: -o specifies name of object file */
1771     {
1772       setMainValue ("objdstfilename", fullDstFileName);
1773     }
1774   else
1775     {
1776       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1777     }
1778   if (fullDstFileName)
1779     /* if we're linking, -o gives the final file name */
1780     {
1781       setMainValue ("linkdstfilename", fullDstFileName);
1782     }
1783   else
1784     {
1785       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1786     }
1787
1788 }
1789
1790 static void
1791 sig_handler (int signal)
1792 {
1793   char *sig_string;
1794
1795   switch (signal)
1796     {
1797     case SIGABRT:
1798       sig_string = "SIGABRT";
1799       break;
1800     case SIGTERM:
1801       sig_string = "SIGTERM";
1802       break;
1803     case SIGINT:
1804       sig_string = "SIGINT";
1805       break;
1806     case SIGSEGV:
1807       sig_string = "SIGSEGV";
1808       break;
1809     default:
1810       sig_string = "Unknown?";
1811       break;
1812     }
1813   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1814   exit (1);
1815 }
1816
1817 /*
1818  * main routine
1819  * initialises and calls the parser
1820  */
1821
1822 int
1823 main (int argc, char **argv, char **envp)
1824 {
1825   /* turn all optimizations off by default */
1826   memset (&optimize, 0, sizeof (struct optimize));
1827
1828   /*printVersionInfo (); */
1829
1830   if (NUM_PORTS==0) {
1831     fprintf (stderr, "Build error: no ports are enabled.\n");
1832     exit (1);
1833   }
1834
1835   /* install atexit handler */
1836   atexit(rm_tmpfiles);
1837
1838   /* install signal handler;
1839      it's only purpuse is to call exit() to remove temp files */
1840   if (!getenv("SDCC_LEAVE_SIGNALS"))
1841     {
1842       signal (SIGABRT, sig_handler);
1843       signal (SIGTERM, sig_handler);
1844       signal (SIGINT , sig_handler);
1845       signal (SIGSEGV, sig_handler);
1846     }
1847
1848   /* Before parsing the command line options, do a
1849    * search for the port and processor and initialize
1850    * them if they're found. (We can't gurantee that these
1851    * will be the first options specified).
1852    */
1853
1854   _findPort (argc, argv);
1855
1856 #ifdef JAMIN_DS390
1857   if (strcmp(port->target, "mcs51") == 0) {
1858     printf("DS390 jammed in A\n");
1859           _setPort ("ds390");
1860     ds390_jammed = 1;
1861   }
1862 #endif
1863
1864   _findProcessor (argc, argv);
1865
1866   /* Initalise the port. */
1867   if (port->init)
1868     port->init ();
1869
1870   // Create a default exe search path from the path to the sdcc command
1871
1872
1873   setDefaultOptions ();
1874 #ifdef JAMIN_DS390
1875   if (ds390_jammed) {
1876     options.model = MODEL_SMALL;
1877     options.stack10bit=0;
1878   }
1879 #endif
1880   parseCmdLine (argc, argv);
1881
1882   /* if no input then printUsage & exit */
1883   if (!options.c1mode && !fullSrcFileName && !nrelFiles)
1884     {
1885       printUsage ();
1886       exit (0);
1887     }
1888
1889   initValues ();
1890   _discoverPaths (argv[0]);
1891
1892   /* initMem() is expensive, but
1893      initMem() must called before port->finaliseOptions ().
1894      And the z80 port needs port->finaliseOptions(),
1895      even if we're only linking. */
1896   initMem ();
1897   port->finaliseOptions ();
1898
1899   if (fullSrcFileName || options.c1mode)
1900     {
1901       preProcess (envp);
1902
1903       initSymt ();
1904       initiCode ();
1905       initCSupport ();
1906       initBuiltIns();
1907       initPeepHole ();
1908
1909       if (options.verbose)
1910         printf ("sdcc: Generating code...\n");
1911
1912       yyparse ();
1913       if (fatalError) {
1914         exit (1);
1915       }
1916
1917       if (TARGET_IS_PIC) {
1918         /* TSD PIC port hack - if the PIC port option is enabled
1919            and SDCC is used to generate PIC code, then we will
1920            generate .asm files in gpasm's format instead of SDCC's
1921            assembler's format
1922         */
1923 #if !OPT_DISABLE_PIC
1924         picglue ();
1925 #endif
1926       }
1927       else {
1928         glue ();
1929       }
1930
1931       if (!options.c1mode && !noAssemble)
1932         {
1933           if (options.verbose)
1934             printf ("sdcc: Calling assembler...\n");
1935           assemble (envp);
1936         }
1937     }
1938   closeDumpFiles();
1939
1940   if (cdbFile)
1941     fclose (cdbFile);
1942
1943   if (!options.cc_only &&
1944       !fatalError &&
1945       !noAssemble &&
1946       !options.c1mode &&
1947       (fullSrcFileName || nrelFiles))
1948     {
1949       if (port->linker.do_link)
1950         port->linker.do_link ();
1951       else
1952         linkEdit (envp);
1953     }
1954
1955   return 0;
1956 }