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