summaryrefslogtreecommitdiff
path: root/src/SDCCutil.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCutil.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCutil.c')
-rw-r--r--src/SDCCutil.c1173
1 files changed, 1173 insertions, 0 deletions
diff --git a/src/SDCCutil.c b/src/SDCCutil.c
new file mode 100644
index 0000000..59bd60c
--- /dev/null
+++ b/src/SDCCutil.c
@@ -0,0 +1,1173 @@
+/*-------------------------------------------------------------------------
+ SDCCutil.c - Small utility functions.
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#undef TRUE
+#undef FALSE
+#endif
+#include <sys/stat.h>
+#include "dbuf.h"
+#include "SDCCglobl.h"
+#include "SDCCmacro.h"
+#include "SDCCutil.h"
+#include "newalloc.h"
+#include "dbuf_string.h"
+#ifndef _WIN32
+#include "findme.h"
+#endif
+
+#include "version.h"
+
+/** Given an array of name, value string pairs creates a new hash
+ containing all of the pairs.
+*/
+hTab *
+populateStringHash (const char **pin)
+{
+ hTab *pret = NULL;
+
+ while (*pin)
+ {
+ shash_add (&pret, pin[0], pin[1]);
+ pin += 2;
+ }
+
+ return pret;
+}
+
+
+/** shell escape string
+ returns dynamically allocated string, which should be free-ed
+*/
+char *
+shell_escape (const char *str)
+{
+#ifdef _WIN32
+ /* see http://www.autohotkey.net/~deleyd/parameters/parameters.htm */
+
+ struct dbuf_s dbuf;
+ int backshl = 0;
+ const char *begin = str;
+ char backslbuf[16];
+ char *backslp;
+
+ dbuf_init (&dbuf, 128);
+
+ /* opening double quotes */
+ dbuf_append_char(&dbuf, '"');
+ while (*str)
+ {
+ if (NULL == begin)
+ begin = str;
+
+ if ('\\' == *str)
+ ++backshl;
+ else
+ {
+ if ('"' == *str)
+ {
+ /* append the remaining characters */
+ if (str > begin)
+ dbuf_append (&dbuf, begin, str - begin);
+
+ /* append additional beckslash */
+ ++backshl;
+
+ /* special handling if last chars before double quote are backslashes */
+ backslp = backslbuf;
+ while (backshl--)
+ {
+ *backslp++ = '\\';
+ if (sizeof (backslbuf) == backslp - backslbuf)
+ {
+ dbuf_append (&dbuf, backslbuf, sizeof (backslbuf));
+ backslp = backslbuf;
+ }
+ }
+ if (backslp > backslbuf)
+ dbuf_append (&dbuf, backslbuf, backslp - backslbuf);
+
+ begin = str;
+ }
+ else if ('%' == *str)
+ {
+ /* diseble env. variable expansion */
+ /* append the remaining characters */
+ if (begin && str > begin)
+ dbuf_append (&dbuf, begin, str - begin);
+
+ /* special handling if last chars before double quote are backslashes */
+ backslp = backslbuf;
+ while (backshl--)
+ {
+ *backslp++ = '\\';
+ if (sizeof (backslbuf) == backslp - backslbuf)
+ {
+ dbuf_append (&dbuf, backslbuf, sizeof (backslbuf));
+ backslp = backslbuf;
+ }
+ }
+ if (backslp > backslbuf)
+ dbuf_append (&dbuf, backslbuf, backslp - backslbuf);
+
+ /* closing doube quotes */
+ backslbuf[0] = '"';
+ backslbuf[1] = *str;
+ /* re opening double quotes */
+ backslbuf[2] = '"';
+ dbuf_append (&dbuf, backslbuf, 3);
+ begin = NULL;
+ }
+ backshl = 0;
+ }
+ ++str;
+ }
+ /* append the remaining characters */
+ if (begin && str > begin)
+ dbuf_append (&dbuf, begin, str - begin);
+
+ /* special handling if last chars before double quote are backslashes */
+ backslp = backslbuf;
+ while (backshl--)
+ {
+ *backslp++ = '\\';
+ if (sizeof (backslbuf) == backslp - backslbuf)
+ {
+ dbuf_append (&dbuf, backslbuf, sizeof (backslbuf));
+ backslp = backslbuf;
+ }
+ }
+ if (backslp > backslbuf)
+ dbuf_append (&dbuf, backslbuf, backslp - backslbuf);
+
+ /* closing doube quotes */
+ dbuf_append_char (&dbuf, '"');
+
+ return dbuf_detach_c_str (&dbuf);
+#else
+ struct dbuf_s dbuf;
+ const char *s = str;
+ const char *begin = str;
+
+ dbuf_init (&dbuf, 128);
+
+ while (*s)
+ {
+ switch (*s)
+ {
+ case ' ': case '\t': case '\n': /* IFS white space */
+ case '\'': case '"': case '\\': /* quoting chars */
+ case '|': case '&': case ';': /* shell metacharacters */
+ case '(': case ')': case '<': case '>':
+ case '!': case '{': case '}': /* reserved words */
+ case '*': case '[': case '?': case ']': /* globbing chars */
+ case '^':
+ case '$': case '`': /* expansion chars */
+ case ',': /* brace expansion */
+ /* flush */
+ if (s > begin)
+ dbuf_append (&dbuf, begin, s - begin);
+
+ dbuf_append_char (&dbuf, '\\');
+ begin = s;
+ break;
+
+ case '~': /* tilde expansion */
+ if (s == str || s[-1] == '=' || s[-1] == ':')
+ {
+ /* flush */
+ if (s > begin)
+ dbuf_append (&dbuf, begin, s - begin);
+
+ dbuf_append_char (&dbuf, '\\');
+ begin = s;
+ }
+ break;
+
+ case '#': /* comment char */
+ {
+ /* flush */
+ if (s > begin)
+ dbuf_append (&dbuf, begin, s - begin);
+
+ dbuf_append_char (&dbuf, '\\');
+ begin = s;
+ }
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ ++s;
+ }
+ /* flush */
+ if (s > begin)
+ dbuf_append (&dbuf, begin, s - begin);
+
+ return dbuf_detach_c_str (&dbuf);
+#endif
+}
+
+/** Prints elements of the set to the file, each element on new line
+*/
+void
+fputStrSet (FILE * fp, set * list)
+{
+ const char *s;
+
+ for (s = setFirstItem (list); s != NULL; s = setNextItem (list))
+ {
+ fputs (s, fp);
+ fputc ('\n', fp);
+ }
+}
+
+/** Prepend / append / process given strings to each item of string set.
+ The result is in a new string set.
+*/
+set *
+processStrSet (set * list, const char *pre, const char *post, char *(*func)(const char *))
+{
+ set *new_list = NULL;
+ const char *item;
+ struct dbuf_s dbuf;
+
+ for (item = setFirstItem (list); item != NULL; item = setNextItem (list))
+ {
+ dbuf_init (&dbuf, PATH_MAX);
+
+ if (pre)
+ dbuf_append_str (&dbuf, pre);
+
+ if (func)
+ {
+ char *s = func (item);
+
+ dbuf_append_str (&dbuf, s);
+ Safe_free (s);
+ }
+ else
+ dbuf_append_str (&dbuf, item);
+
+ if (post)
+ dbuf_append_str (&dbuf, post);
+
+ addSet (&new_list, dbuf_detach_c_str (&dbuf));
+ }
+
+ return new_list;
+}
+
+/** Given a set returns a string containing all of the strings seperated
+ by spaces. The returned string is on the heap.
+*/
+const char *
+joinStrSet (set * list)
+{
+ const char *s;
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+
+ for (s = setFirstItem (list); s != NULL; s = setNextItem (list))
+ {
+ dbuf_append_str (&dbuf, s);
+ dbuf_append_char (&dbuf, ' ');
+ }
+
+ return dbuf_detach_c_str (&dbuf);
+}
+
+/** Split the path string to the directory and file name (including extension) components.
+ The directory component doesn't contain trailing directory separator.
+ Returns true if the path contains the directory separator. */
+int
+dbuf_splitPath (const char *path, struct dbuf_s *dir, struct dbuf_s *file)
+{
+ const char *p;
+ int ret;
+ const char *end = &path[strlen (path)];
+
+ for (p = end - 1; p >= path && !IS_DIR_SEPARATOR (*p); --p)
+ ;
+
+ ret = p >= path;
+
+ if (NULL != dir)
+ {
+ int len = p - path;
+
+ if (0 < len)
+ dbuf_append (dir, path, len);
+ }
+
+ if (NULL != file)
+ {
+ int len;
+
+ ++p;
+ len = end - p;
+
+ if (0 < len)
+ dbuf_append (file, p, len);
+ }
+
+ return ret;
+}
+
+/** Split the path string to the file name (including directory) and file extension components.
+ File extension component contains the extension separator.
+ Returns true if the path contains the extension separator. */
+int
+dbuf_splitFile (const char *path, struct dbuf_s *file, struct dbuf_s *ext)
+{
+ const char *p;
+ const char *end = &path[strlen (path)];
+
+ for (p = end - 1; p >= path && !IS_DIR_SEPARATOR (*p) && '.' != *p; --p)
+ ;
+
+ if (p < path || '.' != *p)
+ {
+ dbuf_append_str (file, path);
+
+ return 0;
+ }
+ else
+ {
+ if (NULL != file)
+ {
+ int len = p - path;
+
+ if (0 < len)
+ dbuf_append (file, path, len);
+ }
+
+ if (NULL != ext)
+ {
+ int len = end - p;
+
+ if (0 < len)
+ dbuf_append (ext, p, len);
+ }
+
+ return 1;
+ }
+}
+
+/** Combine directory and the file name to a path string using the DIR_SEPARATOR_CHAR.
+ */
+void
+dbuf_makePath (struct dbuf_s *path, const char *dir, const char *file)
+{
+ if (dir != NULL)
+ dbuf_append_str (path, dir);
+
+ dbuf_append_char (path, DIR_SEPARATOR_CHAR);
+
+ if (file != NULL)
+ dbuf_append_str (path, file);
+}
+
+/** Given a file with path information in the binary files directory,
+ returns the directory component. Used for discovery of bin
+ directory of SDCC installation. Returns NULL if the path is
+ impossible.
+*/
+#ifdef _WIN32
+const char *
+getBinPath (const char *prel)
+{
+ struct dbuf_s path;
+ const char *p;
+
+ dbuf_init (&path, 128);
+ dbuf_splitPath (prel, &path, NULL);
+
+ p = dbuf_c_str (&path);
+ if ('\0' != *p)
+ return p;
+ else
+ {
+ char module[PATH_MAX];
+
+ dbuf_destroy (&path);
+
+ /* not enough info in prel; do it with module name */
+ if (0 != GetModuleFileName (NULL, module, sizeof (module)))
+ {
+ dbuf_init (&path, 128);
+
+ dbuf_splitPath (module, &path, NULL);
+ return dbuf_detach_c_str (&path);
+ }
+ else
+ return NULL;
+ }
+}
+#else
+const char *
+getBinPath (const char *prel)
+{
+ const char *ret_path;
+
+ if (NULL != (ret_path = findProgramPath (prel)))
+ {
+ struct dbuf_s path;
+
+ dbuf_init (&path, 128);
+
+ dbuf_splitPath (ret_path, &path, NULL);
+ free ((void *) ret_path);
+ return dbuf_detach_c_str (&path);
+ }
+ else
+ return NULL;
+}
+#endif
+
+/** Returns true if the given path exists.
+ */
+bool
+pathExists (const char *ppath)
+{
+ struct stat s;
+
+ return stat (ppath, &s) == 0;
+}
+
+static hTab *_mainValues;
+
+void
+setMainValue (const char *pname, const char *pvalue)
+{
+ assert (pname);
+
+ shash_add (&_mainValues, pname, pvalue);
+}
+
+char *
+buildMacros (const char *cmd)
+{
+ return eval_macros (_mainValues, cmd);
+}
+
+char *
+buildCmdLine (const char **cmds, const char *p1, const char *p2, const char *p3, set * list)
+{
+ int first = 1;
+ struct dbuf_s dbuf;
+
+ assert (cmds != NULL);
+
+ dbuf_init (&dbuf, 256);
+
+ while (*cmds)
+ {
+ const char *p, *from, *par;
+ int sep = 1;
+
+ from = *cmds;
+ cmds++;
+
+ /* See if it has a '$' anywhere - if not, just copy */
+ if ((p = strchr (from, '$')))
+ {
+ /* include first part of cmd */
+ if (p != from)
+ {
+ if (!first && sep)
+ dbuf_append_char (&dbuf, ' ');
+ dbuf_append (&dbuf, from, p - from);
+ sep = 0;
+ }
+ from = p + 2;
+
+ /* include parameter */
+ p++;
+ switch (*p)
+ {
+ case '1':
+ par = p1;
+ break;
+
+ case '2':
+ par = p2;
+ break;
+
+ case '3':
+ par = p3;
+ break;
+
+ case 'l':
+ {
+ const char *tmp;
+ par = NULL;
+
+ if (list != NULL && (tmp = (const char *) setFirstItem (list)) != NULL)
+ {
+ do
+ {
+ if (*tmp != '\0')
+ {
+ if (sep)
+ dbuf_append_char (&dbuf, ' '); /* seperate it */
+ dbuf_append_str (&dbuf, tmp);
+ tmp++;
+ sep = 1;
+ }
+ }
+ while ((tmp = (const char *) setNextItem (list)) != NULL);
+ }
+ }
+ break;
+
+ default:
+ par = NULL;
+ assert (0);
+ }
+
+ if (par && *par != '\0')
+ {
+ if (!first && sep)
+ dbuf_append_char (&dbuf, ' '); /* seperate it */
+ dbuf_append_str (&dbuf, par);
+ sep = 0;
+ }
+ }
+
+ /* include the rest of cmd, e.g. ".asm" from "$1.asm" */
+ if (*from != '\0')
+ {
+ if (!first && sep)
+ dbuf_append_char (&dbuf, ' '); /* seperate it */
+ dbuf_append_str (&dbuf, from);
+ sep = 0;
+ }
+
+ first = 0;
+ }
+
+ return dbuf_detach_c_str (&dbuf);
+}
+
+char *
+buildCmdLine2 (const char *pcmd, ...)
+{
+ va_list ap;
+ char *poutcmd;
+
+ assert (pcmd);
+ assert (_mainValues);
+
+ va_start (ap, pcmd);
+
+ poutcmd = mvsprintf (_mainValues, pcmd, ap);
+
+ va_end (ap);
+
+ return poutcmd;
+}
+
+void
+populateMainValues (const char **ppin)
+{
+ _mainValues = populateStringHash (ppin);
+}
+
+/** Returns true if sz starts with the string given in key.
+ */
+bool
+startsWith (const char *sz, const char *key)
+{
+ return !strncmp (sz, key, strlen (key));
+}
+
+/** Removes any newline characters from the string. Not strictly the
+ same as perl's chomp.
+*/
+void
+chomp (char *sz)
+{
+ char *nl;
+ while ((nl = strrchr (sz, '\n')))
+ *nl = '\0';
+}
+
+hTab *
+getRuntimeVariables (void)
+{
+ return _mainValues;
+}
+
+/* strncpy() with guaranteed NULL termination. */
+char *
+strncpyz (char *dest, const char *src, size_t n)
+{
+ assert (n > 0);
+
+ --n;
+ /* paranoia... */
+ if (strlen (src) > n)
+ {
+ fprintf (stderr, "strncpyz prevented buffer overrun!\n");
+ }
+
+ strncpy (dest, src, n);
+ dest[n] = 0;
+ return dest;
+}
+
+/* like strncat() with guaranteed NULL termination
+ * The passed size should be the size of the dest buffer, not the number of
+ * bytes to copy.
+ */
+char *
+strncatz (char *dest, const char *src, size_t n)
+{
+ size_t maxToCopy;
+ size_t destLen = strlen (dest);
+
+ assert (n > 0);
+ assert (n > destLen);
+
+ maxToCopy = n - destLen - 1;
+
+ /* paranoia... */
+ if (strlen (src) + destLen >= n)
+ {
+ fprintf (stderr, "strncatz prevented buffer overrun!\n");
+ }
+
+ strncat (dest, src, maxToCopy);
+ dest[n - 1] = 0;
+ return dest;
+}
+
+/*-----------------------------------------------------------------*/
+/* getBuildNumber - return build number */
+/*-----------------------------------------------------------------*/
+const char *
+getBuildNumber (void)
+{
+ return (SDCC_BUILD_NUMBER);
+}
+
+/*-----------------------------------------------------------------*/
+/* getBuildEnvironment - return environment used to build SDCC */
+/*-----------------------------------------------------------------*/
+const char *
+getBuildEnvironment (void)
+{
+#ifdef __CYGWIN__
+ return "CYGWIN";
+#elif defined __MINGW64__
+ return "MINGW64";
+#elif defined __MINGW32__
+ return "MINGW32";
+#elif defined __DJGPP__
+ return "DJGPP";
+#elif defined(_MSC_VER)
+ return "MSVC";
+#elif defined(__BORLANDC__)
+ return "BORLANDC";
+#elif defined(__APPLE__)
+#if defined(__i386__)
+ return "Mac OS X i386";
+#elif defined(__x86_64__)
+ return "Mac OS X x86_64";
+#else
+ return "Mac OS X ppc";
+#endif
+#elif defined(__linux__)
+ return "Linux";
+#elif defined(__NetBSD__)
+ return "NetBSD";
+#elif defined(__FreeBSD__)
+ return "FreeBSD";
+#elif defined(__OpenBSD__)
+ return "OpenBSD";
+#elif defined(__sun)
+#if defined(__i386)
+ return "Solaris i386";
+#elif defined(__amd64)
+ return "Solaris amd64";
+#else
+ return "Solaris SPARC";
+#endif
+#else
+ return "UNIX";
+#endif
+}
+
+size_t
+SDCCsnprintf (char *dst, size_t n, const char *fmt, ...)
+{
+ va_list args;
+ int len;
+
+ va_start (args, fmt);
+
+ len = vsnprintf (dst, n, fmt, args);
+
+ va_end (args);
+
+ /* on some gnu systems, vsnprintf returns -1 if output is truncated.
+ * In the C99 spec, vsnprintf returns the number of characters that
+ * would have been written, were space available.
+ */
+ if ((len < 0) || (size_t) len >= n)
+ {
+ fprintf (stderr, "internal error: sprintf truncated.\n");
+ }
+
+ return len;
+}
+
+/** Pragma tokenizer
+ */
+void
+init_pragma_token (struct pragma_token_s *token)
+{
+ dbuf_init (&token->dbuf, 16);
+ token->type = TOKEN_UNKNOWN;
+}
+
+char *
+get_pragma_token (const char *s, struct pragma_token_s *token)
+{
+ dbuf_set_length (&token->dbuf, 0);
+
+ /* skip leading spaces */
+ while ('\n' != *s && isspace (*s))
+ ++s;
+
+ if ('\0' == *s || '\n' == *s)
+ {
+ token->type = TOKEN_EOL;
+ }
+ else
+ {
+ char *end;
+
+ long val = strtol (s, &end, 0);
+
+ if (end != s && ('\0' == *end || isspace (*end)))
+ {
+ token->val.int_val = val;
+ token->type = TOKEN_INT;
+ dbuf_append (&token->dbuf, s, end - s);
+ s = end;
+ }
+ else
+ {
+ while ('\0' != *s && !isspace (*s))
+ {
+ dbuf_append_char (&token->dbuf, *s);
+ ++s;
+ }
+
+ token->type = TOKEN_STR;
+ }
+ }
+
+ return (char *) s;
+}
+
+const char *
+get_pragma_string (struct pragma_token_s *token)
+{
+ return dbuf_c_str (&token->dbuf);
+}
+
+void
+free_pragma_token (struct pragma_token_s *token)
+{
+ dbuf_destroy (&token->dbuf);
+}
+
+/*! /fn char hexEscape(char **src)
+
+ /param src Pointer to 'x' from start of hex character value
+*/
+
+unsigned long int
+hexEscape (const char **src)
+{
+ char *s;
+ unsigned long value;
+
+ ++*src; /* Skip over the 'x' */
+
+ value = strtoul (*src, &s, 16);
+
+ if (s == *src)
+ {
+ /* no valid hex found */
+ werror (E_INVALID_HEX);
+ }
+
+ *src = s;
+
+ return value;
+}
+
+/*------------------------------------------------------------------*/
+/* universalEscape - process an hex constant of exactly four digits */
+/* return the hex value, throw a warning for illegal octal */
+/* adjust src to point at the last proccesed char */
+/*------------------------------------------------------------------*/
+
+unsigned long int
+universalEscape (const char **str, unsigned int n)
+{
+ unsigned int digits;
+ unsigned long value = 0;
+ const char *s = *str;
+
+ if (!options.std_c95)
+ {
+ werror (W_UNIVERSAL_C95);
+ }
+
+ ++*str; /* Skip over the 'u' or 'U' */
+
+ for (digits = 0; digits < n; ++digits)
+ {
+ if (**str >= '0' && **str <= '7')
+ {
+ value = (value << 4) + (**str - '0');
+ ++*str;
+ }
+ else if ((**str | 0x20) >= 'a' && (**str | 0x20) <= 'f')
+ {
+ value = (value << 4) + (**str - 'a' + 10);
+ ++*str;
+ }
+ else
+ break;
+ }
+ if (digits != n || value < 0x00a0 && value != 0x0024 && value != 0x0040 && value != 0x0060 || value >= 0xd800 && 0xdfff >= value)
+ {
+ werror (E_INVALID_UNIVERSAL, s);
+ }
+
+ return value;
+}
+
+/*------------------------------------------------------------------*/
+/* octalEscape - process an octal constant of max three digits */
+/* return the octal value, throw a warning for illegal octal */
+/* adjust src to point at the last proccesed char */
+/*------------------------------------------------------------------*/
+
+unsigned long int
+octalEscape (const char **str)
+{
+ int digits;
+ unsigned value = 0;
+
+ for (digits = 0; digits < 3; ++digits)
+ {
+ if (**str >= '0' && **str <= '7')
+ {
+ value = value * 8 + (**str - '0');
+ ++*str;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return value;
+}
+
+/*!
+ /fn const char *copyStr (const char *src, size_t *size)
+
+ Copies source string to a dynamically allocated buffer interpreting
+ escape sequences and special characters
+
+ /param src Buffer containing the source string with escape sequecnes
+ /param size Pointer to loction where the resulting buffer length is written
+ /return Dynamically allocated resulting buffer
+*/
+
+const char *
+copyStr (const char *src, size_t *size)
+{
+ const char *begin = NULL;
+ struct dbuf_s dbuf;
+
+ dbuf_init(&dbuf, 128);
+
+ while (*src)
+ {
+ if (*src == '\"')
+ {
+ if (begin)
+ {
+ /* copy what we have until now */
+ dbuf_append (&dbuf, begin, src - begin);
+ begin = NULL;
+ }
+ ++src;
+ }
+ else if (*src == '\\')
+ {
+ unsigned long int c;
+ bool universal = FALSE;
+
+ if (begin)
+ {
+ /* copy what we have until now */
+ dbuf_append (&dbuf, begin, src - begin);
+ begin = NULL;
+ }
+ ++src;
+ switch (*src)
+ {
+ case 'n':
+ c = '\n';
+ break;
+
+ case 't':
+ c = '\t';
+ break;
+
+ case 'v':
+ c = '\v';
+ break;
+
+ case 'b':
+ c = '\b';
+ break;
+
+ case 'r':
+ c = '\r';
+ break;
+
+ case 'f':
+ c = '\f';
+ break;
+
+ case 'a':
+ c = '\a';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ c = octalEscape (&src);
+ --src;
+ break;
+
+ case 'x':
+ c = hexEscape (&src);
+ --src;
+ break;
+
+ case 'u':
+ c = universalEscape (&src, 4);
+ universal = TRUE;
+ --src;
+ break;
+
+ case 'U':
+ c = universalEscape (&src, 8);
+ universal = TRUE;
+ --src;
+ break;
+
+ case '\\':
+ case '\?':
+ case '\'':
+ case '\"':
+ default:
+ c = *src;
+ break;
+ }
+ if (universal) // Encode one utf-32 character to utf-8
+ {
+ char s[5] = "\0\0\0\0";
+ if (c < 0x80)
+ s[0] = (char)c;
+ else if (c < 0x800)
+ {
+ s[0] = (c >> 6) & 0x1f | 0xc0;
+ s[1] = (c >> 0) & 0x3f | 0x80;
+ }
+ else if (c < 0x10000)
+ {
+ s[0] = (c >> 12) & 0x0f | 0xe0;
+ s[1] = (c >> 6) & 0x3f | 0x80;
+ s[2] = (c >> 0) & 0x3f | 0x80;
+ }
+ else if (c < 0x110000)
+ {
+ s[0] = (c >> 18) & 0x07 | 0xf0;
+ s[1] = (c >> 12) & 0x3f | 0x80;
+ s[2] = (c >> 6) & 0x3f | 0x80;
+ s[3] = (c >> 0) & 0x3f | 0x80;
+ }
+ else
+ wassert (0);
+ dbuf_append_str (&dbuf, s);
+ }
+ else
+ dbuf_append_char (&dbuf, (char)c);
+
+ ++src;
+ }
+ else
+ {
+ if (!begin)
+ begin = src;
+ ++src;
+ }
+ }
+
+ if (begin)
+ {
+ /* copy what we have until now */
+ dbuf_append (&dbuf, begin, src - begin);
+ begin = NULL;
+ }
+
+ if (size)
+ {
+ /* include null terminator character
+ appended by dbuf_detach_c_str() */
+ *size = dbuf_get_length (&dbuf) + 1;
+ }
+
+ return dbuf_detach_c_str (&dbuf);
+}
+
+static char prefix[256] = "";
+static char suffix[256] = "";
+static char cmd[4096] = "";
+
+void getPrefixSuffix(const char *arg)
+{
+ const char *p;
+ const char sdcc[] = "sdcc";
+
+ if (!arg)
+ return;
+
+ p = arg + strlen (arg);
+ while (p != arg && *(p - 1) != '\\' && *(p - 1) != '/')
+ p--;
+ arg = p;
+
+ /* found no "sdcc" in command line argv[0] */
+ if ((p = strstr (arg, sdcc)) == NULL)
+ return;
+
+ /* found more than one "sdcc" in command line argv[0] */
+ if (strstr (p + strlen (sdcc), sdcc) != NULL)
+ return;
+
+ /* copy prefix and suffix */
+ strncpy (prefix, arg, p - arg);
+ strcpy (suffix, p + strlen (sdcc));
+}
+
+char *setPrefixSuffix(const char *arg)
+{
+ const char *p;
+
+ if (!arg)
+ return NULL;
+ else
+ memset (cmd, 0x00, sizeof (cmd));
+
+ /* find the core name of command line */
+ for (p = arg; (*p) && isblank (*p); p++);
+ arg = p;
+ assert (strstr (arg, ".exe") == NULL);
+ for (p = arg; (*p) && !isblank (*p); p++);
+
+ /* compose new command line with prefix and suffix */
+ strcpy (cmd, prefix);
+ strncat (cmd, arg, p - arg);
+ strcat (cmd, suffix);
+ strcat (cmd, p);
+
+ return cmd;
+}
+
+char *formatInlineAsm (char *asmStr)
+{
+ char *p, *q;
+
+ if (!asmStr)
+ return NULL;
+ else
+ q = asmStr;
+
+ for (;;)
+ {
+ // omit leading space or tab
+ while (*q == '\t' || *q == ' ')
+ q++;
+ // then record the head of current line
+ p = q;
+ // search for CL or reach the end
+ while (*q != '\n' && *q != '\r' && *q != 0)
+ q++;
+ // omit more CL characters
+ while (*q == '\n' || *q == '\r')
+ q++;
+ // replace the first with tab
+ while (p != q)
+ if (*p == '\t') // '\t' appears first then no need to do
+ {
+ break;
+ }
+ else if (*p == ' ') // find the first space then replace it with tab
+ {
+ *p = '\t';
+ break;
+ }
+ else // go on to search
+ {
+ p++;
+ }
+ // check if end
+ if (*q == 0)
+ return asmStr;
+ }
+}