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