[msvc] Update csproj files
[mono.git] / eglib / src / gstr.c
index 0f66a43372e96e0f2ad6db4ac0ec3ef76290ecd6..98d8faf2679e9822d47a3831b32f3160d766a194 100644 (file)
 #include <ctype.h>
 #include <glib.h>
 
+#ifndef G_OS_WIN32
+#include <pthread.h>
+#endif
+
+#include <errno.h>
+
+/* 
+ * g_strndup and g_vasprintf need to allocate memory with g_malloc if 
+ * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free 
+ * rather than free.
+ */
+
 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
 gchar *
 g_strndup (const gchar *str, gsize n)
 {
-#ifdef HAVE_STRNDUP
+#if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
        return strndup (str, n);
 #else
        if (str) {
@@ -50,6 +62,37 @@ g_strndup (const gchar *str, gsize n)
 #endif
 }
 
+gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
+{
+#if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
+  return vasprintf (ret, fmt, ap);
+#else
+       char *buf;
+       int len;
+       size_t buflen;
+       va_list ap2;
+       
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+       ap2 = ap;
+       len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
+#else
+       va_copy(ap2, ap);
+       len = vsnprintf(NULL, 0, fmt, ap2);
+#endif
+
+       if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
+               len = vsnprintf(buf, buflen, fmt, ap);
+               *ret = buf;
+       } else {
+               *ret = NULL;
+               len = -1;
+       }
+
+       va_end(ap2);
+       return len;
+#endif
+}
+
 void
 g_strfreev (gchar **str_array)
 {
@@ -131,7 +174,7 @@ g_strdup_vprintf (const gchar *format, va_list args)
        int n;
        char *ret;
        
-       n = vasprintf (&ret, format, args);
+       n = g_vasprintf (&ret, format, args);
        if (n == -1)
                return NULL;
 
@@ -146,7 +189,7 @@ g_strdup_printf (const gchar *format, ...)
        int n;
 
        va_start (args, format);
-       n = vasprintf (&ret, format, args);
+       n = g_vasprintf (&ret, format, args);
        va_end (args);
        if (n == -1)
                return NULL;
@@ -154,10 +197,72 @@ g_strdup_printf (const gchar *format, ...)
        return ret;
 }
 
+
+/*
+Max error number we support. It's empirically found by looking at our target OS.
+
+Last this was checked was June-2017.
+
+Apple is at 106.
+Android is at 133.
+*/
+#define MONO_ERRNO_MAX 200
+#define str(s) #s
+
+#ifndef G_OS_WIN32
+static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+static char *error_messages [MONO_ERRNO_MAX];
+
 const gchar *
 g_strerror (gint errnum)
 {
-       return strerror (errnum);
+       if (errnum < 0)
+               errnum = -errnum;
+       if (errnum >= MONO_ERRNO_MAX)
+               return ("Error number higher than " str (MONO_ERRNO_MAX));
+
+       if (!error_messages [errnum]) {
+#ifndef G_OS_WIN32
+               pthread_mutex_lock (&strerror_lock);
+#endif
+
+#ifdef HAVE_STRERROR_R
+               char tmp_buff [128]; //Quite arbitrary, should be large enough
+               char *buff = tmp_buff;
+               int buff_len = sizeof (tmp_buff);
+               int r;
+               buff [0] = 0;
+
+               while ((r = strerror_r (errnum, buff, buff_len - 1))) {
+                       if (r != ERANGE) {
+                               buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
+                               break;
+                       }
+                       if (buff == tmp_buff)
+                               buff = g_malloc (buff_len * 2);
+                       else
+                               buff = g_realloc (buff, buff_len * 2);
+                       buff_len *= 2;
+                //Spec is not clean on whether size argument includes space for null terminator or not 
+               }
+               if (!error_messages [errnum])
+                       error_messages [errnum] = g_strdup (buff);
+               if (buff != tmp_buff)
+                       g_free (buff);
+#else
+               if (!error_messages [errnum])
+                       error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
+#endif
+
+
+#ifndef G_OS_WIN32
+               pthread_mutex_unlock (&strerror_lock);
+#endif
+
+       }
+       return error_messages [errnum];
 }
 
 gchar *
@@ -251,8 +356,12 @@ g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
        }
 
        if (*string) {
-               /* Add the rest of the string as the last element */
-               add_to_vector (&vector, size, g_strdup (string));
+               if (strcmp (string, delimiter) == 0)
+                       add_to_vector (&vector, size, g_strdup (""));
+               else {
+                       /* Add the rest of the string as the last element */
+                       add_to_vector (&vector, size, g_strdup (string));
+               }
                size++;
        }