added --print-search-dirs command line option
[fw/sdcc] / src / SDCCmain.c
1 /*-------------------------------------------------------------------------
2   SDCCmain.c - main file
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include <signal.h>
26 #include "common.h"
27 #include <ctype.h>
28 #include "newalloc.h"
29 #include "SDCCerr.h"
30 #include "BuildCmd.h"
31 #include "MySystem.h"
32 #include "SDCCmacro.h"
33 #include "SDCCutil.h"
34 #include "SDCCdebug.h"
35 #include "SDCCargs.h"
36
37 #ifdef _WIN32
38 #include <process.h>
39 #else
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #endif
43
44 //REMOVE ME!!!
45 extern int yyparse ();
46
47 FILE *srcFile;                  /* source file          */
48 char *fullSrcFileName;          /* full name for the source file; */
49                                 /* can be NULL while c1mode or linking without compiling */
50 char *fullDstFileName;          /* full name for the output file; */
51                                 /* only given by -o, otherwise NULL */
52 char *dstFileName;              /* destination file name without extension */
53 char *dstPath = "";             /* path for the output files; */
54                                 /* "" is equivalent with cwd */
55 char *moduleName;               /* module name is source file without path and extension */
56                                 /* can be NULL while linking without compiling */
57 /*
58  * in following definitions fixed length arrays are very dangerous!
59  * Sets should be used instead. See definition of asmOptions.
60  */
61 const char *preArgv[128];       /* pre-processor arguments  */
62 int currRegBank = 0;
63 int RegBankUsed[4]={1, 0, 0, 0}; /*JCF: Reg Bank 0 used by default*/
64 struct optimize optimize;
65 struct options options;
66 int preProcOnly = 0;
67 int noAssemble = 0;
68 set *asmOptions = NULL;         /* set of assembler options */
69 char *linkOptions[128];
70 char *libFiles[128];
71 int nlibFiles = 0;
72 char *libPaths[128];
73 int nlibPaths = 0;
74 char *relFiles[128];
75 int nrelFiles = 0;
76
77 /* uncomment JAMIN_DS390 to always override and use ds390 port
78   for mcs51 work.  This is temporary, for compatibility testing. */
79 /* #define JAMIN_DS390 */
80 #ifdef JAMIN_DS390
81 int ds390_jammed = 0;
82 #endif
83
84 // Globally accessible scratch buffer for file names.
85 char scratchFileName[PATH_MAX];
86 char buffer[PATH_MAX * 2];
87
88 #define OPTION_HELP     "-help"
89
90 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
91
92 #define OPTION_STACK_8BIT       "--stack-8bit"
93 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
94 #define OPTION_LARGE_MODEL      "--model-large"
95 #define OPTION_MEDIUM_MODEL     "--model-medium"
96 #define OPTION_SMALL_MODEL      "--model-small"
97 #define OPTION_FLAT24_MODEL     "--model-flat24"
98 #define OPTION_DUMP_ALL         "--dumpall"
99 #define OPTION_PEEP_FILE        "--peep-file"
100 #define OPTION_LIB_PATH         "--lib-path"
101 #define OPTION_XSTACK_LOC       "--xstack-loc"
102 #define OPTION_CALLEE_SAVES     "--callee-saves"
103 #define OPTION_STACK_LOC        "--stack-loc"
104 #define OPTION_XRAM_LOC         "--xram-loc"
105 #define OPTION_IRAM_SIZE        "--iram-size"
106 #define OPTION_VERSION          "--version"
107 #define OPTION_DATA_LOC         "--data-loc"
108 #define OPTION_CODE_LOC         "--code-loc"
109 #define OPTION_IDATA_LOC        "--idata-loc"
110 #define OPTION_NO_LABEL_OPT     "--nolabelopt"
111 #define OPTION_NO_LOOP_INV      "--noinvariant"
112 #define OPTION_NO_LOOP_IND      "--noinduction"
113 #define OPTION_LESS_PEDANTIC    "--less-pedantic"
114 #define OPTION_NO_GCSE          "--nogcse"
115 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
116 #define OPTION_TINI_LIBID       "--tini-libid"
117 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
118 #define OPTION_XRAM_SIZE        "--xram-size"
119 #define OPTION_CODE_SIZE        "--code-size"
120 #define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
121 #define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
122 #define OPTION_PRINT_SEARCH_DIRS "--print-search-dirs"
123
124 static const OPTION
125 optionsTable[] = {
126     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
127     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
128     { 'd',  NULL,                   NULL, NULL },
129     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
130     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
131     { 'A',  NULL,                   NULL, NULL },
132     { 'U',  NULL,                   NULL, NULL },
133     { 'C',  NULL,                   NULL, "Preprocessor option" },
134     { 'M',  NULL,                   NULL, "Preprocessor option" },
135     { 'V',  NULL,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
136     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
137     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
138     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
139     { 'l',  NULL,                   NULL, "Include the given library in the link" },
140     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
141     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
142     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
143     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
144     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
145     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
146     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
147     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
148     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
149     { 0,    OPTION_NO_LABEL_OPT,    NULL, "Disable label optimisation" },
150     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
151     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
152     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
153     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
154     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
155     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
156     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
157     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
158     { 0,    "--dumploop",           &options.dump_loop, NULL },
159     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
160     { 0,    "--dumpliverange",      &options.dump_range, NULL },
161     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
162     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
163     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
164     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
165     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
166     { 0,    OPTION_XRAM_SIZE,       NULL, "<nnnn> External Ram size" },
167     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
168     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
169     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
170     { 0,    OPTION_CODE_SIZE,       NULL, "<nnnn> Code Segment size" },
171     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
172     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
173     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
174     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
175     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
176     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
177     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
178     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
179     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
180     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
181     { 0,    "--nooverlay",          &options.noOverlay, NULL },
182     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
183     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
184     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
185     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
186     { 0,    "--peep-asm",           &options.asmpeep, NULL },
187     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
188     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
189     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
190     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code." },
191     { 0,    "--help",               NULL, "Display this help" },
192     { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
193     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
194     { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
195     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
196     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
197     { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
198     { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
199     { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
200     { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
201     { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
202     { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
203     { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
204     { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
205     { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
206     { 0,    OPTION_NO_XINIT_OPT,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
207     { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
208     { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
209     { 0,    OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
210     /* End of options */
211     { 0,    NULL }
212 };
213
214 /** Table of all unsupported options and help text to display when one
215     is used.
216 */
217 typedef struct {
218     /** shortOpt as in OPTIONS. */
219     char shortOpt;
220     /** longOpt as in OPTIONS. */
221     const char *longOpt;
222     /** Message to display inside W_UNSUPPORTED_OPT when this option
223         is used. */
224     const char *message;
225 } UNSUPPORTEDOPT;
226
227 static const UNSUPPORTEDOPT 
228 unsupportedOptTable[] = {
229     { 'X',  NULL,       "use --xstack-loc instead" },
230     { 'x',  NULL,       "use --xstack instead" },
231     { 'i',  NULL,       "use --idata-loc instead" },
232     { 'r',  NULL,       "use --xdata-loc instead" },
233     { 's',  NULL,       "use --code-loc instead" },
234     { 'Y',  NULL,       "use -I instead" }
235 };
236
237 /** List of all default constant macros.
238  */
239 static const char *_baseValues[] = {
240   "cpp", "sdcpp",
241   "cppextraopts", "",
242   /* Path seperator character */
243   "sep", DIR_SEPARATOR_STRING,
244   NULL
245 };
246
247 static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
248
249 PORT *port;
250
251 static PORT *_ports[] =
252 {
253 #if !OPT_DISABLE_MCS51
254   &mcs51_port,
255 #endif
256 #if !OPT_DISABLE_GBZ80
257   &gbz80_port,
258 #endif
259 #if !OPT_DISABLE_Z80
260   &z80_port,
261 #endif
262 #if !OPT_DISABLE_AVR
263   &avr_port,
264 #endif
265 #if !OPT_DISABLE_DS390
266   &ds390_port,
267 #endif
268 #if !OPT_DISABLE_PIC
269   &pic_port,
270 #endif
271 #if !OPT_DISABLE_TININative
272   &tininative_port,
273 #endif
274 #if !OPT_DISABLE_XA51
275   &xa51_port,
276 #endif
277 #if !OPT_DISABLE_DS400
278   &ds400_port,  
279 #endif  
280 };
281
282 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
283
284 #if !OPT_DISABLE_PIC
285 extern void picglue ();
286 #endif
287
288 /** Sets the port to the one given by the command line option.
289     @param    The name minus the option (eg 'mcs51')
290     @return     0 on success.
291 */
292 static void
293 _setPort (const char *name)
294 {
295   int i;
296   for (i = 0; i < NUM_PORTS; i++)
297     {
298       if (!strcmp (_ports[i]->target, name))
299         {
300           port = _ports[i];
301           return;
302         }
303     }
304   /* Error - didnt find */
305   werror (E_UNKNOWN_TARGET, name);
306   exit (1);
307 }
308
309 /* Override the default processor with the one specified 
310  * on the command line */
311 static void
312 _setProcessor (char *_processor)
313 {
314   port->processor = _processor;
315   fprintf(stderr,"Processor: %s\n",_processor);
316 }
317
318 static void
319 _validatePorts (void)
320 {
321   int i;
322   for (i = 0; i < NUM_PORTS; i++)
323     {
324       if (_ports[i]->magic != PORT_MAGIC)
325         {
326           /* Uncomment this line to debug which port is causing the problem
327            * (the target name is close to the beginning of the port struct 
328            * and probably can be accessed just fine). */
329           fprintf(stderr,"%s :",_ports[i]->target);
330           wassertl (0, "Port definition structure is incomplete");
331         }
332     }
333 }
334
335 /* search through the command line options for the port */
336 static void
337 _findPort (int argc, char **argv)
338 {
339   _validatePorts ();
340
341   while (argc--)
342     {
343       if (!strncmp (*argv, "-m", 2))
344         {
345           _setPort (*argv + 2);
346           return;
347         }
348       argv++;
349     }
350   /* Use the first in the list */
351   port = _ports[0];
352 }
353
354 /* search through the command line options for the processor */
355 static void
356 _findProcessor (int argc, char **argv)
357 {
358   while (argc--)
359     {
360       if (!strncmp (*argv, "-p", 2))
361         {
362           _setProcessor (*argv + 2);
363           return;
364         }
365       argv++;
366     }
367
368   /* no error if processor was not specified. */
369 }
370
371 /*-----------------------------------------------------------------*/
372 /* printVersionInfo - prints the version info        */
373 /*-----------------------------------------------------------------*/
374 void
375 printVersionInfo ()
376 {
377   int i;
378
379   fprintf (stderr,
380            "SDCC : ");
381   for (i = 0; i < NUM_PORTS; i++)
382     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
383
384   fprintf (stderr, " " SDCC_VERSION_STR
385 #ifdef SDCC_SUB_VERSION_STR
386            "/" SDCC_SUB_VERSION_STR
387 #endif
388            " (" __DATE__ ")"
389 #ifdef __CYGWIN__
390            " (CYGWIN)\n"
391 #elif defined __MINGW32__
392            " (MINGW32)\n"
393 #elif defined __DJGPP__
394            " (DJGPP)\n"
395 #elif defined(_MSC_VER)
396            " (MSVC)\n"
397 #elif defined(__BORLANDC__)
398            " (BORLANDC)\n"
399 #else
400            " (UNIX) \n"
401 #endif
402     );
403 }
404
405 static void
406 printOptions(const OPTION *optionsTable)
407 {
408   int i;
409   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++) 
410     {
411       fprintf(stdout, "  %c%c  %-20s  %s\n", 
412               optionsTable[i].shortOpt !=0 ? '-' : ' ',
413               optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
414               optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
415               optionsTable[i].help != NULL ? optionsTable[i].help : ""
416               );
417     }
418 }
419
420 /*-----------------------------------------------------------------*/
421 /* printUsage - prints command line syntax         */
422 /*-----------------------------------------------------------------*/
423 void
424 printUsage ()
425 {
426     int i;
427     printVersionInfo();
428     fprintf (stdout,
429              "Usage : sdcc [options] filename\n"
430              "Options :-\n"
431              );
432
433     printOptions(optionsTable);
434
435     for (i = 0; i < NUM_PORTS; i++)
436       {
437         if (_ports[i]->poptions != NULL)
438           {
439             fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
440             printOptions (_ports[i]->poptions);
441           }
442       }
443
444     exit (0);
445 }
446
447 /*-----------------------------------------------------------------*/
448 /* parseWithComma - separates string with comma                    */
449 /*-----------------------------------------------------------------*/
450 void
451 parseWithComma (char **dest, char *src)
452 {
453   int i = 0;
454
455   strtok (src, "\r\n \t");
456   /* skip the initial white spaces */
457   while (isspace (*src))
458     src++;
459   dest[i++] = src;
460   while (*src)
461     {
462       if (*src == ',')
463         {
464           *src = '\0';
465           src++;
466           if (*src)
467             dest[i++] = src;
468           continue;
469         }
470       src++;
471     }
472 }
473
474 /*-----------------------------------------------------------------*/
475 /* setParseWithComma - separates string with comma to a set        */
476 /*-----------------------------------------------------------------*/
477 void
478 setParseWithComma (set **dest, char *src)
479 {
480   char *p;
481
482   /* skip the initial white spaces */
483   while (isspace (*src))
484     src++;
485
486   if ((p = strtok(src, ",")) != NULL) {
487     do
488     {
489       addSet(dest, p);
490     } while ((p = strtok(NULL, ",")) != NULL);
491   }
492 }
493
494 /*-----------------------------------------------------------------*/
495 /* setDefaultOptions - sets the default options                    */
496 /*-----------------------------------------------------------------*/
497 static void
498 setDefaultOptions ()
499 {
500   int i;
501
502   for (i = 0; i < 128; i++)
503     preArgv[i] = linkOptions[i] = relFiles[i] = libFiles[i] = libPaths[i] = NULL;
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       relFiles[nrelFiles++] = s;
620       return;
621     }
622
623   /* if .lib or .LIB */
624   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
625     {
626       libFiles[nlibFiles++] = 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 static 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 static 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                 libPaths[nlibPaths++] = 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                 parseWithComma (options.calleeSaves, 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_XRAM_LOC) == 0)
919             {
920                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
921                 continue;
922             }
923
924           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
925             {
926                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
927                 continue;
928             }
929
930           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
931             {
932                 options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
933                 options.xram_size_set = TRUE;
934                 continue;
935             }
936
937           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
938             {
939                 options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
940                 continue;
941             }
942
943           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
944             {
945                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
946                 continue;
947             }
948
949           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
950             {
951                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
952                 continue;
953             }
954
955           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
956             {
957                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
958                 continue;
959             }
960
961           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
962             {
963               optimize.global_cse = 0;
964               continue;
965             }
966
967           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
968             {
969               optimize.loopInvariant = 0;
970               continue;
971             }
972
973           if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
974             {
975               optimize.label4 = 0;
976               continue;
977             }
978
979           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
980             {
981               optimize.loopInduction = 0;
982               continue;
983             }
984
985           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
986             {
987               options.lessPedantic = 1;
988               setErrorLogLevel(ERROR_LEVEL_WARNING);
989               continue;
990             }
991
992           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
993             {
994               options.shortis8bits=1;
995               continue;
996             }
997
998           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
999             {
1000                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
1001                 continue;
1002             }
1003           
1004           if (!port->parseOption (&argc, argv, &i))
1005             {
1006               werror (W_UNKNOWN_OPTION, argv[i]);
1007             }
1008           else
1009             {
1010               continue;
1011             }
1012         }
1013
1014       /* if preceded by  '-' then option */
1015       if (*argv[i] == '-')
1016         {
1017           switch (argv[i][1])
1018             {
1019             case 'h':
1020               verifyShortOption(argv[i]);
1021
1022               printUsage ();
1023               exit (0);
1024               break;
1025
1026             case 'm':
1027               /* Used to select the port. But this has already been done. */
1028               break;
1029
1030             case 'p':
1031               /* Used to select the processor in port. But this has
1032                * already been done. */
1033               break;
1034
1035             case 'c':
1036               verifyShortOption(argv[i]);
1037
1038               options.cc_only = 1;
1039               break;
1040
1041             case 'L':
1042                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
1043                 break;
1044
1045             case 'l':
1046                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
1047                 break;
1048             
1049             case 'o':
1050               {
1051                 char *p;
1052
1053                 /* copy the file name into the buffer */
1054                 strncpyz(buffer, getStringArg("-o", argv, &i, argc), 
1055                          sizeof(buffer));
1056                 /* point to last character */
1057                 p = buffer + strlen (buffer) - 1;
1058                 if (*p == DIR_SEPARATOR_CHAR)
1059                   {
1060                     /* only output path specified */
1061                     dstPath = Safe_strdup (buffer);
1062                     fullDstFileName = NULL;
1063                   }
1064                 else
1065                   {
1066                     fullDstFileName = Safe_strdup (buffer);
1067
1068                     /* get rid of the "."-extension */
1069
1070                     /* is there a dot at all? */
1071                     if (strrchr (buffer, '.') &&
1072                         /* is the dot in the filename, not in the path? */
1073                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1074                       *strrchr (buffer, '.') = '\0';
1075
1076                     dstFileName = Safe_strdup (buffer);
1077
1078                     /* strip module name to get path */
1079                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1080                     if (p)
1081                       {
1082                         /* path with trailing / */
1083                         p[1] = '\0';
1084                         dstPath = Safe_strdup (buffer);
1085                       }
1086                   }
1087                 break;
1088               }
1089
1090             case 'W':
1091               /* pre-processer options */
1092               if (argv[i][2] == 'p')
1093                 {
1094                   parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
1095                 }
1096               /* linker options */
1097               else if (argv[i][2] == 'l')
1098                 {
1099                   parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
1100                 }
1101               /* assembler options */
1102               else if (argv[i][2] == 'a')
1103                 {
1104                   setParseWithComma (&asmOptions, getStringArg("-Wa", argv, &i, argc));
1105                 }
1106               else
1107                 {
1108                   werror (W_UNKNOWN_OPTION, argv[i]);
1109                 }
1110               break;
1111
1112             case 'v':
1113               verifyShortOption(argv[i]);
1114
1115               printVersionInfo ();
1116               exit (0);
1117               break;
1118
1119               /* preprocessor options */
1120             case 'M':
1121               {
1122                 preProcOnly = 1;
1123                 addToList (preArgv, "-M");
1124                 break;
1125               }
1126             case 'C':
1127               {
1128                 addToList (preArgv, "-C");
1129                 break;
1130               }
1131
1132             case 'd':
1133             case 'D':
1134             case 'I':
1135             case 'A':
1136             case 'U':
1137               {
1138                 char sOpt = argv[i][1];
1139                 char *rest;
1140
1141                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1142                   {
1143                     i++;
1144                     if (i >= argc)
1145                       {
1146                           /* No argument. */
1147                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1148                           break;
1149                       }
1150                     else
1151                       {
1152                           rest = argv[i];
1153                       }
1154                   }
1155                 else
1156                   rest = &argv[i][2];
1157
1158                 if (sOpt == 'Y')
1159                   sOpt = 'I';
1160
1161                 SNPRINTF (buffer, sizeof(buffer),
1162                   ((sOpt == 'I') ? "-%c\"%s\"": "-%c%s"), sOpt, rest);
1163                 addToList (preArgv, buffer);
1164               }
1165               break;
1166
1167             default:
1168               if (!port->parseOption (&argc, argv, &i))
1169                 werror (W_UNKNOWN_OPTION, argv[i]);
1170             }
1171           continue;
1172         }
1173
1174       if (!port->parseOption (&argc, argv, &i))
1175         {
1176            /* no option must be a filename */
1177            if (options.c1mode)
1178              {
1179                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1180              }
1181          else
1182              {
1183                 processFile (argv[i]);
1184              }
1185         }
1186     }
1187
1188   /* some sanity checks in c1 mode */
1189   if (options.c1mode)
1190     {
1191       int i;
1192
1193       if (fullSrcFileName)
1194         {
1195           fclose (srcFile);
1196           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1197         }
1198       fullSrcFileName = NULL;
1199       for (i = 0; i < nrelFiles; ++i)
1200         {
1201           werror (W_NO_FILE_ARG_IN_C1, relFiles[i]);
1202         }
1203       for (i = 0; i < nlibFiles; ++i)
1204         {
1205           werror (W_NO_FILE_ARG_IN_C1, libFiles[i]);
1206         }
1207       nrelFiles = nlibFiles = 0;
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       /* use the modulename from the C-source */
1223       if (fullSrcFileName)
1224         {
1225           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1226
1227           dstFileName = Safe_alloc (bufSize);
1228           strncpyz (dstFileName, dstPath, bufSize);
1229           strncatz (dstFileName, moduleName, bufSize);
1230         }
1231       /* use the modulename from the first object file */
1232       else if (nrelFiles >= 1)
1233         {
1234           char *objectName;
1235           size_t bufSize;
1236
1237           strncpyz (buffer, relFiles[0], sizeof(buffer));
1238           /* remove extension (it must be .rel) */
1239           *strrchr (buffer, '.') = '\0';
1240           /* remove path */
1241           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1242           if (objectName)
1243             {
1244               ++objectName;
1245             }
1246           else
1247             {
1248               objectName = buffer;
1249             }
1250           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1251           dstFileName = Safe_alloc (bufSize);
1252           strncpyz (dstFileName, dstPath, bufSize);
1253           strncatz (dstFileName, objectName, bufSize);
1254         }
1255       /* else no module given: help text is displayed */
1256     }
1257
1258   /* set up external stack location if not explicitly specified */
1259   if (!options.xstack_loc)
1260     options.xstack_loc = options.xdata_loc;
1261
1262   /* if debug option is set then open the cdbFile */
1263   if (options.debug && fullSrcFileName)
1264     {
1265       SNPRINTF (scratchFileName, sizeof(scratchFileName),
1266                 "%s.adb", dstFileName); //JCF: Nov 30, 2002
1267       if(debugFile->openFile(scratchFileName))
1268         debugFile->writeModule(moduleName);
1269       else
1270         werror (E_FILE_OPEN_ERR, scratchFileName);
1271     }
1272   return 0;
1273 }
1274
1275 /*-----------------------------------------------------------------*/
1276 /* linkEdit : - calls the linkage editor  with options             */
1277 /*-----------------------------------------------------------------*/
1278 static void
1279 linkEdit (char **envp)
1280 {
1281   FILE *lnkfile;
1282   char *segName, *c;
1283   int i, system_ret;
1284
1285   /* first we need to create the <filename>.lnk file */
1286   SNPRINTF (scratchFileName, sizeof(scratchFileName),
1287             "%s.lnk", dstFileName);
1288   if (!(lnkfile = fopen (scratchFileName, "w")))
1289     {
1290       werror (E_FILE_OPEN_ERR, scratchFileName);
1291       exit (1);
1292     }
1293
1294   /* now write the options.  JCF: added option 'y' */
1295   fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1296
1297   /* if iram size specified */
1298   if (options.iram_size)
1299     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1300
1301   /* if xram size specified */
1302   if (options.xram_size_set)
1303     fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1304
1305   /* if code size specified */
1306   if (options.code_size)
1307     fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1308
1309   if (options.debug)
1310     fprintf (lnkfile, "-z\n");
1311
1312 #define WRITE_SEG_LOC(N, L) \
1313     segName = Safe_strdup(N); \
1314     c = strtok(segName, " \t"); \
1315     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1316     if (segName) { Safe_free(segName); }
1317
1318   /* code segment start */
1319   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1320
1321   /* data segment start */
1322   if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
1323           WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1324   }
1325
1326   /* xdata start */
1327   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1328
1329   /* indirect data */
1330   if (IDATA_NAME) {
1331     WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1332   }
1333
1334   /* bit segment start */
1335   WRITE_SEG_LOC (BIT_NAME, 0);
1336
1337   /* JCF: stack start */
1338   if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1339         WRITE_SEG_LOC ("SSEG", options.stack_loc);
1340   }
1341
1342   /* add the extra linker options */
1343   for (i = 0; linkOptions[i]; i++)
1344     fprintf (lnkfile, "%s\n", linkOptions[i]);
1345
1346   /* other library paths if specified */
1347   for (i = 0; i < nlibPaths; i++)
1348     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1349
1350   /* standard library path */
1351   if (!options.nostdlib)
1352     {
1353       switch (options.model)
1354         {
1355         case MODEL_SMALL:
1356           c = "small";
1357           break;
1358         case MODEL_LARGE:
1359           c = "large";
1360           break;
1361         case MODEL_FLAT24:
1362           /* c = "flat24"; */
1363             if (TARGET_IS_DS390)
1364             {
1365                 c = "ds390";
1366             }
1367             else if (TARGET_IS_DS400)
1368             {
1369                 c = "ds400";
1370             }
1371             else
1372             {
1373                 fprintf(stderr, 
1374                         "Add support for your FLAT24 target in %s @ line %d\n",
1375                         __FILE__, __LINE__);
1376                 exit(-1);
1377             }
1378           break;
1379         case MODEL_PAGE0:
1380           c = "xa51";
1381           break;
1382         default:
1383           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1384           c = "unknown";
1385           break;
1386         }
1387       mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
1388
1389       /* standard library files */
1390 #if !OPT_DISABLE_DS390
1391       if (options.model == MODEL_FLAT24)
1392         {
1393             if (TARGET_IS_DS390)
1394             {
1395                 fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1396             }
1397             else if (TARGET_IS_DS400)
1398             {
1399                 fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1400             }
1401             else
1402             {
1403                 fprintf(stderr, 
1404                         "Add support for your FLAT24 target in %s @ line %d\n",
1405                         __FILE__, __LINE__);
1406                 exit(-1);
1407             }
1408         }
1409 #endif
1410
1411 #if !OPT_DISABLE_XA51 
1412 #ifdef STD_XA51_LIB
1413       if (options.model == MODEL_PAGE0)
1414         {
1415           fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1416         }
1417 #endif
1418 #endif
1419       fprintf (lnkfile, "-l %s\n", STD_LIB);
1420       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1421       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1422       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1423     }
1424
1425   /* additional libraries if any */
1426   for (i = 0; i < nlibFiles; i++)
1427     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1428
1429   /* put in the object files */
1430   if (fullSrcFileName)
1431     fprintf (lnkfile, "%s ", dstFileName);
1432
1433   for (i = 0; i < nrelFiles; i++)
1434     fprintf (lnkfile, "%s\n", relFiles[i]);
1435
1436   fprintf (lnkfile, "\n-e\n");
1437   fclose (lnkfile);
1438
1439   if (options.verbose)
1440     printf ("sdcc: Calling linker...\n");
1441
1442   /* build linker output filename */
1443
1444   /* -o option overrides default name? */
1445   if (fullDstFileName)
1446     {
1447       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1448     }
1449   else
1450     {
1451       /* the linked file gets the name of the first modul */
1452       if (fullSrcFileName)
1453         {
1454           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1455         }
1456       else
1457         {
1458           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1459           /* strip ".rel" extension */
1460           *strrchr (scratchFileName, '.') = '\0';
1461         }
1462       strncatz (scratchFileName, 
1463                 options.out_fmt ? ".S19" : ".ihx",
1464                 sizeof(scratchFileName));
1465     }
1466
1467   if (port->linker.cmd)
1468     {
1469       char buffer2[PATH_MAX];
1470       buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
1471       buildCmdLine2 (buffer, buffer2, sizeof(buffer));
1472     }
1473   else
1474     {
1475       buildCmdLine2 (buffer, port->linker.mcmd, sizeof(buffer));
1476     }
1477
1478   system_ret = my_system (buffer);
1479   /* TODO: most linker don't have a -o parameter */
1480   /* -o option overrides default name? */
1481   if (fullDstFileName)
1482     {
1483       char *p, *q;
1484       /* the linked file gets the name of the first modul */
1485       if (fullSrcFileName)
1486         {
1487           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1488           p = strlen (scratchFileName) + scratchFileName;
1489         }
1490       else
1491         {
1492           strncpyz (scratchFileName, relFiles[0], sizeof(scratchFileName));
1493           /* strip ".rel" extension */
1494           p = strrchr (scratchFileName, '.');
1495           if (p)
1496             {
1497               *p = 0;
1498             }
1499         }
1500       strncatz (scratchFileName,
1501                 options.out_fmt ? ".S19" : ".ihx",
1502                 sizeof(scratchFileName));
1503       rename (scratchFileName, fullDstFileName);
1504
1505       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1506       q = strrchr (buffer, '.');
1507       if (!q)
1508         {
1509           /* no extension: append new extensions */
1510           q = strlen (buffer) + buffer;
1511         }
1512
1513       *p = 0;
1514       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1515       *q = 0;
1516       strncatz(buffer, ".map", sizeof(buffer));
1517       rename (scratchFileName, buffer);
1518       *p = 0;
1519       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1520       *q = 0;
1521       strncatz(buffer, ".mem", sizeof(buffer));
1522       rename (scratchFileName, buffer);
1523     }
1524   if (system_ret)
1525     {
1526       exit (1);
1527     }
1528 }
1529
1530 /*-----------------------------------------------------------------*/
1531 /* assemble - spawns the assembler with arguments                  */
1532 /*-----------------------------------------------------------------*/
1533 static void
1534 assemble (char **envp)
1535 {
1536     /* build assembler output filename */
1537
1538     /* -o option overrides default name? */
1539     if (options.cc_only && fullDstFileName) {
1540         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1541     } else {
1542         /* the assembled file gets the name of the first modul */
1543         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1544         strncatz (scratchFileName, port->linker.rel_ext, 
1545                   sizeof(scratchFileName));
1546     }
1547
1548     if (port->assembler.do_assemble) {
1549         port->assembler.do_assemble(asmOptions);
1550         return ;
1551     } else if (port->assembler.cmd) {
1552         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1553                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1554                       asmOptions);
1555     } else {
1556         buildCmdLine2 (buffer, port->assembler.mcmd, sizeof(buffer));
1557     }
1558
1559     if (my_system (buffer)) {
1560         /* either system() or the assembler itself has reported an error
1561            perror ("Cannot exec assembler");
1562         */
1563         exit (1);
1564     }
1565     /* TODO: most assembler don't have a -o parameter */
1566     /* -o option overrides default name? */
1567     if (options.cc_only && fullDstFileName) {
1568         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1569         strncatz (scratchFileName, 
1570                   port->linker.rel_ext,
1571                   sizeof(scratchFileName));
1572         rename (scratchFileName, fullDstFileName);
1573     }
1574 }
1575
1576 /*-----------------------------------------------------------------*/
1577 /* preProcess - spawns the preprocessor with arguments       */
1578 /*-----------------------------------------------------------------*/
1579 static int
1580 preProcess (char **envp)
1581 {
1582   if (options.c1mode)
1583     {
1584       yyin = stdin;
1585     }
1586   else
1587     {
1588       /* if using external stack define the macro */
1589       if (options.useXstack)
1590         addToList (preArgv, "-DSDCC_USE_XSTACK");
1591
1592       /* set the macro for stack autos  */
1593       if (options.stackAuto)
1594         addToList (preArgv, "-DSDCC_STACK_AUTO");
1595
1596       /* set the macro for stack autos  */
1597       if (options.stack10bit)
1598         addToList (preArgv, "-DSDCC_STACK_TENBIT");
1599
1600       /* set the macro for no overlay  */
1601       if (options.noOverlay)
1602         addToList (preArgv, "-DSDCC_NOOVERLAY");
1603
1604       /* set the macro for large model  */
1605       switch (options.model)
1606         {
1607         case MODEL_LARGE:
1608           addToList (preArgv, "-DSDCC_MODEL_LARGE");
1609           break;
1610         case MODEL_SMALL:
1611           addToList (preArgv, "-DSDCC_MODEL_SMALL");
1612           break;
1613         case MODEL_COMPACT:
1614           addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1615           break;
1616         case MODEL_MEDIUM:
1617           addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1618           break;
1619         case MODEL_FLAT24:
1620           addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1621           break;
1622         case MODEL_PAGE0:
1623           addToList (preArgv, "-DSDCC_MODEL_PAGE0");
1624           break;
1625         default:
1626           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1627           break;
1628         }
1629
1630       /* add port (processor information to processor */
1631       addToList (preArgv, "-DSDCC_{port}");
1632       addToList (preArgv, "-D__{port}");
1633
1634       /* standard include path */
1635       if (!options.nostdinc) {
1636         addToList (preArgv, "-I\"{includedir}\"");
1637       }
1638
1639       setMainValue ("cppextraopts", join(preArgv));
1640
1641       if (preProcOnly && fullDstFileName)
1642         {
1643           /* -E and -o given */
1644           setMainValue ("cppoutfilename", fullDstFileName);
1645         }
1646       else
1647         {
1648           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1649           setMainValue ("cppoutfilename", NULL);
1650         }
1651
1652       if (options.verbose)
1653         printf ("sdcc: Calling preprocessor...\n");
1654
1655       buildCmdLine2 (buffer, _preCmd, sizeof(buffer));
1656
1657       if (preProcOnly) {
1658         if (my_system (buffer)) {
1659           exit (1);
1660         }
1661
1662         exit (0);
1663       }
1664
1665       yyin = my_popen (buffer);
1666       if (yyin == NULL) {
1667           perror ("Preproc file not found");
1668           exit (1);
1669       }
1670       addSetHead (&pipeSet, yyin);
1671     }
1672
1673   return 0;
1674 }
1675
1676 /* Set bin paths */
1677 static void
1678 setBinPaths(const char *argv0)
1679 {
1680   char *p;
1681   char buf[PATH_MAX];
1682
1683   /*
1684    * Search logic:
1685    *
1686    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1687    * 2. - path(argv[0])
1688    * 3. - $PATH
1689    */
1690
1691   /* do it in reverse mode, so that addSetHead() can be used
1692      instead of slower addSet() */
1693
1694   if ((p = getBinPath(argv0)) != NULL)
1695     addSetHead(&binPathSet, Safe_strdup(p));
1696
1697   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1698     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1699     addSetHead(&binPathSet, Safe_strdup(buf));
1700   }
1701
1702   if (options.printSearchDirs) {
1703     printf("programs: ");
1704     if (NULL != (p = (char *)setFirstItem(binPathSet))) {
1705       printf("%s", p);
1706       while (NULL != (p = (char *)setNextItem(binPathSet)))
1707         printf(":%s", p);
1708     }
1709     putchar('\n');
1710   }
1711 }
1712
1713 /* Set system include path */
1714 static void
1715 setIncludePath(const char *datadir)
1716 {
1717   char *p;
1718   char buf[PATH_MAX];
1719
1720   /*
1721    * Search logic:
1722    *
1723    * 1. - $SDCC_INCLUDE
1724    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
1725    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
1726    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
1727    */
1728
1729   if ((p = getenv(SDCC_INCLUDE_NAME)) == NULL) {
1730     SNPRINTF(buf, sizeof buf, "%s" INCLUDE_DIR_SUFFIX, datadir);
1731     p = buf;
1732   }
1733
1734   if (options.printSearchDirs)
1735     printf("includedir: %s\n", p);
1736
1737   setMainValue ("includedir", p);
1738 }
1739
1740 /* Set system lib path */
1741 static void
1742 setLibPath(const char *datadir)
1743 {
1744   char *p;
1745   char buf[PATH_MAX];
1746
1747   /*
1748    * Search logic:
1749    *
1750    * 1. - $SDCC_LIB
1751    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
1752    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
1753    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
1754    */
1755
1756   if ((p = getenv(SDCC_LIB_NAME)) == NULL) {
1757     SNPRINTF(buf, sizeof buf, "%s" LIB_DIR_SUFFIX, datadir);
1758     p = buf;
1759   }
1760
1761   if (options.printSearchDirs)
1762     printf("libdir: %s\n", p);
1763
1764   setMainValue ("libdir", p);
1765 }
1766
1767 /* Set data path */
1768 static void
1769 setDataPaths(const char *argv0)
1770 {
1771   char *p;
1772   char buf[PATH_MAX];
1773
1774   /*
1775    * Search logic:
1776    *
1777    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
1778    * 2. - path(argv[0])/BIN2DATA_DIR
1779    * 3. - DATADIR (only on *nix)
1780    */
1781
1782   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1783     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
1784     p = buf;
1785   }
1786   else if ((p = getBinPath(argv0)) != NULL) {
1787     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
1788     p = buf;
1789   }
1790   else {
1791 #ifdef _WIN32
1792     /* this should never happen... */
1793     wassertl(0, "Can't get binary path");
1794     p = ".";
1795 #else /* *nix paltform */
1796     p = DATADIR; /* last resort */
1797 #endif
1798   }
1799
1800   if (options.printSearchDirs)
1801     printf("datadir: %s\n", p);
1802
1803   setIncludePath(p);
1804   setLibPath(p);
1805
1806   setMainValue ("datadir", p);
1807 }
1808
1809 static void
1810 initValues (void)
1811 {
1812   populateMainValues (_baseValues);
1813   setMainValue ("port", port->target);
1814   setMainValue ("objext", port->linker.rel_ext);
1815   setMainValue ("asmext", port->assembler.file_ext);
1816
1817   setMainValue ("dstfilename", dstFileName);
1818   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1819
1820   if (options.cc_only && fullDstFileName)
1821     /* compile + assemble and -o given: -o specifies name of object file */
1822     {
1823       setMainValue ("objdstfilename", fullDstFileName);
1824     }
1825   else
1826     {
1827       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1828     }
1829   if (fullDstFileName)
1830     /* if we're linking, -o gives the final file name */
1831     {
1832       setMainValue ("linkdstfilename", fullDstFileName);
1833     }
1834   else
1835     {
1836       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1837     }
1838
1839 }
1840
1841 static void
1842 sig_handler (int signal)
1843 {
1844   char *sig_string;
1845
1846   switch (signal)
1847     {
1848     case SIGABRT:
1849       sig_string = "SIGABRT";
1850       break;
1851     case SIGTERM:
1852       sig_string = "SIGTERM";
1853       break;
1854     case SIGINT:
1855       sig_string = "SIGINT";
1856       break;
1857     case SIGSEGV:
1858       sig_string = "SIGSEGV";
1859       break;
1860     default:
1861       sig_string = "Unknown?";
1862       break;
1863     }
1864   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1865   exit (1);
1866 }
1867
1868 /*
1869  * main routine
1870  * initialises and calls the parser
1871  */
1872
1873 int
1874 main (int argc, char **argv, char **envp)
1875 {
1876   /* turn all optimizations off by default */
1877   memset (&optimize, 0, sizeof (struct optimize));
1878
1879   /*printVersionInfo (); */
1880
1881   if (NUM_PORTS==0) {
1882     fprintf (stderr, "Build error: no ports are enabled.\n");
1883     exit (1);
1884   }
1885
1886   /* install atexit handler */
1887   atexit(rm_tmpfiles);
1888
1889   /* install signal handler;
1890      it's only purpuse is to call exit() to remove temp files */
1891   if (!getenv("SDCC_LEAVE_SIGNALS"))
1892     {
1893       signal (SIGABRT, sig_handler);
1894       signal (SIGTERM, sig_handler);
1895       signal (SIGINT , sig_handler);
1896       signal (SIGSEGV, sig_handler);
1897     }
1898
1899   /* Before parsing the command line options, do a
1900    * search for the port and processor and initialize
1901    * them if they're found. (We can't gurantee that these
1902    * will be the first options specified).
1903    */
1904
1905   _findPort (argc, argv);
1906
1907 #ifdef JAMIN_DS390
1908   if (strcmp(port->target, "mcs51") == 0) {
1909     printf("DS390 jammed in A\n");
1910           _setPort ("ds390");
1911     ds390_jammed = 1;
1912   }
1913 #endif
1914
1915   _findProcessor (argc, argv);
1916
1917   /* Initalise the port. */
1918   if (port->init)
1919     port->init ();
1920
1921   setDefaultOptions ();
1922 #ifdef JAMIN_DS390
1923   if (ds390_jammed) {
1924     options.model = MODEL_SMALL;
1925     options.stack10bit=0;
1926   }
1927 #endif
1928   parseCmdLine (argc, argv);
1929
1930   initValues ();
1931   setBinPaths(argv[0]);
1932   setDataPaths(argv[0]);
1933
1934   /* if print search dirs then exit */
1935   if (options.printSearchDirs)
1936     exit(0);
1937
1938   /* if no input then printUsage & exit */
1939   if (!options.c1mode && !fullSrcFileName && !nrelFiles)
1940     {
1941       printUsage ();
1942       exit (0);
1943     }
1944
1945   /* initMem() is expensive, but
1946      initMem() must called before port->finaliseOptions ().
1947      And the z80 port needs port->finaliseOptions(),
1948      even if we're only linking. */
1949   initMem ();
1950   port->finaliseOptions ();
1951
1952   if (fullSrcFileName || options.c1mode)
1953     {
1954       preProcess (envp);
1955
1956       initSymt ();
1957       initiCode ();
1958       initCSupport ();
1959       initBuiltIns();
1960       initPeepHole ();
1961
1962       if (options.verbose)
1963         printf ("sdcc: Generating code...\n");
1964
1965       yyparse ();
1966
1967       pclose(yyin);
1968       deleteSetItem(&pipeSet, yyin);
1969
1970       if (fatalError) {
1971         exit (1);
1972       }
1973
1974       if (TARGET_IS_PIC) {
1975         /* TSD PIC port hack - if the PIC port option is enabled
1976            and SDCC is used to generate PIC code, then we will
1977            generate .asm files in gpasm's format instead of SDCC's
1978            assembler's format
1979         */
1980 #if !OPT_DISABLE_PIC
1981         picglue ();
1982 #endif
1983       }
1984       else {
1985         glue ();
1986       }
1987
1988       if (!options.c1mode && !noAssemble)
1989         {
1990           if (options.verbose)
1991             printf ("sdcc: Calling assembler...\n");
1992           assemble (envp);
1993         }
1994     }
1995   closeDumpFiles();
1996
1997   if (options.debug && debugFile)
1998     debugFile->closeFile();
1999
2000   if (!options.cc_only &&
2001       !fatalError &&
2002       !noAssemble &&
2003       !options.c1mode &&
2004       (fullSrcFileName || nrelFiles))
2005     {
2006       if (port->linker.do_link)
2007         port->linker.do_link ();
2008       else
2009         linkEdit (envp);
2010     }
2011
2012   return 0;
2013 }