* src/SDCCsymt.c (initCSupport): fix compile warning on Cygwin
[fw/sdcc] / src / SDCCmain.c
index 69687e9364e6b64bdf8bc01642df2aaa68ad2519..754b8034802d816d3b6c28bf8514718d976a35dd 100644 (file)
    what you give them.   Help stamp out software-hoarding!
 -------------------------------------------------------------------------*/
 
-#define USE_SYSTEM_SYSTEM_CALLS
-
+#include <signal.h>
 #include "common.h"
 #include <ctype.h>
 #include "newalloc.h"
 #include "SDCCerr.h"
+#include "BuildCmd.h"
+#include "MySystem.h"
+#include "SDCCmacro.h"
+#include "SDCCutil.h"
+#include "SDCCargs.h"
 
 #if NATIVE_WIN32
 #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>
-
-#else
-// No unistd.h in Borland C++
-extern int access (const char *, int);
-#define X_OK 1
-
 #endif
 
+/** Name of the environment variable checked for other instalations. */
+#define SDCCDIR_NAME "SDCCDIR"
+
 //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 */
+char *fullSrcFileName;         /* full name for the source file; */
+                               /* can be NULL while 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 *moduleName;              /* module name is source file without path and extension */
+                               /* can be NULL while linking without compiling */
 const char *preArgv[128];      /* pre-processor arguments  */
 int currRegBank = 0;
+int RegBankUsed[4]={1, 0, 0, 0};       /*JCF: Reg Bank 0 used by default*/
 struct optimize optimize;
 struct options options;
-char *VersionString = SDCC_VERSION_STR /*"Version 2.1.8a" */ ;
-short preProcOnly = 0;
-short noAssemble = 0;
+char *VersionString = SDCC_VERSION_STR;
+int preProcOnly = 0;
+int noAssemble = 0;
 char *linkOptions[128];
 const char *asmOptions[128];
 char *libFiles[128];
@@ -72,77 +77,176 @@ char *relFiles[128];
 int nrelFiles = 0;
 bool verboseExec = FALSE;
 char *preOutName;
+bool noXinitOpt = FALSE;
 
-// In MSC VC6 default search path for exe's to path for this
+/* 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
 
-#if defined(_MSC_VER)
+// Globally accessible scratch buffer for file names.
+char scratchFileName[PATH_MAX];
+char buffer[PATH_MAX];
 
-char DefaultExePath[_MAX_PATH];
+// In MSC VC6 default search path for exe's to path for this
 
-#endif
+char DefaultExePath[128];
+
+#define OPTION_HELP    "-help"
+
+#define LENGTH(_a)     (sizeof(_a)/sizeof(*(_a)))
+
+#define OPTION_STACK_8BIT      "--stack-8bit"
+#define OPTION_OUT_FMT_IHX     "--out-fmt-ihx"
+#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_XSTACK_LOC      "--xstack-loc"
+#define OPTION_CALLEE_SAVES    "--callee-saves"
+#define OPTION_STACK_LOC       "--stack-loc"
+#define OPTION_XRAM_LOC                "--xram-loc"
+#define OPTION_IRAM_SIZE       "--iram-size"
+#define OPTION_VERSION         "--version"
+#define OPTION_DATA_LOC                "--data-loc"
+#define OPTION_CODE_LOC                "--code-loc"
+#define OPTION_IDATA_LOC       "--idata-loc"
+#define OPTION_NO_LOOP_INV     "--noinvariant"
+#define OPTION_NO_LOOP_IND     "--noinduction"
+#define OPTION_LESS_PEDANTIC   "--lesspedantic"
+#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_XRAM_SIZE       "--xram-size"
+#define OPTION_CODE_SIZE       "--code-size"
+
+static const OPTION 
+optionsTable[] = {
+    { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
+    { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
+    { '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" },
+    { 'V',  NULL,                   &verboseExec, "Execute verbosely.  Show sub commands as they are run" },
+    { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
+    { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
+    { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
+    { 'l',  NULL,                   NULL, "Include the given library in the link" },
+    { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
+    { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
+    { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
+    { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
+    { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
+    { 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)" },
+    { 0,    "--xstack",             &options.useXstack, "Use external stack" },
+    { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
+    { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
+    { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
+    { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
+    { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
+    { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
+    { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
+    { 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_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 Ram 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 },
+    { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
+    { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
+    { 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 floar support functions" },
+    { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
+    { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
+    { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
+    { 0,    "--nooverlay",          &options.noOverlay, NULL },
+    { 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,    "--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, NULL },
+    { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
+    { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
+    { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
+    { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The input is preprocessed code, the output is assembly code." },
+    { 0,    "--help",               NULL, "Display this help" },
+    { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
+    { 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,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
+    { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
+    { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
+    { 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" },
+    { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
+    { 0,    "--stack-probe",               &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
+    { 0,    "--tini-libid",        NULL,"<nnnn> LibraryID used in -mTININative"},
+    { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
+    { 0,    "--parms-in-bank1",            &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
+    { 0,    OPTION_NO_XINIT_OPT,    &noXinitOpt, "don't memcpy initialized xram from code"},
+    /* End of options */
+    { 0,    NULL }
+};
 
-/* 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
+/** 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" }
+};
+
+/** List of all default constant macros.
+ */
+static const char *_baseValues[] = {
+  "cpp", "{bindir}{sep}sdcpp",
+  "cppextraopts", "",
+  /* Path seperator character */
+  "sep", DIR_SEPARATOR_STRING,
+  NULL
 };
 
+static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} {fullsrcfilename} {cppoutfilename}";
+
 PORT *port;
 
 static PORT *_ports[] =
@@ -163,28 +267,27 @@ static PORT *_ports[] =
   &ds390_port,
 #endif
 #if !OPT_DISABLE_PIC
-  &pic14_port,
+  &pic_port,
 #endif
-#if !OPT_DISABLE_I186
-  &i186_port,
+#if !OPT_DISABLE_TININative
+  &tininative_port,
 #endif
-#if !OPT_DISABLE_TLCS900H
-  &tlcs900h_port,
+#if !OPT_DISABLE_XA51
+  &xa51_port,
 #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 ();
+#if !OPT_DISABLE_PIC
+extern void picglue ();
+#endif
 
 /** Sets the port to the one given by the command line option.
     @param    The name minus the option (eg 'mcs51')
     @return     0 on success.
 */
-static int 
+static void
 _setPort (const char *name)
 {
   int i;
@@ -193,7 +296,7 @@ _setPort (const char *name)
       if (!strcmp (_ports[i]->target, name))
        {
          port = _ports[i];
-         return 0;
+         return;
        }
     }
   /* Error - didnt find */
@@ -201,7 +304,16 @@ _setPort (const char *name)
   exit (1);
 }
 
-static void 
+/* Override the default processor with the one specified 
+ * on the command line */
+static void
+_setProcessor (char *_processor)
+{
+  port->processor = _processor;
+  fprintf(stderr,"Processor: %s\n",_processor);
+}
+
+static void
 _validatePorts (void)
 {
   int i;
@@ -209,145 +321,55 @@ _validatePorts (void)
     {
       if (_ports[i]->magic != PORT_MAGIC)
        {
-         printf ("Error: port %s is incomplete.\n", _ports[i]->target);
-         wassert (0);
+         /* 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';
+  _validatePorts ();
 
-  while (*cmds)
+  while (argc--)
     {
-
-      from = *cmds;
-      cmds++;
-
-      /* See if it has a '$' anywhere - if not, just copy */
-      if ((p = strchr (from, '$')))
+      if (!strncmp (*argv, "-m", 2))
        {
-         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);
-           }
+         _setPort (*argv + 2);
+         return;
        }
-      strcat (into, from);     // this includes the ".asm" from "$1.asm"
-
-      strcat (into, " ");
+      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)
-{
-  const char *p, *from;
 
-  while (*cmds)
+/* search through the command line options for the processor */
+static void
+_findProcessor (int argc, char **argv)
+{
+  while (argc--)
     {
-      *args = into;
-      args++;
-
-      from = *cmds;
-      cmds++;
-      *into = '\0';
-
-      /* See if it has a '$' anywhere - if not, just copy */
-      if ((p = strchr (from, '$')))
+      if (!strncmp (*argv, "-p", 2))
        {
-         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);
-           }
+         _setProcessor (*argv + 2);
+         return;
        }
-      strcat (into, from);
-      if (strlen (into) == 0)
-       args--;
-      into += strlen (into) + 1;
+      argv++;
     }
-  *args = NULL;
+
+  /* no error if processor was not specified. */
 }
-#endif
 
 /*-----------------------------------------------------------------*/
 /* printVersionInfo - prints the version info        */
 /*-----------------------------------------------------------------*/
-void 
+void
 printVersionInfo ()
 {
   int i;
@@ -356,68 +378,83 @@ printVersionInfo ()
           "SDCC : ");
   for (i = 0; i < NUM_PORTS; i++)
     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
+
   fprintf (stderr, " %s"
 #ifdef SDCC_SUB_VERSION_STR
           "/" SDCC_SUB_VERSION_STR
 #endif
-          " ` "
-#ifdef __CYGWIN32__
-          " (CYGWIN32)\n"
+           " (" __DATE__ ")"
+#ifdef __CYGWIN__
+          " (CYGWIN)\n"
+#elif defined __MINGW32__
+          " (MINGW32) \n"
 #else
-#ifdef __DJGPP__
+#  ifdef __DJGPP__
           " (DJGPP) \n"
-#else
+#  else
+#    if defined(_MSC_VER)
+          " (WIN32) \n"
+#    else
           " (UNIX) \n"
-#endif
+#    endif
+#  endif
 #endif
 
           ,VersionString
     );
 }
 
+static void
+printOptions(const OPTION *optionsTable)
+{
+  int i;
+  for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++) 
+    {
+      fprintf(stdout, "  %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         */
 /*-----------------------------------------------------------------*/
-void 
+void
 printUsage ()
 {
-  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;
+    printVersionInfo();
+    fprintf (stdout,
+             "Usage : sdcc [options] filename\n"
+             "Options :-\n"
+             );
+    
+    printOptions(optionsTable);
+
+    for (i = 0; i < NUM_PORTS; i++)
+      {
+       if (_ports[i]->poptions != NULL)
+         {
+           fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
+           printOptions (_ports[i]->poptions);
+         }
+      }
+
+    exit (0);
 }
 
 /*-----------------------------------------------------------------*/
 /* parseWithComma - separates string with comma                    */
 /*-----------------------------------------------------------------*/
-void 
+void
 parseWithComma (char **dest, char *src)
 {
   int i = 0;
 
-  strtok (src, "\n \t");
+  strtok (src, "\r\n \t");
   /* skip the initial white spaces */
   while (isspace (*src))
     src++;
@@ -439,7 +476,7 @@ parseWithComma (char **dest, char *src)
 /*-----------------------------------------------------------------*/
 /* setDefaultOptions - sets the default options                    */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 setDefaultOptions ()
 {
   int i;
@@ -453,15 +490,17 @@ setDefaultOptions ()
   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.data_loc = 0;                /* JCF: By default let the linker locate data */
   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;
+  options.shortis8bits = 0;
+
+  options.stack10bit=0;
 
   /* now for the optimizations */
   /* turn on the everything */
@@ -473,13 +512,14 @@ setDefaultOptions ()
   optimize.loopInvariant = 1;
   optimize.loopInduction = 1;
 
+  /* now for the ports */
   port->setDefaultOptions ();
 }
 
 /*-----------------------------------------------------------------*/
 /* processFile - determines the type of file from the extension    */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 processFile (char *s)
 {
   char *fext = NULL;
@@ -502,40 +542,55 @@ processFile (char *s)
     {
       /* source file name : not if we already have a
          source file */
-      if (srcFileName)
+      if (fullSrcFileName)
        {
          werror (W_TOO_MANY_SRC, s);
          return;
        }
 
       /* the only source file */
-      if (!(srcFile = fopen ((fullSrcFileName = s), "r")))
+      fullSrcFileName = s;
+      if (!(srcFile = fopen (fullSrcFileName, "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 (1, strlen (buffer) + 1);
-      strcpy (srcFileName, buffer);
+      /* get rid of the "."-extension */
+
+      /* is there a dot at all? */
+      if (strrchr (buffer, '.') &&
+          /* is the dot in the filename, not in the path? */
+          (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
+        {
+        *strrchr (buffer, '.') = '\0';
+        }
 
       /* 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 */
+         for the module name; */
       fext = buffer + strlen (buffer);
+#if NATIVE_WIN32
+      /* do this by going backwards till we
+         get '\' or ':' or start of buffer */
       while (fext != buffer &&
-            *(fext - 1) != '\\' &&
-            *(fext - 1) != '/' &&
+            *(fext - 1) != DIR_SEPARATOR_CHAR &&
             *(fext - 1) != ':')
+        {
        fext--;
-      moduleName = Safe_calloc (1, strlen (fext) + 1);
-      strcpy (moduleName, fext);
-
+        }
+#else
+      /* do this by going backwards till we
+         get '/' or start of buffer */
+      while (fext != buffer &&
+            *(fext - 1) != DIR_SEPARATOR_CHAR)
+        {
+          fext--;
+        }
+#endif
+      moduleName = Safe_strdup ( fext );
       return;
     }
 
@@ -560,56 +615,176 @@ processFile (char *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.
+*/
+static char *
+getStringArg(const char *szStart, char **argv, int *pi, int argc)
 {
-  if (srcFileName)
+  if (argv[*pi][strlen(szStart)]) 
     {
-      if (options.out_name)
-       {
-         werror (W_TOO_MANY_SRC, s);
-         return;
-       }
-      options.out_name = strdup (s);
+      return &argv[*pi][strlen(szStart)];
     }
-  else
+  else 
     {
-      processFile (s);
+      ++(*pi);
+      if (*pi >= argc) 
+        {
+          werror (E_ARGUMENT_MISSING, szStart);
+          /* Die here rather than checking for errors later. */
+          exit(-1);
+        }
+      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. 
+*/
+static int
+getIntArg(const char *szStart, char **argv, int *pi, int argc)
+{
+    return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
+}
+
+static void
+verifyShortOption(const char *opt)
 {
-  /* This is the bad way to do things :) */
-  while (*list)
-    list++;
-  *list = strdup (str);
-  if (!*list)
+  if (strlen(opt) != 2)
     {
-      werror (E_OUT_OF_MEM, __FILE__, 0);
-      exit (1);
+      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];
+                        sprintf(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;
+    }
+}
+
+static bool
+scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
+{
+  int i;
+  for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != 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;
+         }
+       }
+    }
+  // 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;
+        }
 }
 
 /*-----------------------------------------------------------------*/
 /* parseCmdLine - parses the command line and sets the options     */
 /*-----------------------------------------------------------------*/
-int 
+static int
 parseCmdLine (int argc, char **argv)
 {
   int i;
-  char cdbfnbuf[50];
 
   /* go thru all whole command line */
   for (i = 1; i < argc; i++)
@@ -617,586 +792,314 @@ parseCmdLine (int argc, char **argv)
       if (i >= argc)
        break;
 
+      if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
+          {
+              continue;
+          }
+
+      if (tryHandleSimpleOpt(argv, &i) == TRUE)
+          {
+              continue;
+          }
+
       /* options */
       if (argv[i][0] == '-' && argv[i][1] == '-')
        {
-
-         if (strcmp (&argv[i][1], OPTION_HELP) == 0)
+         if (strcmp (argv[i], OPTION_HELP) == 0)
            {
              printUsage ();
              exit (0);
            }
 
-         if (strcmp (&argv[i][1], OPTION_XREGS) == 0)
+         if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
            {
-             options.regExtend = 1;
+             options.stack10bit = 0;
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_LARGE_MODEL) == 0)
+         if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
            {
-             _setModel (MODEL_LARGE, argv[i]);
+             options.out_fmt = 0;
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_MEDIUM_MODEL) == 0)
+         if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
            {
-             _setModel (MODEL_MEDIUM, argv[i]);
+             _setModel (MODEL_LARGE, argv[i]);
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_SMALL_MODEL) == 0)
+         if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
            {
-             _setModel (MODEL_SMALL, argv[i]);
+             _setModel (MODEL_MEDIUM, argv[i]);
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_FLAT24_MODEL) == 0)
+         if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
            {
-             _setModel (MODEL_FLAT24, argv[i]);
+             _setModel (MODEL_SMALL, argv[i]);
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_STACK_10BIT) == 0)
+         if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
            {
-             options.stack10bit = 1;
+             _setModel (MODEL_FLAT24, argv[i]);
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_STACK_AUTO) == 0)
+         if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
            {
-             options.stackAuto = 1;
+             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_DUMP_RAW) == 0)
+         if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
            {
-             options.dump_raw = 1;
-             continue;
+                options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_CYCLOMATIC) == 0)
-           {
-             options.cyclomatic = 1;
-             continue;
+         if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
+            {
+               libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_DUMP_GCSE) == 0)
+         if (strcmp (argv[i], OPTION_VERSION) == 0)
            {
-             options.dump_gcse = 1;
+             printVersionInfo ();
+              exit (0);
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_DUMP_LOOP) == 0)
+         if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
            {
-             options.dump_loop = 1;
-             continue;
+                parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_DUMP_KILL) == 0)
+         if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
            {
-             options.dump_kill = 1;
-             continue;
+                options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_INTLONG_RENT) == 0)
+         if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
            {
-             options.intlong_rent = 1;
-             continue;
+                options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_FLOAT_RENT) == 0)
+         if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
            {
-             options.float_rent = 1;
-             continue;
+                options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_DUMP_RANGE) == 0)
+         if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
            {
-             options.dump_range = 1;
-             continue;
+                options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_DUMP_PACK) == 0)
+         if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
            {
-             options.dump_pack = 1;
-             continue;
+                options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
+                options.xram_size_set = TRUE;
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_DUMP_RASSGN) == 0)
+         if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
            {
-             options.dump_rassgn = 1;
-             continue;
+                options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_OUT_FMT_IHX) == 0)
+         if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
            {
-             options.out_fmt = 0;
-             continue;
+                options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_OUT_FMT_S19) == 0)
+         if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
            {
-             options.out_fmt = 1;
-             continue;
+                options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_NOOVERLAY) == 0)
+         if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
            {
-             options.noOverlay = 1;
-             continue;
+                options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
+                continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_STKAFTRDATA) == 0)
+         if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
            {
-             options.stackOnData = 1;
+             optimize.global_cse = 0;
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_PREPROC_ONLY) == 0)
+         if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
            {
-             preProcOnly = 1;
+             optimize.loopInvariant = 0;
              continue;
            }
 
-         if (strcmp (&argv[i][1], OPTION_C1_MODE) == 0)
+         if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
            {
-             options.c1mode = 1;
+             optimize.loopInduction = 0;
              continue;
            }
 
+          if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
+            {
+             options.lessPedantic = 1;
+              setErrorLogLevel(ERROR_LEVEL_WARNING);
+              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_SHORT_IS_8BITS) == 0) 
+            {
+              options.shortis8bits=1;
+              continue;
+            }
 
-         if (strcmp (&argv[i][1], OPTION_GENERIC) == 0)
+         if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
            {
-             options.genericPtr = 1;
-             continue;
+                options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
+                continue;
            }
-
-         if (strcmp (&argv[i][1], OPTION_NOPEEP) == 0)
+          
+         if (!port->parseOption (&argc, argv, &i))
            {
-             options.nopeep = 1;
-             continue;
+             werror (W_UNKNOWN_OPTION, argv[i]);
            }
-
-         if (strcmp (&argv[i][1], OPTION_ASMPEEP) == 0)
+         else
            {
-             options.asmpeep = 1;
              continue;
            }
+       }
 
-         if (strcmp (&argv[i][1], OPTION_DEBUG) == 0)
+      /* if preceded by  '-' then option */
+      if (*argv[i] == '-')
+       {
+         switch (argv[i][1])
            {
-             options.debug = 1;
-             continue;
-           }
+           case 'h':
+              verifyShortOption(argv[i]);
 
-         if (strcmp (&argv[i][1], OPTION_NODEBUG) == 0)
-           {
-             options.nodebug = 1;
-             continue;
-           }
+             printUsage ();
+             exit (0);
+             break;
 
-         if (strcmp (&argv[i][1], OPTION_NOREGPARMS) == 0)
-           {
-             options.noregparms = 1;
-             continue;
-           }
+           case 'm':
+             /* Used to select the port. But this has already been done. */
+             break;
 
-         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;
-           }
+           case 'p':
+             /* Used to select the processor in port. But this has
+              * already been done. */
+             break;
 
-         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;
-           }
+           case 'c':
+              verifyShortOption(argv[i]);
 
-         if (strcmp (&argv[i][1], OPTION_XSTACK_LOC) == 0)
-           {
+             options.cc_only = 1;
+             break;
 
-             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;
-           }
+           case 'L':
+                libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
+                break;
+
+            case 'l':
+                libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
+                break;
+            
+            case 'o':
+              {
+                char *p;
+
+                /* copy the file name into the buffer */
+                strcpy (buffer, getStringArg("-o", argv, &i, argc));
+                /* point to last character */
+                p = buffer + strlen (buffer) - 1;
+                if (*p == DIR_SEPARATOR_CHAR)
+                  {
+                    /* only output path specified */
+                    dstPath = Safe_strdup (buffer);
+                    fullDstFileName = NULL;
+                  }
+                else
+                  {
+                    fullDstFileName = Safe_strdup (buffer);
+
+                    /* get rid of the "."-extension */
+
+                    /* is there a dot at all? */
+                    if (strrchr (buffer, '.') &&
+                        /* is the dot in the filename, not in the path? */
+                        (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
+                      *strrchr (buffer, '.') = '\0';
+
+                    dstFileName = Safe_strdup (buffer);
+
+                    /* strip module name to get path */
+                    p = strrchr (buffer, DIR_SEPARATOR_CHAR);
+                    if (p)
+                      {
+                        /* path with trailing / */
+                        p[1] = '\0';
+                        dstPath = Safe_strdup (buffer);
+                      }
+                  }
+                break;
+              }
 
-         if (strcmp (&argv[i][1], OPTION_XSTACK) == 0)
-           {
-             options.useXstack = 1;
-             continue;
-           }
+           case 'W':
+              /* pre-processer options */
+              if (argv[i][2] == 'p')
+                {
+                  parseWithComma ((char **)preArgv, getStringArg("-Wp", argv, &i, argc));
+                }
+             /* linker options */
+             else if (argv[i][2] == 'l')
+               {
+                  parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
+               }
+              /* assembler options */
+             else if (argv[i][2] == 'a')
+                {
+                  parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
+                }
+              else
+                {
+                  werror (W_UNKNOWN_OPTION, argv[i]);
+                }
+             break;
 
-         if (strcmp (&argv[i][1], OPTION_MAINRETURN) == 0)
-           {
-             options.mainreturn = 1;
-             continue;
-           }
+           case 'v':
+              verifyShortOption(argv[i]);
 
-         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;
+             printVersionInfo ();
+             exit (0);
+             break;
 
              /* preprocessor options */
            case 'M':
              {
                preProcOnly = 1;
-               _addToList (preArgv, "-M");
+               addToList (preArgv, "-M");
                break;
              }
            case 'C':
              {
-               _addToList (preArgv, "-C");
+               addToList (preArgv, "-C");
                break;
              }
            case 'd':
@@ -1211,16 +1114,25 @@ parseCmdLine (int argc, char **argv)
                if (argv[i][2] == ' ' || argv[i][2] == '\0')
                  {
                    i++;
-                   rest = argv[i];
+                    if (i >= argc)
+                      {
+                          /* No argument. */
+                          werror(E_ARGUMENT_MISSING, argv[i-1]);
+                          break;
+                      }
+                    else
+                      {
+                          rest = argv[i];
+                      }
                  }
                else
                  rest = &argv[i][2];
 
-               if (argv[i][1] == 'Y')
-                 argv[i][1] = 'I';
+               if (sOpt == 'Y')
+                 sOpt = 'I';
 
                sprintf (buffer, "-%c%s", sOpt, rest);
-               _addToList (preArgv, buffer);
+               addToList (preArgv, buffer);
              }
              break;
 
@@ -1234,23 +1146,55 @@ parseCmdLine (int argc, char **argv)
       if (!port->parseOption (&argc, argv, &i))
        {
          /* no option must be a filename */
-         if (options.c1mode)
-           _processC1Arg (argv[i]);
-         else
-           processFile (argv[i]);
+          processFile (argv[i]);
        }
     }
 
+  /* if no dstFileName given with -o, we've to find one: */
+  if (!dstFileName)
+    {
+      /* use the modulename from the C-source */
+      if (fullSrcFileName)
+        {
+          dstFileName = Safe_alloc (strlen (dstPath) + strlen (moduleName) + 1);
+          strcpy (dstFileName, dstPath);
+          strcat (dstFileName, moduleName);
+        }
+      /* use the modulename from the first object file */
+      else if (nrelFiles >= 1)
+        {
+          char *objectName;
+
+          strcpy (buffer, relFiles[0]);
+          /* remove extension (it must be .rel) */
+          *strrchr (buffer, '.') = '\0';
+          /* remove path */
+          objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
+          if (objectName)
+            {
+              ++objectName;
+            }
+          else
+            {
+              objectName = buffer;
+            }
+          dstFileName = Safe_alloc (strlen (dstPath) + strlen (objectName) + 1);
+          strcpy (dstFileName, dstPath);
+          strcat (dstFileName, objectName);
+        }
+      /* else no module given: help text is displayed */
+    }
+
   /* 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)
+  if (options.debug && fullSrcFileName)
     {
-      sprintf (cdbfnbuf, "%s.cdb", srcFileName);
-      if ((cdbFile = fopen (cdbfnbuf, "w")) == NULL)
-       werror (E_FILE_OPEN_ERR, cdbfnbuf);
+      sprintf (scratchFileName, "%s.adb", dstFileName); //JCF: Nov 30, 2002
+      if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
+       werror (E_FILE_OPEN_ERR, scratchFileName);
       else
        {
          /* add a module record */
@@ -1260,211 +1204,72 @@ parseCmdLine (int argc, char **argv)
   return 0;
 }
 
-/*-----------------------------------------------------------------*/
-/* my_system - will call a program with arguments                  */
-/*-----------------------------------------------------------------*/
-
-#if defined(_MSC_VER)
-
-char *try_dir[] =
-{DefaultExePath, NULL};                // TODO : Fill in some default search list
-
-#else
-
-//char *try_dir[]= {SRCDIR "/bin",PREFIX "/bin", NULL};
-char *try_dir[] =
-{NULL};
-
-#endif
-
-#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;
-       }
-      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
-
-int 
-my_system (const char *cmd, char **cmd_argv)
-{
-  char *dir, *got = NULL;
-  int i = 0;
-
-  while (!got && try_dir[i])
-    {
-      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
-
-      if (access (dir, X_OK) == 0)
-       {
-         got = strdup (dir);
-       }
-      free (dir);
-      i++;
-    }
-
-  if (verboseExec)
-    {
-      char **pCmd = cmd_argv;
-      printf ("+ ");
-      while (*pCmd)
-       {
-         printf ("%s ", *pCmd);
-         pCmd++;
-       }
-      printf ("\n");
-    }
-
-  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;
-    }
-
-  return 0;
-}
-#endif
-
 /*-----------------------------------------------------------------*/
 /* linkEdit : - calls the linkage editor  with options             */
 /*-----------------------------------------------------------------*/
-static void 
+static void
 linkEdit (char **envp)
 {
   FILE *lnkfile;
-#ifndef USE_SYSTEM_SYSTEM_CALLS
-  char *argv[128];
-#endif
   char *segName, *c;
-
-  int i;
-  if (!srcFileName)
-    srcFileName = "temp";
+  int i, system_ret;
 
   /* first we need to create the <filename>.lnk file */
-  sprintf (buffer, "%s.lnk", srcFileName);
-  if (!(lnkfile = fopen (buffer, "w")))
+  sprintf (scratchFileName, "%s.lnk", dstFileName);
+  if (!(lnkfile = fopen (scratchFileName, "w")))
     {
-      werror (E_FILE_OPEN_ERR, buffer);
+      werror (E_FILE_OPEN_ERR, scratchFileName);
       exit (1);
     }
 
-  /* now write the options */
-  fprintf (lnkfile, "-mux%c\n", (options.out_fmt ? 's' : 'i'));
+  /* now write the options.  JCF: added option 'y' */
+  fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
 
   /* 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) \
-    segName = strdup(N); \
+    segName = Safe_strdup(N); \
     c = strtok(segName, " \t"); \
     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
-    if (segName) { free(segName); }
+    if (segName) { Safe_free(segName); }
 
   /* code segment start */
   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
 
   /* data segment start */
-  WRITE_SEG_LOC (DATA_NAME, options.data_loc);
+  if(options.data_loc){ /*JCF: If zero, the linker chooses the best place for data*/
+         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);
+  if (IDATA_NAME) {
+    WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
+  }
 
   /* bit segment start */
   WRITE_SEG_LOC (BIT_NAME, 0);
 
+  /* JCF: stack start */
+  if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
+       WRITE_SEG_LOC ("SSEG", options.stack_loc);
+  }
+
   /* add the extra linker options */
   for (i = 0; linkOptions[i]; i++)
     fprintf (lnkfile, "%s\n", linkOptions[i]);
@@ -1476,36 +1281,44 @@ linkEdit (char **envp)
   /* standard library path */
   if (!options.nostdlib)
     {
-      if (IS_DS390_PORT)
+      switch (options.model)
        {
+       case MODEL_SMALL:
+         c = "small";
+         break;
+       case MODEL_LARGE:
+         c = "large";
+         break;
+       case MODEL_FLAT24:
+         /* c = "flat24"; */
          c = "ds390";
+         break;
+       case MODEL_PAGE0:
+         c = "xa51";
+         break;
+       default:
+         werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
+         c = "unknown";
+         break;
        }
-      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);
+      mfprintf (lnkfile, getRuntimeVariables(), "-k {libdir}{sep}%s\n", c);
 
       /* standard library files */
-      if (strcmp (port->target, "ds390") == 0)
+#if !OPT_DISABLE_DS390
+      if (options.model == MODEL_FLAT24)
        {
          fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
        }
+#endif
+
+#if !OPT_DISABLE_XA51 
+#ifdef STD_XA51_LIB
+      if (options.model == MODEL_PAGE0)
+       {
+         fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
+       }
+#endif
+#endif
       fprintf (lnkfile, "-l %s\n", STD_LIB);
       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
@@ -1517,8 +1330,8 @@ linkEdit (char **envp)
     fprintf (lnkfile, "-l %s\n", libFiles[i]);
 
   /* put in the object files */
-  if (strcmp (srcFileName, "temp"))
-    fprintf (lnkfile, "%s ", srcFileName);
+  if (fullSrcFileName)
+    fprintf (lnkfile, "%s ", dstFileName);
 
   for (i = 0; i < nrelFiles; i++)
     fprintf (lnkfile, "%s\n", relFiles[i]);
@@ -1529,141 +1342,223 @@ linkEdit (char **envp)
   if (options.verbose)
     printf ("sdcc: Calling linker...\n");
 
-#ifdef USE_SYSTEM_SYSTEM_CALLS
-  buildCmdLine (buffer, port->linker.cmd, srcFileName, NULL, NULL, NULL);
-  if (my_system (buffer))
+  /* build linker output filename */
+
+  /* -o option overrides default name? */
+  if (fullDstFileName)
     {
-      exit (1);
+      strcpy (scratchFileName, fullDstFileName);
     }
-#else
-  buildCmdLine (buffer, argv, port->linker.cmd, srcFileName, NULL, NULL, NULL);
-  if (my_system (argv[0], argv))
+  else
     {
-      perror ("Cannot exec linker");
-      exit (1);
+      /* the linked file gets the name of the first modul */
+      if (fullSrcFileName)
+        {
+          strcpy (scratchFileName, dstFileName);
+        }
+      else
+        {
+          strcpy (scratchFileName, relFiles[0]);
+          /* strip ".rel" extension */
+          *strrchr (scratchFileName, '.') = '\0';
+        }
+      strcat (scratchFileName, options.out_fmt ? ".S19" : ".ihx");
     }
 
-#endif
+  if (port->linker.cmd)
+    {
+      char buffer2[PATH_MAX];
+      buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, NULL);
+      buildCmdLine2 (buffer, buffer2);
+    }
+  else
+    {
+      buildCmdLine2 (buffer, port->linker.mcmd);
+    }
 
-  if (strcmp (srcFileName, "temp") == 0)
+  system_ret = my_system (buffer);
+  /* TODO: most linker don't have a -o parameter */
+  /* -o option overrides default name? */
+  if (fullDstFileName)
     {
-      /* rename "temp.cdb" to "firstRelFile.cdb" */
-      char *f = strtok (strdup (relFiles[0]), ".");
-      f = strcat (f, ".cdb");
-      rename ("temp.cdb", f);
-      srcFileName = NULL;
+      char *p, *q;
+      /* the linked file gets the name of the first modul */
+      if (fullSrcFileName)
+        {
+          strcpy (scratchFileName, dstFileName);
+          p = strlen (scratchFileName) + scratchFileName;
+        }
+      else
+        {
+          strcpy (scratchFileName, relFiles[0]);
+          /* strip "rel" extension */
+          p = strrchr (scratchFileName, '.') + 1;
+        }
+      strcpy (p, options.out_fmt ? "S19" : "ihx");
+      rename (scratchFileName, fullDstFileName);
+
+      q = strrchr (fullDstFileName, '.');
+      if (q)
+        {
+          /* point after the '.' of the extension */
+          q++;
+        }
+      else
+        {
+          /* no extension: append new extensions */
+          q = strlen (fullDstFileName) + fullDstFileName;
+        }
+      strcpy (p, "map");
+      strcpy (q, "map");
+      rename (scratchFileName, fullDstFileName);
+      strcpy (p, "mem");
+      strcpy (q, "mem");
+      rename (scratchFileName, fullDstFileName);
+    }
+  if (system_ret)
+    {
+      exit (1);
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* assemble - spawns the assembler with arguments                  */
 /*-----------------------------------------------------------------*/
-static void 
+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) {
+        strcpy (scratchFileName, fullDstFileName);
+    } else {
+        /* the assembled file gets the name of the first modul */
+        strcpy (scratchFileName, dstFileName);
+        strcat (scratchFileName, port->linker.rel_ext);
     }
-#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(asmOptions);
+       return ;
+    } else if (port->assembler.cmd) {
+        buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
+                     options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
+                     asmOptions);
+    } else {
+       buildCmdLine2 (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) {
+        strcpy (scratchFileName, dstFileName);
+        strcat (scratchFileName, port->linker.rel_ext);
+        rename (scratchFileName, fullDstFileName);
     }
-#endif
 }
 
-
-
 /*-----------------------------------------------------------------*/
 /* preProcess - spawns the preprocessor with arguments       */
 /*-----------------------------------------------------------------*/
-static int 
+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");
+       addToList (preArgv, "-DSDCC_USE_XSTACK");
 
       /* set the macro for stack autos  */
       if (options.stackAuto)
-       _addToList (preArgv, "-DSDCC_STACK_AUTO");
+       addToList (preArgv, "-DSDCC_STACK_AUTO");
 
       /* set the macro for stack autos  */
       if (options.stack10bit)
-       _addToList (preArgv, "-DSDCC_STACK_TENBIT");
+       addToList (preArgv, "-DSDCC_STACK_TENBIT");
+
+      /* set the macro for no overlay  */
+      if (options.noOverlay)
+        addToList (preArgv, "-DSDCC_NOOVERLAY");
 
       /* set the macro for large model  */
       switch (options.model)
        {
        case MODEL_LARGE:
-         _addToList (preArgv, "-DSDCC_MODEL_LARGE");
+         addToList (preArgv, "-DSDCC_MODEL_LARGE");
          break;
        case MODEL_SMALL:
-         _addToList (preArgv, "-DSDCC_MODEL_SMALL");
+         addToList (preArgv, "-DSDCC_MODEL_SMALL");
          break;
        case MODEL_COMPACT:
-         _addToList (preArgv, "-DSDCC_MODEL_COMPACT");
+         addToList (preArgv, "-DSDCC_MODEL_COMPACT");
          break;
        case MODEL_MEDIUM:
-         _addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
+         addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
          break;
        case MODEL_FLAT24:
-         _addToList (preArgv, "-DSDCC_MODEL_FLAT24");
+         addToList (preArgv, "-DSDCC_MODEL_FLAT24");
+         break;
+       case MODEL_PAGE0:
+         addToList (preArgv, "-DSDCC_MODEL_PAGE0");
          break;
        default:
          werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
          break;
        }
 
-
       /* add port (processor information to processor */
-      sprintf (procDef, "-DSDCC_%s", port->target);
-      _addToList (preArgv, procDef);
+      addToList (preArgv, "-DSDCC_{port}");
+      addToList (preArgv, "-D__{port}");
 
-      if (!preProcOnly)
-       preOutName = strdup (tmpnam (NULL));
+      /* standard include path */
+      if (!options.nostdinc) {
+       addToList (preArgv, "-I{includedir}");
+      }
+
+      setMainValue ("cppextraopts", join(preArgv));
+
+      if (preProcOnly)
+        {
+          if (fullDstFileName)
+              preOutName = Safe_strdup (fullDstFileName);
+        }
+      else
+          preOutName = Safe_strdup (tempfilename ());
+
+      /* Have to set cppoutfilename to something, even if just pre-processing. */
+      setMainValue ("cppoutfilename", preOutName ? preOutName : "");
 
       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);
+      buildCmdLine2 (buffer, _preCmd);
 
-      if (my_system (argv[0], argv))
+      if (my_system (buffer))
        {
-         unlink (preOutName);
-         perror ("Cannot exec Preprocessor");
+          // @FIX: Dario Vecchio 03-05-2001
+          if (preOutName)
+            {
+              unlink (preOutName);
+              Safe_free (preOutName);
+            }
+          // EndFix
          exit (1);
        }
 
-#endif
       if (preProcOnly)
+      {
        exit (0);
+      }
     }
   else
     {
@@ -1680,24 +1575,192 @@ preProcess (char **envp)
   return 0;
 }
 
-static void 
-_findPort (int argc, char **argv)
+static bool
+_setPaths (const char *pprefix)
 {
-  _validatePorts ();
+  /* Logic:
+      Given the prefix and how the directories were layed out at
+      configure time, see if the library and include directories are
+      where expected.  If so, set.
+  */
+  getPathDifference (buffer, PREFIX, SDCC_INCLUDE_DIR);
+  strcpy (scratchFileName, pprefix);
+  strcat (scratchFileName, buffer);
+
+  if (pathExists (scratchFileName))
+    {
+      setMainValue ("includedir", scratchFileName);
+    }
+  else
+    {
+      return FALSE;
+    }
+
+  getPathDifference (buffer, PREFIX, SDCC_LIB_DIR);
+  strcpy (scratchFileName, pprefix);
+  strcat (scratchFileName, buffer);
 
-  argc--;
-  while (argc)
+  if (pathExists (scratchFileName))
     {
-      if (!strncmp (*argv, "-m", 2))
-       {
-         _setPort (*argv + 2);
-         return;
-       }
-      argv++;
-      argc--;
+      setMainValue ("libdir", scratchFileName);
     }
-  /* Use the first in the list */
-  port = _ports[0];
+  else
+    {
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+_discoverPaths (const char *argv0)
+{
+  /* Logic:
+      1.  Try the SDCCDIR environment variable.
+      2.  If (1) fails, and if the argv[0] includes a path, attempt to find the include
+      and library paths with respect to that.  Note that under win32
+      argv[0] is always the full path to the program.
+      3.  If (1) and (2) fail, fall back to the compile time defaults.
+
+      Detecting assumes the same layout as when configured.  If the
+      directories have been further moved about then discovery will
+      fail.
+  */
+
+  /* Some input cases:
+        "c:\fish\sdcc\bin\sdcc"
+        "../bin/sdcc"
+        "/home/fish/bin/sdcc"
+
+      Note that ./sdcc is explicitly not supported as there isn't
+      enough information.
+  */
+  /* bindir is handled differently to the lib and include directories.
+     It's rather unfortunate, but required due to the different
+     install and development layouts.  Logic is different as well.
+     Sigh.
+   */
+  if (strchr (argv0, DIR_SEPARATOR_CHAR))
+    {
+      strcpy (scratchFileName, argv0);
+      *strrchr (scratchFileName, DIR_SEPARATOR_CHAR) = '\0';
+      setMainValue ("bindir", scratchFileName);
+      ExePathList[0] = Safe_strdup (scratchFileName);
+    }
+  else if (getenv (SDCCDIR_NAME) != NULL)
+    {
+      getPathDifference (buffer, PREFIX, BINDIR);
+      strcpy (scratchFileName, getenv (SDCCDIR_NAME));
+      strcat (scratchFileName, buffer);
+      setMainValue ("bindir", scratchFileName);
+      ExePathList[0] = Safe_strdup (scratchFileName);
+    }
+  else
+    {
+      setMainValue ("bindir", BINDIR);
+      ExePathList[0] = BINDIR;
+    }
+
+  do 
+    {
+      /* Case 1 */
+      if (getenv (SDCCDIR_NAME) != NULL)
+        {
+          if (_setPaths (getenv (SDCCDIR_NAME)))
+            {
+              /* Successfully set. */
+              break;
+            }
+          else
+            {
+              /* Include and lib weren't where expected. */
+            }
+        }
+      /* Case 2 */
+      if (strchr (argv0, DIR_SEPARATOR_CHAR))
+        {
+          char *pbase = getPrefixFromBinPath (argv0);
+
+          if (pbase == NULL)
+            {
+              /* A bad path.  Skip. */
+            }
+          else
+            {
+              if (_setPaths (pbase))
+                {
+                  /* Successfully set. */
+                  break;
+                }
+              else
+                {
+                  /* Include and lib weren't where expected. */
+                }
+            }
+        }
+      /* Case 3 */
+      setMainValue ("includedir", SDCC_INCLUDE_DIR);
+      setMainValue ("libdir", SDCC_LIB_DIR);
+    } while (0);
+}
+
+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}");
+    }
+
+}
+
+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;
+    }
+  fprintf (stderr, "Catched signal %d: %s\n", signal, sig_string);
+  exit (1);
 }
 
 /*
@@ -1705,7 +1768,7 @@ _findPort (int argc, char **argv)
  * initialises and calls the parser
  */
 
-int 
+int
 main (int argc, char **argv, char **envp)
 {
   /* turn all optimizations off by default */
@@ -1713,54 +1776,81 @@ main (int argc, char **argv, char **envp)
 
   /*printVersionInfo (); */
 
-  _findPort (argc, argv);
-  /* Initalise the port. */
-  if (port->init)
-    port->init ();
-
-#if defined(_MSC_VER)
+  if (NUM_PORTS==0) {
+    fprintf (stderr, "Build error: no ports are enabled.\n");
+    exit (1);
+  }
 
-  {
-    int i;
+  /* install atexit handler */
+  atexit(rm_tmpfiles);
 
-    // Create a default exe search path from the path to the sdcc command
+  /* install signal handler;
+     it's only purpuse is to call exit() to remove temp files */
+  signal (SIGABRT, sig_handler);
+  signal (SIGTERM, sig_handler);
+  signal (SIGINT , sig_handler);
+  signal (SIGSEGV, sig_handler);
 
-    strcpy (DefaultExePath, argv[0]);
+  /* 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).
+   */
 
-    for (i = strlen (DefaultExePath); i > 0; i--)
-      if (DefaultExePath[i] == '\\')
-       {
-         DefaultExePath[i] = '\0';
-         break;
-       }
+  _findPort (argc, argv);
 
-    if (i == 0)
-      DefaultExePath[0] = '\0';
+#ifdef JAMIN_DS390
+  if (strcmp(port->target, "mcs51") == 0) {
+    printf("DS390 jammed in A\n");
+         _setPort ("ds390");
+    ds390_jammed = 1;
   }
-
 #endif
 
-  setDefaultOptions ();
-  parseCmdLine (argc, argv);
+  _findProcessor (argc, argv);
 
-  initMem ();
+  /* Initalise the port. */
+  if (port->init)
+    port->init ();
 
-  port->finaliseOptions ();
+  // Create a default exe search path from the path to the sdcc command
+
+
+  setDefaultOptions ();
+#ifdef JAMIN_DS390
+  if (ds390_jammed) {
+    options.model = MODEL_SMALL;
+    options.stack10bit=0;
+  }
+#endif
+  parseCmdLine (argc, argv);
 
   /* if no input then printUsage & exit */
-  if ((!options.c1mode && !srcFileName && !nrelFiles) || (options.c1mode && !srcFileName && !options.out_name))
+  if ((!options.c1mode && !fullSrcFileName && !nrelFiles) ||
+      (options.c1mode && !fullSrcFileName))
     {
       printUsage ();
       exit (0);
     }
 
-  if (srcFileName)
+  initValues ();
+  _discoverPaths (argv[0]);
+
+  /* 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)
     {
       preProcess (envp);
 
       initSymt ();
       initiCode ();
       initCSupport ();
+      initBuiltIns();
       initPeepHole ();
 
       if (options.verbose)
@@ -1768,46 +1858,59 @@ main (int argc, char **argv, char **envp)
 
       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 (fatalError) {
+        // @FIX: Dario Vecchio 03-05-2001
+        if (preOutName) {
+          if (yyin && yyin != stdin)
+            fclose (yyin);
+          unlink (preOutName);
+          Safe_free (preOutName);
+        }
+        // EndFix
+        return 1;
+      }
+
+      if (TARGET_IS_PIC) {
+        /* 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
+        picglue ();
 #endif
-           glue ();
-         if (fatalError)
-           {
-             return 1;
-           }
-         if (!options.c1mode)
-           {
-             if (options.verbose)
-               printf ("sdcc: Calling assembler...\n");
-
-             assemble (envp);
-           }
-       }
-      else
-       {
-         return 1;
-       }
+      }
+      else {
+        glue ();
+      }
 
+      if (!options.c1mode && !noAssemble)
+        {
+          if (options.verbose)
+            printf ("sdcc: Calling assembler...\n");
+          assemble (envp);
+        }
     }
 
+  closeDumpFiles();
+
   if (cdbFile)
     fclose (cdbFile);
 
+  if (yyin && yyin != stdin)
+    fclose (yyin);
+
+  if (preOutName && !options.c1mode)
+    {
+      unlink (preOutName);
+      Safe_free (preOutName);
+    }
+
   if (!options.cc_only &&
       !fatalError &&
       !noAssemble &&
       !options.c1mode &&
-      (srcFileName || nrelFiles))
+      (fullSrcFileName || nrelFiles))
     {
       if (port->linker.do_link)
        port->linker.do_link ();
@@ -1815,15 +1918,5 @@ main (int argc, char **argv, char **envp)
        linkEdit (envp);
     }
 
-  if (yyin && yyin != stdin)
-    fclose (yyin);
-
-  if (preOutName && !options.c1mode)
-    {
-      unlink (preOutName);
-      free (preOutName);
-    }
-
   return 0;
-
 }