* src/SDCCglobl.h,
[fw/sdcc] / src / SDCCmain.c
index 69cfb2ebf09066c2c02cea4182dd54bb33a7e384..d720ad8785a9f007972db9132ca63aa9c04a79f4 100644 (file)
@@ -1,5 +1,5 @@
 /*-------------------------------------------------------------------------
 /*-------------------------------------------------------------------------
-  SDCCmain.c - main file               
+  SDCCmain.c - main file
 
              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
 
 
              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
 
    under the terms of the GNU General Public License as published by the
    Free Software Foundation; either version 2, or (at your option) any
    later version.
    under the terms of the GNU General Public License as published by the
    Free Software Foundation; either version 2, or (at your option) any
    later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-   
+
    In other words, you are welcome to use, share and improve this program.
    You are forbidden to forbid anyone else to use, share and improve
    In other words, you are welcome to use, share and improve this program.
    You are forbidden to forbid anyone else to use, share and improve
-   what you give them.   Help stamp out software-hoarding!  
+   what you give them.   Help stamp out software-hoarding!
 -------------------------------------------------------------------------*/
 
 -------------------------------------------------------------------------*/
 
-//#define USE_SYSTEM_SYSTEM_CALLS
+#ifdef _WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
 
 
+#include <signal.h>
 #include "common.h"
 #include <ctype.h>
 #include "newalloc.h"
 #include "common.h"
 #include <ctype.h>
 #include "newalloc.h"
+#include "dbuf_string.h"
 #include "SDCCerr.h"
 #include "SDCCerr.h"
-
-#if NATIVE_WIN32
+#include "BuildCmd.h"
+#include "MySystem.h"
+#include "SDCCmacro.h"
+#include "SDCCutil.h"
+#include "SDCCdebug.h"
+#include "SDCCargs.h"
+
+#ifdef _WIN32
 #include <process.h>
 #else
 #include <process.h>
 #else
-#include "spawn.h"
-#endif
-
-// This is a bit messy because we define link ourself
-#if !defined(__BORLANDC__) && !defined(_MSC_VER)
-
+#include <sys/stat.h>
 #include <unistd.h>
 #include <unistd.h>
+#endif
 
 
-#else
-// No unistd.h in Borland C++
-extern int access(const char *, int);
-#define X_OK 1
+/* REMOVE ME!!! */
+extern int yyparse (void);
+
+FILE *srcFile;                  /* source file          */
+char *fullSrcFileName;          /* full name for the source file; */
+                                /* can be NULL while c1mode or linking without compiling */
+char *fullDstFileName;          /* full name for the output file; */
+                                /* only given by -o, otherwise NULL */
+char *dstFileName;              /* destination file name without extension */
+char *dstPath = "";             /* path for the output files; */
+                                /* "" is equivalent with cwd */
+char *moduleNameBase;           /* module name base is source file without path and extension */
+                                /* can be NULL while linking without compiling */
+char *moduleName;               /* module name is same as module name base, but with all */
+                                /* non-alphanumeric characters replaced with underscore */
+int currRegBank = 0;
+int RegBankUsed[4] = {1, 0, 0, 0}; /*JCF: Reg Bank 0 used by default*/
+int BitBankUsed;                /* MB: overlayable bit bank */
+struct optimize optimize;
+struct options options;
+int preProcOnly = 0;
+int noAssemble = 0;
+set *preArgvSet = NULL;         /* pre-processor arguments  */
+set *asmOptionsSet = NULL;      /* set of assembler options */
+set *linkOptionsSet = NULL;     /* set of linker options */
+set *libFilesSet = NULL;
+set *libPathsSet = NULL;
+set *relFilesSet = NULL;
+set *dataDirsSet = NULL;        /* list of data search directories */
+set *includeDirsSet = NULL;     /* list of include search directories */
+set *userIncDirsSet = NULL;     /* list of user include directories */
+set *libDirsSet = NULL;         /* list of lib search directories */
+
+/* uncomment JAMIN_DS390 to always override and use ds390 port
+  for mcs51 work.  This is temporary, for compatibility testing. */
+/* #define JAMIN_DS390 */
+#ifdef JAMIN_DS390
+int ds390_jammed = 0;
+#endif
 
 
+/* Globally accessible scratch buffer for file names.
+   TODO: replace them with local buffers */
+char scratchFileName[PATH_MAX];
+char buffer[PATH_MAX * 2];
+
+#define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
+
+#define OPTION_HELP             "--help"
+#define OPTION_STACK_8BIT       "--stack-8bit"
+#define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
+#define OPTION_OUT_FMT_S19      "--out-fmt-s19"
+#define OPTION_LARGE_MODEL      "--model-large"
+#define OPTION_MEDIUM_MODEL     "--model-medium"
+#define OPTION_SMALL_MODEL      "--model-small"
+#define OPTION_FLAT24_MODEL     "--model-flat24"
+#define OPTION_DUMP_ALL         "--dumpall"
+#define OPTION_PEEP_FILE        "--peep-file"
+#define OPTION_LIB_PATH         "--lib-path"
+#define OPTION_CALLEE_SAVES     "--callee-saves"
+#define OPTION_STACK_LOC        "--stack-loc"
+#define OPTION_XSTACK_LOC       "--xstack-loc"
+#define OPTION_DATA_LOC         "--data-loc"
+#define OPTION_IDATA_LOC        "--idata-loc"
+#define OPTION_XRAM_LOC         "--xram-loc"
+#define OPTION_CODE_LOC         "--code-loc"
+#define OPTION_STACK_SIZE       "--stack-size"
+#define OPTION_IRAM_SIZE        "--iram-size"
+#define OPTION_XRAM_SIZE        "--xram-size"
+#define OPTION_CODE_SIZE        "--code-size"
+#define OPTION_VERSION          "--version"
+#define OPTION_NO_LABEL_OPT     "--nolabelopt"
+#define OPTION_NO_LOOP_INV      "--noinvariant"
+#define OPTION_NO_LOOP_IND      "--noinduction"
+#define OPTION_LESS_PEDANTIC    "--less-pedantic"
+#define OPTION_DISABLE_WARNING  "--disable-warning"
+#define OPTION_NO_GCSE          "--nogcse"
+#define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
+#define OPTION_TINI_LIBID       "--tini-libid"
+#define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
+#define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
+#define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
+#define OPTION_PRINT_SEARCH_DIRS "--print-search-dirs"
+#define OPTION_MSVC_ERROR_STYLE "--vc"
+#define OPTION_USE_STDOUT       "--use-stdout"
+#define OPTION_PACK_IRAM        "--pack-iram"
+#define OPTION_NO_PACK_IRAM     "--no-pack-iram"
+#define OPTION_NO_PEEP_COMMENTS "--no-peep-comments"
+#define OPTION_NO_GEN_COMMENTS  "--no-gen-comments"
+#define OPTION_OPT_CODE_SPEED   "--opt-code-speed"
+#define OPTION_OPT_CODE_SIZE    "--opt-code-size"
+#define OPTION_STD_C89          "--std-c89"
+#define OPTION_STD_C99          "--std-c99"
+#define OPTION_STD_SDCC89       "--std-sdcc89"
+#define OPTION_STD_SDCC99       "--std-sdcc99"
+#define OPTION_CODE_SEG         "--codeseg"
+#define OPTION_CONST_SEG        "--constseg"
+#define OPTION_DOLLARS_IN_IDENT "--fdollars-in-identifiers"
+#define OPTION_UNSIGNED_CHAR    "--funsigned-char"
+
+static const OPTION
+optionsTable[] = {
+    { 0,    NULL,                   NULL, "General options" },
+    { 0,    OPTION_HELP,            NULL, "Display this help" },
+    { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
+    { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
+    { 'V',  NULL,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
+    { 'd',  NULL,                   NULL, NULL },
+    { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
+    { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
+    { 'A',  NULL,                   NULL, NULL },
+    { 'U',  NULL,                   NULL, NULL },
+    { 'C',  NULL,                   NULL, "Preprocessor option" },
+    { 'M',  NULL,                   NULL, "Preprocessor option" },
+    { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
+    { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
+    { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
+    { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
+    { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code." },
+    { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
+    { 0,    OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
+    { 0,    OPTION_MSVC_ERROR_STYLE, &options.vc_err_style, "messages are compatible with Micro$oft visual studio"},
+    { 0,    OPTION_USE_STDOUT,      NULL, "send errors to stdout instead of stderr"},
+    { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
+    { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
+    { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
+    { 0,    OPTION_DISABLE_WARNING, NULL, "<nnnn> Disable specific warning" },
+    { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
+    { 0,    "--cyclomatic",         &options.cyclomatic, "Display complexity of compiled functions" },
+    { 0,    OPTION_STD_C89,         NULL, "Use C89 standard only" },
+    { 0,    OPTION_STD_SDCC89,      NULL, "Use C89 standard with SDCC extensions (default)" },
+    { 0,    OPTION_STD_C99,         NULL, "Use C99 standard only (incomplete)" },
+    { 0,    OPTION_STD_SDCC99,      NULL, "Use C99 standard with SDCC extensions (incomplete)" },
+    { 0,    OPTION_DOLLARS_IN_IDENT, &options.dollars_in_ident, "Permit '$' as an identifier character" },
+    { 0,    OPTION_UNSIGNED_CHAR,   &options.unsigned_char, "Make \"char\" unsigned by default" },
+
+    { 0,    NULL,                   NULL, "Code generation options"},
+    { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
+    { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
+    { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
+    { 0,    OPTION_MEDIUM_MODEL,    NULL, "external paged data space is used" },
+    { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
+#if !OPT_DISABLE_DS390
+    { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
+    { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
+    { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
+#endif
+    { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
+    { 0,    "--xstack",             &options.useXstack, "Use external stack" },
+    { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
+    { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the float support functions" },
+    { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
+    { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
+    { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
+    { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
+    { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
+    { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
+#if !OPT_DISABLE_DS390
+    { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
+#endif
+    { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
+#if !OPT_DISABLE_TININative
+    { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
+#endif
+#if !OPT_DISABLE_DS390
+    { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
+#endif
+#if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51
+    { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
+#endif
+    { 0,    OPTION_NO_XINIT_OPT,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
+    { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
+    { 0,    OPTION_NO_PEEP_COMMENTS, &options.noPeepComments, "don't include peephole optimizer comments"},
+    { 0,    OPTION_NO_GEN_COMMENTS, &options.noGenComments, "don't include code generator comments"},
+#if !OPT_DISABLE_Z80 || !OPT_DISABLE_GBZ80
+    { 0,    "--no-std-crt0", &options.no_std_crt0, "For the z80/gbz80 do not link default crt0.o"},
+#endif
+    { 0,    OPTION_SHORT_IS_8BITS,  NULL, "Make short 8 bits (for old times sake)" },
+    { 0,    OPTION_CODE_SEG,        NULL, "<name> use this name for the code segment" },
+    { 0,    OPTION_CONST_SEG,       NULL, "<name> use this name for the const segment" },
+
+    { 0,    NULL,                   NULL, "Optimization options"},
+    { 0,    "--nooverlay",          &options.noOverlay, "Disable overlaying leaf function auto variables" },
+    { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
+    { 0,    OPTION_NO_LABEL_OPT,    NULL, "Disable label optimisation" },
+    { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
+    { 0,    OPTION_NO_LOOP_IND,     NULL, "Disable loop variable induction" },
+    { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
+    { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
+    { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
+    { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
+    { 0,    "--peep-asm",           &options.asmpeep, "Enable peephole optimization on inline assembly" },
+    { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peephole file" },
+    { 0,    OPTION_OPT_CODE_SPEED,  NULL, "Optimize for code speed rather than size" },
+    { 0,    OPTION_OPT_CODE_SIZE,   NULL, "Optimize for code size rather than speed" },
+
+    { 0,    NULL,                   NULL, "Internal debugging options"},
+    { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
+    { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
+    { 0,    "--dumploop",           &options.dump_loop, NULL },
+    { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
+    { 0,    "--dumpliverange",      &options.dump_range, NULL },
+    { 0,    "--dumpregpack",        &options.dump_pack, NULL },
+    { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
+    { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
+    { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
+    { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
+
+    { 0,    NULL,                   NULL, "Linker options" },
+    { 'l',  NULL,                   NULL, "Include the given library in the link" },
+    { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
+    { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
+    { 0,    OPTION_OUT_FMT_IHX,     NULL, "Output in Intel hex format" },
+    { 0,    OPTION_OUT_FMT_S19,     NULL, "Output in S19 hex format" },
+    { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
+    { 0,    OPTION_XRAM_SIZE,       NULL, "<nnnn> External Ram size" },
+    { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
+    { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Stack start location" },
+    { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
+    { 0,    OPTION_CODE_SIZE,       NULL, "<nnnn> Code Segment size" },
+    { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
+    { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
+    { 0,    OPTION_IDATA_LOC,       NULL, NULL },
+#if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51 || !OPT_DISABLE_PIC
+    { 0,    OPTION_STACK_SIZE,      NULL,"MCS51/DS390/PIC - Tells the linker to allocate this space for stack"},
+#endif
+#if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51
+    { 0,    OPTION_PACK_IRAM,       NULL,"MCS51/DS390 - Tells the linker to pack variables in internal ram (default)"},
+    { 0,    OPTION_NO_PACK_IRAM,    &options.no_pack_iram,"MCS51/DS390 - Tells the linker not to pack variables in internal ram"},
 #endif
 
 #endif
 
-//REMOVE ME!!!
-extern int yyparse();
-
-FILE  *srcFile         ;/* source file          */
-FILE  *cdbFile = NULL  ;/* debugger information output file */
-char  *fullSrcFileName ;/* full name for the source file */
-char  *srcFileName     ;/* source file name with the .c stripped */
-char  *moduleName      ;/* module name is srcFilename stripped of any path */
-const char *preArgv[128]          ;/* pre-processor arguments  */
-int   currRegBank = 0 ;
-struct optimize optimize ;
-struct options  options ;
-char *VersionString = SDCC_VERSION_STR /*"Version 2.1.8a"*/;
-short preProcOnly = 0;
-short noAssemble = 0;
-char *linkOptions[128];
-const char *asmOptions[128];
-char *libFiles[128] ;
-int nlibFiles = 0;
-char *libPaths[128] ;
-int nlibPaths = 0;
-char *relFiles[128];
-int nrelFiles = 0;
-bool verboseExec = FALSE;
-char    *preOutName;
-
-// In MSC VC6 default search path for exe's to path for this
-
-#if defined(_MSC_VER)
-
-char DefaultExePath[_MAX_PATH] ;
+    /* End of options */
+    { 0,    NULL }
+};
 
 
-#endif
+/** Table of all unsupported options and help text to display when one
+    is used.
+*/
+typedef struct {
+    /** shortOpt as in OPTIONS. */
+    char shortOpt;
+    /** longOpt as in OPTIONS. */
+    const char *longOpt;
+    /** Message to display inside W_UNSUPPORTED_OPT when this option
+        is used. */
+    const char *message;
+} UNSUPPORTEDOPT;
+
+static const UNSUPPORTEDOPT
+unsupportedOptTable[] = {
+    { 'X',  NULL,       "use --xstack-loc instead" },
+    { 'x',  NULL,       "use --xstack instead" },
+    { 'i',  NULL,       "use --idata-loc instead" },
+    { 'r',  NULL,       "use --xdata-loc instead" },
+    { 's',  NULL,       "use --code-loc instead" },
+    { 'Y',  NULL,       "use -I instead" }
+};
 
 
-/* Far functions, far data */
-#define OPTION_LARGE_MODEL "-model-large"
-/* Far functions, near data */
-#define OPTION_MEDIUM_MODEL "-model-medium"
-#define OPTION_SMALL_MODEL "-model-small"
-#define OPTION_FLAT24_MODEL "-model-flat24"
-#define OPTION_STACK_AUTO  "-stack-auto"
-#define OPTION_STACK_10BIT "-stack-10bit"
-#define OPTION_XSTACK      "-xstack"
-#define OPTION_GENERIC     "-generic"
-#define OPTION_NO_GCSE     "-nogcse"
-#define OPTION_NO_LOOP_INV "-noinvariant"
-#define OPTION_NO_LOOP_IND "-noinduction"
-#define OPTION_NO_JTBOUND  "-nojtbound"
-#define OPTION_NO_LOOPREV  "-noloopreverse"
-#define OPTION_XREGS       "-regextend"
-#define OPTION_COMP_ONLY   "-compile-only"
-#define OPTION_DUMP_RAW    "-dumpraw"
-#define OPTION_DUMP_GCSE   "-dumpgcse"
-#define OPTION_DUMP_LOOP   "-dumploop"
-#define OPTION_DUMP_KILL   "-dumpdeadcode"
-#define OPTION_DUMP_RANGE  "-dumpliverange"
-#define OPTION_DUMP_PACK   "-dumpregpack"
-#define OPTION_DUMP_RASSGN "-dumpregassign"
-#define OPTION_DUMP_ALL    "-dumpall"
-#define OPTION_XRAM_LOC    "-xram-loc"
-#define OPTION_IRAM_SIZE   "-iram-size"
-#define OPTION_XSTACK_LOC  "-xstack-loc"
-#define OPTION_CODE_LOC    "-code-loc"
-#define OPTION_STACK_LOC   "-stack-loc"
-#define OPTION_DATA_LOC    "-data-loc"
-#define OPTION_IDATA_LOC   "-idata-loc"
-#define OPTION_PEEP_FILE   "-peep-file"
-#define OPTION_LIB_PATH    "-lib-path"
-#define OPTION_INTLONG_RENT "-int-long-reent"
-#define OPTION_FLOAT_RENT  "-float-reent"
-#define OPTION_OUT_FMT_IHX "-out-fmt-ihx"
-#define OPTION_OUT_FMT_S19 "-out-fmt-s19"
-#define OPTION_CYCLOMATIC  "-cyclomatic"
-#define OPTION_NOOVERLAY   "-nooverlay"
-#define OPTION_MAINRETURN  "-main-return"
-#define OPTION_NOPEEP      "-no-peep"
-#define OPTION_ASMPEEP     "-peep-asm"
-#define OPTION_DEBUG       "-debug"
-#define OPTION_NODEBUG    "-nodebug"
-#define OPTION_VERSION     "-version"
-#define OPTION_STKAFTRDATA "-stack-after-data"
-#define OPTION_PREPROC_ONLY "-preprocessonly"
-#define OPTION_C1_MODE   "-c1mode"
-#define OPTION_HELP         "-help"
-#define OPTION_CALLEE_SAVES "-callee-saves"
-#define OPTION_NOREGPARMS   "-noregparms"
-#define OPTION_NOSTDLIB     "-nostdlib"
-#define OPTION_NOSTDINC     "-nostdinc"
-#define OPTION_VERBOSE      "-verbose"
-#define OPTION_ANSIINT     "-ansiint"
-static const char *_preCmd[] = {
-    "sdcpp", "-Wall", "-lang-c++", "-DSDCC=1", 
-    "$l", "-I" SDCC_INCLUDE_DIR, "$1", "$2", NULL
+/** List of all default constant macros.
+ */
+static const char *_baseValues[] = {
+  "cpp", "sdcpp",
+  "cppextraopts", "",
+  /* Path seperator character */
+  "sep", DIR_SEPARATOR_STRING,
+  NULL
 };
 
 };
 
+static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
+
 PORT *port;
 
 PORT *port;
 
-static PORT *_ports[] = {
+static PORT *_ports[] =
+{
 #if !OPT_DISABLE_MCS51
 #if !OPT_DISABLE_MCS51
-   &mcs51_port,
+  &mcs51_port,
 #endif
 #if !OPT_DISABLE_GBZ80
 #endif
 #if !OPT_DISABLE_GBZ80
-    &gbz80_port,
+  &gbz80_port,
 #endif
 #if !OPT_DISABLE_Z80
 #endif
 #if !OPT_DISABLE_Z80
-    &z80_port,
+  &z80_port,
 #endif
 #if !OPT_DISABLE_AVR
 #endif
 #if !OPT_DISABLE_AVR
-    &avr_port,
+  &avr_port,
 #endif
 #if !OPT_DISABLE_DS390
 #endif
 #if !OPT_DISABLE_DS390
-    &ds390_port,
+  &ds390_port,
+#endif
+#if !OPT_DISABLE_PIC16
+  &pic16_port,
 #endif
 #if !OPT_DISABLE_PIC
 #endif
 #if !OPT_DISABLE_PIC
-    &pic14_port,
+  &pic_port,
 #endif
 #endif
-#if !OPT_DISABLE_I186
-   &i186_port,
+#if !OPT_DISABLE_TININative
+  &tininative_port,
 #endif
 #endif
-#if !OPT_DISABLE_TLCS900H
-   &tlcs900h_port,
+#if !OPT_DISABLE_XA51
+  &xa51_port,
+#endif
+#if !OPT_DISABLE_DS400
+  &ds400_port,
+#endif
+#if !OPT_DISABLE_HC08
+  &hc08_port,
 #endif
 };
 
 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
 
 #endif
 };
 
 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
 
-/**
-   remove me - TSD a hack to force sdcc to generate gpasm format .asm files.
- */
-extern void             pic14glue();
-
 /** Sets the port to the one given by the command line option.
 /** Sets the port to the one given by the command line option.
-    @param             The name minus the option (eg 'mcs51')
-    @return            0 on success.
+    @param    The name minus the option (eg 'mcs51')
+    @return     0 on success.
 */
 */
-static int _setPort(const char *name)
+static void
+_setPort (const char *name)
 {
 {
-    int i;
-    for (i=0; i<NUM_PORTS; i++) {
-       if (!strcmp(_ports[i]->target, name)) {
-           port = _ports[i];
-           return 0;
-       }
+  int i;
+  for (i = 0; i < NUM_PORTS; i++)
+    {
+      if (!strcmp (_ports[i]->target, name))
+        {
+          port = _ports[i];
+          return;
+        }
     }
     }
-    /* Error - didnt find */
-    werror(E_UNKNOWN_TARGET,name);
-    exit(1);
+  /* Error - didnt find */
+  werror (E_UNKNOWN_TARGET, name);
+  exit (1);
 }
 
 }
 
-static void _validatePorts(void)
+/* Override the default processor with the one specified
+ * on the command line */
+static void
+_setProcessor (char *_processor)
 {
 {
-    int i;
-    for (i=0; i<NUM_PORTS; i++) {
-       if (_ports[i]->magic != PORT_MAGIC) {
-           printf("Error: port %s is incomplete.\n", _ports[i]->target);
-           wassert(0);
-       }
+  port->processor = _processor;
+}
+
+static void
+_validatePorts (void)
+{
+  int i;
+  for (i = 0; i < NUM_PORTS; i++)
+    {
+      if (_ports[i]->magic != PORT_MAGIC)
+        {
+          /* Uncomment this line to debug which port is causing the problem
+           * (the target name is close to the beginning of the port struct
+           * and probably can be accessed just fine). */
+          fprintf(stderr,"%s :",_ports[i]->target);
+          wassertl (0, "Port definition structure is incomplete");
+        }
     }
 }
 
     }
 }
 
-#ifdef USE_SYSTEM_SYSTEM_CALLS
-void buildCmdLine(char *into, const char **cmds, 
-                         const char *p1, const char *p2, 
-                         const char *p3, const char **list)
+/* search through the command line options for the port */
+static void
+_findPort (int argc, char **argv)
 {
 {
-    const char *p, *from;
-
-    *into = '\0';
-
-    while (*cmds) {
-
-       from = *cmds;
-       cmds++;
-
-       /* See if it has a '$' anywhere - if not, just copy */
-       if ((p = strchr(from, '$'))) {
-           strncat(into, from, p - from);
-           /* seperate it */
-           strcat(into, " ");
-           from = p+2;
-           p++;
-           switch (*p) {
-           case '1':
-               if (p1)
-                   strcat(into, p1);
-               break;
-           case '2':
-               if (p2)
-                   strcat(into, p2);
-               break;
-           case '3':
-               if (p3)
-                   strcat(into, p3);
-               break;
-           case 'l': {
-               const char **tmp = list;
-               if (tmp) {
-                   while (*tmp) {
-                       strcat(into, *tmp);
-                       strcat(into, " ");
-                       tmp++;
-                   }
-               }
-               break;
-           }
-           default:
-               assert(0);
-           }
-       }
-       strcat(into, from); // this includes the ".asm" from "$1.asm"
-       strcat(into, " ");
+  _validatePorts ();
+
+  while (argc--)
+    {
+      if (!strncmp (*argv, "-m", 2))
+        {
+          _setPort (*argv + 2);
+          return;
+        }
+      argv++;
     }
     }
+
+  /* Use the first in the list */
+  port = _ports[0];
 }
 }
-#else
-void buildCmdLine(char *into, char **args, const char **cmds, 
-                         const char *p1, const char *p2, 
-                         const char *p3, const char **list)
+
+/* search through the command line options for the processor */
+static void
+_findProcessor (int argc, char **argv)
 {
 {
-    const char *p, *from;
-
-    while (*cmds) {
-       *args = into;
-       args++;
-
-       from = *cmds;
-       cmds++;
-       *into = '\0';
-
-       /* See if it has a '$' anywhere - if not, just copy */
-       if ((p = strchr(from, '$'))) {
-           strncpy(into, from, p - from);
-           /* NULL terminate it */
-           into[p-from] = '\0';
-           from = p+2;
-           p++;
-           switch (*p) {
-           case '1':
-               if (p1)
-                   strcat(into, p1);
-               break;
-           case '2':
-               if (p2)
-                   strcat(into, p2);
-               break;
-           case '3':
-               if (p3)
-                   strcat(into, p3);
-               break;
-           case 'l': {
-               const char **tmp = list;
-               if (tmp) {
-                   while (*tmp) {
-                       strcpy(into, *tmp);
-                       into += strlen(into)+1;
-                       *args = into;
-                       args++;
-                       tmp++;
-                   }
-               }
-               break;
-           }
-           default:
-               assert(0);
-           }
-       }
-       strcat(into, from);
-       if (strlen(into) == 0)
-           args--;
-       into += strlen(into)+1;
+  while (argc--)
+    {
+      if (!strncmp (*argv, "-p", 2))
+        {
+          _setProcessor (*argv + 2);
+          return;
+        }
+      argv++;
     }
     }
-    *args = NULL;
+
+  /* no error if processor was not specified. */
 }
 }
-#endif
 
 /*-----------------------------------------------------------------*/
 
 /*-----------------------------------------------------------------*/
-/* printVersionInfo - prints the version info                     */
+/* printVersionInfo - prints the version info        */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-void   printVersionInfo ()
+void
+printVersionInfo (FILE *stream)
 {
 {
-    int i;
-    
-    fprintf (stderr,
-            "SDCC : ");
-    for (i=0; i<NUM_PORTS; i++)
-       fprintf(stderr, "%s%s", i==0 ? "" : "/", _ports[i]->target);
-    fprintf(stderr, " %s"
+  int i;
+
+  fprintf (stream,
+           "SDCC : ");
+  for (i = 0; i < NUM_PORTS; i++)
+    fprintf (stream, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
+
+  fprintf (stream, " " SDCC_VERSION_STR
 #ifdef SDCC_SUB_VERSION_STR
 #ifdef SDCC_SUB_VERSION_STR
-           "/" SDCC_SUB_VERSION_STR
+           "/" SDCC_SUB_VERSION_STR
 #endif
 #endif
-           " ` "
-#ifdef __CYGWIN32__
-               " (CYGWIN32)\n"
+           " #%s (" __DATE__ ")"
+#ifdef __CYGWIN__
+           " (CYGWIN)\n"
+#elif defined __MINGW32__
+           " (MINGW32)\n"
+#elif defined __DJGPP__
+           " (DJGPP)\n"
+#elif defined(_MSC_VER)
+           " (MSVC)\n"
+#elif defined(__BORLANDC__)
+           " (BORLANDC)\n"
 #else
 #else
-# ifdef __DJGPP__
-               " (DJGPP) \n"
-# else
-               " (UNIX) \n"
-# endif
+           " (UNIX) \n"
 #endif
 #endif
+    , getBuildNumber() );
+}
 
 
-           , VersionString
-           );
+static void
+printOptions(const OPTION *optionsTable, FILE *stream)
+{
+  int i;
+  for (i = 0;
+       optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL
+       || optionsTable[i].help != NULL;
+       i++)
+    {
+      if (!optionsTable[i].shortOpt && !optionsTable[i].longOpt
+          && optionsTable[i].help)
+        {
+          fprintf (stream, "\n%s:\n", optionsTable[i].help);
+        }
+      else
+        {
+          fprintf(stream, "  %c%c  %-20s  %s\n",
+                  optionsTable[i].shortOpt !=0 ? '-' : ' ',
+                  optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
+                  optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
+                  optionsTable[i].help != NULL ? optionsTable[i].help : ""
+                  );
+        }
+    }
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
-/* printUsage - prints command line syntax                        */
+/* printUsage - prints command line syntax         */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-void   printUsage ()
+static void
+printUsage (void)
 {
 {
-       printVersionInfo ();
-       fprintf (stderr,
-                "Usage : [options] filename\n"
-                "Options :-\n"
-                "\t-m<proc>             -     Target processor <proc>.  Default %s\n"
-                "\t                           Try --version for supported values of <proc>\n"
-                "\t--model-large        -     Large Model\n"
-                "\t--model-small        -     Small Model (default)\n"
-                "\t--stack-auto         -     Stack automatic variables\n"
-                "\t--xstack             -     Use external stack\n"
-                "\t--xram-loc <nnnn>    -     External Ram start location\n"
-                "\t--xstack-loc <nnnn>  -     Xternal Stack Location\n"
-                "\t--code-loc <nnnn>    -     Code Segment Location\n"
-                "\t--stack-loc <nnnn>   -     Stack pointer initial value\n"
-                "\t--data-loc <nnnn>    -     Direct data start location\n"
-                "\t--idata-loc <nnnn>   -     Indirect data start location\n"
-                "\t--iram-size <nnnn>   -     Internal Ram size\n"
-                "\t--nojtbound          -     Don't generate boundary check for jump tables\n"
-                "\t--generic            -     All unqualified ptrs converted to '_generic'\n"
-                "PreProcessor Options :-\n"
-                "\t-Dmacro             -       Define Macro\n"          
-                "\t-Ipath              -       Include \"*.h\" path\n"
-                "Note: this is NOT a complete list of options see docs for details\n",
-                _ports[0]->target
-                );             
-       exit (0);
+    int i;
+    FILE *stream = stderr;
+
+    printVersionInfo (stream);
+    fprintf (stream,
+             "Usage : sdcc [options] filename\n"
+             "Options :-\n"
+             );
+
+    printOptions (optionsTable, stream);
+
+    for (i = 0; i < NUM_PORTS; i++)
+      {
+        if (_ports[i]->poptions != NULL)
+          {
+            fprintf (stream, "\nSpecial options for the %s port:\n", _ports[i]->target);
+            printOptions (_ports[i]->poptions, stream);
+          }
+      }
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
-/* parseWithComma - separates string with comma                    */
+/* setParseWithComma - separates string with comma to a set        */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-void parseWithComma (char **dest,char *src)
+void
+setParseWithComma (set **dest, const char *src)
 {
 {
-    int i = 0;
-    
-    strtok(src,"\n \t");
-    /* skip the initial white spaces */
-    while (isspace(*src)) src++;
-    dest[i++] = src;
-    while (*src) {
-       if (*src == ',') {
-           *src = '\0';
-           src++;
-           if (*src)
-               dest[i++] = src;
-           continue ;
-       }
-       src++;
+  const char *p, *end;
+  struct dbuf_s dbuf;
+
+  /* skip the initial white spaces */
+  while (isspace((unsigned char)*src))
+    ++src;
+
+  /* skip the trailing white spaces */
+  end = &src[strlen(src) - 1];
+  while (end >= src && isspace((unsigned char)*end))
+    --end;
+  ++end;
+
+  p = src;
+  while (src < end)
+    {
+      dbuf_init (&dbuf, 16);
+
+      while (p < end && ',' != *p)
+        ++p;
+      dbuf_append (&dbuf, src, p - src);
+
+      /* null terminate the buffer */
+      dbuf_c_str (&dbuf);
+      addSet(dest, dbuf_detach (&dbuf));
+
+      src = ++p;
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* setDefaultOptions - sets the default options                    */
 /*-----------------------------------------------------------------*/
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* setDefaultOptions - sets the default options                    */
 /*-----------------------------------------------------------------*/
-static void setDefaultOptions()
+static void
+setDefaultOptions (void)
 {
 {
-    int i ;
-
-    for ( i = 0 ; i < 128 ; i++)
-       preArgv[i] = asmOptions [i] =
-           linkOptions[i] = relFiles[i] = libFiles[i] =
-           libPaths[i] = NULL ;
-
-    /* first the options part */
-    options.stack_loc = 0; /* stack pointer initialised to 0 */
-    options.xstack_loc= 0; /* xternal stack starts at 0 */
-    options.code_loc  = 0; /* code starts at 0 */
-    options.data_loc  = 0x0030; /* data starts at 0x0030 */
-    options.xdata_loc = 0;
-    options.idata_loc = 0x80;
-    options.genericPtr = 1;   /* default on */
-    options.nopeep    = 0;
-    options.model = port->general.default_model;
-    options.nostdlib=0;
-    options.nostdinc=0;
-    options.verbose=0;
-
-    /* now for the optimizations */
-    /* turn on the everything */
-    optimize.global_cse = 1;    
-    optimize.label1 = 1;
-    optimize.label2 = 1;
-    optimize.label3 = 1;
-    optimize.label4 = 1;    
-    optimize.loopInvariant = 1;
-    optimize.loopInduction = 1;
-
-    port->setDefaultOptions();
+  /* first the options part */
+  options.stack_loc = 0;          /* stack pointer initialised to 0 */
+  options.xstack_loc = 0;         /* xternal stack starts at 0 */
+  options.code_loc = 0;           /* code starts at 0 */
+  options.data_loc = 0;           /* JCF: By default let the linker locate data */
+  options.xdata_loc = 0;
+  options.idata_loc = 0;          /* MB: No need to limit idata to 0x80-0xFF */
+  options.nopeep = 0;
+  options.model = port->general.default_model;
+  options.nostdlib = 0;
+  options.nostdinc = 0;
+  options.verbose = 0;
+  options.shortis8bits = 0;
+  options.std_sdcc = 1;           /* enable SDCC language extensions */
+  options.std_c99 = 0;            /* default to C89 until more C99 support */
+  options.code_seg = CODE_NAME;   /* default to CSEG for generated code */
+  options.const_seg = CONST_NAME; /* default to CONST for generated code */
+
+  options.stack10bit=0;
+
+  /* now for the optimizations */
+  /* turn on the everything */
+  optimize.global_cse = 1;
+  optimize.label1 = 1;
+  optimize.label2 = 1;
+  optimize.label3 = 1;
+  optimize.label4 = 1;
+  optimize.loopInvariant = 1;
+  optimize.loopInduction = 1;
+
+  /* now for the ports */
+  port->setDefaultOptions ();
 }
 
 /*-----------------------------------------------------------------*/
 /* processFile - determines the type of file from the extension    */
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
 /* processFile - determines the type of file from the extension    */
 /*-----------------------------------------------------------------*/
-static void processFile (char *s)
+static void
+processFile (char *s)
 {
 {
-    char *fext = NULL;
-    
-    /* get the file extension */
-    fext = s + strlen(s);
-    while ((fext != s) && *fext != '.') fext--;
-    
-    /* now if no '.' then we don't know what the file type is
-       so give a warning and return */
-    if (fext == s) {
-       werror(W_UNKNOWN_FEXT,s);
-       return ;
+  const char *extp;
+  struct dbuf_s ext;
+  struct dbuf_s path;
+
+  dbuf_init (&ext, 128);
+  dbuf_init (&path, 128);
+
+  /* get the file extension.
+     If no '.' then we don't know what the file type is
+     so give a warning and return */
+  if (!dbuf_splitFile (s, &path, &ext))
+    {
+      werror (W_UNKNOWN_FEXT, s);
+
+      dbuf_destroy (&ext);
+      dbuf_destroy (&path);
+
+      return;
     }
 
     }
 
-    /* otherwise depending on the file type */
-    if (strcmp(fext,".c") == 0 || strcmp(fext,".C") == 0 || options.c1mode) {
-       /* source file name : not if we already have a 
-          source file */
-       if (srcFileName) {
-           werror(W_TOO_MANY_SRC,s);
-           return ;
-       }
-
-       /* the only source file */       
-       if (!(srcFile = fopen((fullSrcFileName = s),"r"))) {
-           werror(E_FILE_OPEN_ERR,s);
-           exit (1);
-       }
-       
-       /* copy the file name into the buffer */
-       strcpy(buffer,s);
-       
-       /* get rid of the "." */
-       strtok(buffer,".");
-       srcFileName = Safe_calloc(strlen(buffer)+1);
-       strcpy(srcFileName,buffer);
-
-       /* get rid of any path information 
-          for the module name; do this by going
-          backwards till we get to either '/' or '\' or ':'
-          or start of buffer */
-       fext = buffer + strlen(buffer);
-       while (fext != buffer && 
-              *(fext -1) != '\\'  &&
-              *(fext-1) != '/'   &&
-              *(fext-1) != ':')
-           fext--;
-       moduleName = Safe_calloc(strlen(fext)+1);
-       strcpy(moduleName,fext);
-       
-       return ;
+  /* otherwise depending on the file type */
+  extp = dbuf_c_str (&ext);
+  if (STRCASECMP (extp, ".c") == 0)
+    {
+      char *p;
+
+      dbuf_destroy (&ext);
+
+      /* source file name : not if we already have a
+         source file */
+      if (fullSrcFileName)
+        {
+          werror (W_TOO_MANY_SRC, s);
+
+          dbuf_destroy (&path);
+
+          return;
+        }
+
+      /* the only source file */
+      fullSrcFileName = s;
+      if (!(srcFile = fopen (fullSrcFileName, "r")))
+        {
+          werror (E_FILE_OPEN_ERR, s);
+
+          dbuf_destroy (&path);
+
+          exit (1);
+        }
+
+      /* get rid of any path information
+         for the module name; */
+      dbuf_init (&ext, 128);
+
+      dbuf_splitPath (dbuf_c_str (&path), NULL, &ext);
+      dbuf_destroy (&path);
+
+      moduleNameBase = Safe_strdup (dbuf_c_str (&ext));
+      moduleName = dbuf_detach (&ext);
+
+      for (p = moduleName; *p; ++p)
+        if (!isalnum ((unsigned char)*p))
+          *p = '_';
+      return;
     }
 
     }
 
-    /* if the extention is type .rel or .r or .REL or .R 
-       addtional object file will be passed to the linker */
-    if (strcmp(fext,".r") == 0 || strcmp(fext,".rel") == 0 ||
-       strcmp(fext,".R") == 0 || strcmp(fext,".REL") == 0 ||
-       strcmp(fext, port->linker.rel_ext) == 0)
-       {
-       relFiles[nrelFiles++] = s;
-       return ;
+  /* if the extention is type .rel or .r or .REL or .R
+     additional object file will be passed to the linker */
+  if (STRCASECMP (extp, ".r") == 0 || STRCASECMP (extp, ".rel") == 0 ||
+      strcmp (extp, port->linker.rel_ext) == 0)
+    {
+      dbuf_destroy (&ext);
+      dbuf_destroy (&path);
+
+      addSet (&relFilesSet, Safe_strdup (s));
+      return;
     }
 
     }
 
-    /* if .lib or .LIB */
-    if (strcmp(fext,".lib") == 0 || strcmp(fext,".LIB") == 0) {
-       libFiles[nlibFiles++] = s;
-       return;
+  /* if .lib or .LIB */
+  if (STRCASECMP (extp, ".lib") == 0)
+    {
+      dbuf_destroy (&ext);
+      dbuf_destroy (&path);
+
+      addSet (&libFilesSet, Safe_strdup (s));
+      return;
     }
 
     }
 
-    werror(W_UNKNOWN_FEXT,s);
-  
+  dbuf_destroy (&ext);
+  dbuf_destroy (&path);
+
+  werror (W_UNKNOWN_FEXT, s);
 }
 
 }
 
-static void _processC1Arg(char *s)
+static void
+_setModel (int model, const char *sz)
+{
+  if (port->general.supported_models & model)
+    options.model = model;
+  else
+    werror (W_UNSUPPORTED_MODEL, sz, port->target);
+}
+
+/** Gets the string argument to this option.  If the option is '--opt'
+    then for input of '--optxyz' or '--opt xyz' returns xyz.
+*/
+char *
+getStringArg(const char *szStart, char **argv, int *pi, int argc)
 {
 {
-    if (srcFileName) {
-       if (options.out_name) {
-           werror(W_TOO_MANY_SRC,s);
-           return;
-       }
-       options.out_name = strdup(s);
+  if (argv[*pi][strlen(szStart)])
+    {
+      return &argv[*pi][strlen(szStart)];
     }
     }
-    else {
-       processFile(s);
+  else
+    {
+      ++(*pi);
+      if (*pi >= argc)
+        {
+          werror (E_ARGUMENT_MISSING, szStart);
+          /* Die here rather than checking for errors later. */
+          exit (EXIT_FAILURE);
+        }
+      else
+        {
+          return argv[*pi];
+        }
     }
 }
 
     }
 }
 
-static void _addToList(const char **list, const char *str)
+/** Gets the integer argument to this option using the same rules as
+    getStringArg.
+*/
+int
+getIntArg(const char *szStart, char **argv, int *pi, int argc)
 {
 {
-    /* This is the bad way to do things :) */
-    while (*list)
-       list++;
-    *list = strdup(str);
-    if (!*list) {
-       werror(E_OUT_OF_MEM,__FILE__, 0);
-       exit (1);
+  return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
+}
+
+static void
+verifyShortOption(const char *opt)
+{
+  if (strlen(opt) != 2)
+    {
+      werror (W_EXCESS_SHORT_OPTIONS, opt);
     }
     }
-    *(++list) = NULL;
 }
 
 }
 
-static void _setModel(int model, const char *sz)
+static bool
+tryHandleUnsupportedOpt(char **argv, int *pi)
 {
 {
-    if (port->general.supported_models & model)
-       options.model = model;
-    else
-       werror(W_UNSUPPORTED_MODEL, sz, port->target);
+  if (argv[*pi][0] == '-')
+    {
+      const char *longOpt = "";
+      char shortOpt = -1;
+      int i;
+
+      if (argv[*pi][1] == '-')
+        {
+          /* Long option. */
+          longOpt = argv[*pi];
+        }
+      else
+        {
+          shortOpt = argv[*pi][1];
+        }
+      for (i = 0; i < LENGTH(unsupportedOptTable); i++)
+        {
+          if (unsupportedOptTable[i].shortOpt == shortOpt ||
+              (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt)))
+            {
+              /* Found an unsupported opt. */
+              char buffer[100];
+              SNPRINTF(buffer, sizeof(buffer),
+                "%s%c%c",
+                longOpt ? longOpt : "",
+                shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
+              werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
+              return 1;
+            }
+        }
+      /* Didn't find in the table */
+      return 0;
+    }
+  else
+    {
+      /* Not an option, so can't be unsupported :) */
+      return 0;
+    }
 }
 
 }
 
-/*-----------------------------------------------------------------*/
-/* parseCmdLine - parses the command line and sets the options     */
-/*-----------------------------------------------------------------*/
-int   parseCmdLine ( int argc, char **argv )
+static bool
+scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
 {
 {
-    int i ;      
-    char cdbfnbuf[50];
-
-    /* go thru all whole command line  */
-    for ( i = 1; i < argc; i++ ) {
-       if ( i >= argc )
-           break ;
-
-       /* options */
-       if (argv[i][0] == '-' && argv[i][1] == '-') {
-           
-           if (strcmp(&argv[i][1],OPTION_HELP) == 0) {
-               printUsage();
-                exit(0);
-           }       
-
-           if (strcmp(&argv[i][1],OPTION_XREGS) == 0) {
-               options.regExtend = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_LARGE_MODEL) == 0) {
-               _setModel(MODEL_LARGE, argv[i]);
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_MEDIUM_MODEL) == 0) {
-               _setModel(MODEL_MEDIUM, argv[i]);
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_SMALL_MODEL) == 0) {
-               _setModel(MODEL_SMALL, argv[i]);
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_FLAT24_MODEL) == 0) {
-               _setModel(MODEL_FLAT24, argv[i]);
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_STACK_10BIT) == 0) {
-               options.stack10bit = 1;
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_STACK_AUTO) == 0) {
-               options.stackAuto = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DUMP_RAW) == 0) {
-               options.dump_raw = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_CYCLOMATIC) == 0) {
-               options.cyclomatic = 1;
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_DUMP_GCSE) == 0) {
-               options.dump_gcse = 1;
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_DUMP_LOOP) == 0) {
-               options.dump_loop = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DUMP_KILL) == 0) {
-               options.dump_kill = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_INTLONG_RENT) == 0) {
-               options.intlong_rent = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_FLOAT_RENT) == 0) {
-               options.float_rent = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DUMP_RANGE) == 0) {
-               options.dump_range = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DUMP_PACK) == 0) {
-               options.dump_pack = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DUMP_RASSGN) == 0) {
-               options.dump_rassgn = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_OUT_FMT_IHX) == 0) {
-               options.out_fmt = 0;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_OUT_FMT_S19) == 0) {
-               options.out_fmt = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NOOVERLAY) == 0) {
-               options.noOverlay = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_STKAFTRDATA) == 0) {
-               options.stackOnData = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_PREPROC_ONLY) == 0) {
-               preProcOnly = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_C1_MODE) == 0) {
-               options.c1mode = 1;
-                continue;
-           }
-
-           
-           if (strcmp(&argv[i][1],OPTION_DUMP_ALL) == 0) {
-               options.dump_rassgn = 
-                options.dump_pack   =
-                options.dump_range  = 
-                options.dump_kill   = 
-                options.dump_loop   = 
-                options.dump_gcse   = 
-                options.dump_raw    = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_COMP_ONLY) == 0) {
-               options.cc_only = 1;
-                continue;
-           }
-   
-           if (strcmp(&argv[i][1],OPTION_GENERIC) == 0) {
-               options.genericPtr = 1;
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_NOPEEP) == 0) {
-               options.nopeep = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_ASMPEEP) == 0) {
-               options.asmpeep = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DEBUG) == 0) {
-               options.debug = 1;              
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NODEBUG) == 0) {
-               options.nodebug = 1;            
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NOREGPARMS) == 0) {
-               options.noregparms = 1;         
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_PEEP_FILE) == 0) {
-               if (argv[i][1+strlen(OPTION_PEEP_FILE)]) 
-                   options.peep_file = 
-                       &argv[i][1+strlen(OPTION_PEEP_FILE)];
-               else
-                   options.peep_file = argv[++i];
-               continue ;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_LIB_PATH) == 0) {
-               if (argv[i][1+strlen(OPTION_LIB_PATH)]) 
-                   libPaths[nlibPaths++] = 
-                       &argv[i][1+strlen(OPTION_PEEP_FILE)];
-               else
-                   libPaths[nlibPaths++] = argv[++i];
-               continue ;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_XSTACK_LOC) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_XSTACK_LOC)])
-                   options.xstack_loc = 
-                       (int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_XSTACK_LOC)]));
-                   else
-                       options.xstack_loc = 
-                           (int) floatFromVal(constVal(argv[++i]));
-               continue ;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_XSTACK) == 0) {
-               options.useXstack = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_MAINRETURN) == 0) {
-               options.mainreturn = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_CALLEE_SAVES) == 0) {
-               if (argv[i][1+strlen(OPTION_CALLEE_SAVES)])
-                   parseWithComma(options.calleeSaves
-                                  ,&argv[i][1+strlen(OPTION_CALLEE_SAVES)]);
-               else
-                   parseWithComma(options.calleeSaves,argv[++i]);
-                continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_STACK_LOC) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_STACK_LOC)])
-                   options.stack_loc = 
-                       (int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_STACK_LOC)]));
-                   else
-                       options.stack_loc = 
-                           (int) floatFromVal(constVal(argv[++i]));
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_XRAM_LOC) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_XRAM_LOC)])
-                   options.xdata_loc = 
-                       (unsigned int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_XRAM_LOC)]));
-                   else
-                       options.xdata_loc = 
-                           (unsigned int) floatFromVal(constVal(argv[++i]));
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_IRAM_SIZE) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_IRAM_SIZE)])
-                   options.iram_size = 
-                       (int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_IRAM_SIZE)]));
-                   else
-                       options.iram_size = 
-                           (int) floatFromVal(constVal(argv[++i]));
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_VERSION) == 0) {              
-               printVersionInfo();
-               exit(0);
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_DATA_LOC) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_DATA_LOC)])
-                   options.data_loc = 
-                       (int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_DATA_LOC)]));
-                   else
-                       options.data_loc = 
-                           (int) floatFromVal(constVal(argv[++i]));
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_IDATA_LOC) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_IDATA_LOC)])
-                   options.idata_loc = 
-                       (int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_IDATA_LOC)]));
-                   else
-                       options.idata_loc = 
-                           (int) floatFromVal(constVal(argv[++i]));
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_CODE_LOC) == 0) {
-               
-               if (argv[i][1+strlen(OPTION_CODE_LOC)])
-                   options.code_loc = 
-                       (int) floatFromVal(constVal(&argv[i][1+strlen(OPTION_CODE_LOC)]));
-                   else
-                       options.code_loc = 
-                           (int) floatFromVal(constVal(argv[++i]));
-               continue;
-           }
-
-           
-           if (strcmp(&argv[i][1],OPTION_NO_JTBOUND) == 0) {
-               optimize.noJTabBoundary = 1;
-                continue;
-           }
-           if (strcmp(&argv[i][1],OPTION_NO_GCSE) == 0) {
-               optimize.global_cse = 0;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NO_LOOP_INV) == 0) {
-               optimize.loopInvariant = 0;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NO_LOOP_IND) == 0) {
-               optimize.loopInduction = 0;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NO_LOOPREV) == 0) {
-               optimize.noLoopReverse = 1;
-                continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NOSTDLIB) == 0) {
-               options.nostdlib=1;
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_NOSTDINC) == 0) {
-               options.nostdinc=1;
-               continue;
-           }
-
-           if (strcmp(&argv[i][1],OPTION_VERBOSE) == 0) {
-               options.verbose=1;
-               continue;
-           }
-           
-           if (strcmp(&argv[i][1],OPTION_ANSIINT) == 0) {
-               options.ANSIint=1;
-               continue;
-           }       
-
-           if (!port->parseOption(&argc, argv, &i))
-           {
-               werror(W_UNKNOWN_OPTION,argv[i]);
-           }
-           else
-           {
-               continue;
-           }
-       }      
-
-       /* these are undocumented options */
-       /* if preceded by '/' then turn off certain optmizations, used
-          for debugging only these are also the legacy options from
-          version 1.xx will be removed gradually.
-          It may be an absolute filename.
-       */
-       if ( *argv[i] == '/' && strlen(argv[i]) < 3) {
-           switch (argv[i][1]) {
-               
-           case 'p':
-               optimize.ptrArithmetic=0;
-               break;
-
-           case 'L':
-               switch (argv[i][2]) {
-               case '\0':
-                   optimize.label1 = 
-                       optimize.label2 =
-                       optimize.label3 = 
-                       optimize.label4 = 0 ;
-                   break;
-               case '1':
-                   optimize.label1 = 0;
-                   break;
-               case '2':
-                   optimize.label2 = 0;
-                   break;
-               case '3':
-                   optimize.label3 = 0;
-                   break;
-               case '4':
-                   optimize.label4 = 0;
-                   break;
-               }
-               break;
-               
-           case 'l' :
-               switch (argv[i][2]) {               
-               case 'i' :
-                   optimize.loopInvariant = 0;
-                   break;
-               case 'n' :
-                   optimize.loopInduction = 0;
-                   break;
-
-
-               }
-               break ;
-           case 'g' :
-               optimize.global_cse = 0;
-               break;
-
-           }
-           continue ;
-       }
-
-       /* if preceded by  '-' then option */
-       if ( *argv[i] == '-' ) {
-           switch (argv[i][1]) {
-           case 'h'    :
-               printUsage();
-               exit(0);
-               break;
-               
-           case 'E':
-               preProcOnly = 1;
-               break;
-
-           case 'm':
-               /* Used to select the port */
-               if (_setPort(argv[i] + 2)) {
-                   werror(W_UNSUPP_OPTION,"-m","Unrecognised processor");
-               }
-               break;
-           
-           case 'a'    : 
-               werror(W_UNSUPP_OPTION,"-a","use --stack-auto instead");
-               break ;
-               
-           case 'g'    :
-               werror(W_UNSUPP_OPTION,"-g","use --generic instead");
-               break;
-                               
-           case 'X'    :       /* use external stack           */
-               werror(W_UNSUPP_OPTION,"-X","use --xstack-loc instead");
-               break ;
-               
-           case 'x'    :
-               werror(W_UNSUPP_OPTION,"-x","use --xstack instead");
-               break;
-               
-           case 'p'    :       /* stack pointer intial value */
-           case 'P'    :
-               werror(W_UNSUPP_OPTION,"-p","use --stack-loc instead");
-               break ;
-                               
-           case 'i'    :
-               werror(W_UNSUPP_OPTION,"-i","use --idata-loc instead");
-               break ;
-               
-           case 'r'    :
-               werror(W_UNSUPP_OPTION,"-r","use --xdata-loc instead");
-               break ;
-               
-           case 's'    :
-               werror(W_UNSUPP_OPTION,"-s","use --code-loc instead");
-               break ;         
-                               
-           case 'c':      
-               options.cc_only = 1;
-               break;  
-
-           case 'Y':
-               werror(W_UNSUPP_OPTION,"-Y","use -I instead");
-               break;
-               
-           case 'L' :
-               if (argv[i][2])
-                   libPaths[nlibPaths++] = &argv[i][2];
-               else
-                   libPaths[nlibPaths++] = argv[++i];
-               break;
-               
-           case 'W':
-               /* linker options */
-               if (argv[i][2] == 'l') {
-                   if (argv[i][3])
-                       parseWithComma(linkOptions,&argv[i][3]);
-                   else
-                       parseWithComma(linkOptions,argv[++i]);
-               } else {
-                   /* assembler options */
-                   if (argv[i][2] == 'a') {
-                       if (argv[i][3])
-                           parseWithComma((char **)asmOptions,&argv[i][3]);
-                       else
-                           parseWithComma((char **)asmOptions,argv[++i]);
-                       
-                   } else {
-                       werror(W_UNKNOWN_OPTION,argv[i]);                      
-                   }
-               }
-               break;
-           case 'S':
-               noAssemble = 1;
-               break;
-
-           case 'V':
-             verboseExec = TRUE;
-             break;
-
-           case 'v':
-               printVersionInfo();
-               exit(0);
-               break;
-
-               /* preprocessor options */              
-           case 'M':
-             {
-               preProcOnly=1;
-               _addToList(preArgv, "-M");
-               break;
-             }
-           case 'C':
-             {
-               _addToList(preArgv, "-C");
-               break;
-             }
-           case 'd':
-           case 'D':
-           case 'I':
-           case 'A':
-           case 'U':
-               {
-                   char sOpt = argv[i][1] ;
-                   char *rest ;
-                   
-                   if ( argv[i][2] == ' ' || argv[i][2] == '\0') {
-                       i++ ;
-                       rest = argv[i] ;
-                   }
-                   else
-                       rest = &argv[i][2] ;
-                   
-                   if ( argv[i][1] == 'Y' )
-                       argv[i][1] = 'I';
-
-                   sprintf(buffer, "-%c%s", sOpt, rest);
-                   _addToList(preArgv, buffer);
-               }
-               break ;
-
-           default:
-               if (!port->parseOption(&argc, argv, &i))
-                   werror(W_UNKNOWN_OPTION,argv[i]);
-           }
-           continue ;
-       }
-
-       if (!port->parseOption(&argc, argv, &i)) {
-           /* no option must be a filename */
-           if (options.c1mode)
-               _processC1Arg(argv[i]);
-           else
-               processFile(argv[i]);
-       }
-    }  
-
-    /* set up external stack location if not explicitly specified */
-    if ( !options.xstack_loc )
-       options.xstack_loc = options.xdata_loc ;
-
-    /* if debug option is set the open the cdbFile */
-    if (!options.nodebug && srcFileName) {
-       sprintf(cdbfnbuf,"%s.cdb",srcFileName);
-       if ((cdbFile = fopen(cdbfnbuf,"w")) == NULL)
-           werror(E_FILE_OPEN_ERR,cdbfnbuf);
-       else {
-           /* add a module record */
-           fprintf(cdbFile,"M:%s\n",moduleName);
-       }
+  int i;
+  for (i = 0;
+       optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL
+       || optionsTable[i].help != NULL;
+       i++)
+    {
+      if (optionsTable[i].shortOpt == shortOpt ||
+          (longOpt && optionsTable[i].longOpt &&
+           strcmp(optionsTable[i].longOpt, longOpt) == 0))
+        {
+
+          /* If it is a flag then we can handle it here */
+          if (optionsTable[i].pparameter != NULL)
+            {
+              if (optionsTable[i].shortOpt == shortOpt)
+                {
+                  verifyShortOption(argv[*pi]);
+                }
+
+              (*optionsTable[i].pparameter)++;
+              return 1;
+            }
+          else {
+            /* Not a flag.  Handled manually later. */
+            return 0;
+          }
+        }
     }
     }
-    return 0;
+  /* Didn't find in the table */
+  return 0;
+}
+
+static bool
+tryHandleSimpleOpt(char **argv, int *pi)
+{
+    if (argv[*pi][0] == '-')
+        {
+            const char *longOpt = "";
+            char shortOpt = -1;
+
+            if (argv[*pi][1] == '-')
+                {
+                    /* Long option. */
+                    longOpt = argv[*pi];
+                }
+            else
+                {
+                    shortOpt = argv[*pi][1];
+                }
+
+            if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
+              {
+                return 1;
+              }
+            else if (port && port->poptions &&
+                     scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
+              {
+                return 1;
+              }
+            else
+              {
+                return 0;
+              }
+        }
+    else
+        {
+            /* Not an option, so can't be handled. */
+            return 0;
+        }
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
-/* my_system - will call a program with arguments                  */
+/* parseCmdLine - parses the command line and sets the options     */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
+static int
+parseCmdLine (int argc, char **argv)
+{
+  int i;
 
 
-#if defined(_MSC_VER)
+  /* go thru all whole command line */
+  for (i = 1; i < argc; i++)
+    {
+      if (i >= argc)
+        break;
 
 
-char *try_dir[]= {DefaultExePath, NULL};                       // TODO : Fill in some default search list
+      if (tryHandleUnsupportedOpt(argv, &i) == TRUE)
+        {
+          continue;
+        }
 
 
-#else
+      if (tryHandleSimpleOpt(argv, &i) == TRUE)
+        {
+          continue;
+        }
 
 
-//char *try_dir[]= {SRCDIR "/bin",PREFIX "/bin", NULL};
-char *try_dir[]= {NULL};
+      /* options */
+      if (argv[i][0] == '-' && argv[i][1] == '-')
+        {
+          if (strcmp (argv[i], OPTION_USE_STDOUT) == 0)
+            {
+              if (options.use_stdout == 0)
+                {
+                  options.use_stdout = 1;
+                  dup2(STDOUT_FILENO, STDERR_FILENO);
+                }
+              continue;
+            }
+          if (strcmp (argv[i], OPTION_HELP) == 0)
+            {
+              printUsage ();
+              exit (EXIT_SUCCESS);
+            }
+
+          if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
+            {
+              options.stack10bit = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
+            {
+              options.out_fmt = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_OUT_FMT_S19) == 0)
+            {
+              options.out_fmt = 1;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
+            {
+              _setModel (MODEL_LARGE, argv[i]);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
+            {
+              _setModel (MODEL_MEDIUM, argv[i]);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
+            {
+              _setModel (MODEL_SMALL, argv[i]);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
+            {
+              _setModel (MODEL_FLAT24, argv[i]);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
+            {
+              options.dump_rassgn =
+                options.dump_pack =
+                options.dump_range =
+                options.dump_kill =
+                options.dump_loop =
+                options.dump_gcse =
+                options.dump_raw = 1;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
+            {
+              options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
+            {
+              addSet(&libPathsSet, Safe_strdup(getStringArg(OPTION_LIB_PATH, argv, &i, argc)));
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_VERSION) == 0)
+            {
+              printVersionInfo (stdout);
+              exit (EXIT_SUCCESS);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
+            {
+              setParseWithComma(&options.calleeSavesSet, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
+            {
+              options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
+            {
+              options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_STACK_SIZE) == 0)
+            {
+              options.stack_size = getIntArg(OPTION_STACK_SIZE, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
+            {
+              options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
+            {
+              options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
+            {
+              options.xram_size = getIntArg(OPTION_XRAM_SIZE, argv, &i, argc);
+              options.xram_size_set = TRUE;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
+            {
+              options.code_size = getIntArg(OPTION_CODE_SIZE, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
+            {
+              options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
+            {
+              options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
+            {
+              options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
+            {
+              optimize.global_cse = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
+            {
+              optimize.loopInvariant = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
+            {
+              optimize.label4 = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
+            {
+              optimize.loopInduction = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_OPT_CODE_SPEED) == 0)
+            {
+              optimize.codeSpeed = 1;
+              optimize.codeSize = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_OPT_CODE_SIZE) == 0)
+            {
+              optimize.codeSpeed = 0;
+              optimize.codeSize = 1;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0)
+            {
+              options.lessPedantic = 1;
+              setErrorLogLevel(ERROR_LEVEL_WARNING);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_DISABLE_WARNING) == 0)
+            {
+              int w = getIntArg(OPTION_DISABLE_WARNING, argv, &i, argc);
+              if (w < MAX_ERROR_WARNING)
+                {
+                  setWarningDisabled(w);
+                }
+              continue;
+            }
+
+          if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0)
+            {
+              options.shortis8bits=1;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
+            {
+              options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_STD_C89) == 0)
+            {
+              options.std_c99 = 0;
+              options.std_sdcc = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_STD_C99) == 0)
+            {
+              options.std_c99 = 1;
+              options.std_sdcc = 0;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_STD_SDCC89) == 0)
+            {
+              options.std_c99 = 0;
+              options.std_sdcc = 1;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_STD_SDCC99) == 0)
+            {
+              options.std_c99 = 1;
+              options.std_sdcc = 1;
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_CODE_SEG) == 0)
+            {
+              struct dbuf_s segname;
+
+              dbuf_init (&segname, 16);
+              dbuf_printf (&segname, "%-8s(CODE)", getStringArg (OPTION_CODE_SEG, argv, &i, argc));
+              options.code_seg = dbuf_detach (&segname);
+              continue;
+            }
+
+          if (strcmp (argv[i], OPTION_CONST_SEG) == 0)
+            {
+              struct dbuf_s segname;
+
+              dbuf_init (&segname, 16);
+              dbuf_printf (&segname, "%-8s(CODE)", getStringArg (OPTION_CONST_SEG, argv, &i, argc));
+              options.const_seg = dbuf_detach (&segname);
+              continue;
+            }
+
+          if (!port->parseOption (&argc, argv, &i))
+            {
+              werror (W_UNKNOWN_OPTION, argv[i]);
+              continue;
+            }
+          else
+            {
+              continue;
+            }
+        }
 
 
-#endif
+      /* if preceded by  '-' then option */
+      if (*argv[i] == '-')
+        {
+          switch (argv[i][1])
+            {
+            case 'h':
+              verifyShortOption(argv[i]);
+
+              printUsage ();
+              exit (EXIT_SUCCESS);
+              break;
+
+            case 'm':
+              /* Used to select the port. But this has already been done. */
+              break;
+
+            case 'p':
+              /* Used to select the processor in port. But this has
+               * already been done. */
+              break;
+
+            case 'c':
+              verifyShortOption(argv[i]);
+
+              options.cc_only = 1;
+              break;
+
+            case 'L':
+                addSet(&libPathsSet, Safe_strdup(getStringArg("-L", argv, &i, argc)));
+                break;
+
+            case 'l':
+                addSet(&libFilesSet, Safe_strdup(getStringArg("-l", argv, &i, argc)));
+                break;
+
+            case 'o':
+              {
+                char *outName = getStringArg("-o", argv, &i, argc);
+                size_t len = strlen(outName);
+
+                /* point to last character */
+                if (IS_DIR_SEPARATOR(outName[len - 1]))
+                  {
+                    /* only output path specified */
+                    dstPath = Safe_malloc(len);
+                    memcpy(dstPath, outName, len - 1);
+                    dstPath[len - 1] = '\0';
+                    fullDstFileName = NULL;
+                  }
+                else
+                  {
+                    struct dbuf_s path;
+
+                    dbuf_init (&path, 128);
+                    fullDstFileName = Safe_strdup (outName);
+
+                    /* get rid of the "."-extension */
+                    dbuf_splitFile (outName, &path, NULL);
+
+                    dbuf_c_str (&path);
+                    dstFileName = dbuf_detach (&path);
+
+                    dbuf_init (&path, 128);
+                    /* strip module name to get path */
+                    if (dbuf_splitPath (dstFileName, &path, NULL))
+                      {
+                        dbuf_c_str (&path);
+                        dstPath = dbuf_detach (&path);
+                      }
+                    else
+                      dbuf_destroy (&path);
+                  }
+                break;
+              }
+
+            case 'W':
+              /* pre-processer options */
+              if (argv[i][2] == 'p')
+                {
+                  setParseWithComma(&preArgvSet, getStringArg("-Wp", argv, &i, argc));
+                }
+              /* linker options */
+              else if (argv[i][2] == 'l')
+                {
+                  setParseWithComma(&linkOptionsSet, getStringArg("-Wl", argv, &i, argc));
+                }
+              /* assembler options */
+              else if (argv[i][2] == 'a')
+                {
+                  setParseWithComma(&asmOptionsSet, getStringArg("-Wa", argv, &i, argc));
+                }
+              else
+                {
+                  werror (W_UNKNOWN_OPTION, argv[i]);
+                }
+              break;
+
+            case 'v':
+              verifyShortOption(argv[i]);
+
+              printVersionInfo (stdout);
+              exit (0);
+              break;
+
+              /* preprocessor options */
+            case 'M':
+              {
+                preProcOnly = 1;
+                if (argv[i][2] == 'M')
+                  addSet(&preArgvSet, Safe_strdup("-MM"));
+                else
+                  addSet(&preArgvSet, Safe_strdup("-M"));
+                break;
+              }
+            case 'C':
+              {
+                addSet(&preArgvSet, Safe_strdup("-C"));
+                break;
+              }
+
+            case 'd':
+            case 'D':
+            case 'I':
+            case 'A':
+            case 'U':
+              {
+                char sOpt = argv[i][1];
+                char *rest;
+
+                if (argv[i][2] == ' ' || argv[i][2] == '\0')
+                  {
+                    i++;
+                    if (i >= argc)
+                      {
+                        /* No argument. */
+                        werror(E_ARGUMENT_MISSING, argv[i-1]);
+                        break;
+                      }
+                    else
+                      {
+                        rest = argv[i];
+                      }
+                  }
+                else
+                  rest = &argv[i][2];
+
+                if (sOpt == 'Y')
+                  sOpt = 'I';
+
+                SNPRINTF (buffer, sizeof(buffer),
+                  ((sOpt == 'I') ? "-%c\"%s\"": "-%c%s"), sOpt, rest);
+                addSet(&preArgvSet, Safe_strdup(buffer));
+                if(sOpt == 'I') {
+                  addSet(&includeDirsSet, Safe_strdup(rest));
+                  addSet(&userIncDirsSet, Safe_strdup(rest));
+                }
+              }
+              break;
+
+            default:
+              if (!port->parseOption (&argc, argv, &i))
+                werror (W_UNKNOWN_OPTION, argv[i]);
+            }
+          continue;
+        }
 
 
-#ifdef USE_SYSTEM_SYSTEM_CALLS
-int my_system (const char *cmd)
-{    
-  int argsStart, e, i=0;
-  char *cmdLine=NULL;
-
-  argsStart=strstr(cmd, " ")-cmd;
-  
-  // try to find the command in predefined path's
-  while (try_dir[i]) {
-    cmdLine = (char*)malloc(strlen(try_dir[i])+strlen(cmd)+10);
-    strcpy(cmdLine, try_dir[i]); // the path
-    strcat(cmdLine, "/");
-    strncat(cmdLine, cmd, argsStart); // the command
-#if NATIVE_WIN32
-    strcat(cmdLine, ".exe");
-    /* Mung slashes into backslashes to keep WIndoze happy. */
-    {
-      char *r=cmdLine;
-      while (*r) {
-       if (*r == '/') {
-         *r = '\\';
-       }
-       r++;
-      }
-    }
-#endif
-    if (access(cmdLine, X_OK) == 0) {
-      // the arguments
-      strcat(cmdLine, cmd+argsStart);
-      break;
+      if (!port->parseOption (&argc, argv, &i))
+        {
+          /* no option must be a filename */
+          if (options.c1mode)
+            {
+              werror (W_NO_FILE_ARG_IN_C1, argv[i]);
+            }
+          else
+            {
+              processFile (argv[i]);
+            }
+        }
     }
     }
-    free(cmdLine);
-    cmdLine=NULL;
-    i++;
-  }
-  
-  if (verboseExec) {
-    printf ("+ %s\n", cmdLine ? cmdLine : cmd);
-  }
-  
-  if (cmdLine) {
-    // command found in predefined path
-    e=system(cmdLine);
-    free(cmdLine);
-  } else {
-    // trust on $PATH
-    e=system(cmd);
-  }
-  return e;
-}
 
 
-#else
+  /* some sanity checks in c1 mode */
+  if (options.c1mode)
+    {
+      const char *s;
 
 
-int my_system (const char *cmd, char **cmd_argv)
-{    
-    char *dir, *got= NULL; int i= 0;
+      if (fullSrcFileName)
+        {
+          fclose (srcFile);
+          werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
+        }
+      fullSrcFileName = NULL;
+      for (s = setFirstItem(relFilesSet); s != NULL; s = setNextItem(relFilesSet))
+        {
+          werror (W_NO_FILE_ARG_IN_C1, s);
+        }
+      for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
+        {
+          werror (W_NO_FILE_ARG_IN_C1, s);
+        }
+      deleteSet(&relFilesSet);
+      deleteSet(&libFilesSet);
 
 
-    while (!got && try_dir[i])
+      if (options.cc_only || noAssemble || preProcOnly)
+        {
+          werror (W_ILLEGAL_OPT_COMBINATION);
+        }
+      options.cc_only = noAssemble = preProcOnly = 0;
+      if (!dstFileName)
+        {
+          werror (E_NEED_OPT_O_IN_C1);
+          exit (1);
+        }
+    }
+  /* if no dstFileName given with -o, we've to find one: */
+  if (!dstFileName)
     {
     {
-        dir= (char*)Safe_malloc(strlen(try_dir[i])+strlen(cmd)+10);
-        strcpy(dir, try_dir[i]);
-        strcat(dir, "/");
-        strcat(dir, cmd);
-
-#if NATIVE_WIN32
-        strcat(dir, ".exe");
-
-        /* Mung slashes into backslashes to keep WIndoze happy. */
-       {
-           char *r;
-           r = dir;
-           
-           while (*r)
-               {
-                   if (*r == '/')
-                       {
-                           *r = '\\';
-                       }
-                   r++;
-               }
-       }
-#endif
+      const char *s;
 
 
-        if (access(dir, X_OK) == 0)
+      /* use the modulename from the C-source */
+      if (fullSrcFileName)
         {
         {
-            got= strdup(dir);
+          struct dbuf_s path;
+
+                 if (*dstPath != '\0')
+            {
+              dbuf_init(&path, 128);
+              dbuf_makePath (&path, dstPath, moduleNameBase);
+              dbuf_c_str (&path);
+              dstFileName = dbuf_detach (&path);
+            }
+          else
+            dstFileName = Safe_strdup(moduleNameBase);
         }
         }
-        free(dir);
-        i++;
+      /* use the modulename from the first object file */
+      else if ((s = peekSet(relFilesSet)) != NULL)
+        {
+          struct dbuf_s file;
+
+          dbuf_init(&file, 128);
+
+          dbuf_splitPath (s, NULL, &file);
+
+          if (*dstPath != '\0')
+            {
+              struct dbuf_s path;
+
+              dbuf_init(&path, 128);
+              dbuf_makePath (&path, dstPath, dbuf_c_str (&file));
+              dbuf_destroy (&file);
+              dbuf_c_str (&path);
+              dstFileName = dbuf_detach (&path);
+            }
+          else
+            {
+              dbuf_c_str (&file);
+              dstFileName = dbuf_detach (&file);
+            }
+        }
+      /* else no module given: help text is displayed */
     }
 
     }
 
-    if (verboseExec) {
-       char **pCmd = cmd_argv;
-       printf ("+ ");
-       while (*pCmd) {
-           printf("%s ", *pCmd);
-           pCmd++;
-       }
-       printf("\n");
+  /* set int, long and float reentrancy based on stack-auto */
+  if (options.stackAuto)
+    {
+      options.intlong_rent++;
+      options.float_rent++;
     }
 
     }
 
-    if (got)
-               {
-      i= spawnv(P_WAIT,got,cmd_argv) == -1;
-               free(got) ;
-               }
-    else
-      i= spawnvp(P_WAIT,cmd,cmd_argv) == -1;
-    if (i) {
-       perror("Cannot exec process ");
-       return -1;
+  /* mcs51 has an assembly coded float library that's always reentrant */
+  if (TARGET_IS_MCS51)
+    {
+      options.float_rent++;
+    }
+
+  /* set up external stack location if not explicitly specified */
+  if (!options.xstack_loc)
+    options.xstack_loc = options.xdata_loc;
+
+  /* if debug option is set then open the cdbFile */
+  if (options.debug && fullSrcFileName)
+    {
+      SNPRINTF (scratchFileName, sizeof(scratchFileName),
+                "%s.adb", dstFileName); /*JCF: Nov 30, 2002*/
+      if(debugFile->openFile(scratchFileName))
+        debugFile->writeModule(moduleName);
+      else
+        werror (E_FILE_OPEN_ERR, scratchFileName);
     }
     }
-    
-    return 0;
+  MSVC_style(options.vc_err_style);
+
+  return 0;
 }
 }
-#endif
 
 /*-----------------------------------------------------------------*/
 /* linkEdit : - calls the linkage editor  with options             */
 /*-----------------------------------------------------------------*/
 
 /*-----------------------------------------------------------------*/
 /* linkEdit : - calls the linkage editor  with options             */
 /*-----------------------------------------------------------------*/
-static void linkEdit (char **envp)
+static void
+linkEdit (char **envp)
 {
 {
-    FILE *lnkfile ;
-#ifndef USE_SYSTEM_SYSTEM_CALLS
-    char *argv[128];
-#endif
-    char *segName, *c;
+  FILE *lnkfile;
+  char *segName, *c;
+  int system_ret;
+  const char *s;
+  char linkerScriptFileName[PATH_MAX];
 
 
-    int i;
-    if (!srcFileName)
-       srcFileName = "temp";
-
-    /* first we need to create the <filename>.lnk file */
-    sprintf(buffer,"%s.lnk",srcFileName);
-    if (!(lnkfile = fopen(buffer,"w"))) {
-       werror(E_FILE_OPEN_ERR,buffer);
-       exit(1);
-    }
+  linkerScriptFileName[0] = 0;
+
+  if(port->linker.needLinkerScript)
+    {
+      char out_fmt;
+
+      switch (options.out_fmt)
+        {
+        case 0:
+          out_fmt = 'i';        /* Intel hex */
+          break;
+        case 1:
+          out_fmt = 's';        /* Motorola S19 */
+          break;
+        case 2:
+          out_fmt = 't';        /* Elf */
+          break;
+        default:
+          out_fmt = 'i';
+        }
+
+      /* first we need to create the <filename>.lnk file */
+      SNPRINTF (linkerScriptFileName, sizeof(scratchFileName),
+        "%s.lnk", dstFileName);
+      if (!(lnkfile = fopen (linkerScriptFileName, "w")))
+        {
+          werror (E_FILE_OPEN_ERR, linkerScriptFileName);
+          exit (1);
+        }
 
 
-    /* now write the options */
-    fprintf(lnkfile,"-mux%c\n", (options.out_fmt ? 's' : 'i'));
+      if (TARGET_Z80_LIKE)
+        {
+          fprintf (lnkfile, "--\n-m\n-j\n-x\n-%c %s\n",
+            out_fmt, dstFileName);
+        }
+      else /*For all the other ports.  Including pics???*/
+        {
+          fprintf (lnkfile, "-myux%c\n", out_fmt);
+          if(!options.no_pack_iram)
+              fprintf (lnkfile, "-Y\n");
+        }
+
+      if (!(TARGET_Z80_LIKE)) /*Not for the z80, gbz80*/
+        {
+          /* if iram size specified */
+          if (options.iram_size)
+            fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
+
+          /* if stack size specified*/
+          if(options.stack_size)
+              fprintf (lnkfile, "-A 0x%02x\n", options.stack_size);
 
 
-    /* if iram size specified */
-    if (options.iram_size)
-       fprintf(lnkfile,"-a 0x%04x\n",options.iram_size);
-    
-    /*if (options.debug) */
-    fprintf(lnkfile,"-z\n");
+          /* if xram size specified */
+          if (options.xram_size_set)
+            fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
+
+          /* if code size specified */
+          if (options.code_size)
+            fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
+
+          if (options.debug)
+            fprintf (lnkfile, "-z\n");
+        }
 
 #define WRITE_SEG_LOC(N, L) \
 
 #define WRITE_SEG_LOC(N, L) \
-    segName = strdup(N); \
-    c = strtok(segName, " \t"); \
-    fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
-    if (segName) { free(segName); } 
-    
-    /* code segment start */
-    WRITE_SEG_LOC(CODE_NAME, options.code_loc);
-    
-     /* data segment start */
-     WRITE_SEG_LOC(DATA_NAME, options.data_loc);
-                 
-    /* xdata start */
-    WRITE_SEG_LOC(XDATA_NAME, options. xdata_loc);
-
-    /* indirect data */
-    WRITE_SEG_LOC(IDATA_NAME, options.idata_loc);
-
-    /* bit segment start */
-    WRITE_SEG_LOC(BIT_NAME, 0);
-    
-    /* add the extra linker options */
-    for (i=0; linkOptions[i] ; i++)
-       fprintf(lnkfile,"%s\n",linkOptions[i]);
-
-    /* other library paths if specified */
-    for (i = 0 ; i < nlibPaths ; i++ )
-       fprintf (lnkfile,"-k %s\n",libPaths[i]);
-
-    /* standard library path */
-    if (!options.nostdlib) {
-      if (IS_DS390_PORT) {
-       c="ds390";
-      } else {
-       switch(options.model)
-         {
-         case MODEL_SMALL:
-           c = "small";
-           break;
-         case MODEL_LARGE:
-           c = "large";
-           break;
-         case MODEL_FLAT24:
-           c = "flat24";
-           break;
-         default:
-           werror(W_UNKNOWN_MODEL, __FILE__, __LINE__);
-           c = "unknown";
-           break;
-         }
-      }
-      fprintf (lnkfile,"-k %s/%s\n",SDCC_LIB_DIR/*STD_LIB_PATH*/,c);
-      
+  segName = Safe_strdup(N); \
+  c = strtok(segName, " \t"); \
+  fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
+  if (segName) { Safe_free(segName); }
+
+      if (!(TARGET_Z80_LIKE)) /*Not for the z80, gbz80*/
+        {
+
+          /* code segment start */
+          WRITE_SEG_LOC (HOME_NAME, options.code_loc);
+
+          /* data segment start. If zero, the linker chooses
+             the best place for data */
+          if (options.data_loc)
+            {
+              WRITE_SEG_LOC (DATA_NAME, options.data_loc);
+            }
+
+          /* xdata segment start. If zero, the linker chooses
+             the best place for xdata */
+          if (options.xdata_loc)
+            {
+              WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
+            }
+
+          /* pdata/xstack segment start. If zero, the linker
+             chooses the best place for them */
+          if (options.xstack_loc)
+            {
+              WRITE_SEG_LOC (PDATA_NAME, options.xstack_loc);
+            }
+
+          /* indirect data */
+          if (IDATA_NAME)
+            {
+              WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
+            }
+
+          /* bit segment start */
+          WRITE_SEG_LOC (BIT_NAME, 0);
+
+          /* stack start */
+          if ( (options.stack_loc) && (options.stack_loc<0x100) &&
+               !TARGET_IS_HC08)
+            {
+              WRITE_SEG_LOC ("SSEG", options.stack_loc);
+            }
+        }
+      else /*For the z80, gbz80*/
+        {
+          WRITE_SEG_LOC ("_CODE", options.code_loc);
+          WRITE_SEG_LOC ("_DATA", options.data_loc);
+        }
+
+      /* If the port has any special linker area declarations, get 'em */
+      if (port->extraAreas.genExtraAreaLinkOptions)
+        {
+          port->extraAreas.genExtraAreaLinkOptions(lnkfile);
+        }
+
+      /* add the extra linker options */
+      fputStrSet(lnkfile, linkOptionsSet);
+
+      /* command line defined library paths if specified */
+      for (s = setFirstItem(libPathsSet); s != NULL; s = setNextItem(libPathsSet))
+        fprintf (lnkfile, "-k %s\n", s);
+
+      /* standard library path */
+      if (!options.nostdlib)
+        {
+          if (!(TARGET_Z80_LIKE || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
+            {
+              switch (options.model)
+                {
+                case MODEL_SMALL:
+                  if (options.stackAuto)
+                    c = "small-stack-auto";
+                  else
+                    c = "small";
+                  break;
+                case MODEL_MEDIUM:
+                  if (options.stackAuto)
+                    c = "medium-stack-auto";
+                  else
+                    c = "medium";
+                  break;
+                case MODEL_LARGE:
+                  if (options.stackAuto)
+                    c = "large-stack-auto";
+                  else
+                    c = "large";
+                  break;
+                case MODEL_FLAT24:
+                  /* c = "flat24"; */
+                  if (TARGET_IS_DS390)
+                    {
+                      c = "ds390";
+                    }
+                  else if (TARGET_IS_DS400)
+                    {
+                      c = "ds400";
+                    }
+                  else
+                    {
+                      fprintf(stderr,
+                        "Add support for your FLAT24 target in %s @ line %d\n",
+                        __FILE__, __LINE__);
+                      exit (EXIT_FAILURE);
+                    }
+                  break;
+                case MODEL_PAGE0:
+                  c = "xa51";
+                  break;
+                default:
+                  werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
+                  c = "unknown";
+                  break;
+                }
+            }
+          else /*for the z80, gbz80*/
+            {
+              if (TARGET_IS_HC08)
+                c = "hc08";
+              else if (TARGET_IS_Z80)
+                c = "z80";
+              else
+                c = "gbz80";
+            }
+          for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
+            mfprintf (lnkfile, getRuntimeVariables(), "-k %s{sep}%s\n", s, c);
+        }
+
+      /* command line defined library files if specified */
+      for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
+        fprintf (lnkfile, "-l %s\n", s);
+
       /* standard library files */
       /* standard library files */
-      if (strcmp(port->target, "ds390")==0) {
-       fprintf (lnkfile,"-l %s\n",STD_DS390_LIB);
-      }
-      fprintf (lnkfile,"-l %s\n",STD_LIB);
-      fprintf (lnkfile,"-l %s\n",STD_INT_LIB);
-      fprintf (lnkfile,"-l %s\n",STD_LONG_LIB);
-      fprintf (lnkfile,"-l %s\n",STD_FP_LIB);
+      if (!options.nostdlib)
+        {
+#if !OPT_DISABLE_DS390
+          if (options.model == MODEL_FLAT24)
+            {
+              if (TARGET_IS_DS390)
+                {
+                  fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
+                }
+              else if (TARGET_IS_DS400)
+                {
+                  fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
+                }
+              else
+                {
+                  fprintf(stderr,
+                    "Add support for your FLAT24 target in %s @ line %d\n",
+                    __FILE__, __LINE__);
+                  exit (EXIT_FAILURE);
+                }
+              }
+#endif
+
+#if !OPT_DISABLE_XA51
+#ifdef STD_XA51_LIB
+          if (options.model == MODEL_PAGE0)
+            {
+              fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
+            }
+#endif
+#endif
+          if (TARGET_IS_MCS51)
+            {
+              fprintf (lnkfile, "-l mcs51\n");
+            }
+          if (!(TARGET_Z80_LIKE || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
+            { /*Why the z80 port is not using the standard libraries?*/
+              fprintf (lnkfile, "-l %s\n", STD_LIB);
+              fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
+              fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
+              fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
+            }
+          else if (TARGET_IS_HC08)
+            {
+              fprintf (lnkfile, "-l hc08\n");
+            }
+          else if (TARGET_IS_Z80)
+            {
+              fprintf (lnkfile, "-l z80\n");
+            }
+          else if (TARGET_IS_GBZ80)
+            {
+              fprintf (lnkfile, "-l gbz80\n");
+            }
+        }
+
+      /*For the z80 and gbz80 ports, try to find where crt0.o is...
+      It is very important for this file to be first on the linking proccess
+      so the areas are set in the correct order, expecially _GSINIT*/
+      if ((TARGET_Z80_LIKE) && !options.no_std_crt0) /*For the z80, gbz80*/
+        {
+          char crt0path[PATH_MAX];
+          FILE * crt0fp;
+          set *tempSet=NULL;
+
+          tempSet = appendStrSet(libDirsSet, NULL, DIR_SEPARATOR_STRING);
+          tempSet = appendStrSet(tempSet, NULL, c);
+          mergeSets(&tempSet, libPathsSet);
+
+          for (s = setFirstItem(tempSet); s != NULL; s = setNextItem(tempSet))
+            {
+              sprintf (crt0path, "%s%scrt0.o",
+                s, DIR_SEPARATOR_STRING);
+
+              crt0fp=fopen(crt0path, "r");
+              if(crt0fp!=NULL)/*Found it!*/
+                {
+                  fclose(crt0fp);
+                  #ifdef __CYGWIN__
+                  {
+                    /*The CYGWIN version of the z80-gbz80 linker is getting confused with
+                    windows paths, so convert them to the CYGWIN format*/
+                    char posix_path[PATH_MAX];
+                    void cygwin_conv_to_full_posix_path(char * win_path, char * posix_path);
+                    cygwin_conv_to_full_posix_path(crt0path, posix_path);
+                    strcpy(crt0path, posix_path);
+                  }
+                  #endif
+                  fprintf (lnkfile, "%s\n", crt0path);
+                  break;
+                }
+            }
+          if(s==NULL) fprintf (stderr, "Warning: couldn't find crt0.o\n");
+        }
+
+      /* put in the object files */
+      if (fullSrcFileName)
+        fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
+
+      fputStrSet(lnkfile, relFilesSet);
+
+      fprintf (lnkfile, "\n-e\n");
+      fclose (lnkfile);
+    } /* if(port->linker.needLinkerScript) */
+
+  if (options.verbose)
+    printf ("sdcc: Calling linker...\n");
+
+  /* build linker output filename */
+
+  /* -o option overrides default name? */
+  if (fullDstFileName)
+    {
+      strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
     }
     }
+  else
+    {
+      /* the linked file gets the name of the first modul */
+      if (fullSrcFileName)
+        {
+          strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
+        }
+      else
+        {
+          s = peekSet(relFilesSet);
+
+          assert(s);
 
 
-    /* additional libraries if any */
-    for (i = 0 ; i < nlibFiles; i++)
-       fprintf (lnkfile,"-l %s\n",libFiles[i]);
+          strncpyz (scratchFileName, s, sizeof(scratchFileName));
+          /* strip ".rel" extension */
+          *strrchr (scratchFileName, '.') = '\0';
+        }
+      strncatz (scratchFileName,
+        options.out_fmt ? ".S19" : ".ihx",
+        sizeof(scratchFileName));
+    }
 
 
-    /* put in the object files */
-    if (strcmp(srcFileName,"temp"))
-       fprintf (lnkfile,"%s ",srcFileName);
+  if (port->linker.cmd)
+    {
+      char buffer2[PATH_MAX];
+      char buffer3[PATH_MAX];
+      set *tempSet=NULL, *libSet=NULL;
 
 
-    for (i = 0 ; i < nrelFiles ; i++ )
-       fprintf (lnkfile,"%s\n",relFiles[i]);
+      strcpy(buffer3, linkerScriptFileName);
+      if(/*TARGET_IS_PIC16 ||*/ TARGET_IS_PIC) {
 
 
-    fprintf (lnkfile,"\n-e\n");
-    fclose(lnkfile);
+         /* use $l to set the linker include directories */
+         tempSet = appendStrSet(libDirsSet, "-I\"", "\"");
+         mergeSets(&linkOptionsSet, tempSet);
 
 
-    if (options.verbose)
-      printf ("sdcc: Calling linker...\n");
+         tempSet = appendStrSet(libPathsSet, "-I\"", "\"");
+         mergeSets(&linkOptionsSet, tempSet);
 
 
-#ifdef USE_SYSTEM_SYSTEM_CALLS
-    buildCmdLine(buffer, port->linker.cmd, srcFileName, NULL, NULL, NULL);
-    if (my_system(buffer)) {
-      exit(1);
+         /* use $3 for libraries from command line --> libSet */
+         mergeSets(&libSet, libFilesSet);
+
+         tempSet = appendStrSet(relFilesSet, "", "");
+         mergeSets(&libSet, tempSet);
+//         libSet = reverseSet(libSet);
+
+        if(fullSrcFileName) {
+//              strcpy(buffer3, strrchr(fullSrcFileName, DIR_SEPARATOR_CHAR)+1);
+                /* if it didn't work, revert to old behaviour */
+                if(!strlen(buffer3))strcpy(buffer3, dstFileName);
+                strcat(buffer3, port->linker.rel_ext);
+
+        } else strcpy(buffer3, "");
+      }
+
+      buildCmdLine (buffer2, port->linker.cmd, buffer3, scratchFileName, (libSet?joinStrSet(libSet):NULL), linkOptionsSet);
+
+      buildCmdLine2 (buffer, sizeof(buffer), buffer2);
     }
     }
-#else
-    buildCmdLine(buffer, argv, port->linker.cmd, srcFileName, NULL, NULL, NULL);
-    if (my_system(argv[0], argv)) {
-       perror("Cannot exec linker");
-       exit(1);
+  else
+    {
+      buildCmdLine2 (buffer, sizeof(buffer), port->linker.mcmd);
     }
 
     }
 
-#endif
+  /*  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer); */
+
+  system_ret = my_system (buffer);
+
+  /* TODO: most linker don't have a -o parameter */
+  /* -o option overrides default name? */
+  if (fullDstFileName)
+    {
+      char *p, *q;
+      /* the linked file gets the name of the first modul */
+      if (fullSrcFileName)
+        {
+          strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
+          p = strlen (scratchFileName) + scratchFileName;
+        }
+      else
+        {
+          s = peekSet(relFilesSet);
+
+          assert(s);
+
+          strncpyz (scratchFileName, s, sizeof(scratchFileName));
+          /* strip ".rel" extension */
+          p = strrchr (scratchFileName, '.');
+          if (p)
+            {
+              *p = 0;
+            }
+        }
+      strncatz (scratchFileName,
+        options.out_fmt ? ".S19" : ".ihx",
+        sizeof(scratchFileName));
+      if (FILENAME_CMP (fullDstFileName, scratchFileName))
+        remove (fullDstFileName);
+      rename (scratchFileName, fullDstFileName);
+
+      strncpyz (buffer, fullDstFileName, sizeof(buffer));
+      q = strrchr (buffer, '.');
+      if (!q)
+        {
+          /* no extension: append new extensions */
+          q = strlen (buffer) + buffer;
+        }
 
 
-    if (strcmp(srcFileName,"temp") == 0) {
-       /* rename "temp.cdb" to "firstRelFile.cdb" */
-       char *f = strtok(strdup(relFiles[0]),".");
-       f = strcat(f,".cdb");
-       rename("temp.cdb",f);       
-       srcFileName = NULL;
+      *p = 0;
+      strncatz (scratchFileName, ".map", sizeof(scratchFileName));
+      *q = 0;
+      strncatz(buffer, ".map", sizeof(buffer));
+      if (FILENAME_CMP (scratchFileName, buffer))
+        remove (buffer);
+      rename (scratchFileName, buffer);
+      *p = 0;
+      strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
+      *q = 0;
+      strncatz(buffer, ".mem", sizeof(buffer));
+      if (FILENAME_CMP (scratchFileName, buffer))
+        remove (buffer);
+      rename (scratchFileName, buffer);
+      if (options.debug)
+        {
+          *p = 0;
+          strncatz (scratchFileName, ".cdb", sizeof(scratchFileName));
+          *q = 0;
+          strncatz(buffer, ".cdb", sizeof(buffer));
+          if (FILENAME_CMP (scratchFileName, buffer))
+            remove (buffer);
+          rename (scratchFileName, buffer);
+          /* and the OMF file without extension: */
+          *p = 0;
+          *q = 0;
+          if (FILENAME_CMP (scratchFileName, buffer))
+            remove (buffer);
+          rename (scratchFileName, buffer);
+        }
+    }
+  if (system_ret)
+    {
+      exit (1);
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* assemble - spawns the assembler with arguments                  */
 /*-----------------------------------------------------------------*/
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* assemble - spawns the assembler with arguments                  */
 /*-----------------------------------------------------------------*/
-static void assemble (char **envp)
+static void
+assemble (char **envp)
 {
 {
-#ifdef USE_SYSTEM_SYSTEM_CALLS
-    buildCmdLine(buffer, port->assembler.cmd, srcFileName, NULL, NULL, asmOptions);
-    if (my_system(buffer)) {
-      exit(1);
+    /* build assembler output filename */
+
+    /* -o option overrides default name? */
+    if (options.cc_only && fullDstFileName) {
+        strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
+    } else {
+        /* the assembled file gets the name of the first modul */
+        strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
+        strncatz (scratchFileName, port->linker.rel_ext,
+                  sizeof(scratchFileName));
     }
     }
-#else
-    char *argv[128];  /* assembler arguments */
 
 
-    buildCmdLine(buffer, argv, port->assembler.cmd, srcFileName, NULL, NULL, asmOptions);
+    if (port->assembler.do_assemble) {
+        port->assembler.do_assemble(asmOptionsSet);
+        return ;
+    } else if (port->assembler.cmd) {
+        buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
+                      options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
+                      asmOptionsSet);
+    } else {
+        buildCmdLine2 (buffer, sizeof(buffer), port->assembler.mcmd);
+    }
 
 
-    if (my_system(argv[0], argv)) {
-       perror("Cannot exec assembler");
-       exit(1);
+    if (my_system (buffer)) {
+        /* either system() or the assembler itself has reported an error
+           perror ("Cannot exec assembler");
+        */
+        exit (1);
+    }
+    /* TODO: most assembler don't have a -o parameter */
+    /* -o option overrides default name? */
+    if (options.cc_only && fullDstFileName) {
+        strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
+        strncatz (scratchFileName,
+                  port->linker.rel_ext,
+                  sizeof(scratchFileName));
+        if (strcmp (scratchFileName, fullDstFileName))
+          remove (fullDstFileName);
+        rename (scratchFileName, fullDstFileName);
     }
     }
-#endif
 }
 
 }
 
-
-
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-/* preProcess - spawns the preprocessor with arguments            */
+/* preProcess - spawns the preprocessor with arguments       */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
-static int preProcess (char **envp)
+static int
+preProcess (char **envp)
 {
 {
-#ifndef USE_SYSTEM_SYSTEM_CALLS
-    char *argv[128];
-#endif
-    char procDef[128];
-
-    preOutName = NULL;
-
-    if (!options.c1mode) {
-       /* if using external stack define the macro */
-       if ( options.useXstack )
-           _addToList(preArgv, "-DSDCC_USE_XSTACK");
-       
-       /* set the macro for stack autos        */
-       if ( options.stackAuto )
-           _addToList(preArgv, "-DSDCC_STACK_AUTO");
-           
-       /* set the macro for stack autos        */
-       if ( options.stack10bit )
-           _addToList(preArgv, "-DSDCC_STACK_TENBIT"); 
-    
-       /* set the macro for large model        */
-       switch(options.model)
-           {
-           case MODEL_LARGE:
-               _addToList(preArgv, "-DSDCC_MODEL_LARGE");
-               break;
-           case MODEL_SMALL:
-               _addToList(preArgv, "-DSDCC_MODEL_SMALL");
-               break;
-           case MODEL_COMPACT:
-               _addToList(preArgv, "-DSDCC_MODEL_COMPACT");
-               break;
-           case MODEL_MEDIUM:
-               _addToList(preArgv, "-DSDCC_MODEL_MEDIUM");
-               break;
-           case MODEL_FLAT24:
-               _addToList(preArgv, "-DSDCC_MODEL_FLAT24");
-               break;
-           default:
-               werror(W_UNKNOWN_MODEL, __FILE__, __LINE__);
-               break;
-           }       
-           
-    
-       /* add port (processor information to processor */
-       sprintf(procDef,"-DSDCC_%s",port->target);
-       _addToList(preArgv,procDef);
-
-       if (!preProcOnly)
-           preOutName = strdup(tmpnam(NULL));
-
-       if (options.verbose)
-         printf ("sdcc: Calling preprocessor...\n");
-
-#ifdef USE_SYSTEM_SYSTEM_CALLS
-       buildCmdLine(buffer, _preCmd, fullSrcFileName, 
-                     preOutName, srcFileName, preArgv);
-       if (my_system(buffer)) {
-         exit(1);
-       }
-#else
-       buildCmdLine(buffer, argv, _preCmd, fullSrcFileName, 
-                     preOutName, srcFileName, preArgv);
+  if (options.c1mode)
+    {
+      yyin = stdin;
+    }
+  else
+    {
+      const char *s;
+      set *inclList = NULL;
+
+      if (NULL != port->linker.rel_ext)
+        {
+#define OBJ_EXT_STR     "-obj-ext="
+#define OBJ_EXT_LEN     ((sizeof OBJ_EXT_STR) - 1)
+          char *buf = Safe_alloc(strlen(port->linker.rel_ext) + (OBJ_EXT_LEN + 1));
+          strcpy(buf, OBJ_EXT_STR);
+          strcpy(&buf[OBJ_EXT_LEN], port->linker.rel_ext);
+          addSet(&preArgvSet, buf);
+        }
 
 
-       if (my_system(argv[0], argv)) {
-           unlink (preOutName);
-           perror("Cannot exec Preprocessor");
-           exit(1);
-       }
+      /* if using dollar signs in identifiers */
+      if (options.dollars_in_ident)
+        addSet(&preArgvSet, Safe_strdup("--fdollars-in-identifiers"));
 
 
-#endif
-       if (preProcOnly)
-           exit(0);
+      /* if using external stack define the macro */
+      if (options.useXstack)
+        addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
+
+      /* set the macro for stack autos  */
+      if (options.stackAuto)
+        addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_AUTO"));
+
+      /* set the macro for stack autos  */
+      if (options.stack10bit)
+        addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_TENBIT"));
+
+      /* set the macro for no overlay  */
+      if (options.noOverlay)
+        addSet(&preArgvSet, Safe_strdup("-DSDCC_NOOVERLAY"));
+
+      /* set the macro for large model  */
+      switch (options.model)
+        {
+        case MODEL_LARGE:
+          addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_LARGE"));
+          break;
+        case MODEL_SMALL:
+          addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_SMALL"));
+          break;
+        case MODEL_COMPACT:
+          addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_COMPACT"));
+          break;
+        case MODEL_MEDIUM:
+          addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_MEDIUM"));
+          break;
+        case MODEL_FLAT24:
+          addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_FLAT24"));
+          break;
+        case MODEL_PAGE0:
+          addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_PAGE0"));
+          break;
+        default:
+          werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
+          break;
+        }
+
+      /* add SDCC version number */
+      {
+        char buf[20];
+        SNPRINTF(buf, sizeof(buf), "-DSDCC=%d%d%d",
+                 SDCC_VERSION_HI, SDCC_VERSION_LO, SDCC_VERSION_P);
+        addSet(&preArgvSet, Safe_strdup(buf));
+      }
+
+      /* add port (processor information to processor */
+      addSet(&preArgvSet, Safe_strdup("-DSDCC_{port}"));
+      addSet(&preArgvSet, Safe_strdup("-D__{port}"));
+
+      if (port && port->processor && TARGET_IS_PIC) {
+        char proc[512];
+       SNPRINTF(&proc[0], 512, "-DSDCC_PROCESSOR=\"%s\"", port->processor);
+       addSet(&preArgvSet, Safe_strdup(proc));
+      }
+
+      /* standard include path */
+      if (!options.nostdinc) {
+        inclList = appendStrSet(includeDirsSet, "-I\"", "\"");
+        mergeSets(&preArgvSet, inclList);
+      }
+
+      setMainValue("cppextraopts", (s = joinStrSet(preArgvSet)));
+      Safe_free((void *)s);
+      if (inclList != NULL)
+        deleteSet(&inclList);
+
+      if (preProcOnly && fullDstFileName)
+        {
+          /* -E and -o given */
+          setMainValue ("cppoutfilename", fullDstFileName);
+        }
+      else
+        {
+          /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
+          setMainValue ("cppoutfilename", NULL);
+        }
+
+      if (options.verbose)
+        printf ("sdcc: Calling preprocessor...\n");
+      buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
+
+      if (preProcOnly) {
+        if (my_system (buffer)) {
+          exit (1);
+        }
+
+        exit (0);
+      }
+
+      yyin = my_popen (buffer);
+      if (yyin == NULL) {
+          perror ("Preproc file not found");
+          exit (1);
+      }
     }
     }
-    else {
-       preOutName = fullSrcFileName;
+
+  return 0;
+}
+
+/* Set bin paths */
+static void
+setBinPaths(const char *argv0)
+{
+  const char *p;
+  char buf[PATH_MAX];
+
+  /*
+   * Search logic:
+   *
+   * 1. - $SDCCDIR/PREFIX2BIN_DIR
+   * 2. - path(argv[0])
+   * 3. - $PATH
+   */
+
+  /* do it in reverse mode, so that addSetHead() can be used
+     instead of slower addSet() */
+
+  if ((p = getBinPath(argv0)) != NULL)
+    addSetHead(&binPathSet, (void *)p);
+
+  if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
+    SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
+    addSetHead(&binPathSet, Safe_strdup(buf));
+  }
+}
+
+/* Set system include path */
+static void
+setIncludePath(void)
+{
+  char *p;
+  char *p2=NULL;
+  set *tempSet=NULL;
+
+  /*
+   * Search logic:
+   *
+   * 1. - $SDCC_INCLUDE/target
+   * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX/target
+   * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX/target
+   * 4. - DATADIR/INCLUDE_DIR_SUFFIX/target (only on *nix)
+   * 5. - $SDCC_INCLUDE
+   * 6. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
+   * 7. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
+   * 8. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
+   */
+
+  if (options.nostdinc)
+      return;
+
+  tempSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX);
+  includeDirsSet = appendStrSet(tempSet, NULL, DIR_SEPARATOR_STRING);
+  includeDirsSet = appendStrSet(includeDirsSet, NULL, port->target);
+  mergeSets(&includeDirsSet, tempSet);
+
+  if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
+  {
+    addSetHead(&includeDirsSet, p);
+    p2=Safe_alloc(strlen(p)+strlen(DIR_SEPARATOR_STRING)+strlen(port->target)+1);
+    if(p2!=NULL)
+    {
+        strcpy(p2, p);
+        strcat(p2, DIR_SEPARATOR_STRING);
+        strcat(p2, port->target);
+        addSetHead(&includeDirsSet, p2);
     }
     }
+  }
+}
+
+/* Set system lib path */
+static void
+setLibPath(void)
+{
+  char *p;
 
 
-    yyin = fopen(preOutName, "r");
-    if (yyin == NULL) {
-       perror("Preproc file not found\n");
-       exit(1);
+  /*
+   * Search logic:
+   *
+   * 1. - $SDCC_LIB
+   * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
+   * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
+   * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
+   */
+
+  if (options.nostdlib)
+      return;
+
+  libDirsSet = appendStrSet(dataDirsSet, NULL, LIB_DIR_SUFFIX);
+
+  if ((p = getenv(SDCC_LIB_NAME)) != NULL)
+    addSetHead(&libDirsSet, p);
+}
+
+/* Set data path */
+static void
+setDataPaths(const char *argv0)
+{
+  const char *p;
+  char buf[PATH_MAX];
+
+  /*
+   * Search logic:
+   *
+   * 1. - $SDCC_HOME/PREFIX2DATA_DIR
+   * 2. - path(argv[0])/BIN2DATA_DIR
+   * 3. - DATADIR (only on *nix)
+   */
+
+  if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
+    SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
+    addSet(&dataDirsSet, Safe_strdup(buf));
+  }
+
+  if ((p = getBinPath(argv0)) != NULL) {
+    SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
+    free((void *)p);
+    addSet(&dataDirsSet, Safe_strdup(buf));
+  }
+
+#ifdef _WIN32
+  if (peekSet(dataDirsSet) == NULL) {
+    /* this should never happen... */
+    wassertl(0, "Can't get binary path");
+  }
+#else
+  addSet(&dataDirsSet, Safe_strdup(DATADIR));
+#endif
+
+  setIncludePath();
+  setLibPath();
+}
+
+static void
+initValues (void)
+{
+  populateMainValues (_baseValues);
+  setMainValue ("port", port->target);
+  setMainValue ("objext", port->linker.rel_ext);
+  setMainValue ("asmext", port->assembler.file_ext);
+
+  setMainValue ("dstfilename", dstFileName);
+  setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
+
+  if (options.cc_only && fullDstFileName)
+    /* compile + assemble and -o given: -o specifies name of object file */
+    {
+      setMainValue ("objdstfilename", fullDstFileName);
+    }
+  else
+    {
+      setMainValue ("objdstfilename", "{stdobjdstfilename}");
+    }
+  if (fullDstFileName)
+    /* if we're linking, -o gives the final file name */
+    {
+      setMainValue ("linkdstfilename", fullDstFileName);
+    }
+  else
+    {
+      setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
     }
     }
-    
-    return 0;
+
 }
 
 }
 
-static void _findPort(int argc, char **argv)
+static void doPrintSearchDirs(void)
 {
 {
-    _validatePorts();
-
-    argc--;
-    while (argc) {
-       if (!strncmp(*argv, "-m", 2)) {
-           _setPort(*argv + 2);
-           return;
-       }
-       argv++;
-       argc--;
+    printf("programs:\n");
+    fputStrSet(stdout, binPathSet);
+
+    printf("datadir:\n");
+    fputStrSet(stdout, dataDirsSet);
+
+    printf("includedir:\n");
+    fputStrSet(stdout, includeDirsSet);
+
+    printf("libdir:\n");
+    fputStrSet(stdout, libDirsSet);
+    fputStrSet(stdout, libPathsSet);
+}
+
+
+static void
+sig_handler (int signal)
+{
+  char *sig_string;
+
+  switch (signal)
+    {
+    case SIGABRT:
+      sig_string = "SIGABRT";
+      break;
+    case SIGTERM:
+      sig_string = "SIGTERM";
+      break;
+    case SIGINT:
+      sig_string = "SIGINT";
+      break;
+    case SIGSEGV:
+      sig_string = "SIGSEGV";
+      break;
+    default:
+      sig_string = "Unknown?";
+      break;
     }
     }
-    /* Use the first in the list */
-    port = _ports[0];
+  fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
+  exit (1);
 }
 
 }
 
-/* 
+/*
  * main routine
  * initialises and calls the parser
  */
 
  * main routine
  * initialises and calls the parser
  */
 
-int main ( int argc, char **argv , char **envp)
+int
+main (int argc, char **argv, char **envp)
 {
 {
-    /* turn all optimizations off by default */
-    memset(&optimize,0,sizeof(struct optimize));
+  /* turn all optimizations off by default */
+  memset (&optimize, 0, sizeof (struct optimize));
 
 
-    /*printVersionInfo ();*/
-
-    _findPort(argc, argv);
-    /* Initalise the port. */
-    if (port->init)
-       port->init();
+  if (NUM_PORTS==0) {
+    fprintf (stderr, "Build error: no ports are enabled.\n");
+    exit (1);
+  }
 
 
-#if defined(_MSC_VER)
+  /* install signal handler;
+     it's only purpose is to call exit() to remove temp files */
+  if (!getenv("SDCC_LEAVE_SIGNALS"))
+    {
+      signal (SIGABRT, sig_handler);
+      signal (SIGTERM, sig_handler);
+      signal (SIGINT , sig_handler);
+      signal (SIGSEGV, sig_handler);
+    }
 
 
-      {
-      int i ;
+  /* Before parsing the command line options, do a
+   * search for the port and processor and initialize
+   * them if they're found. (We can't gurantee that these
+   * will be the first options specified).
+   */
 
 
-      // Create a default exe search path from the path to the sdcc command
+  _findPort (argc, argv);
 
 
-      strcpy(DefaultExePath,argv[0]) ;
+#ifdef JAMIN_DS390
+  if (strcmp(port->target, "mcs51") == 0) {
+    printf("DS390 jammed in A\n");
+    _setPort ("ds390");
+    ds390_jammed = 1;
+  }
+#endif
 
 
-      for(i = strlen(DefaultExePath) ; i > 0 ; i--)
-       if (DefaultExePath[i] == '\\')
-         {
-         DefaultExePath[i] = '\0' ;
-         break ;
-         }
+  _findProcessor (argc, argv);
 
 
-      if (i == 0)
-       DefaultExePath[0] = '\0' ;
-      }
+  /* Initalise the port. */
+  if (port->init)
+    port->init ();
 
 
+  setDefaultOptions ();
+#ifdef JAMIN_DS390
+  if (ds390_jammed) {
+    options.model = MODEL_SMALL;
+    options.stack10bit=0;
+  }
 #endif
 
 #endif
 
-    setDefaultOptions();
-    parseCmdLine(argc,argv);
+  parseCmdLine (argc, argv);
+
+  if (options.verbose && NULL != port->processor)
+    printf("Processor: %s\n", port->processor);
+
+  initValues ();
 
 
-    initMem();
+  setBinPaths(argv[0]);
+  setDataPaths(argv[0]);
 
 
-    port->finaliseOptions();
+  if(port->initPaths)
+        port->initPaths();
 
 
-    /* if no input then printUsage & exit */
-    if ((!options.c1mode && !srcFileName && !nrelFiles) || (options.c1mode && !srcFileName && !options.out_name)) {
-       printUsage();
-       exit(0);
+  if(options.printSearchDirs)
+        doPrintSearchDirs();
+
+  /* if no input then printUsage & exit */
+  if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL)
+    {
+      if (options.printSearchDirs)
+        exit (EXIT_SUCCESS);
+      printUsage();
+      exit (EXIT_FAILURE);
     }
     }
-       
-    if (srcFileName) {
-       preProcess(envp) ;
-
-       initSymt();
-       initiCode();
-       initCSupport ();
-       initPeepHole();
-
-       if (options.verbose)
-         printf ("sdcc: Generating code...\n");
-
-       yyparse();
-
-       if (!fatalError) 
-       {
-/* TSD PIC port hack - if the PIC port option is enabled
-   and SDCC is used to generate PIC code, then we will
-   generate .asm files in gpasm's format instead of SDCC's
-   assembler's format
-*/
-#if !OPT_DISABLE_PIC
-         if(IS_PIC_PORT)
-           pic14glue();
-         else
-#endif
-           glue();
-           if (fatalError)
-           {
-               return 1;
-           }
-           if (!options.c1mode)
-           {
-               if (options.verbose)
-                 printf ("sdcc: Calling assembler...\n");
-
-               assemble(envp);
-           }
-       }
-       else 
-       {
-           return 1;
+
+  /* initMem() is expensive, but
+     initMem() must called before port->finaliseOptions ().
+     And the z80 port needs port->finaliseOptions(),
+     even if we're only linking. */
+  initMem ();
+  port->finaliseOptions ();
+
+  if (fullSrcFileName || options.c1mode)
+    {
+      preProcess (envp);
+
+      initSymt ();
+      initiCode ();
+      initCSupport ();
+      initBuiltIns();
+      initPeepHole ();
+
+      if (options.verbose)
+        printf ("sdcc: Generating code...\n");
+
+      yyparse ();
+
+      if (pclose(yyin))
+        fatalError = 1;
+
+      if (fatalError) {
+        exit (EXIT_FAILURE);
+      }
+
+      if (port->general.do_glue != NULL)
+        (*port->general.do_glue)();
+      else
+        {
+          /* this shouldn't happen */
+          assert(FALSE);
+          /* in case of NDEBUG */
+          glue();
+        }
+
+      if (fatalError) {
+        exit (1);
+      }
+
+      if (!options.c1mode && !noAssemble)
+        {
+          if (options.verbose)
+            printf ("sdcc: Calling assembler...\n");
+          assemble (envp);
         }
         }
-       
-    }
-    
-    if (cdbFile)
-       fclose(cdbFile);
-
-    if (!options.cc_only && 
-       !fatalError      &&
-       !noAssemble      &&
-       !options.c1mode  &&
-       (srcFileName || nrelFiles)) {
-       if (port->linker.do_link)
-           port->linker.do_link();
-       else
-         linkEdit (envp);
     }
     }
+  closeDumpFiles();
+
+  if (options.debug && debugFile)
+    debugFile->closeFile();
 
 
-    if (yyin && yyin != stdin)
-       fclose(yyin);
+  if (!options.cc_only &&
+      !fatalError &&
+      !noAssemble &&
+      !options.c1mode &&
+      (fullSrcFileName || peekSet(relFilesSet) != NULL))
+    {
+      if (options.verbose)
+        printf ("sdcc: Calling linker...\n");
 
 
-    if (preOutName && !options.c1mode) {
-        unlink(preOutName);
-        free(preOutName);
+      if (port->linker.do_link)
+        port->linker.do_link ();
+      else
+        linkEdit (envp);
     }
 
     }
 
-    return 0;
-    
-  }
+  return 0;
+}