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 #include <libgen.h>
30 #endif
31 
32 #include <signal.h>
33 #include "common.h"
34 #include <ctype.h>
35 #include "dbuf_string.h"
36 #include "SDCCerr.h"
37 #include "SDCCmacro.h"
38 #include "SDCCargs.h"
39 
40 #ifdef _WIN32
41 #include <process.h>
42 #else
43 #include <sys/stat.h>
44 #include <unistd.h>
45 #include <sys/resource.h>
46 #endif
47 
48 /* REMOVE ME!!! */
49 extern int yyparse (void);
50 
51 FILE *srcFile;                  /* source file */
52 const char *fullSrcFileName;    /* full name for the source file; */
53                                 /* can be NULL while c1mode or linking without compiling */
54 const char *fullDstFileName;    /* full name for the output file; */
55                                 /* only given by -o, otherwise NULL */
56 const char *dstFileName;        /* destination file name without extension */
57 const char *moduleName;         /* module name is same as module name base, but with all */
58                                 /* non-alphanumeric characters replaced with underscore */
59 int currRegBank = 0;
60 int RegBankUsed[4] = { 1, 0, 0, 0 };    /*JCF: Reg Bank 0 used by default */
61 
62 int BitBankUsed;                /* MB: overlayable bit bank */
63 struct optimize optimize;
64 struct options options;
65 int preProcOnly = 0;
66 int noAssemble = 0;
67 set *preArgvSet = NULL;         /* pre-processor arguments  */
68 set *asmOptionsSet = NULL;      /* set of assembler options */
69 set *linkOptionsSet = NULL;     /* set of linker options */
70 set *libFilesSet = NULL;
71 set *libPathsSet = NULL;
72 set *relFilesSet = NULL;
73 set *dataDirsSet = NULL;        /* list of data search directories */
74 set *includeDirsSet = NULL;     /* list of include search directories */
75 set *userIncDirsSet = NULL;     /* list of user include directories */
76 set *libDirsSet = NULL;         /* list of lib search directories */
77 bool regalloc_dry_run = FALSE;
78 
79 static const char *dstPath = "";          /* path for the output files; */
80                                           /* "" is equivalent with cwd */
81 static const char *moduleNameBase = NULL; /* module name base is source file without path and extension */
82                                           /* can be NULL while linking without compiling */
83 
84 /* uncomment JAMIN_DS390 to always override and use ds390 port
85   for mcs51 work.  This is temporary, for compatibility testing. */
86 /* #define JAMIN_DS390 */
87 #ifdef JAMIN_DS390
88 static int ds390_jammed = 0;
89 #endif
90 
91 /* Globally accessible scratch buffer for file names.
92    TODO: replace them with local buffers */
93 char buffer[PATH_MAX * 2];
94 
95 #define LENGTH(_a)      (sizeof (_a) / sizeof (*(_a)))
96 
97 #define OPTION_HELP                 "--help"
98 #define OPTION_OUT_FMT_IHX          "--out-fmt-ihx"
99 #define OPTION_OUT_FMT_S19          "--out-fmt-s19"
100 #define OPTION_PEEP_FILE            "--peep-file"
101 #define OPTION_LIB_PATH             "--lib-path"
102 #define OPTION_CALLEE_SAVES         "--callee-saves"
103 #define OPTION_STACK_LOC            "--stack-loc"
104 #define OPTION_XSTACK_LOC           "--xstack-loc"
105 #define OPTION_DATA_LOC             "--data-loc"
106 #define OPTION_IDATA_LOC            "--idata-loc"
107 #define OPTION_XRAM_LOC             "--xram-loc"
108 #define OPTION_CODE_LOC             "--code-loc"
109 #define OPTION_IRAM_SIZE            "--iram-size"
110 #define OPTION_XRAM_SIZE            "--xram-size"
111 #define OPTION_CODE_SIZE            "--code-size"
112 #define OPTION_VERSION              "--version"
113 #define OPTION_NO_LABEL_OPT         "--nolabelopt"
114 #define OPTION_NO_LOOP_INV          "--noinvariant"
115 #define OPTION_NO_LOOP_IND          "--noinduction"
116 #define OPTION_LESS_PEDANTIC        "--less-pedantic"
117 #define OPTION_DISABLE_WARNING      "--disable-warning"
118 #define OPTION_WERROR               "--Werror"
119 #define OPTION_DEBUG                "--debug"
120 #define OPTION_NO_GCSE              "--nogcse"
121 #define OPTION_NO_XINIT_OPT         "--no-xinit-opt"
122 #define OPTION_NO_CCODE_IN_ASM      "--no-c-code-in-asm"
123 #define OPTION_ICODE_IN_ASM         "--i-code-in-asm"
124 #define OPTION_PRINT_SEARCH_DIRS    "--print-search-dirs"
125 #define OPTION_MSVC_ERROR_STYLE     "--vc"
126 #define OPTION_USE_STDOUT           "--use-stdout"
127 #define OPTION_NO_PEEP_COMMENTS     "--no-peep-comments"
128 #define OPTION_VERBOSE_ASM          "--fverbose-asm"
129 #define OPTION_OPT_CODE_SPEED       "--opt-code-speed"
130 #define OPTION_OPT_CODE_SIZE        "--opt-code-size"
131 #define OPTION_STD_C89              "--std-c89"
132 #define OPTION_STD_C95              "--std-c95"
133 #define OPTION_STD_C99              "--std-c99"
134 #define OPTION_STD_C11              "--std-c11"
135 #define OPTION_STD_C2X              "--std-c2x"
136 #define OPTION_STD_SDCC89           "--std-sdcc89"
137 #define OPTION_STD_SDCC99           "--std-sdcc99"
138 #define OPTION_STD_SDCC11           "--std-sdcc11"
139 #define OPTION_STD_SDCC2X           "--std-sdcc2x"
140 #define OPTION_CODE_SEG             "--codeseg"
141 #define OPTION_CONST_SEG            "--constseg"
142 #define OPTION_DATA_SEG             "--dataseg"
143 #define OPTION_DOLLARS_IN_IDENT     "--fdollars-in-identifiers"
144 #define OPTION_SIGNED_CHAR          "--fsigned-char"
145 #define OPTION_USE_NON_FREE         "--use-non-free"
146 #define OPTION_PEEP_RETURN          "--peep-return"
147 #define OPTION_NO_PEEP_RETURN       "--no-peep-return"
148 #define OPTION_NO_OPTSDCC_IN_ASM    "--no-optsdcc-in-asm"
149 #define OPTION_MAX_ALLOCS_PER_NODE  "--max-allocs-per-node"
150 #define OPTION_NO_LOSPRE            "--nolospre"
151 #define OPTION_ALLOW_UNSAFE_READ    "--allow-unsafe-read"
152 #define OPTION_DUMP_AST             "--dump-ast"
153 #define OPTION_DUMP_I_CODE          "--dump-i-code"
154 #define OPTION_DUMP_GRAPHS          "--dump-graphs"
155 
156 #define OPTION_SMALL_MODEL          "--model-small"
157 #define OPTION_MEDIUM_MODEL         "--model-medium"
158 #define OPTION_LARGE_MODEL          "--model-large"
159 #define OPTION_HUGE_MODEL           "--model-huge"
160 
161 static const OPTION optionsTable[] = {
162   {0,   NULL, NULL, "General options"},
163   {0,   OPTION_HELP, NULL, "Display this help"},
164   {'v', OPTION_VERSION, NULL, "Display sdcc's version"},
165   {0,   "--verbose", &options.verbose, "Trace calls to the preprocessor, assembler, and linker"},
166   {'V', NULL, &options.verboseExec, "Execute verbosely. Show sub commands as they are run"},
167   {'d', NULL, NULL, "Output list of mcaro definitions in effect. Use with -E"},
168   {'D', NULL, NULL, "Define macro as in -Dmacro"},
169   {'I', NULL, NULL, "Add to the include (*.h) path, as in -Ipath"},
170   {'A', NULL, NULL, NULL},
171   {'U', NULL, NULL, "Undefine macro as in -Umacro"},
172   {'M', NULL, NULL, "Preprocessor option"},
173   {'W', NULL, NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)"},
174   {'S', NULL, &noAssemble, "Compile only; do not assemble or link"},
175   {'c', "--compile-only", &options.cc_only, "Compile and assemble, but do not link"},
176   {'E', "--preprocessonly", &preProcOnly, "Preprocess only, do not compile"},
177   {0,   "--c1mode", &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code."},
178   {'o', NULL, NULL, "Place the output into the given path resp. file"},
179   {0,   OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
180   {0,   OPTION_MSVC_ERROR_STYLE, &options.vc_err_style, "messages are compatible with Micro$oft visual studio"},
181   {0,   OPTION_USE_STDOUT, NULL, "send errors to stdout instead of stderr"},
182   {0,   "--nostdlib", &options.nostdlib, "Do not include the standard library directory in the search path"},
183   {0,   "--nostdinc", &options.nostdinc, "Do not include the standard include directory in the search path"},
184   {0,   OPTION_LESS_PEDANTIC, NULL, "Disable some of the more pedantic warnings"},
185   {0,   OPTION_DISABLE_WARNING, NULL, "<nnnn> Disable specific warning"},
186   {0,   OPTION_WERROR, NULL, "Treat the warnings as errors"},
187   {0,   OPTION_DEBUG, NULL, "Enable debugging symbol output"},
188   {0,   "--cyclomatic", &options.cyclomatic, "Display complexity of compiled functions"},
189   {0,   OPTION_STD_C89, NULL, "Use ISO C90 (aka ANSI C89) standard (slightly incomplete)"},
190   {0,   OPTION_STD_SDCC89, NULL, "Use ISO C90 (aka ANSI C89) standard with SDCC extensions"},
191   {0,   OPTION_STD_C95, NULL, "Use ISO C95 (aka ISO C94) standard (slightly incomplete)"},
192   {0,   OPTION_STD_C99, NULL, "Use ISO C99 standard (incomplete)"},
193   {0,   OPTION_STD_SDCC99, NULL, "Use ISO C99 standard with SDCC extensions"},
194   {0,   OPTION_STD_C11, NULL, "Use ISO C11 standard (incomplete)"},
195   {0,   OPTION_STD_SDCC11, NULL, "Use ISO C11 standard with SDCC extensions (default)"},
196   {0,   OPTION_STD_C2X, NULL, "Use ISO C2X standard (incomplete)"},
197   {0,   OPTION_STD_SDCC2X, NULL, "Use ISO C2X standard with SDCC extensions"},
198   {0,   OPTION_DOLLARS_IN_IDENT, &options.dollars_in_ident, "Permit '$' as an identifier character"},
199   {0,   OPTION_SIGNED_CHAR, &options.signed_char, "Make \"char\" signed by default"},
200   {0,   OPTION_USE_NON_FREE, &options.use_non_free, "Search / include non-free licensed libraries and header files"},
201 
202   {0,   NULL, NULL, "Code generation options"},
203   {'m', NULL, NULL, "Set the port to use e.g. -mz80."},
204   {'p', NULL, NULL, "Select port specific processor e.g. -mpic14 -p16f84"},
205   {0,   "--stack-auto", &options.stackAuto, "Stack automatic variables"},
206   {0,   "--xstack", &options.useXstack, "Use external stack"},
207   {0,   "--int-long-reent", &options.intlong_rent, "Use reentrant calls on the int and long support functions"},
208   {0,   "--float-reent", &options.float_rent, "Use reentrant calls on the float support functions"},
209   {0,   "--xram-movc", &options.xram_movc, "Use movc instead of movx to read xram (xdata)"},
210   {0,   OPTION_CALLEE_SAVES, &options.calleeSavesSet, "<func[,func,...]> Cause the called function to save registers instead of the caller", CLAT_SET},
211   {0,   "--profile", &options.profile, "On supported ports, generate extra profiling information"},
212   {0,   "--fomit-frame-pointer", &options.omitFramePtr, "Leave out the frame pointer."},
213   {0,   "--all-callee-saves", &options.all_callee_saves, "callee will always save registers used"},
214   {0,   "--stack-probe", &options.stack_probe, "insert call to function __stack_probe at each function prologue"},
215   {0,   OPTION_NO_XINIT_OPT, &options.noXinitOpt, "don't memcpy initialized xram from code"},
216   {0,   OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
217   {0,   OPTION_NO_PEEP_COMMENTS, &options.noPeepComments, "don't include peephole optimizer comments"},
218   {0,   OPTION_CODE_SEG, NULL, "<name> use this name for the code segment"},
219   {0,   OPTION_CONST_SEG, NULL, "<name> use this name for the const segment"},
220   {0,   OPTION_DATA_SEG, NULL, "<name> use this name for the data segment"},
221 
222   {0,   NULL, NULL, "Optimization options"},
223   {0,   "--nooverlay", &options.noOverlay, "Disable overlaying leaf function auto variables"},
224   {0,   OPTION_NO_GCSE, NULL, "Disable the GCSE optimisation"},
225   {0,   OPTION_NO_LABEL_OPT, NULL, "Disable label optimisation"},
226   {0,   OPTION_NO_LOOP_INV, NULL, "Disable optimisation of invariants"},
227   {0,   OPTION_NO_LOOP_IND, NULL, "Disable loop variable induction"},
228   {0,   "--noloopreverse", &optimize.noLoopReverse, "Disable the loop reverse optimisation"},
229   {0,   "--no-peep", &options.nopeep, "Disable the peephole assembly file optimisation"},
230   {0,   "--no-reg-params", &options.noRegParams, "On some ports, disable passing some parameters in registers"},
231   {0,   "--peep-asm", &options.asmpeep, "Enable peephole optimization on inline assembly"},
232   {0,   OPTION_PEEP_RETURN, NULL, "Enable peephole optimization for return instructions"},
233   {0,   OPTION_NO_PEEP_RETURN, NULL, "Disable peephole optimization for return instructions"},
234   {0,   OPTION_PEEP_FILE, &options.peep_file, "<file> use this extra peephole file", CLAT_STRING},
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   {0,   OPTION_MAX_ALLOCS_PER_NODE, &options.max_allocs_per_node, "Maximum number of register assignments considered at each node of the tree decomposition", CLAT_INTEGER},
238   {0,   OPTION_NO_LOSPRE, NULL, "Disable lospre"},
239   {0,   OPTION_ALLOW_UNSAFE_READ, NULL, "Allow optimizations to read any memory location anytime"},
240   {0,   "--nostdlibcall", &optimize.noStdLibCall, "Disable optimization of calls to standard library"},
241 
242   {0,   NULL, NULL, "Internal debugging options"},
243   {0,   OPTION_DUMP_AST, &options.dump_ast, "Dump front-end AST before generating i-code"},
244   {0,   OPTION_DUMP_I_CODE, &options.dump_i_code, "Dump the i-code structure at all stages"},
245   {0,   OPTION_DUMP_GRAPHS, &options.dump_graphs, "Dump graphs (control-flow, conflict, etc)"},
246   {0,   OPTION_ICODE_IN_ASM, &options.iCodeInAsm, "Include i-code as comments in the asm file"},
247   {0,   OPTION_VERBOSE_ASM, &options.verboseAsm, "Include code generator comments in the asm output"},
248 
249   {0,   NULL, NULL, "Linker options"},
250   {'l', NULL, NULL, "Include the given library in the link"},
251   {'L', NULL, NULL, "Add the next field to the library search path"},
252   {0,   OPTION_LIB_PATH, &libPathsSet, "<path> use this path to search for libraries", CLAT_ADD_SET},
253   {0,   OPTION_OUT_FMT_IHX, NULL, "Output in Intel hex format"},
254   {0,   OPTION_OUT_FMT_S19, NULL, "Output in S19 hex format"},
255   {0,   OPTION_XRAM_LOC, NULL, "<nnnn> External Ram start location", CLAT_INTEGER},
256   {0,   OPTION_XRAM_SIZE, NULL, "<nnnn> External Ram size"},
257   {0,   OPTION_IRAM_SIZE, &options.iram_size, "<nnnn> Internal Ram size", CLAT_INTEGER},
258   {0,   OPTION_XSTACK_LOC, &options.xstack_loc, "<nnnn> External Stack start location", CLAT_INTEGER},
259   {0,   OPTION_CODE_LOC, &options.code_loc, "<nnnn> Code Segment Location", CLAT_INTEGER},
260   {0,   OPTION_CODE_SIZE, &options.code_size, "<nnnn> Code Segment size", CLAT_INTEGER},
261   {0,   OPTION_STACK_LOC, &options.stack_loc, "<nnnn> Stack pointer initial value", CLAT_INTEGER},
262   {0,   OPTION_DATA_LOC, &options.data_loc, "<nnnn> Direct data start location", CLAT_INTEGER},
263   {0,   OPTION_IDATA_LOC, &options.idata_loc, NULL, CLAT_INTEGER},
264 
265   {0,   OPTION_NO_OPTSDCC_IN_ASM, &options.noOptsdccInAsm, "Do not emit .optsdcc in asm"},
266   /* End of options */
267   {0,   NULL}
268 };
269 
270 /** Table of all unsupported options and help text to display when one
271     is used.
272 */
273 typedef struct
274 {
275     /** shortOpt as in OPTIONS. */
276   char shortOpt;
277     /** longOpt as in OPTIONS. */
278   const char *longOpt;
279     /** Message to display inside W_UNSUPPORTED_OPT when this option
280         is used. */
281   const char *message;
282 } UNSUPPORTEDOPT;
283 
284 static const UNSUPPORTEDOPT unsupportedOptTable[] = {
285   {'X', NULL, "use --xstack-loc instead"},
286   {'x', NULL, "use --xstack instead"},
287   {'i', NULL, "use --idata-loc instead"},
288   {'r', NULL, "use --xdata-loc instead"},
289   {'s', NULL, "use --code-loc instead"},
290   {'Y', NULL, "use -I instead"},
291   {0, "--fommit-frame-pointer", "use --fomit-frame-pointer instead"},
292 };
293 
294 /** List of all default constant macros.
295  */
296 static const char *_baseValues[] = {
297   "cpp", "sdcpp",
298   "cppextraopts", "",
299   /* Path seperator character */
300   "sep", DIR_SEPARATOR_STRING,
301   NULL
302 };
303 
304 static const char *_preCmd = "{cpp} -nostdinc -Wall {cppstd}{cppextraopts} {fullsrcfilename} {cppoutfilename}";
305 
306 PORT *port;
307 
308 static PORT *_ports[] = {
309 #if !OPT_DISABLE_MCS51
310   &mcs51_port,
311 #endif
312 #if !OPT_DISABLE_Z80
313   &z80_port,
314 #endif
315 #if !OPT_DISABLE_Z180
316   &z180_port,
317 #endif
318 #if !OPT_DISABLE_R2K
319   &r2k_port,
320 #endif
321 #if !OPT_DISABLE_R3KA
322   &r3ka_port,
323 #endif
324 #if !OPT_DISABLE_GBZ80
325   &gbz80_port,
326 #endif
327 #if !OPT_DISABLE_TLCS90
328   &tlcs90_port,
329 #endif
330 #if !OPT_DISABLE_EZ80_Z80
331   &ez80_z80_port,
332 #endif
333 #if !OPT_DISABLE_AVR
334   &avr_port,
335 #endif
336 #if !OPT_DISABLE_DS390
337   &ds390_port,
338 #endif
339 #if !OPT_DISABLE_PIC16
340   &pic16_port,
341 #endif
342 #if !OPT_DISABLE_PIC14
343   &pic_port,
344 #endif
345 #if !OPT_DISABLE_TININative
346   &tininative_port,
347 #endif
348 #if !OPT_DISABLE_DS400
349   &ds400_port,
350 #endif
351 #if !OPT_DISABLE_HC08
352   &hc08_port,
353 #endif
354 #if !OPT_DISABLE_S08
355   &s08_port,
356 #endif
357 #if !OPT_DISABLE_STM8
358   &stm8_port,
359 #endif
360 #if !OPT_DISABLE_PDK13
361   &pdk13_port,
362 #endif
363 #if !OPT_DISABLE_PDK14
364   &pdk14_port,
365 #endif
366 #if !OPT_DISABLE_PDK15
367   &pdk15_port,
368 #endif
369 };
370 
371 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
372 
373 /** Sets the port to the one given by the command line option.
374     @param    The name minus the option (eg 'mcs51')
375     @return     0 on success.
376 */
377 static void
_setPort(const char * name)378 _setPort (const char *name)
379 {
380   int i;
381   for (i = 0; i < NUM_PORTS; i++)
382     {
383       if (!strcmp (_ports[i]->target, name))
384         {
385           port = _ports[i];
386           return;
387         }
388     }
389   /* Error - didnt find */
390   werror (E_UNKNOWN_TARGET, name);
391   exit (EXIT_FAILURE);
392 }
393 
394 /* Override the default processor with the one specified
395  * on the command line */
396 static void
_setProcessor(char * _processor)397 _setProcessor (char *_processor)
398 {
399   port->processor = _processor;
400 }
401 
402 static void
_validatePorts(void)403 _validatePorts (void)
404 {
405   int i;
406   for (i = 0; i < NUM_PORTS; i++)
407     {
408       if (_ports[i]->magic != PORT_MAGIC)
409         {
410           /* Uncomment this line to debug which port is causing the problem
411            * (the target name is close to the beginning of the port struct
412            * and probably can be accessed just fine). */
413           fprintf (stderr, "%s :", _ports[i]->target);
414           wassertl (0, "Port definition structure is incomplete");
415         }
416     }
417 }
418 
419 
420 static char *
program_name(const char * path)421 program_name (const char *path)
422 {
423 #ifdef _WIN32
424   char fname[_MAX_FNAME];
425 
426   _splitpath (path, NULL, NULL, fname, NULL);
427   return Safe_strdup (fname);
428 #else
429   char *tmpPath = Safe_strdup (path);
430   char *res = Safe_strdup (basename (tmpPath));
431 
432   Safe_free (tmpPath);
433   return res;
434 #endif
435 }
436 
437 /* search through the command line for the port */
438 static void
_findPort(int argc,char ** argv)439 _findPort (int argc, char **argv)
440 {
441   char *programName = program_name (*argv);
442   int found = 0;
443   int i;
444 
445   _validatePorts ();
446 
447   /* try to assign port by command line option */
448   while (argc-- && !found)
449     {
450       if (!strncmp (*argv, "-m", 2))
451         {
452           _setPort (*argv + 2);
453           found = 1;
454         }
455       argv++;
456     }
457 
458   /* try to assign port by the name of the executable */
459   for (i = 0; i < NUM_PORTS && !found; i++)
460     {
461       if (strstr (programName, _ports[i]->target))
462         {
463           _setPort (_ports[i]->target);
464           found = 1;
465         }
466     }
467 
468   if (!found)
469     {
470       /* Use the first in the list as default */
471       port = _ports[0];
472     }
473 
474   Safe_free (programName);
475 }
476 
477 /* search through the command line options for the processor */
478 static void
_findProcessor(int argc,char ** argv)479 _findProcessor (int argc, char **argv)
480 {
481   while (argc--)
482     {
483       if (!strncmp (*argv, "-p", 2))
484         {
485           _setProcessor (*argv + 2);
486           return;
487         }
488       argv++;
489     }
490 
491   /* no error if processor was not specified. */
492 }
493 
494 /*-----------------------------------------------------------------*/
495 /* printVersionInfo - prints the version info        */
496 /*-----------------------------------------------------------------*/
497 void
printVersionInfo(FILE * stream)498 printVersionInfo (FILE * stream)
499 {
500   int i;
501 
502   fprintf (stream, "SDCC : ");
503   for (i = 0; i < NUM_PORTS; i++)
504     fprintf (stream, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
505 
506   fprintf (stream, " " SDCC_VERSION_STR
507 #ifdef SDCC_SUB_VERSION_STR
508            "/" SDCC_SUB_VERSION_STR
509 #endif
510            " #%s (%s)\n", getBuildNumber (), getBuildEnvironment ());
511   fprintf (stream, "published under GNU General Public License (GPL)\n");
512 }
513 
514 static void
printOptions(const OPTION * optionsTable,FILE * stream)515 printOptions (const OPTION * optionsTable, FILE * stream)
516 {
517   int i;
518   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL || optionsTable[i].help != NULL; i++)
519     {
520       if (!optionsTable[i].shortOpt && !optionsTable[i].longOpt && optionsTable[i].help)
521         {
522           fprintf (stream, "\n%s:\n", optionsTable[i].help);
523         }
524       else
525         {
526           fprintf (stream, "  %c%c  %-20s  %s\n",
527                    optionsTable[i].shortOpt != 0 ? '-' : ' ',
528                    optionsTable[i].shortOpt != 0 ? optionsTable[i].shortOpt : ' ',
529                    optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
530                    optionsTable[i].help != NULL ? optionsTable[i].help : "");
531         }
532     }
533 }
534 
535 /*-----------------------------------------------------------------*/
536 /* printUsage - prints command line syntax         */
537 /*-----------------------------------------------------------------*/
538 static void
printUsage(bool err)539 printUsage (bool err)
540 {
541   int i;
542   FILE *stream = err ? stderr : stdout;
543 
544   printVersionInfo (stream);
545   fprintf (stream,
546            "Usage : sdcc [options] filename\n"
547            "Options :-\n");
548 
549   printOptions (optionsTable, stream);
550 
551   for (i = 0; i < NUM_PORTS; i++)
552     {
553       if (_ports[i]->poptions != NULL)
554         {
555           fprintf (stream, "\nSpecial options for the %s port:\n", _ports[i]->target);
556           printOptions (_ports[i]->poptions, stream);
557         }
558     }
559 }
560 
561 /*-----------------------------------------------------------------*/
562 /* setParseWithComma - separates string with comma to a set        */
563 /*-----------------------------------------------------------------*/
564 void
setParseWithComma(set ** dest,const char * src)565 setParseWithComma (set ** dest, const char *src)
566 {
567   const char *p, *end;
568   struct dbuf_s dbuf;
569 
570   /* skip the initial white spaces */
571   while (isspace ((unsigned char) *src))
572     ++src;
573 
574   /* skip the trailing white spaces */
575   end = &src[strlen (src) - 1];
576   while (end >= src && isspace ((unsigned char) *end))
577     --end;
578   ++end;
579 
580   p = src;
581   while (src < end)
582     {
583       dbuf_init (&dbuf, 16);
584 
585       while (p < end && ',' != *p)
586         ++p;
587       dbuf_append (&dbuf, src, p - src);
588       addSet (dest, dbuf_detach_c_str (&dbuf));
589 
590       src = ++p;
591     }
592 }
593 
594 /*-------------------------------------------------------------*/
595 /* setStackSize - set the stack size of a running sdcc process */
596 /*-------------------------------------------------------------*/
597 static void
setStackSize(void)598 setStackSize (void)
599 {
600 #if defined (HAVE_SETRLIMIT) && defined (RLIMIT_STACK)
601   struct rlimit rl = {4 * 1024 * 1024, 4 * 1024 * 1024};
602   setrlimit (RLIMIT_STACK, &rl);
603 #endif
604 }
605 
606 /*-----------------------------------------------------------------*/
607 /* setDefaultOptions - sets the default options                    */
608 /*-----------------------------------------------------------------*/
609 static void
setDefaultOptions(void)610 setDefaultOptions (void)
611 {
612   /* first the options part */
613   options.stack_loc = 0;        /* stack pointer initialised to 0 */
614   options.xstack_loc = 1;       /* xternal stack starts at 1 */
615   options.code_loc = 0;         /* code starts at 0 */
616   options.data_loc = 0;         /* JCF: By default let the linker locate data */
617   options.xdata_loc = 1;        /* MB: Do not use address 0 by default as it equals NULL */
618   options.idata_loc = 0;        /* MB: No need to limit idata to 0x80-0xFF */
619   options.nopeep = 0;
620   options.model = port->general.default_model;
621   options.nostdlib = 0;
622   options.nostdinc = 0;
623   options.verbose = 0;
624   options.std_sdcc = 1;         /* enable SDCC language extensions */
625   options.std_c95 = 1;
626   options.std_c99 = 1;
627   options.std_c11 = 1;          /* default to C11 (we want inline by default, so we need at least C99, and support for C11 is more complete than C99) */
628   options.std_c2x = 0;
629   options.code_seg = CODE_NAME ? Safe_strdup (CODE_NAME) : NULL;        /* default to CSEG for generated code */
630   options.const_seg = CONST_NAME ? Safe_strdup (CONST_NAME) : NULL;     /* default to CONST for generated code */
631   options.data_seg = DATA_NAME ? Safe_strdup (DATA_NAME) : NULL;        /* default to DATA for non-initialized data */
632   options.stack10bit = 0;
633   options.out_fmt = 0;
634   options.dump_graphs = 0;
635   options.dependencyFileOpt = 0;
636 
637   /* now for the optimizations */
638   /* turn on the everything */
639   optimize.global_cse = 1;
640   optimize.label1 = 1;
641   optimize.label2 = 1;
642   optimize.label3 = 1;
643   optimize.label4 = 1;
644   optimize.loopInvariant = 1;
645   optimize.loopInduction = 1;
646   options.max_allocs_per_node = 3000;
647   optimize.lospre = 1;
648   optimize.allow_unsafe_read = 0;
649 
650   /* now for the ports */
651   port->setDefaultOptions ();
652 }
653 
654 /*-----------------------------------------------------------------*/
655 /* processFile - determines the type of file from the extension    */
656 /*-----------------------------------------------------------------*/
657 static void
processFile(char * s)658 processFile (char *s)
659 {
660   const char *extp;
661   struct dbuf_s ext;
662   struct dbuf_s path;
663 
664   dbuf_init (&ext, 128);
665   dbuf_init (&path, PATH_MAX);
666 
667   /* get the file extension.
668      If no '.' then we don't know what the file type is
669      so give an error and return */
670   if (!dbuf_splitFile (s, &path, &ext))
671     {
672       werror (E_UNKNOWN_FEXT, s);
673 
674       dbuf_destroy (&ext);
675       dbuf_destroy (&path);
676 
677       return;
678     }
679 
680   /* otherwise depending on the file type */
681   extp = dbuf_c_str (&ext);
682   if (STRCASECMP (extp, ".c") == 0 || STRCASECMP (extp, ".h") == 0)
683     {
684       char *p, *m;
685 
686       dbuf_destroy (&ext);
687 
688       /* source file name : not if we already have a
689          source file */
690       if (fullSrcFileName)
691         {
692           werror (W_TOO_MANY_SRC, s);
693 
694           dbuf_destroy (&path);
695 
696           return;
697         }
698 
699       /* the only source file */
700       fullSrcFileName = s;
701       if (!(srcFile = fopen (fullSrcFileName, "r")))
702         {
703           werror (E_FILE_OPEN_ERR, s);
704 
705           dbuf_destroy (&path);
706 
707           exit (EXIT_FAILURE);
708         }
709 
710       /* get rid of any path information
711          for the module name; */
712       dbuf_init (&ext, 128);
713 
714       dbuf_splitPath (dbuf_c_str (&path), NULL, &ext);
715       dbuf_destroy (&path);
716 
717       moduleNameBase = Safe_strdup (dbuf_c_str (&ext));
718       m = dbuf_detach (&ext);
719 
720       for (p = m; *p; ++p)
721         if (!isalnum ((unsigned char) *p))
722           *p = '_';
723       moduleName = m;
724       return;
725     }
726 
727   /* if the extension is type rel_ext
728      additional object file will be passed to the linker */
729   if (STRCASECMP (extp, port->linker.rel_ext) == 0)
730     {
731       dbuf_destroy (&ext);
732       dbuf_destroy (&path);
733 
734       addSet (&relFilesSet, Safe_strdup (s));
735       return;
736     }
737 
738   /* if .lib or .LIB */
739   if (STRCASECMP (extp, ".lib") == 0)
740     {
741       dbuf_destroy (&ext);
742       dbuf_destroy (&path);
743 
744       addSet (&libFilesSet, Safe_strdup (s));
745       return;
746     }
747 
748   dbuf_destroy (&ext);
749   dbuf_destroy (&path);
750 
751   werror (E_UNKNOWN_FEXT, s);
752 }
753 
754 static void
_setModel(int model,const char * sz)755 _setModel (int model, const char *sz)
756 {
757   if (port->general.supported_models & model)
758     options.model = model;
759   else
760     werror (W_UNSUPPORTED_MODEL, sz, port->target);
761 }
762 
763 /** Gets the string argument to this option.  If the option is '--opt'
764     then for input of '--optxyz' or '--opt xyz' returns xyz.
765 */
766 char *
getStringArg(const char * szStart,char ** argv,int * pi,int argc)767 getStringArg (const char *szStart, char **argv, int *pi, int argc)
768 {
769   if (argv[*pi][strlen (szStart)])
770     {
771       return &argv[*pi][strlen (szStart)];
772     }
773   else
774     {
775       ++(*pi);
776       if (*pi >= argc)
777         {
778           werror (E_ARGUMENT_MISSING, szStart);
779           /* Die here rather than checking for errors later. */
780           exit (EXIT_FAILURE);
781         }
782       else
783         {
784           return argv[*pi];
785         }
786     }
787 }
788 
789 /** Gets the integer argument to this option using the same rules as
790     getStringArg.
791 */
792 long
getIntArg(const char * szStart,char ** argv,int * pi,int argc)793 getIntArg (const char *szStart, char **argv, int *pi, int argc)
794 {
795   char *p;
796   int val;
797   char *str = getStringArg (szStart, argv, pi, argc);
798 
799   val = strtol (str, &p, 0);
800   if (p == str || *p != '\0')
801     {
802       werror (E_BAD_INT_ARGUMENT, szStart);
803       /* Die here rather than checking for errors later. */
804       exit (EXIT_FAILURE);
805     }
806   return val;
807 }
808 
809 static void
verifyShortOption(const char * opt)810 verifyShortOption (const char *opt)
811 {
812   if (strlen (opt) != 2)
813     {
814       werror (W_EXCESS_SHORT_OPTIONS, opt);
815     }
816 }
817 
818 static bool
tryHandleUnsupportedOpt(char ** argv,int * pi)819 tryHandleUnsupportedOpt (char **argv, int *pi)
820 {
821   if (argv[*pi][0] == '-')
822     {
823       const char *longOpt = "";
824       char shortOpt = -1;
825       int i;
826 
827       if (argv[*pi][1] == '-')
828         {
829           /* Long option. */
830           longOpt = argv[*pi];
831         }
832       else
833         {
834           shortOpt = argv[*pi][1];
835         }
836       for (i = 0; i < LENGTH (unsupportedOptTable); i++)
837         {
838           if (unsupportedOptTable[i].shortOpt == shortOpt ||
839               (longOpt && unsupportedOptTable[i].longOpt && !strcmp (unsupportedOptTable[i].longOpt, longOpt)))
840             {
841               /* Found an unsupported opt. */
842               struct dbuf_s dbuf;
843 
844               dbuf_init (&dbuf, 100);
845               dbuf_printf (&dbuf, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
846               werror (W_UNSUPP_OPTION, dbuf_detach_c_str (&dbuf), unsupportedOptTable[i].message);
847               return 1;
848             }
849         }
850       /* Didn't find in the table */
851       return 0;
852     }
853   else
854     {
855       /* Not an option, so can't be unsupported :) */
856       return 0;
857     }
858 }
859 
860 static bool
scanOptionsTable(const OPTION * optionsTable,char shortOpt,const char * longOpt,char ** argv,int * pi,int argc)861 scanOptionsTable (const OPTION * optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi, int argc)
862 {
863   int i;
864 
865   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL || optionsTable[i].help != NULL; i++)
866     {
867       if (optionsTable[i].shortOpt == shortOpt)
868         {
869           if (optionsTable[i].pparameter != NULL)
870             {
871               verifyShortOption (argv[*pi]);
872 
873               (*(int *) optionsTable[i].pparameter)++;
874 
875               return TRUE;
876             }
877         }
878       else
879         {
880           size_t len = optionsTable[i].longOpt ? strlen (optionsTable[i].longOpt) : 0;
881 
882           if (longOpt &&
883               (optionsTable[i].arg_type != CLAT_BOOLEAN ||
884                (optionsTable[i].arg_type == CLAT_BOOLEAN && len == strlen (longOpt) && optionsTable[i].longOpt)) &&
885               strncmp (optionsTable[i].longOpt, longOpt, len) == 0)
886             {
887               /* If it is a flag then we can handle it here */
888               if (optionsTable[i].pparameter != NULL)
889                 {
890                   switch (optionsTable[i].arg_type)
891                     {
892                     case CLAT_BOOLEAN:
893                       (*(int *) optionsTable[i].pparameter)++;
894                       break;
895 
896                     case CLAT_INTEGER:
897                       *(int *) optionsTable[i].pparameter = getIntArg (optionsTable[i].longOpt, argv, pi, argc);
898                       break;
899 
900                     case CLAT_STRING:
901                       if (*(char **) optionsTable[i].pparameter)
902                         Safe_free (*(char **) optionsTable[i].pparameter);
903                       *(char **) optionsTable[i].pparameter =
904                         Safe_strdup (getStringArg (optionsTable[i].longOpt, argv, pi, argc));
905                       break;
906 
907                     case CLAT_SET:
908                       if (*(set **) optionsTable[i].pparameter)
909                         {
910                           deleteSet ((set **) optionsTable[i].pparameter);
911                         }
912                       setParseWithComma ((set **) optionsTable[i].pparameter,
913                                          getStringArg (optionsTable[i].longOpt, argv, pi, argc));
914                       break;
915 
916                     case CLAT_ADD_SET:
917                       addSet ((set **) optionsTable[i].pparameter,
918                               Safe_strdup (getStringArg (optionsTable[i].longOpt, argv, pi, argc)));
919                       break;
920                     }
921                   return TRUE;
922                 }
923               else
924                 {
925                   /* Not a flag.  Handled manually later. */
926                   return FALSE;
927                 }
928             }
929         }
930     }
931   /* Didn't find in the table */
932   return FALSE;
933 }
934 
935 static bool
tryHandleSimpleOpt(char ** argv,int * pi,int argc)936 tryHandleSimpleOpt (char **argv, int *pi, int argc)
937 {
938   if (argv[*pi][0] == '-')
939     {
940       const char *longOpt = "";
941       char shortOpt = -1;
942 
943       if (argv[*pi][1] == '-')
944         {
945           /* Long option. */
946           longOpt = argv[*pi];
947         }
948       else
949         {
950           shortOpt = argv[*pi][1];
951         }
952 
953       if (scanOptionsTable (optionsTable, shortOpt, longOpt, argv, pi, argc))
954         {
955           return TRUE;
956         }
957       else if (port && port->poptions && scanOptionsTable (port->poptions, shortOpt, longOpt, argv, pi, argc))
958         {
959           return TRUE;
960         }
961       else
962         {
963           return FALSE;
964         }
965     }
966   else
967     {
968       /* Not an option, so can't be handled. */
969       return FALSE;
970     }
971 }
972 
973 /*-----------------------------------------------------------------*/
974 /* parseCmdLine - parses the command line and sets the options     */
975 /*-----------------------------------------------------------------*/
976 static int
parseCmdLine(int argc,char ** argv)977 parseCmdLine (int argc, char **argv)
978 {
979   int i;
980 
981   /* go thru all whole command line */
982   for (i = 1; i < argc; i++)
983     {
984       if (i >= argc)
985         break;
986 
987       /* check port specific options before general ones */
988       if (port->parseOption (&argc, argv, &i) == TRUE)
989         {
990           continue;
991         }
992 
993       if (tryHandleUnsupportedOpt (argv, &i) == TRUE)
994         {
995           continue;
996         }
997 
998       if (tryHandleSimpleOpt (argv, &i, argc) == TRUE)
999         {
1000           continue;
1001         }
1002 
1003       /* options */
1004       if (argv[i][0] == '-' && argv[i][1] == '-')
1005         {
1006           if (strcmp (argv[i], OPTION_USE_STDOUT) == 0)
1007             {
1008               if (options.use_stdout == 0)
1009                 {
1010                   options.use_stdout = 1;
1011                   dup2 (STDOUT_FILENO, STDERR_FILENO);
1012                 }
1013               continue;
1014             }
1015           if (strcmp (argv[i], OPTION_HELP) == 0)
1016             {
1017               printUsage (FALSE);
1018               exit (EXIT_SUCCESS);
1019             }
1020 
1021           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
1022             {
1023               options.out_fmt = 'i';
1024               continue;
1025             }
1026 
1027           if (strcmp (argv[i], OPTION_OUT_FMT_S19) == 0)
1028             {
1029               options.out_fmt = 's';
1030               continue;
1031             }
1032 
1033           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
1034             {
1035               _setModel (MODEL_SMALL, argv[i]);
1036               continue;
1037             }
1038 
1039           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
1040             {
1041               _setModel (MODEL_MEDIUM, argv[i]);
1042               continue;
1043             }
1044 
1045           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
1046             {
1047               _setModel (MODEL_LARGE, argv[i]);
1048               continue;
1049             }
1050 
1051           if (strcmp (argv[i], OPTION_HUGE_MODEL) == 0)
1052             {
1053               _setModel (MODEL_HUGE, argv[i]);
1054               continue;
1055             }
1056 
1057           if (strcmp (argv[i], OPTION_VERSION) == 0)
1058             {
1059               printVersionInfo (stdout);
1060               exit (EXIT_SUCCESS);
1061               continue;
1062             }
1063 
1064           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
1065             {
1066               int val = getIntArg (OPTION_XRAM_LOC, argv, &i, argc);
1067               if (options.xdata_loc == options.xstack_loc)
1068                 options.xstack_loc = val;
1069               options.xdata_loc = val;
1070               continue;
1071             }
1072 
1073           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
1074             {
1075               options.xram_size = getIntArg (OPTION_XRAM_SIZE, argv, &i, argc);
1076               options.xram_size_set = TRUE;
1077               continue;
1078             }
1079 
1080           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
1081             {
1082               optimize.global_cse = 0;
1083               continue;
1084             }
1085 
1086           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
1087             {
1088               optimize.loopInvariant = 0;
1089               continue;
1090             }
1091 
1092           if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
1093             {
1094               optimize.label2 = 0;
1095               optimize.label4 = 0;
1096               continue;
1097             }
1098 
1099           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
1100             {
1101               optimize.loopInduction = 0;
1102               continue;
1103             }
1104 
1105           if (strcmp (argv[i], OPTION_OPT_CODE_SPEED) == 0)
1106             {
1107               optimize.codeSpeed = 1;
1108               optimize.codeSize = 0;
1109               continue;
1110             }
1111 
1112           if (strcmp (argv[i], OPTION_OPT_CODE_SIZE) == 0)
1113             {
1114               optimize.codeSpeed = 0;
1115               optimize.codeSize = 1;
1116               continue;
1117             }
1118 
1119           if (strcmp (argv[i], OPTION_NO_LOSPRE) == 0)
1120             {
1121               optimize.lospre = 0;
1122               continue;
1123             }
1124 
1125           if (strcmp (argv[i], OPTION_ALLOW_UNSAFE_READ) == 0)
1126             {
1127               optimize.allow_unsafe_read = 1;
1128               continue;
1129             }
1130 
1131           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0)
1132             {
1133               options.lessPedantic = 1;
1134               setErrorLogLevel (ERROR_LEVEL_WARNING);
1135               continue;
1136             }
1137 
1138           if (strcmp (argv[i], OPTION_DISABLE_WARNING) == 0)
1139             {
1140               int w = getIntArg (OPTION_DISABLE_WARNING, argv, &i, argc);
1141               setWarningDisabled (w);
1142               continue;
1143             }
1144 
1145           if (strcmp (argv[i], OPTION_WERROR) == 0)
1146             {
1147               setWError (1);
1148               addSet (&preArgvSet, Safe_strdup ("-Werror"));
1149               continue;
1150             }
1151 
1152           if (strcmp (argv[i], OPTION_STD_C89) == 0)
1153             {
1154               options.std_c95 = 0;
1155               options.std_c99 = 0;
1156               options.std_c11 = 0;
1157               options.std_c2x = 0;
1158               options.std_sdcc = 0;
1159               continue;
1160             }
1161 
1162           if (strcmp (argv[i], OPTION_STD_C95) == 0)
1163             {
1164               options.std_c95 = 1;
1165               options.std_c99 = 0;
1166               options.std_c11 = 0;
1167               options.std_c2x = 0;
1168               options.std_sdcc = 0;
1169               continue;
1170             }
1171 
1172           if (strcmp (argv[i], OPTION_STD_C99) == 0)
1173             {
1174               options.std_c95 = 1;
1175               options.std_c99 = 1;
1176               options.std_c11 = 0;
1177               options.std_c2x = 0;
1178               options.std_sdcc = 0;
1179               continue;
1180             }
1181 
1182           if (strcmp (argv[i], OPTION_STD_C11) == 0)
1183             {
1184               options.std_c95 = 1;
1185               options.std_c99 = 1;
1186               options.std_c11 = 1;
1187               options.std_c2x = 0;
1188               options.std_sdcc = 0;
1189               continue;
1190             }
1191 
1192           if (strcmp (argv[i], OPTION_STD_C2X) == 0)
1193             {
1194               options.std_c95 = 1;
1195               options.std_c99 = 1;
1196               options.std_c11 = 1;
1197               options.std_c2x = 1;
1198               options.std_sdcc = 0;
1199               continue;
1200             }
1201 
1202           if (strcmp (argv[i], OPTION_STD_SDCC89) == 0)
1203             {
1204               options.std_c95 = 0;
1205               options.std_c99 = 0;
1206               options.std_c11 = 0;
1207               options.std_c2x = 0;
1208               options.std_sdcc = 1;
1209               continue;
1210             }
1211 
1212           if (strcmp (argv[i], OPTION_STD_SDCC99) == 0)
1213             {
1214               options.std_c95 = 1;
1215               options.std_c99 = 1;
1216               options.std_c11 = 0;
1217               options.std_c2x = 0;
1218               options.std_sdcc = 1;
1219               continue;
1220             }
1221 
1222           if (strcmp (argv[i], OPTION_STD_SDCC11) == 0)
1223             {
1224               options.std_c95 = 1;
1225               options.std_c99 = 1;
1226               options.std_c11 = 1;
1227               options.std_c2x = 0;
1228               options.std_sdcc = 1;
1229               continue;
1230             }
1231 
1232           if (strcmp (argv[i], OPTION_STD_SDCC2X) == 0)
1233             {
1234               options.std_c95 = 1;
1235               options.std_c99 = 1;
1236               options.std_c11 = 1;
1237               options.std_c2x = 1;
1238               options.std_sdcc = 1;
1239               continue;
1240             }
1241 
1242           if (strcmp (argv[i], OPTION_CODE_SEG) == 0)
1243             {
1244               struct dbuf_s segname;
1245 
1246               dbuf_init (&segname, 16);
1247               dbuf_printf (&segname, "%-8s(CODE)", getStringArg (OPTION_CODE_SEG, argv, &i, argc));
1248               if (options.code_seg)
1249                 Safe_free (options.code_seg);
1250               options.code_seg = dbuf_detach (&segname);
1251               continue;
1252             }
1253 
1254           if (strcmp (argv[i], OPTION_CONST_SEG) == 0)
1255             {
1256               struct dbuf_s segname;
1257 
1258               dbuf_init (&segname, 16);
1259               dbuf_printf (&segname, "%-8s(CODE)", getStringArg (OPTION_CONST_SEG, argv, &i, argc));
1260               if (options.const_seg)
1261                 Safe_free (options.const_seg);
1262               options.const_seg = dbuf_detach (&segname);
1263               continue;
1264             }
1265 
1266           if (strcmp (argv[i], OPTION_DATA_SEG) == 0)
1267             {
1268               struct dbuf_s segname;
1269 
1270               dbuf_init (&segname, 16);
1271               dbuf_printf (&segname, "%-8s(DATA)", getStringArg (OPTION_DATA_SEG, argv, &i, argc));
1272               if (options.data_seg)
1273                 Safe_free (options.data_seg);
1274               options.data_seg = dbuf_detach (&segname);
1275               continue;
1276             }
1277 
1278           if (strcmp (argv[i], OPTION_PEEP_RETURN) == 0)
1279             {
1280               options.peepReturn = 1;
1281               continue;
1282             }
1283 
1284           if (strcmp (argv[i], OPTION_NO_PEEP_RETURN) == 0)
1285             {
1286               options.peepReturn = -1;
1287               continue;
1288             }
1289 
1290           if (strcmp (argv[i], OPTION_DEBUG) == 0)
1291             {
1292               if (options.peepReturn == 0)
1293                   options.peepReturn = -1;
1294               options.debug = 1;
1295               continue;
1296             }
1297 
1298           werror (W_UNKNOWN_OPTION, argv[i]);
1299           continue;
1300         }
1301 
1302       /* if preceded by  '-' then option */
1303       if (*argv[i] == '-')
1304         {
1305           switch (argv[i][1])
1306             {
1307             case 'h':
1308               verifyShortOption (argv[i]);
1309 
1310               printUsage (FALSE);
1311               exit (EXIT_SUCCESS);
1312               break;
1313 
1314             case 'm':
1315               /* Used to select the port. But this has already been done. */
1316               break;
1317 
1318             case 'p':
1319               /* Used to select the processor in port. But this has
1320                * already been done. */
1321               break;
1322 
1323             case 'c':
1324               verifyShortOption (argv[i]);
1325 
1326               options.cc_only = 1;
1327               break;
1328 
1329             case 'L':
1330               addSet (&libPathsSet, Safe_strdup (getStringArg ("-L", argv, &i, argc)));
1331               break;
1332 
1333             case 'l':
1334               addSet (&libFilesSet, Safe_strdup (getStringArg ("-l", argv, &i, argc)));
1335               break;
1336 
1337             case 'o':
1338               {
1339                 char *outName = getStringArg ("-o", argv, &i, argc);
1340                 size_t len = strlen (outName);
1341 
1342                 /* point to last character */
1343                 if (IS_DIR_SEPARATOR (outName[len - 1]))
1344                   {
1345                     /* only output path specified */
1346                     dstPath = Safe_strndup (outName, len - 1);
1347                     fullDstFileName = NULL;
1348                   }
1349                 else
1350                   {
1351                     struct dbuf_s path;
1352 
1353                     dbuf_init (&path, PATH_MAX);
1354                     fullDstFileName = Safe_strdup (outName);
1355 
1356                     /* get rid of the "."-extension */
1357                     dbuf_splitFile (outName, &path, NULL);
1358 
1359                     dstFileName = dbuf_detach_c_str (&path);
1360 
1361                     dbuf_init (&path, PATH_MAX);
1362                     /* strip module name to get path */
1363                     if (dbuf_splitPath (dstFileName, &path, NULL))
1364                       dstPath = dbuf_detach_c_str (&path);
1365                     else
1366                       dbuf_destroy (&path);
1367                   }
1368                 break;
1369               }
1370 
1371             case 'W':
1372               /* pre-processer options */
1373               if (argv[i][2] == 'p')
1374                 {
1375                   setParseWithComma (&preArgvSet, getStringArg ("-Wp", argv, &i, argc));
1376                 }
1377               /* linker options */
1378               else if (argv[i][2] == 'l')
1379                 {
1380                   setParseWithComma (&linkOptionsSet, getStringArg ("-Wl", argv, &i, argc));
1381                 }
1382               /* assembler options */
1383               else if (argv[i][2] == 'a')
1384                 {
1385                   setParseWithComma (&asmOptionsSet, getStringArg ("-Wa", argv, &i, argc));
1386                 }
1387               else
1388                 {
1389                   werror (W_UNKNOWN_OPTION, argv[i]);
1390                 }
1391               break;
1392 
1393             case 'v':
1394               verifyShortOption (argv[i]);
1395 
1396               printVersionInfo (stdout);
1397               exit (EXIT_SUCCESS);
1398               break;
1399 
1400               /* preprocessor options */
1401             case 'M':
1402               {
1403                 if (argv[i][2] == 'M')
1404                   {
1405                     if (argv[i][3] == 'D')
1406                       {
1407                         options.dependencyFileOpt = USER_DEPENDENCY_FILE_OPT;
1408                       }
1409                     else
1410                       {
1411                         addSet (&preArgvSet, Safe_strdup ("-MM"));
1412                         preProcOnly = 1;
1413                       }
1414                   }
1415                 else
1416                   {
1417                     if (argv[i][2] == 'D')
1418                       {
1419                         options.dependencyFileOpt = SYSTEM_DEPENDENCY_FILE_OPT;
1420                       }
1421                     else
1422                       {
1423                         addSet (&preArgvSet, Safe_strdup ("-M"));
1424                         preProcOnly = 1;
1425                       }
1426                   }
1427                 break;
1428               }
1429 
1430             case 'd':
1431             case 'D':
1432             case 'I':
1433             case 'A':
1434             case 'U':
1435               {
1436                 char sOpt = argv[i][1];
1437                 char *rest, *s;
1438                 struct dbuf_s dbuf;
1439 
1440                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1441                   {
1442                     i++;
1443                     if (i >= argc)
1444                       {
1445                         /* No argument. */
1446                         werror (E_ARGUMENT_MISSING, argv[i - 1]);
1447                         break;
1448                       }
1449                     else
1450                       {
1451                         rest = argv[i];
1452                       }
1453                   }
1454                 else
1455                   rest = &argv[i][2];
1456 
1457                 if (sOpt == 'Y')
1458                   sOpt = 'I';
1459 
1460                 s = shell_escape (rest);
1461                 dbuf_init (&dbuf, 256);
1462                 dbuf_printf (&dbuf, "-%c%s", sOpt, s);
1463                 Safe_free (s);
1464                 addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
1465                 if (sOpt == 'I')
1466                   {
1467                     addSet (&includeDirsSet, Safe_strdup (rest));
1468                     addSet (&userIncDirsSet, Safe_strdup (rest));
1469                   }
1470               }
1471               break;
1472 
1473             default:
1474               werror (W_UNKNOWN_OPTION, argv[i]);
1475             }
1476           continue;
1477         }
1478 
1479       /* no option must be a filename */
1480       if (options.c1mode)
1481         {
1482           werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1483         }
1484       else
1485         {
1486           processFile (argv[i]);
1487         }
1488     }
1489 
1490   /* some sanity checks in c1 mode */
1491   if (options.c1mode)
1492     {
1493       const char *s;
1494 
1495       if (fullSrcFileName)
1496         {
1497           fclose (srcFile);
1498           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1499         }
1500       fullSrcFileName = NULL;
1501       for (s = setFirstItem (relFilesSet); s != NULL; s = setNextItem (relFilesSet))
1502         {
1503           werror (W_NO_FILE_ARG_IN_C1, s);
1504         }
1505       for (s = setFirstItem (libFilesSet); s != NULL; s = setNextItem (libFilesSet))
1506         {
1507           werror (W_NO_FILE_ARG_IN_C1, s);
1508         }
1509       deleteSet (&relFilesSet);
1510       deleteSet (&libFilesSet);
1511 
1512       if (options.cc_only || noAssemble || preProcOnly)
1513         {
1514           werror (W_ILLEGAL_OPT_COMBINATION);
1515         }
1516       options.cc_only = noAssemble = preProcOnly = 0;
1517       if (!dstFileName)
1518         {
1519           werror (E_NEED_OPT_O_IN_C1);
1520           exit (EXIT_FAILURE);
1521         }
1522       else
1523         {
1524           char *p, *m;
1525 
1526           m = Safe_strdup (dstFileName);
1527           for (p = m; *p; ++p)
1528             if (!isalnum ((unsigned char) *p))
1529               *p = '_';
1530           moduleName = m;
1531         }
1532     }
1533   /* if no dstFileName given with -o, we've to find one: */
1534   if (!dstFileName)
1535     {
1536       const char *s;
1537 
1538       /* use the modulename from the C-source */
1539       if (fullSrcFileName)
1540         {
1541           struct dbuf_s path;
1542 
1543           if (*dstPath != '\0')
1544             {
1545               dbuf_init (&path, 128);
1546               dbuf_makePath (&path, dstPath, moduleNameBase);
1547               dstFileName = dbuf_detach_c_str (&path);
1548             }
1549           else
1550             dstFileName = Safe_strdup (moduleNameBase);
1551         }
1552       /* use the modulename from the first object file */
1553       else if ((s = peekSet (relFilesSet)) != NULL)
1554         {
1555           struct dbuf_s file;
1556 
1557           dbuf_init (&file, 128);
1558 
1559           /* get rid of the "."-extension */
1560           dbuf_splitFile (s, &file, NULL);
1561 
1562           s = dbuf_detach_c_str (&file);
1563 
1564           dbuf_init (&file, PATH_MAX);
1565 
1566           dbuf_splitPath (s, NULL, &file);
1567 
1568           if (*dstPath != '\0')
1569             {
1570               struct dbuf_s path;
1571 
1572               dbuf_init (&path, PATH_MAX);
1573               dbuf_makePath (&path, dstPath, dbuf_detach_c_str (&file));
1574               dstFileName = dbuf_detach_c_str (&path);
1575             }
1576           else
1577             {
1578               dstFileName = dbuf_detach_c_str (&file);
1579             }
1580         }
1581       /* else no module given: help text is displayed */
1582     }
1583 
1584   /* set int, long and float reentrancy based on stack-auto */
1585   if (options.stackAuto)
1586     {
1587       options.intlong_rent++;
1588       options.float_rent++;
1589     }
1590 
1591   /* if debug option is set then open the cdbFile */
1592   if (options.debug && fullSrcFileName)
1593     {
1594       struct dbuf_s adbFile;
1595 
1596       dbuf_init (&adbFile, PATH_MAX);
1597       dbuf_append_str (&adbFile, dstFileName);
1598       dbuf_append_str (&adbFile, ".adb");
1599 
1600       if (debugFile->openFile (dbuf_c_str (&adbFile)))
1601         debugFile->writeModule (moduleName);
1602       else
1603         werror (E_FILE_OPEN_ERR, dbuf_c_str (&adbFile));
1604 
1605       dbuf_destroy (&adbFile);
1606     }
1607   MSVC_style (options.vc_err_style);
1608 
1609   return 0;
1610 }
1611 
1612 /*-----------------------------------------------------------------*/
1613 /* finalizeOptions - finalize (post-process) options               */
1614 /*-----------------------------------------------------------------*/
1615 static void
finalizeOptions(void)1616 finalizeOptions (void)
1617 {
1618   /* no peephole comments if not verbose asm */
1619   if (!options.verboseAsm)
1620     options.noPeepComments = 1;
1621 }
1622 
1623 static const char *
getOutFmtExt(void)1624 getOutFmtExt (void)
1625 {
1626   switch (options.out_fmt)
1627     {
1628     default:
1629     case 'i':
1630       return ".ihx";
1631 
1632     case 's':
1633       return ".s19";
1634 
1635     case 'E':
1636       return ".elf";
1637     }
1638 }
1639 
1640 /*-----------------------------------------------------------------*/
1641 /* linkEdit : - calls the linkage editor  with options             */
1642 /*-----------------------------------------------------------------*/
1643 static void
linkEdit(char ** envp)1644 linkEdit (char **envp)
1645 {
1646   FILE *lnkfile;
1647   int system_ret;
1648   const char *s;
1649   struct dbuf_s linkerScriptFileName;
1650   struct dbuf_s binFileName;
1651   char *buf, *tb;
1652 
1653   dbuf_init (&linkerScriptFileName, PATH_MAX);
1654   dbuf_init (&binFileName, PATH_MAX);
1655 
1656   if (port->linker.needLinkerScript)
1657     {
1658       char out_fmt = (options.out_fmt == 0) ? 'i' : options.out_fmt;
1659 
1660       if (NULL != fullDstFileName)
1661         {
1662           dbuf_append_str (&binFileName, fullDstFileName);
1663         }
1664       else
1665         {
1666           dbuf_append_str (&binFileName, dstFileName);
1667           dbuf_append_str (&binFileName, getOutFmtExt ());
1668         }
1669 
1670       /* first we need to create the <filename>.lk file */
1671       dbuf_printf (&linkerScriptFileName, "%s.lk", dstFileName);
1672       if (!(lnkfile = fopen (dbuf_c_str (&linkerScriptFileName), "w")))
1673         {
1674           werror (E_FILE_OPEN_ERR, dbuf_c_str (&linkerScriptFileName));
1675           exit (EXIT_FAILURE);
1676         }
1677 
1678       if (TARGET_Z80_LIKE)
1679         {
1680           fprintf (lnkfile, "-mjwx\n-%c %s\n", out_fmt, dbuf_c_str (&binFileName));
1681         }
1682       else                      /* For all the other ports which need linker script */
1683         {
1684           fprintf (lnkfile, "-muwx\n-%c %s\n", out_fmt, dbuf_c_str (&binFileName));
1685           if (TARGET_MCS51_LIKE)
1686             fprintf (lnkfile, "-M\n");
1687           if (!options.no_pack_iram)
1688             fprintf (lnkfile, "-Y\n");
1689           else
1690             werror (W_DEPRECATED_OPTION, "--no-pack-iram");
1691         }
1692 
1693       if (!TARGET_Z80_LIKE)   /* Not for the z80, gbz80 */
1694         {
1695           /* if iram size specified */
1696           if (options.iram_size)
1697             fprintf (lnkfile, "-I 0x%04x\n", options.iram_size);
1698 
1699           /* if stack size specified */
1700           if (options.stack_size)
1701             fprintf (lnkfile, "-S 0x%02x\n", options.stack_size);
1702 
1703           /* if xram size specified */
1704           if (options.xram_size_set)
1705             fprintf (lnkfile, "-X 0x%04x\n", options.xram_size);
1706 
1707           /* if code size specified */
1708           if (options.code_size)
1709             fprintf (lnkfile, "-C 0x%04x\n", options.code_size);
1710         }
1711 
1712       if (options.debug)
1713         fprintf (lnkfile, "-y\n");
1714 
1715 #define WRITE_SEG_LOC(N, L) \
1716   if (N) \
1717   { \
1718     char *c, *segName; \
1719     segName = Safe_strdup (N); \
1720     c = strtok (segName, " \t"); \
1721     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1722     if (segName) { Safe_free (segName); } \
1723   }
1724 
1725       if (!TARGET_Z80_LIKE)   /* Not for the z80, z180, gbz80 */
1726         {
1727 
1728           /* code segment start */
1729           WRITE_SEG_LOC (HOME_NAME, options.code_loc);
1730 
1731           /* data segment start. If zero, the linker chooses
1732              the best place for data */
1733           if (options.data_loc)
1734             {
1735               WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1736             }
1737 
1738           /* xdata segment start. If zero, the linker chooses
1739              the best place for xdata */
1740           if (options.xdata_loc)
1741             {
1742               WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1743             }
1744 
1745           /* pdata/xstack segment start. If zero, the linker
1746              chooses the best place for them */
1747           if (options.xstack_loc)
1748             {
1749               WRITE_SEG_LOC (PDATA_NAME, options.xstack_loc);
1750             }
1751 
1752           /* indirect data */
1753           if (IDATA_NAME)
1754             {
1755               WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1756             }
1757 
1758           /* bit segment start */
1759           WRITE_SEG_LOC (BIT_NAME, 0);
1760 
1761           /* stack start */
1762           if ((options.stack_loc) && (options.stack_loc < 0x100) && !TARGET_HC08_LIKE)
1763             {
1764               WRITE_SEG_LOC ("SSEG", options.stack_loc);
1765             }
1766         }
1767       else                      /* For the z80, z180, gbz80 */
1768         {
1769           WRITE_SEG_LOC ("_CODE", options.code_loc);
1770           WRITE_SEG_LOC ("_DATA", options.data_loc);
1771         }
1772 
1773       /* If the port has any special linker area declarations, get 'em */
1774       if (port->extraAreas.genExtraAreaLinkOptions)
1775         {
1776           port->extraAreas.genExtraAreaLinkOptions (lnkfile);
1777         }
1778 
1779       /* add the extra linker options */
1780       fputStrSet (lnkfile, linkOptionsSet);
1781 
1782       /* command line defined library paths if specified */
1783       for (s = setFirstItem (libPathsSet); s != NULL; s = setNextItem (libPathsSet))
1784         fprintf (lnkfile, "-k %s\n", s);
1785 
1786       /* standard library path */
1787       if (!options.nostdlib)
1788         {
1789           for (s = setFirstItem (libDirsSet); s != NULL; s = setNextItem (libDirsSet))
1790             fprintf (lnkfile, "-k %s\n", s);
1791         }
1792 
1793       /* command line defined library files if specified */
1794       for (s = setFirstItem (libFilesSet); s != NULL; s = setNextItem (libFilesSet))
1795         fprintf (lnkfile, "-l %s\n", s);
1796 
1797       /* standard library files */
1798       if (!options.nostdlib)
1799         {
1800           if (NULL != port->linker.libs)
1801             {
1802               const char *const *p;
1803 
1804               for (p = port->linker.libs; NULL != *p; ++p)
1805                 {
1806                   fprintf (lnkfile, "-l %s\n", *p);
1807                 }
1808             }
1809         }
1810 
1811       /* put in the object file, generated from the C cource */
1812       if (fullSrcFileName)
1813         {
1814           struct dbuf_s path;
1815 
1816           dbuf_init (&path, PATH_MAX);
1817           dbuf_printf (&path, "%s%s", dstFileName, port->linker.rel_ext);
1818           addSetHead (&relFilesSet, dbuf_detach (&path));
1819         }
1820 
1821       if (!options.no_std_crt0)
1822         {
1823           const char *const *p;
1824           set *crtSet = NULL;
1825 
1826           if (NULL != port->linker.crt)
1827             {
1828               struct dbuf_s crtpath;
1829 
1830               dbuf_init (&crtpath, PATH_MAX);
1831 
1832               for (p = port->linker.crt; NULL != *p; ++p)
1833                 {
1834                   /* Try to find where C runtime files are ...
1835                      It is very important for this file to be first on the linking proccess
1836                      so the areas are set in the correct order, expecially _GSINIT */
1837                   for (s = setFirstItem (libDirsSet); s != NULL; s = setNextItem (libDirsSet))
1838                     {
1839                       dbuf_set_length (&crtpath, 0);
1840                       dbuf_printf (&crtpath, "%s%c%s", s, DIR_SEPARATOR_CHAR, *p);
1841 
1842                       if (!access (dbuf_c_str (&crtpath), 0))   /* Found it! */
1843                         {
1844                           /* append C runtime file to the crt list */
1845                           addSet (&crtSet, Safe_strdup (dbuf_c_str (&crtpath)));
1846                           break;
1847                         }
1848                     }
1849                   if (NULL == s)
1850                     {
1851                       /* not found in standard library directories, search in user defined library paths */
1852                       /* TODO: should crt be searched here at all? */
1853                       for (s = setFirstItem (libPathsSet); s != NULL; s = setNextItem (libPathsSet))
1854                         {
1855                           dbuf_set_length (&crtpath, 0);
1856                           dbuf_printf (&crtpath, "%s%c%s", s, DIR_SEPARATOR_CHAR, *p);
1857 
1858                           if (!access (dbuf_c_str (&crtpath), 0))       /* Found it! */
1859                             {
1860                               /* append C runtime file to the crt list */
1861                               addSet (&crtSet, Safe_strdup (dbuf_c_str (&crtpath)));
1862                               break;
1863                             }
1864                         }
1865                     }
1866                   if (NULL == s)
1867                     fprintf (stderr, "Warning: couldn't find %s\n", *p);
1868                 }
1869               dbuf_destroy (&crtpath);
1870             }
1871 
1872           /* Merge crtSet and relFilesSet */
1873           mergeSets (&crtSet, relFilesSet);
1874           relFilesSet = crtSet;
1875         }
1876 
1877       /* put in all object files */
1878       fputStrSet (lnkfile, relFilesSet);
1879 
1880       fprintf (lnkfile, "\n-e\n");
1881       fclose (lnkfile);
1882     }                           /* if(port->linker.needLinkerScript) */
1883 
1884   if (port->linker.cmd)
1885     {
1886       /* shell_escape file names */
1887       char *b3 = shell_escape (dbuf_c_str (&linkerScriptFileName));
1888       char *bfn = shell_escape (dbuf_c_str (&binFileName));
1889 
1890       buf = buildCmdLine (port->linker.cmd, b3, bfn, NULL, linkOptionsSet);
1891       Safe_free (b3);
1892       Safe_free (bfn);
1893     }
1894   else
1895     {
1896       buf = buildMacros (port->linker.mcmd);
1897     }
1898 
1899   dbuf_destroy (&linkerScriptFileName);
1900 
1901   tb = setPrefixSuffix (buf);
1902   if (options.verbose)
1903     printf ("sdcc: %s\n", tb);
1904   system_ret = sdcc_system (tb);
1905 
1906   /* if the binary file name is defined,
1907      rename the linker output file name to binary file name */
1908   if (fullDstFileName)
1909     {
1910       struct dbuf_s lkrFileName;
1911 
1912       dbuf_init (&lkrFileName, PATH_MAX);
1913       dbuf_append_str (&lkrFileName, dstFileName);
1914       dbuf_append_str (&lkrFileName, getOutFmtExt ());
1915 
1916       if (FILENAME_CMP (dbuf_c_str (&binFileName), dbuf_c_str (&lkrFileName)))
1917         remove (dbuf_c_str (&binFileName));
1918       rename (dbuf_c_str (&lkrFileName), dbuf_c_str (&binFileName));
1919 
1920       dbuf_destroy (&lkrFileName);
1921     }
1922 
1923   dbuf_destroy (&binFileName);
1924 
1925   if (system_ret)
1926     exit (EXIT_FAILURE);
1927 }
1928 
1929 /*-----------------------------------------------------------------*/
1930 /* assemble - spawns the assembler with arguments                  */
1931 /*-----------------------------------------------------------------*/
1932 static void
assemble(char ** envp)1933 assemble (char **envp)
1934 {
1935   struct dbuf_s asmName;
1936 
1937   if (port->assembler.do_assemble)
1938     {
1939       port->assembler.do_assemble (asmOptionsSet);
1940     }
1941   else
1942     {
1943       char *buf, *tb;
1944 
1945       /* build assembler output filename */
1946       dbuf_init (&asmName, PATH_MAX);
1947 
1948       /* -o option overrides default name? */
1949       if (options.cc_only && fullDstFileName)
1950         {
1951           dbuf_append_str (&asmName, fullDstFileName);
1952         }
1953       else
1954         {
1955           /* the assembled file gets the name of the first module */
1956           dbuf_printf (&asmName, "%s%s", dstFileName, port->linker.rel_ext);
1957         }
1958 
1959       if (port->assembler.cmd)
1960         {
1961           /* shell_escape file names */
1962           char *dfn = shell_escape (dstFileName);
1963           char *asmn = shell_escape (dbuf_c_str (&asmName));
1964 
1965           buf = buildCmdLine (port->assembler.cmd, dfn, asmn,
1966                     options.debug ? port->assembler.debug_opts : port->assembler.plain_opts, asmOptionsSet);
1967           Safe_free (dfn);
1968           Safe_free (asmn);
1969         }
1970       else
1971         {
1972           buf = buildMacros (port->assembler.mcmd);
1973         }
1974 
1975       dbuf_destroy (&asmName);
1976       tb = setPrefixSuffix (buf);
1977 
1978       if (options.verbose)
1979         printf ("sdcc: %s\n", tb);
1980       if (sdcc_system (tb))
1981         {
1982           Safe_free (buf);
1983           /* either system() or the assembler itself has reported an error */
1984           exit (EXIT_FAILURE);
1985         }
1986       Safe_free (buf);
1987 
1988       if (options.cc_only && fullDstFileName && TARGET_PIC_LIKE)
1989         {
1990           /* gpasm assembler doesn't properly handle the -o option:
1991              the file extension is replaced with .o,
1992              so sdcc have to rename the object file manually.
1993              This has been fixed in gpasm svn:
1994              http://sourceforge.net/tracker/?func=detail&aid=3018645&group_id=41924&atid=431665
1995              TODO: This code should be removed when the next gputils version
1996              after gpasm-0.13.7 beta will be released */
1997           struct dbuf_s outName;
1998           dbuf_init (&outName, PATH_MAX);
1999           dbuf_printf (&outName, "%s%s", dstFileName, port->linker.rel_ext);
2000 
2001           if (strcmp (dbuf_c_str (&outName), fullDstFileName))
2002             {
2003               /* file names are different: rename the genatated object file */
2004               remove (fullDstFileName);
2005               rename (dbuf_c_str (&outName), fullDstFileName);
2006             }
2007           dbuf_destroy (&outName);
2008         }
2009     }
2010 }
2011 
2012 /*-----------------------------------------------------------------*/
2013 /* preProcess - spawns the preprocessor with arguments             */
2014 /*-----------------------------------------------------------------*/
2015 static int
preProcess(char ** envp)2016 preProcess (char **envp)
2017 {
2018   if (options.c1mode)
2019     {
2020       yyin = stdin;
2021     }
2022   else
2023     {
2024       const char *s;
2025       set *inclList = NULL;
2026       char *buf;
2027 
2028       if (NULL != port->linker.rel_ext)
2029         {
2030           struct dbuf_s dbuf;
2031 
2032           dbuf_init (&dbuf, 256);
2033           dbuf_printf (&dbuf, "-obj-ext=%s", port->linker.rel_ext);
2034           addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2035         }
2036 
2037       if (options.dependencyFileOpt)
2038         {
2039           struct dbuf_s dbuf;
2040 
2041           dbuf_init (&dbuf, PATH_MAX);
2042           if (options.dependencyFileOpt == SYSTEM_DEPENDENCY_FILE_OPT)
2043             dbuf_append_str (&dbuf, "-MD ");
2044           else
2045             dbuf_append_str (&dbuf, "-MMD ");
2046           if (fullDstFileName)
2047             dbuf_splitFile (fullDstFileName, &dbuf, NULL);
2048           else
2049             dbuf_append_str (&dbuf, dstFileName);
2050           dbuf_append_str (&dbuf, ".d");
2051           addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2052 
2053           dbuf_init (&dbuf, PATH_MAX);
2054           if (fullDstFileName)
2055             dbuf_printf (&dbuf, "-MT %s", fullDstFileName);
2056           else
2057             dbuf_printf (&dbuf, "-MT %s%s", dstFileName, port->linker.rel_ext);
2058           addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2059         }
2060 
2061       /* if using dollar signs in identifiers */
2062       if (options.dollars_in_ident)
2063         addSet (&preArgvSet, Safe_strdup ("-fdollars-in-identifiers"));
2064 
2065       /* if using external stack define the macro */
2066       if (options.useXstack)
2067         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_USE_XSTACK"));
2068 
2069       /* set the macro for stack autos  */
2070       if (options.stackAuto)
2071         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_STACK_AUTO"));
2072 
2073       /* set the macro for stack autos  */
2074       if (options.stack10bit)
2075         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_STACK_TENBIT"));
2076 
2077       /* set the macro for no overlay  */
2078       if (options.noOverlay)
2079         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_NOOVERLAY"));
2080 
2081       /* set the macro for unsigned char  */
2082       if (options.signed_char)
2083         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_CHAR_SIGNED"));
2084       else
2085         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_CHAR_UNSIGNED"));
2086 
2087       /* set the macro for non-free  */
2088       if (options.use_non_free)
2089         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_USE_NON_FREE"));
2090 
2091       /* set the macro for large model  */
2092       switch (options.model)
2093         {
2094         case MODEL_LARGE:
2095           addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_LARGE"));
2096           break;
2097 
2098         case MODEL_SMALL:
2099           addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_SMALL"));
2100           break;
2101 
2102         case MODEL_COMPACT:
2103           addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_COMPACT"));
2104           break;
2105 
2106         case MODEL_MEDIUM:
2107           addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_MEDIUM"));
2108           break;
2109 
2110         case MODEL_HUGE:
2111           addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_HUGE"));
2112           break;
2113 
2114         case MODEL_FLAT24:
2115           addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_FLAT24"));
2116           break;
2117 
2118         case NO_MODEL:
2119           break;
2120 
2121         default:
2122           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
2123           break;
2124         }
2125 
2126       /* set macro corresponding to compiler option */
2127       if (options.intlong_rent)
2128         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_INT_LONG_REENT"));
2129 
2130       /* set macro corresponding to compiler option */
2131       if (options.float_rent)
2132         addSet (&preArgvSet, Safe_strdup ("-D__SDCC_FLOAT_REENT"));
2133 
2134       if (options.all_callee_saves)
2135         addSet(&preArgvSet, Safe_strdup("-D__SDCC_ALL_CALLEE_SAVES"));
2136 
2137       /* add SDCC version number */
2138       {
2139         struct dbuf_s dbuf;
2140 
2141         dbuf_init (&dbuf, 32);
2142         dbuf_printf (&dbuf, "-D__SDCC=%d_%d_%d", SDCC_VERSION_HI, SDCC_VERSION_LO, SDCC_VERSION_P);
2143         addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2144       }
2145       {
2146         struct dbuf_s dbuf;
2147 
2148         dbuf_init (&dbuf, 32);
2149         dbuf_printf (&dbuf, "-D__SDCC_VERSION_MAJOR=%d", SDCC_VERSION_HI);
2150         addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2151       }
2152       {
2153         struct dbuf_s dbuf;
2154 
2155         dbuf_init (&dbuf, 32);
2156         dbuf_printf (&dbuf, "-D__SDCC_VERSION_MINOR=%d", SDCC_VERSION_LO);
2157         addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2158       }
2159       {
2160         struct dbuf_s dbuf;
2161 
2162         dbuf_init (&dbuf, 32);
2163         dbuf_printf (&dbuf, "-D__SDCC_VERSION_PATCH=%d", SDCC_VERSION_P);
2164         addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2165       }
2166 
2167       /* A macro that has been deprecated since 3.2.0,
2168         since its name makes it non-compliant.
2169         It got removed a few times, but keeps coming back.
2170         This time it got added back for the 3.7.0 release
2171         to support the old SiLabs IDE */
2172       if (TARGET_IS_MCS51 && options.std_sdcc)
2173         {
2174           struct dbuf_s dbuf;
2175 
2176           dbuf_init (&dbuf, 32);
2177           dbuf_printf (&dbuf, "-DSDCC=%d%d%d", SDCC_VERSION_HI, SDCC_VERSION_LO, SDCC_VERSION_P);
2178           addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2179         }
2180 
2181       /* add SDCC revision number */
2182       {
2183         struct dbuf_s dbuf;
2184 
2185         dbuf_init (&dbuf, 20);
2186         dbuf_printf (&dbuf, "-D__SDCC_REVISION=%s", getBuildNumber ());
2187         addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
2188       }
2189 
2190       /* add port (processor information to processor */
2191       addSet (&preArgvSet, Safe_strdup ("-D__SDCC_{port}"));
2192 
2193       /* Optional C features not (yet) supported by SDCC */
2194       addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_COMPLEX__=1"));
2195       addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_THREADS__=1"));
2196       addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_ATOMICS__=1"));
2197       addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_VLA__=1"));
2198 
2199       /* Character encoding  - these need to be set in device/lib/Makefile.in for $CPP, too */
2200       addSet (&preArgvSet, Safe_strdup ("-D__STDC_ISO_10646__=201409L")); // wchar_t is UTF-32
2201       addSet (&preArgvSet, Safe_strdup ("-D__STDC_UTF_16__=1")); // char16_t is UTF-16
2202       addSet (&preArgvSet, Safe_strdup ("-D__STDC_UTF_32__=1")); // char32_t is UTF-32
2203 
2204       /* standard include path */
2205       if (!options.nostdinc)
2206         {
2207           inclList = processStrSet (includeDirsSet, "-isystem ", NULL, shell_escape);
2208           mergeSets (&preArgvSet, inclList);
2209         }
2210 
2211       setMainValue ("cppextraopts", (s = joinStrSet (preArgvSet)));
2212       Safe_free ((void *) s);
2213       if (inclList != NULL)
2214         deleteSet (&inclList);
2215 
2216       if (preProcOnly && fullDstFileName)
2217         {
2218           /* -E and -o given */
2219           char *s = shell_escape (fullDstFileName);
2220 
2221           setMainValue ("cppoutfilename", s);
2222           Safe_free (s);
2223         }
2224       else
2225         {
2226           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
2227           setMainValue ("cppoutfilename", NULL);
2228         }
2229 
2230       if (options.verbose)
2231         printf ("sdcc: Calling preprocessor...\n");
2232       buf = buildMacros (_preCmd);
2233       buf = setPrefixSuffix (buf);
2234       if (options.verbose)
2235         printf ("sdcc: %s\n", buf);
2236 
2237       if (preProcOnly)
2238         {
2239           if (sdcc_system (buf))
2240             {
2241               exit (EXIT_FAILURE);
2242             }
2243 
2244           exit (EXIT_SUCCESS);
2245         }
2246 
2247       yyin = sdcc_popen (buf);
2248       if (yyin == NULL)
2249         {
2250           perror ("Preproc file not found");
2251           exit (EXIT_FAILURE);
2252         }
2253     }
2254 
2255   return 0;
2256 }
2257 
2258 /* Set bin paths */
2259 static void
setBinPaths(const char * argv0)2260 setBinPaths (const char *argv0)
2261 {
2262   const char *p;
2263 
2264   /*
2265    * Search logic:
2266    *
2267    * 1. - $SDCCDIR/PREFIX2BIN_DIR
2268    * 2. - path(argv[0])
2269    * 3. - $PATH
2270    */
2271 
2272   /* do it in reverse mode, so that addSetHead() can be used
2273      instead of slower addSet() */
2274 
2275   if ((p = getBinPath (argv0)) != NULL)
2276     addSetHead (&binPathSet, (void *) p);
2277 
2278   if ((p = getenv (SDCC_DIR_NAME)) != NULL)
2279     {
2280       struct dbuf_s dbuf;
2281 
2282       dbuf_init (&dbuf, PATH_MAX);
2283       dbuf_append_str (&dbuf, p);
2284       dbuf_append_str (&dbuf, PREFIX2BIN_DIR);
2285       addSetHead (&binPathSet, dbuf_detach_c_str (&dbuf));
2286     }
2287 }
2288 
2289 /* Set system include path */
2290 static void
setIncludePath(void)2291 setIncludePath (void)
2292 {
2293   /*
2294    * Search logic:
2295    *
2296    *  1. - $SDCC_INCLUDE/target
2297    *  2. - $SDCC_INCLUDE
2298    *  3. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX/target
2299    *  4. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX/target
2300    *  5. - DATADIR/INCLUDE_DIR_SUFFIX/target (only on *nix)
2301    *  6. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
2302    *  7. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
2303    *  8. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
2304    *  9. - $SDCC_HOME/PREFIX2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX/target
2305    * 10. - path(argv[0])/BIN2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX/target
2306    * 11. - DATADIR/NON_FREE_INCLUDE_DIR_SUFFIX/target (only on *nix)
2307    * 12. - $SDCC_HOME/PREFIX2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX
2308    * 13. - path(argv[0])/BIN2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX
2309    * 14. - DATADIR/NON_FREE_INCLUDE_DIR_SUFFIX (only on *nix)
2310    */
2311 
2312   if (!options.nostdinc)
2313     {
2314       char *p;
2315       set *tempSet;
2316 
2317       tempSet = processStrSet (dataDirsSet, NULL, INCLUDE_DIR_SUFFIX, NULL);
2318       includeDirsSet = processStrSet (tempSet, NULL, DIR_SEPARATOR_STRING, NULL);
2319       includeDirsSet = processStrSet (includeDirsSet, NULL, port->target, NULL);
2320       mergeSets (&includeDirsSet, tempSet);
2321 
2322       if (options.use_non_free)
2323         {
2324           set *tempSet1;
2325 
2326           tempSet = processStrSet (dataDirsSet, NULL, NON_FREE_INCLUDE_DIR_SUFFIX, NULL);
2327           tempSet1 = processStrSet (tempSet, NULL, DIR_SEPARATOR_STRING, NULL);
2328           tempSet1 = processStrSet (tempSet1, NULL, port->target, NULL);
2329           mergeSets (&tempSet1, tempSet);
2330           mergeSets (&includeDirsSet, tempSet1);
2331         }
2332 
2333       if ((p = getenv (SDCC_INCLUDE_NAME)) != NULL)
2334         {
2335           struct dbuf_s dbuf;
2336 
2337           dbuf_init (&dbuf, PATH_MAX);
2338           addSetHead (&includeDirsSet, p);
2339           dbuf_makePath (&dbuf, p, port->target);
2340           addSetHead (&includeDirsSet, dbuf_detach (&dbuf));
2341         }
2342     }
2343 }
2344 
2345 /* Set system lib path */
2346 static void
setLibPath(void)2347 setLibPath (void)
2348 {
2349   /*
2350    * Search logic:
2351    *
2352    * 1. - $SDCC_LIB/<model>
2353    * 2. - $SDCC_LIB
2354    * 3. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
2355    * 4. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
2356    * 5. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
2357    * 6. - $SDCC_HOME/PREFIX2DATA_DIR/NON_FREE_LIB_DIR_SUFFIX/<model>
2358    * 7. - path(argv[0])/BIN2DATA_DIR/NON_FREE_LIB_DIR_SUFFIX/<model>
2359    * 8. - DATADIR/NON_FREE_LIB_DIR_SUFFIX/<model> (only on *nix)
2360    */
2361 
2362   if (!options.nostdlib)
2363     {
2364       char *p;
2365       const char *targetname;
2366 
2367       struct dbuf_s dbuf;
2368 
2369       dbuf_init (&dbuf, PATH_MAX);
2370 
2371       targetname = port->target;
2372 
2373       dbuf_makePath (&dbuf, LIB_DIR_SUFFIX, port->general.get_model ? port->general.get_model () : targetname);
2374       libDirsSet = processStrSet (dataDirsSet, NULL, dbuf_c_str (&dbuf), NULL);
2375 
2376       if (options.use_non_free)
2377         {
2378           dbuf_set_length (&dbuf, 0);
2379           dbuf_makePath (&dbuf, NON_FREE_LIB_DIR_SUFFIX, port->general.get_model ? port->general.get_model () : targetname);
2380           mergeSets (&libDirsSet, processStrSet (dataDirsSet, NULL, dbuf_c_str (&dbuf), NULL));
2381         }
2382 
2383       if ((p = getenv (SDCC_LIB_NAME)) != NULL)
2384         {
2385           addSetHead (&libDirsSet, Safe_strdup (p));
2386 
2387           dbuf_set_length (&dbuf, 0);
2388           dbuf_makePath (&dbuf, p, port->general.get_model ? port->general.get_model () : targetname);
2389           addSetHead (&libDirsSet, dbuf_detach (&dbuf));
2390         }
2391       else
2392         dbuf_destroy (&dbuf);
2393     }
2394 }
2395 
2396 /* Set data path */
2397 static void
setDataPaths(const char * argv0)2398 setDataPaths (const char *argv0)
2399 {
2400   const char *p;
2401 
2402   /*
2403    * Search logic:
2404    *
2405    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
2406    * 2. - path(argv[0])/BIN2DATA_DIR
2407    * 3. - DATADIR (only on *nix)
2408    */
2409 
2410   if ((p = getenv (SDCC_DIR_NAME)) != NULL)
2411     {
2412       struct dbuf_s dbuf;
2413 
2414       dbuf_init (&dbuf, PATH_MAX);
2415       dbuf_append_str (&dbuf, p);
2416       dbuf_append_str (&dbuf, PREFIX2DATA_DIR);
2417       addSetHead (&dataDirsSet, dbuf_detach_c_str (&dbuf));
2418     }
2419 
2420   if ((p = getBinPath (argv0)) != NULL)
2421     {
2422       struct dbuf_s dbuf;
2423 
2424       dbuf_init (&dbuf, PATH_MAX);
2425       dbuf_append_str (&dbuf, p);
2426       dbuf_append_str (&dbuf, BIN2DATA_DIR);
2427       addSetHead (&dataDirsSet, dbuf_detach_c_str (&dbuf));
2428     }
2429 
2430 #ifdef _WIN32
2431   if (peekSet (dataDirsSet) == NULL)
2432     {
2433       /* this should never happen... */
2434       wassertl (0, "Can't get binary path");
2435     }
2436 #else
2437   addSet (&dataDirsSet, Safe_strdup (DATADIR));
2438 #endif
2439 
2440   setIncludePath ();
2441   setLibPath ();
2442 }
2443 
2444 static void
initValues(void)2445 initValues (void)
2446 {
2447   char *s;
2448 
2449   populateMainValues (_baseValues);
2450   setMainValue ("port", port->target);
2451   setMainValue ("objext", port->linker.rel_ext);
2452   setMainValue ("asmext", port->assembler.file_ext);
2453 
2454   setMainValue ("dstfilename", dstFileName);
2455 
2456   s = fullSrcFileName ? shell_escape (fullSrcFileName) : "fullsrcfilename";
2457   setMainValue ("fullsrcfilename", s);
2458   if (fullSrcFileName)
2459     Safe_free (s);
2460 
2461   if (options.cc_only && fullDstFileName)
2462     /* compile + assemble and -o given: -o specifies name of object file */
2463     {
2464       setMainValue ("objdstfilename", fullDstFileName);
2465     }
2466   else
2467     {
2468       setMainValue ("objdstfilename", "{stdobjdstfilename}");
2469     }
2470   if (fullDstFileName)
2471     /* if we're linking, -o gives the final file name */
2472     {
2473       setMainValue ("linkdstfilename", fullDstFileName);
2474     }
2475   else
2476     {
2477       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
2478     }
2479 
2480   /*
2481    * Make sure the preprocessor is called with the "-std" option
2482    * corresponding to the --std used to start sdcc
2483    */
2484   setMainValue ("cppstd",
2485     options.std_c11 ? "-std=c11 " :
2486     (options.std_c99 ? "-std=c99 " :
2487     (options.std_c95 ? "-std=iso9899:199409 " :
2488     "-std=c89 ")));
2489 }
2490 
2491 static void
doPrintSearchDirs(void)2492 doPrintSearchDirs (void)
2493 {
2494   const char *s;
2495 
2496   printf ("programs:\n");
2497   fputStrSet (stdout, binPathSet);
2498 
2499   printf ("datadir:\n");
2500   fputStrSet (stdout, dataDirsSet);
2501 
2502   printf ("includedir:\n");
2503   fputStrSet (stdout, includeDirsSet);
2504 
2505   printf ("libdir:\n");
2506   for (s = setFirstItem (libDirsSet); s != NULL; s = setNextItem (libDirsSet))
2507     fprintf (stdout, "%s\n", s);
2508 
2509   printf ("libpath:\n");
2510   fputStrSet (stdout, libPathsSet);
2511 }
2512 
2513 
2514 static void
sig_handler(int signal)2515 sig_handler (int signal)
2516 {
2517   char *sig_string;
2518 
2519   switch (signal)
2520     {
2521     case SIGABRT:
2522       sig_string = "SIGABRT";
2523       break;
2524 
2525     case SIGTERM:
2526       sig_string = "SIGTERM";
2527       break;
2528 
2529     case SIGINT:
2530       sig_string = "SIGINT";
2531       break;
2532 
2533     case SIGSEGV:
2534       sig_string = "SIGSEGV";
2535       break;
2536 
2537     default:
2538       sig_string = "Unknown?";
2539       break;
2540     }
2541   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
2542   exit (EXIT_FAILURE);
2543 }
2544 
2545 /*
2546  * main routine
2547  * initialises and calls the parser
2548  */
2549 
2550 int
main(int argc,char ** argv,char ** envp)2551 main (int argc, char **argv, char **envp)
2552 {
2553   /* get the prefix and the suffix of the sdcc command */
2554   getPrefixSuffix (argv[0]);
2555 
2556   /* set a larger stack size of a running sdcc process to 4MB */
2557   setStackSize ();
2558 
2559   /* turn all optimizations off by default */
2560   memset (&optimize, 0, sizeof (struct optimize));
2561 
2562   if (NUM_PORTS == 0)
2563     {
2564       fprintf (stderr, "Build error: no ports are enabled.\n");
2565       exit (EXIT_FAILURE);
2566     }
2567 
2568   /* install signal handler;
2569      it's only purpose is to call exit() to remove temp files */
2570   if (!getenv ("SDCC_LEAVE_SIGNALS"))
2571     {
2572       signal (SIGABRT, sig_handler);
2573       signal (SIGTERM, sig_handler);
2574       signal (SIGINT, sig_handler);
2575       signal (SIGSEGV, sig_handler);
2576     }
2577 
2578   /* Before parsing the command line options, do a
2579    * search for the port and processor and initialize
2580    * them if they're found. (We can't gurantee that these
2581    * will be the first options specified).
2582    */
2583 
2584   _findPort (argc, argv);
2585 
2586 #ifdef JAMIN_DS390
2587   if (strcmp (port->target, "mcs51") == 0)
2588     {
2589       printf ("DS390 jammed in A\n");
2590       _setPort ("ds390");
2591       ds390_jammed = 1;
2592     }
2593 #endif
2594 
2595   _findProcessor (argc, argv);
2596 
2597   /* Initalise the port. */
2598   if (port->init)
2599     port->init ();
2600 
2601   setDefaultOptions ();
2602 #ifdef JAMIN_DS390
2603   if (ds390_jammed)
2604     {
2605       options.model = MODEL_SMALL;
2606       options.stack10bit = 0;
2607     }
2608 #endif
2609 
2610   parseCmdLine (argc, argv);
2611 
2612   if (options.verbose && NULL != port->processor)
2613     printf ("Processor: %s\n", port->processor);
2614 
2615   initValues ();
2616 
2617   setBinPaths (argv[0]);
2618   setDataPaths (argv[0]);
2619 
2620   if (port->initPaths)
2621     port->initPaths ();
2622 
2623   if (options.printSearchDirs)
2624     doPrintSearchDirs ();
2625 
2626   /* if no input then printUsage & exit */
2627   if (!options.c1mode && !fullSrcFileName && peekSet (relFilesSet) == NULL)
2628     {
2629       if (options.printSearchDirs)
2630         exit (EXIT_SUCCESS);
2631       printUsage (TRUE);
2632       exit (EXIT_FAILURE);
2633     }
2634 
2635   /* initMem() is expensive, but
2636      initMem() must called before port->finaliseOptions ().
2637      And the z80 port needs port->finaliseOptions(),
2638      even if we're only linking. */
2639   initMem ();
2640 
2641   /* finalize target specific options */
2642   port->finaliseOptions ();
2643 
2644   /* finalize common options */
2645   finalizeOptions ();
2646 
2647   if (fullSrcFileName || options.c1mode)
2648     {
2649       preProcess (envp);
2650 
2651       initSymt ();
2652       initiCode ();
2653       initCSupport ();
2654       initBuiltIns ();
2655       initPeepHole ();
2656 
2657       if (options.verbose)
2658         printf ("sdcc: Generating code...\n");
2659 
2660       yyparse ();
2661 
2662       if (!options.c1mode)
2663         if (sdcc_pclose (yyin))
2664           fatalError = 1;
2665 
2666       if (fatalError)
2667         exit (EXIT_FAILURE);
2668 
2669       if (port->general.do_glue != NULL)
2670         (*port->general.do_glue) ();
2671       else
2672         {
2673           /* this shouldn't happen */
2674           assert (FALSE);
2675           /* in case of NDEBUG */
2676           glue ();
2677         }
2678 
2679       if (fatalError)
2680         exit (EXIT_FAILURE);
2681 
2682       if (!options.c1mode && !noAssemble)
2683         {
2684           if (options.verbose)
2685             printf ("sdcc: Calling assembler...\n");
2686           assemble (envp);
2687         }
2688     }
2689   closeDumpFiles ();
2690 
2691   if (options.debug && debugFile)
2692     debugFile->closeFile ();
2693 
2694   if (!options.cc_only && !fatalError && !noAssemble && !options.c1mode && (fullSrcFileName || peekSet (relFilesSet) != NULL))
2695     {
2696       if (options.verbose)
2697         printf ("sdcc: Calling linker...\n");
2698 
2699       if (port->linker.do_link)
2700         port->linker.do_link ();
2701       else
2702         linkEdit (envp);
2703     }
2704 
2705   return 0;
2706 }
2707 
2708