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