* sim/ucsim/cmd.src/cmdutil.cc: NUL device is detected as CG_FILE type
[fw/sdcc] / src / SDCCmain.c
index 12893d7ea1b2131dcca40d4085de0ae8fff5da4e..e6c867f804fde3906a10072f31901d5854ed04b5 100644 (file)
@@ -32,6 +32,7 @@
 #include "common.h"
 #include <ctype.h>
 #include "newalloc.h"
+#include "dbuf_string.h"
 #include "SDCCerr.h"
 #include "BuildCmd.h"
 #include "MySystem.h"
@@ -87,14 +88,14 @@ set *libDirsSet = NULL;         /* list of lib search directories */
 int ds390_jammed = 0;
 #endif
 
-/* Globally accessible scratch buffer for file names. */
+/* Globally accessible scratch buffer for file names.
+   TODO: replace them with local buffers */
 char scratchFileName[PATH_MAX];
 char buffer[PATH_MAX * 2];
 
-#define OPTION_HELP     "-help"
-
 #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"
@@ -142,11 +143,12 @@ char buffer[PATH_MAX * 2];
 #define OPTION_STD_SDCC99       "--std-sdcc99"
 #define OPTION_CODE_SEG         "--codeseg"
 #define OPTION_CONST_SEG        "--constseg"
+#define OPTION_DOLLARS_IN_IDENT "--fdollars-in-identifiers"
 
 static const OPTION
 optionsTable[] = {
     { 0,    NULL,                   NULL, "General options" },
-    { 0,    "--help",               NULL, "Display this help" },
+    { 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" },
@@ -165,7 +167,7 @@ optionsTable[] = {
     { '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, &options.use_stdout, "send errors to stdout instead of stderr"},
+    { 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" },
@@ -176,12 +178,13 @@ optionsTable[] = {
     { 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,    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, "not supported" },
+    { 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)" },
@@ -257,14 +260,16 @@ optionsTable[] = {
     { 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_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_STACK_SIZE,      NULL,"MCS51/DS390 - Tells the linker to allocate this space for stack"},
     { 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
@@ -306,7 +311,7 @@ static const char *_baseValues[] = {
   NULL
 };
 
-static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
+static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
 
 PORT *port;
 
@@ -376,7 +381,6 @@ static void
 _setProcessor (char *_processor)
 {
   port->processor = _processor;
-  fprintf(stderr,"Processor: %s\n",_processor);
 }
 
 static void
@@ -413,7 +417,7 @@ _findPort (int argc, char **argv)
     }
 
   /* Use the first in the list */
-        port = _ports[0];
+  port = _ports[0];
 }
 
 /* search through the command line options for the processor */
@@ -437,16 +441,16 @@ _findProcessor (int argc, char **argv)
 /* printVersionInfo - prints the version info        */
 /*-----------------------------------------------------------------*/
 void
-printVersionInfo (void)
+printVersionInfo (FILE *stream)
 {
   int i;
 
-  fprintf (stderr,
+  fprintf (stream,
            "SDCC : ");
   for (i = 0; i < NUM_PORTS; i++)
-    fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
+    fprintf (stream, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
 
-  fprintf (stderr, " " SDCC_VERSION_STR
+  fprintf (stream, " " SDCC_VERSION_STR
 #ifdef SDCC_SUB_VERSION_STR
            "/" SDCC_SUB_VERSION_STR
 #endif
@@ -468,7 +472,7 @@ printVersionInfo (void)
 }
 
 static void
-printOptions(const OPTION *optionsTable)
+printOptions(const OPTION *optionsTable, FILE *stream)
 {
   int i;
   for (i = 0;
@@ -479,11 +483,11 @@ printOptions(const OPTION *optionsTable)
       if (!optionsTable[i].shortOpt && !optionsTable[i].longOpt
           && optionsTable[i].help)
         {
-          fprintf (stdout, "\n%s:\n", optionsTable[i].help);
+          fprintf (stream, "\n%s:\n", optionsTable[i].help);
         }
       else
         {
-          fprintf(stdout, "  %c%c  %-20s  %s\n",
+          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 : "",
@@ -496,50 +500,64 @@ printOptions(const OPTION *optionsTable)
 /*-----------------------------------------------------------------*/
 /* printUsage - prints command line syntax         */
 /*-----------------------------------------------------------------*/
-void
+static void
 printUsage (void)
 {
     int i;
-    printVersionInfo();
-    fprintf (stdout,
+    FILE *stream = stderr;
+
+    printVersionInfo (stream);
+    fprintf (stream,
              "Usage : sdcc [options] filename\n"
              "Options :-\n"
              );
 
-    printOptions(optionsTable);
+    printOptions (optionsTable, stream);
 
     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);
+            fprintf (stream, "\nSpecial options for the %s port:\n", _ports[i]->target);
+            printOptions (_ports[i]->poptions, stream);
           }
       }
-
-    exit (0);
 }
 
 /*-----------------------------------------------------------------*/
 /* setParseWithComma - separates string with comma to a set        */
 /*-----------------------------------------------------------------*/
 void
-setParseWithComma (set **dest, char *src)
+setParseWithComma (set **dest, const char *src)
 {
-  char *p;
-  int length;
+  const char *p, *end;
+  struct dbuf_s dbuf;
 
   /* skip the initial white spaces */
-  while (isspace(*src))
-    src++;
+  while (isspace((unsigned char)*src))
+    ++src;
 
   /* skip the trailing white spaces */
-  length = strlen(src);
-  while (length && isspace(src[length-1]))
-    src[--length] = '\0';
+  end = &src[strlen(src) - 1];
+  while (end >= src && isspace((unsigned char)*end))
+    --end;
+  ++end;
+
+  p = src;
+  while (src < end)
+    {
+      dbuf_init (&dbuf, 16);
 
-  for (p = strtok(src, ","); p != NULL; p = strtok(NULL, ","))
-    addSet(dest, Safe_strdup(p));
+      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;
+    }
 }
 
 /*-----------------------------------------------------------------*/
@@ -549,20 +567,20 @@ static void
 setDefaultOptions (void)
 {
   /* 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.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 = 0x80;
+  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.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 */
 
@@ -588,29 +606,42 @@ setDefaultOptions (void)
 static void
 processFile (char *s)
 {
-  char *fext = NULL;
+  const char *extp;
+  struct dbuf_s ext;
+  struct dbuf_s path;
 
-  /* get the file extension */
-  fext = s + strlen (s);
-  while ((fext != s) && *fext != '.')
-    fext--;
+  dbuf_init (&ext, 128);
+  dbuf_init (&path, 128);
 
-  /* now if no '.' then we don't know what the file type is
+  /* get the file extension.
+     If no '.' then we don't know what the file type is
      so give a warning and return */
-  if (fext == s)
+  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)
+  extp = dbuf_c_str (&ext);
+  if (extp[1] == '\0' && (extp[0] == 'c' || extp[0] == 'C'))
     {
+      unsigned 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;
         }
 
@@ -619,71 +650,55 @@ processFile (char *s)
       if (!(srcFile = fopen (fullSrcFileName, "r")))
         {
           werror (E_FILE_OPEN_ERR, s);
-          exit (1);
-        }
 
-      /* copy the file name into the buffer */
-      strncpyz (buffer, s, sizeof(buffer));
+          dbuf_destroy (&path);
 
-      /* 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';
+          exit (1);
         }
 
       /* get rid of any path information
          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) != DIR_SEPARATOR_CHAR &&
-             *(fext - 1) != ':')
-        {
-        fext--;
-        }
-#else
-      /* do this by going backwards till we
-         get '/' or start of buffer */
-      while (fext != buffer &&
-             *(fext - 1) != DIR_SEPARATOR_CHAR)
-        {
-          fext--;
-        }
-#endif
-      moduleNameBase = Safe_strdup ( fext );
-      moduleName = Safe_strdup ( fext );
+      dbuf_init (&ext, 128);
+
+      dbuf_splitPath (dbuf_c_str (&path), NULL, &ext);
+      dbuf_destroy (&path);
 
-      for (fext = moduleName; *fext; fext++)
-        if (!isalnum (*fext))
-          *fext = '_';
+      moduleNameBase = Safe_strdup (dbuf_c_str (&ext));
+      moduleName = dbuf_detach (&ext);
+
+      for (p = moduleName; *p; ++p)
+        if (!isalnum(*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)
+     additional object file will be passed to the linker */
+  if ((extp[1] == '\0' && (extp[0] == 'r' || extp[0] == 'R')) ||
+      strcmp (extp, "rel") == 0 || strcmp (extp, "REL") == 0 ||
+      strcmp (extp, port->linker.rel_ext) == 0)
     {
-      addSet(&relFilesSet, Safe_strdup(s));
+      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)
+  if (strcmp (extp, "lib") == 0 || strcmp (extp, ".LIB") == 0)
     {
-      addSet(&libFilesSet, Safe_strdup(s));
+      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
@@ -712,7 +727,7 @@ getStringArg(const char *szStart, char **argv, int *pi, int argc)
         {
           werror (E_ARGUMENT_MISSING, szStart);
           /* Die here rather than checking for errors later. */
-          exit(-1);
+          exit (EXIT_FAILURE);
         }
       else
         {
@@ -742,42 +757,43 @@ verifyShortOption(const char *opt)
 static bool
 tryHandleUnsupportedOpt(char **argv, int *pi)
 {
-    if (argv[*pi][0] == '-')
-        {
-            const char *longOpt = "";
-            char shortOpt = -1;
-            int i;
+  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;
+      if (argv[*pi][1] == '-')
+        {
+          /* Long option. */
+          longOpt = argv[*pi];
         }
-    else
+      else
         {
-            /* Not an option, so can't be unsupported :) */
-            return 0;
+          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;
     }
 }
 
@@ -882,10 +898,19 @@ parseCmdLine (int argc, char **argv)
       /* 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 (0);
+              exit (EXIT_SUCCESS);
             }
 
           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
@@ -956,8 +981,8 @@ parseCmdLine (int argc, char **argv)
 
           if (strcmp (argv[i], OPTION_VERSION) == 0)
             {
-              printVersionInfo ();
-              exit (0);
+              printVersionInfo (stdout);
+              exit (EXIT_SUCCESS);
               continue;
             }
 
@@ -999,14 +1024,14 @@ parseCmdLine (int argc, char **argv)
 
           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
             {
-              options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
+              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_IRAM_SIZE, argv, &i, argc);
+              options.code_size = getIntArg(OPTION_CODE_SIZE, argv, &i, argc);
               continue;
             }
 
@@ -1125,13 +1150,21 @@ parseCmdLine (int argc, char **argv)
 
           if (strcmp (argv[i], OPTION_CODE_SEG) == 0)
             {
-              options.code_seg = getStringArg(OPTION_CODE_SEG, argv, &i, argc);
+              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)
             {
-              options.const_seg = getStringArg(OPTION_CONST_SEG, argv, &i, argc);
+              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;
             }
 
@@ -1155,7 +1188,7 @@ parseCmdLine (int argc, char **argv)
               verifyShortOption(argv[i]);
 
               printUsage ();
-              exit (0);
+              exit (EXIT_SUCCESS);
               break;
 
             case 'm':
@@ -1183,41 +1216,40 @@ parseCmdLine (int argc, char **argv)
 
             case 'o':
               {
-                char *p;
+                char *outName = getStringArg("-o", argv, &i, argc);
+                size_t len = strlen(outName);
 
-                /* copy the file name into the buffer */
-                strncpyz(buffer, getStringArg("-o", argv, &i, argc),
-                         sizeof(buffer));
                 /* point to last character */
-                p = buffer + strlen (buffer) - 1;
-                if (*p == DIR_SEPARATOR_CHAR)
+                if (IS_DIR_SEPARATOR(outName[len - 1]))
                   {
                     /* only output path specified */
-                    dstPath = Safe_strdup (buffer);
+                    dstPath = Safe_malloc(len);
+                    memcpy(dstPath, outName, len - 1);
+                    dstPath[len - 1] = '\0';
                     fullDstFileName = NULL;
                   }
                 else
                   {
-                    fullDstFileName = Safe_strdup (buffer);
+                    struct dbuf_s path;
 
-                    /* get rid of the "."-extension */
+                    dbuf_init (&path, 128);
+                    fullDstFileName = Safe_strdup (outName);
 
-                    /* 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 the "."-extension */
+                    dbuf_splitFile (outName, &path, NULL);
 
-                    dstFileName = Safe_strdup (buffer);
+                    dbuf_c_str (&path);
+                    dstFileName = dbuf_detach (&path);
 
+                    dbuf_init (&path, 128);
                     /* strip module name to get path */
-                    p = strrchr (buffer, DIR_SEPARATOR_CHAR);
-                    if (p)
+                    if (dbuf_splitPath (dstFileName, &path, NULL))
                       {
-                        /* path with trailing / */
-                        p[1] = '\0';
-                        dstPath = Safe_strdup (buffer);
+                        dbuf_c_str (&path);
+                        dstPath = dbuf_detach (&path);
                       }
+                    else
+                      dbuf_destroy (&path);
                   }
                 break;
               }
@@ -1247,7 +1279,7 @@ parseCmdLine (int argc, char **argv)
             case 'v':
               verifyShortOption(argv[i]);
 
-              printVersionInfo ();
+              printVersionInfo (stdout);
               exit (0);
               break;
 
@@ -1368,35 +1400,41 @@ parseCmdLine (int argc, char **argv)
       /* use the modulename from the C-source */
       if (fullSrcFileName)
         {
-          size_t bufSize = strlen (dstPath) + strlen (moduleNameBase) + 1;
+          struct dbuf_s path;
 
-          dstFileName = Safe_alloc (bufSize);
-          strncpyz (dstFileName, dstPath, bufSize);
-          strncatz (dstFileName, moduleNameBase, bufSize);
+          if (*dstPath != '\0')
+            {
+              dbuf_makePath (&path, dstPath, moduleNameBase);
+              dbuf_c_str (&path);
+              dstFileName = dbuf_detach (&path);
+            }
+          else
+            dstFileName = Safe_strdup(moduleNameBase);
         }
       /* use the modulename from the first object file */
       else if ((s = peekSet(relFilesSet)) != NULL)
         {
-          char *objectName;
-          size_t bufSize;
+          struct dbuf_s file;
+
+          dbuf_init(&file, 128);
 
-          strncpyz (buffer, s, sizeof(buffer));
-          /* remove extension (it must be .rel) */
-          *strrchr (buffer, '.') = '\0';
-          /* remove path */
-          objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
-          if (objectName)
+          dbuf_splitPath (s, NULL, &file);
+
+          if (*dstPath != '\0')
             {
-              ++objectName;
+              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
             {
-              objectName = buffer;
+              dbuf_c_str (&file);
+              dstFileName = dbuf_detach (&file);
             }
-          bufSize = strlen (dstPath) + strlen (objectName) + 1;
-          dstFileName = Safe_alloc (bufSize);
-          strncpyz (dstFileName, dstPath, bufSize);
-          strncatz (dstFileName, objectName, bufSize);
         }
       /* else no module given: help text is displayed */
     }
@@ -1429,7 +1467,6 @@ parseCmdLine (int argc, char **argv)
         werror (E_FILE_OPEN_ERR, scratchFileName);
     }
   MSVC_style(options.vc_err_style);
-  if(options.use_stdout) dup2(STDOUT_FILENO, STDERR_FILENO);
 
   return 0;
 }
@@ -1476,7 +1513,7 @@ linkEdit (char **envp)
           exit (1);
         }
 
-      if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
+      if (TARGET_Z80_LIKE)
         {
           fprintf (lnkfile, "--\n-m\n-j\n-x\n-%c %s\n",
             out_fmt, dstFileName);
@@ -1488,7 +1525,7 @@ linkEdit (char **envp)
               fprintf (lnkfile, "-Y\n");
         }
 
-      if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
+      if (!(TARGET_Z80_LIKE)) /*Not for the z80, gbz80*/
         {
           /* if iram size specified */
           if (options.iram_size)
@@ -1516,7 +1553,7 @@ linkEdit (char **envp)
   fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
   if (segName) { Safe_free(segName); }
 
-      if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
+      if (!(TARGET_Z80_LIKE)) /*Not for the z80, gbz80*/
         {
 
           /* code segment start */
@@ -1524,18 +1561,25 @@ linkEdit (char **envp)
 
           /* data segment start. If zero, the linker chooses
              the best place for data */
-          if(options.data_loc)
+          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)
+          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)
             {
@@ -1574,15 +1618,27 @@ linkEdit (char **envp)
       /* standard library path */
       if (!options.nostdlib)
         {
-          if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80 || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
+          if (!(TARGET_Z80_LIKE || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
             {
               switch (options.model)
                 {
                 case MODEL_SMALL:
-                  c = "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:
-                  c = "large";
+                  if (options.stackAuto)
+                    c = "large-stack-auto";
+                  else
+                    c = "large";
                   break;
                 case MODEL_FLAT24:
                   /* c = "flat24"; */
@@ -1599,7 +1655,7 @@ linkEdit (char **envp)
                       fprintf(stderr,
                         "Add support for your FLAT24 target in %s @ line %d\n",
                         __FILE__, __LINE__);
-                      exit(-1);
+                      exit (EXIT_FAILURE);
                     }
                   break;
                 case MODEL_PAGE0:
@@ -1647,7 +1703,7 @@ linkEdit (char **envp)
                   fprintf(stderr,
                     "Add support for your FLAT24 target in %s @ line %d\n",
                     __FILE__, __LINE__);
-                  exit(-1);
+                  exit (EXIT_FAILURE);
                 }
               }
 #endif
@@ -1664,8 +1720,7 @@ linkEdit (char **envp)
             {
               fprintf (lnkfile, "-l mcs51\n");
             }
-          if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80
-            || TARGET_IS_HC08)) /*Not for the z80, gbz80*/
+          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);
@@ -1689,8 +1744,7 @@ linkEdit (char **envp)
       /*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_IS_Z80 || TARGET_IS_GBZ80) &&
-        !options.no_std_crt0) /*For the z80, gbz80*/
+      if ((TARGET_Z80_LIKE) && !options.no_std_crt0) /*For the z80, gbz80*/
         {
           char crt0path[PATH_MAX];
           FILE * crt0fp;
@@ -1775,7 +1829,7 @@ linkEdit (char **envp)
       set *tempSet=NULL, *libSet=NULL;
 
       strcpy(buffer3, linkerScriptFileName);
-      if(TARGET_IS_PIC16 || TARGET_IS_PIC) {
+      if(/*TARGET_IS_PIC16 ||*/ TARGET_IS_PIC) {
 
          /* use $l to set the linker include directories */
          tempSet = appendStrSet(libDirsSet, "-I\"", "\"");
@@ -1812,6 +1866,7 @@ linkEdit (char **envp)
   /*  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)
@@ -1840,8 +1895,8 @@ linkEdit (char **envp)
       strncatz (scratchFileName,
         options.out_fmt ? ".S19" : ".ihx",
         sizeof(scratchFileName));
-      if (strcmp (fullDstFileName, scratchFileName))
-        unlink (fullDstFileName);
+      if (FILENAME_CMP (fullDstFileName, scratchFileName))
+        remove (fullDstFileName);
       rename (scratchFileName, fullDstFileName);
 
       strncpyz (buffer, fullDstFileName, sizeof(buffer));
@@ -1856,15 +1911,15 @@ linkEdit (char **envp)
       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
       *q = 0;
       strncatz(buffer, ".map", sizeof(buffer));
-      if (strcmp (scratchFileName, buffer))
-        unlink (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 (strcmp (scratchFileName, buffer))
-        unlink (buffer);
+      if (FILENAME_CMP (scratchFileName, buffer))
+        remove (buffer);
       rename (scratchFileName, buffer);
       if (options.debug)
         {
@@ -1872,14 +1927,14 @@ linkEdit (char **envp)
           strncatz (scratchFileName, ".cdb", sizeof(scratchFileName));
           *q = 0;
           strncatz(buffer, ".cdb", sizeof(buffer));
-          if (strcmp (scratchFileName, buffer))
-            unlink (buffer);
+          if (FILENAME_CMP (scratchFileName, buffer))
+            remove (buffer);
           rename (scratchFileName, buffer);
           /* and the OMF file without extension: */
           *p = 0;
           *q = 0;
-          if (strcmp (scratchFileName, buffer))
-            unlink (buffer);
+          if (FILENAME_CMP (scratchFileName, buffer))
+            remove (buffer);
           rename (scratchFileName, buffer);
         }
     }
@@ -1932,7 +1987,7 @@ assemble (char **envp)
                   port->linker.rel_ext,
                   sizeof(scratchFileName));
         if (strcmp (scratchFileName, fullDstFileName))
-          unlink (fullDstFileName);
+          remove (fullDstFileName);
         rename (scratchFileName, fullDstFileName);
     }
 }
@@ -1952,6 +2007,20 @@ preProcess (char **envp)
       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 using dollar signs in identifiers */
+      if (options.dollars_in_ident)
+        addSet(&preArgvSet, Safe_strdup("--fdollars-in-identifiers"));
+
       /* if using external stack define the macro */
       if (options.useXstack)
         addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
@@ -1994,10 +2063,24 @@ preProcess (char **envp)
           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\"", "\"");
@@ -2022,7 +2105,6 @@ preProcess (char **envp)
 
       if (options.verbose)
         printf ("sdcc: Calling preprocessor...\n");
-
       buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
 
       if (preProcOnly) {
@@ -2038,7 +2120,6 @@ preProcess (char **envp)
           perror ("Preproc file not found");
           exit (1);
       }
-      addSetHead (&pipeSet, yyin);
     }
 
   return 0;
@@ -2048,7 +2129,7 @@ preProcess (char **envp)
 static void
 setBinPaths(const char *argv0)
 {
-  char *p;
+  const char *p;
   char buf[PATH_MAX];
 
   /*
@@ -2063,19 +2144,12 @@ setBinPaths(const char *argv0)
      instead of slower addSet() */
 
   if ((p = getBinPath(argv0)) != NULL)
-    addSetHead(&binPathSet, Safe_strdup(p));
+    addSetHead(&binPathSet, (void *)p);
 
   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
     addSetHead(&binPathSet, Safe_strdup(buf));
   }
-
-#if 0
-  if (options.printSearchDirs) {
-    printf("programs:\n");
-    fputStrSet(stdout, binPathSet);
-  }
-#endif
 }
 
 /* Set system include path */
@@ -2119,13 +2193,6 @@ setIncludePath(void)
         addSetHead(&includeDirsSet, p2);
     }
   }
-
-#if 0
-  if (options.printSearchDirs) {
-    printf("includedir:\n");
-    fputStrSet(stdout, includeDirsSet);
-  }
-#endif
 }
 
 /* Set system lib path */
@@ -2150,20 +2217,13 @@ setLibPath(void)
 
   if ((p = getenv(SDCC_LIB_NAME)) != NULL)
     addSetHead(&libDirsSet, p);
-
-#if 0
-  if (options.printSearchDirs) {
-    printf("libdir:\n");
-    fputStrSet(stdout, libDirsSet);
-  }
-#endif
 }
 
 /* Set data path */
 static void
 setDataPaths(const char *argv0)
 {
-  char *p;
+  const char *p;
   char buf[PATH_MAX];
 
   /*
@@ -2181,6 +2241,7 @@ setDataPaths(const char *argv0)
 
   if ((p = getBinPath(argv0)) != NULL) {
     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
+    free((void *)p);
     addSet(&dataDirsSet, Safe_strdup(buf));
   }
 
@@ -2193,13 +2254,6 @@ setDataPaths(const char *argv0)
   addSet(&dataDirsSet, Safe_strdup(DATADIR));
 #endif
 
-#if 0
-  if (options.printSearchDirs) {
-    printf("datadir:\n");
-    fputStrSet(stdout, dataDirsSet);
-  }
-#endif
-
   setIncludePath();
   setLibPath();
 }
@@ -2291,18 +2345,13 @@ main (int argc, char **argv, char **envp)
   /* turn all optimizations off by default */
   memset (&optimize, 0, sizeof (struct optimize));
 
-  /*printVersionInfo (); */
-
   if (NUM_PORTS==0) {
     fprintf (stderr, "Build error: no ports are enabled.\n");
     exit (1);
   }
 
-  /* install atexit handler */
-  atexit(rm_tmpfiles);
-
   /* install signal handler;
-     it's only purpuse is to call exit() to remove temp files */
+     it's only purpose is to call exit() to remove temp files */
   if (!getenv("SDCC_LEAVE_SIGNALS"))
     {
       signal (SIGABRT, sig_handler);
@@ -2322,7 +2371,7 @@ main (int argc, char **argv, char **envp)
 #ifdef JAMIN_DS390
   if (strcmp(port->target, "mcs51") == 0) {
     printf("DS390 jammed in A\n");
-          _setPort ("ds390");
+    _setPort ("ds390");
     ds390_jammed = 1;
   }
 #endif
@@ -2340,8 +2389,12 @@ main (int argc, char **argv, char **envp)
     options.stack10bit=0;
   }
 #endif
+
   parseCmdLine (argc, argv);
 
+  if (options.verbose && NULL != port->processor)
+    printf("Processor: %s\n", port->processor);
+
   initValues ();
 
   setBinPaths(argv[0]);
@@ -2354,12 +2407,13 @@ main (int argc, char **argv, char **envp)
         doPrintSearchDirs();
 
   /* if no input then printUsage & exit */
-  if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL) {
-    if (!options.printSearchDirs)
+  if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL)
+    {
+      if (options.printSearchDirs)
+        exit (EXIT_SUCCESS);
       printUsage();
-
-    exit(0);
-  }
+      exit (EXIT_FAILURE);
+    }
 
   /* initMem() is expensive, but
      initMem() must called before port->finaliseOptions ().
@@ -2385,10 +2439,9 @@ main (int argc, char **argv, char **envp)
 
       if (pclose(yyin))
         fatalError = 1;
-      deleteSetItem(&pipeSet, yyin);
 
       if (fatalError) {
-        exit (1);
+        exit (EXIT_FAILURE);
       }
 
       if (port->general.do_glue != NULL)
@@ -2423,6 +2476,9 @@ main (int argc, char **argv, char **envp)
       !options.c1mode &&
       (fullSrcFileName || peekSet(relFilesSet) != NULL))
     {
+      if (options.verbose)
+        printf ("sdcc: Calling linker...\n");
+
       if (port->linker.do_link)
         port->linker.do_link ();
       else