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