Unref callback->cb_data if it was still set when the source is freed.
[platform/upstream/glib.git] / gstrfuncs.c
index 1ed8a2d..792278a 100644 (file)
@@ -2,23 +2,23 @@
  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library 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
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 /*
- * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GLib Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 #include <signal.h>
 #endif
 #include "glib.h"
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
+
 /* do not include <unistd.h> in this place since it
  * inteferes with g_strsignal() on some OSes
  */
@@ -200,9 +205,11 @@ g_strtod (const gchar *nptr,
     {
       gchar *old_locale;
 
-      old_locale = setlocale (LC_NUMERIC, "C");
+      old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
+      setlocale (LC_NUMERIC, "C");
       val_2 = strtod (nptr, &fail_pos_2);
       setlocale (LC_NUMERIC, old_locale);
+      g_free (old_locale);
     }
 
   if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
@@ -669,12 +676,12 @@ g_strsignal (gint signum)
   char *msg;
 
 #ifdef HAVE_STRSIGNAL
-#ifdef GLIB_NATIVE_BEOS
+#ifdef G_OS_BEOS
 extern const char * strsignal(int);
-#else /* !GLIB_NATIVE_BEOS */
+#else /* !G_OS_BEOS */
   /* this is declared differently (const) in string.h on BeOS */
   extern char *strsignal (int sig);
-#endif /* !GLIB_NATIVE_BEOS */
+#endif /* !G_OS_BEOS */
   return strsignal (signum);
 #elif NO_SYS_SIGLIST
   switch (signum)
@@ -790,183 +797,175 @@ extern const char * strsignal(int);
     }
 
   sprintf (msg, "unknown signal (%d)", signum);
-
+  
   return msg;
 }
 
-guint
-g_printf_string_upper_bound (const gchar* format,
-                            va_list      args)
+/* Functions g_strlcpy and g_strlcat were originally developed by
+ * Todd C. Miller <Todd.Miller@courtesan.com> to simplify writing secure code.
+ * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3
+ * for more information.
+ */
+
+#ifdef HAVE_STRLCPY
+/* Use the native ones, if available; they might be implemented in assembly */
+gsize
+g_strlcpy (gchar       *dest,
+          const gchar *src,
+          gsize        dest_size)
 {
-  guint len = 1;
+  g_return_val_if_fail (dest != NULL, 0);
+  g_return_val_if_fail (src  != NULL, 0);
+  
+  return strlcpy (dest, src, dest_size);
+}
 
-  while (*format)
-    {
-      gboolean long_int = FALSE;
-      gboolean extra_long = FALSE;
-      gchar c;
+gsize
+g_strlcat (gchar       *dest,
+          const gchar *src,
+          gsize        dest_size)
+{
+  g_return_val_if_fail (dest != NULL, 0);
+  g_return_val_if_fail (src  != NULL, 0);
+  
+  return strlcat (dest, src, dest_size);
+}
 
-      c = *format++;
+#else /* ! HAVE_STRLCPY */
+/* g_strlcpy
+ *
+ * Copy string src to buffer dest (of buffer size dest_size).  At most
+ * dest_size-1 characters will be copied.  Always NUL terminates
+ * (unless dest_size == 0).  This function does NOT allocate memory.
+ * Unlike strncpy, this function doesn't pad dest (so it's often faster).
+ * Returns size of attempted result, strlen(src),
+ * so if retval >= dest_size, truncation occurred.
+ */
+gsize
+g_strlcpy (gchar       *dest,
+           const gchar *src,
+           gsize        dest_size)
+{
+  register gchar *d = dest;
+  register const gchar *s = src;
+  register gsize n = dest_size;
+  
+  g_return_val_if_fail (dest != NULL, 0);
+  g_return_val_if_fail (src  != NULL, 0);
+  
+  /* Copy as many bytes as will fit */
+  if (n != 0 && --n != 0)
+    do
+      {
+       register gchar c = *s++;
+       
+       *d++ = c;
+       if (c == 0)
+         break;
+      }
+    while (--n != 0);
+  
+  /* If not enough room in dest, add NUL and traverse rest of src */
+  if (n == 0)
+    {
+      if (dest_size != 0)
+       *d = 0;
+      while (*s++)
+       ;
+    }
+  
+  return s - src - 1;  /* count does not include NUL */
+}
 
-      if (c == '%')
+/* g_strlcat
+ *
+ * Appends string src to buffer dest (of buffer size dest_size).
+ * At most dest_size-1 characters will be copied.
+ * Unlike strncat, dest_size is the full size of dest, not the space left over.
+ * This function does NOT allocate memory.
+ * This always NUL terminates (unless siz == 0 or there were no NUL characters
+ * in the dest_size characters of dest to start with).
+ * Returns size of attempted result, which is
+ * MIN (dest_size, strlen (original dest)) + strlen (src),
+ * so if retval >= dest_size, truncation occurred.
+ */
+gsize
+g_strlcat (gchar       *dest,
+           const gchar *src,
+           gsize        dest_size)
+{
+  register gchar *d = dest;
+  register const gchar *s = src;
+  register gsize bytes_left = dest_size;
+  gsize dlength;  /* Logically, MIN (strlen (d), dest_size) */
+  
+  g_return_val_if_fail (dest != NULL, 0);
+  g_return_val_if_fail (src  != NULL, 0);
+  
+  /* Find the end of dst and adjust bytes left but don't go past end */
+  while (*d != 0 && bytes_left-- != 0)
+    d++;
+  dlength = d - dest;
+  bytes_left = dest_size - dlength;
+  
+  if (bytes_left == 0)
+    return dlength + strlen (s);
+  
+  while (*s != 0)
+    {
+      if (bytes_left != 1)
        {
-         gboolean done = FALSE;
-
-         while (*format && !done)
-           {
-             switch (*format++)
-               {
-                 gchar *string_arg;
-
-               case '*':
-                 len += va_arg (args, int);
-                 break;
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                 /* add specified format length, since it might exceed the
-                  * size we assume it to have.
-                  */
-                 format -= 1;
-                 len += strtol (format, (char**) &format, 10);
-                 break;
-               case 'h':
-                 /* ignore short int flag, since all args have at least the
-                  * same size as an int
-                  */
-                 break;
-               case 'l':
-                 if (long_int)
-                   extra_long = TRUE; /* linux specific */
-                 else
-                   long_int = TRUE;
-                 break;
-               case 'q':
-               case 'L':
-                 long_int = TRUE;
-                 extra_long = TRUE;
-                 break;
-               case 's':
-                 string_arg = va_arg (args, char *);
-                 if (string_arg)
-                   len += strlen (string_arg);
-                 else
-                   {
-                     /* add enough padding to hold "(null)" identifier */
-                     len += 16;
-                   }
-                 done = TRUE;
-                 break;
-               case 'd':
-               case 'i':
-               case 'o':
-               case 'u':
-               case 'x':
-               case 'X':
-#ifdef G_HAVE_GINT64
-                 if (extra_long)
-                   (void) va_arg (args, gint64);
-                 else
-#endif /* G_HAVE_GINT64 */
-                   {
-                     if (long_int)
-                       (void) va_arg (args, long);
-                     else
-                       (void) va_arg (args, int);
-                   }
-                 len += extra_long ? 64 : 32;
-                 done = TRUE;
-                 break;
-               case 'D':
-               case 'O':
-               case 'U':
-                 (void) va_arg (args, long);
-                 len += 32;
-                 done = TRUE;
-                 break;
-               case 'e':
-               case 'E':
-               case 'f':
-               case 'g':
-#ifdef HAVE_LONG_DOUBLE
-                 if (extra_long)
-                   (void) va_arg (args, long double);
-                 else
-#endif /* HAVE_LONG_DOUBLE */
-                   (void) va_arg (args, double);
-                 len += extra_long ? 64 : 32;
-                 done = TRUE;
-                 break;
-               case 'c':
-                 (void) va_arg (args, int);
-                 len += 1;
-                 done = TRUE;
-                 break;
-               case 'p':
-               case 'n':
-                 (void) va_arg (args, void*);
-                 len += 32;
-                 done = TRUE;
-                 break;
-               case '%':
-                 len += 1;
-                 done = TRUE;
-                 break;
-               default:
-                 /* ignore unknow/invalid flags */
-                 break;
-               }
-           }
+         *d++ = *s;
+         bytes_left--;
        }
-      else
-       len += 1;
+      s++;
     }
-
-  return len;
+  *d = 0;
+  
+  return dlength + (s - src);  /* count does not include NUL */
 }
+#endif /* ! HAVE_STRLCPY */
 
-void
+gchar*
 g_strdown (gchar *string)
 {
   register guchar *s;
-
-  g_return_if_fail (string != NULL);
-
-  s = string;
-
+  
+  g_return_val_if_fail (string != NULL, NULL);
+  
+  s = (guchar *) string;
+  
   while (*s)
     {
       *s = tolower (*s);
       s++;
     }
+  
+  return (gchar *) string;
 }
 
-void
+gchar*
 g_strup (gchar *string)
 {
   register guchar *s;
 
-  g_return_if_fail (string != NULL);
+  g_return_val_if_fail (string != NULL, NULL);
 
-  s = string;
+  s = (guchar *) string;
 
   while (*s)
     {
       *s = toupper (*s);
       s++;
     }
+
+  return (gchar *) string;
 }
 
-void
+gchar*
 g_strreverse (gchar *string)
 {
-  g_return_if_fail (string != NULL);
+  g_return_val_if_fail (string != NULL, NULL);
 
   if (*string)
     {
@@ -986,6 +985,8 @@ g_strreverse (gchar *string)
          t--;
        }
     }
+
+  return string;
 }
 
 gint
@@ -1032,8 +1033,9 @@ g_strncasecmp (const gchar *s1,
   g_return_val_if_fail (s1 != NULL, 0);
   g_return_val_if_fail (s2 != NULL, 0);
 
-  while (n-- && *s1 && *s2)
+  while (n && *s1 && *s2)
     {
+      n -= 1;
       /* According to A. Cox, some platforms have islower's that
        * don't work right on non-uppercase
        */
@@ -1045,7 +1047,7 @@ g_strncasecmp (const gchar *s1,
     }
 
   if (n)
-    return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
+    return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
   else
     return 0;
 #endif
@@ -1073,14 +1075,31 @@ g_strdelimit (gchar       *string,
 }
 
 gchar*
-g_strccpy (gchar       *dest,
-          const gchar *source)
+g_strcanon (gchar       *string,
+           const gchar *valid_chars,
+           gchar        subsitutor)
 {
-  const gchar *p = source;
-  gchar *q = dest;
+  register gchar *c;
+
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (valid_chars != NULL, NULL);
+
+  for (c = string; *c; c++)
+    {
+      if (!strchr (valid_chars, *c))
+       *c = subsitutor;
+    }
 
-  g_return_val_if_fail (dest != NULL, NULL);
+  return string;
+}
 
+gchar*
+g_strcompress (const gchar *source)
+{
+  const gchar *p = source, *octal;
+  gchar *dest = g_malloc (strlen (source) + 1);
+  gchar *q = dest;
+  
   while (*p)
     {
       if (*p == '\\')
@@ -1091,7 +1110,8 @@ g_strccpy (gchar       *dest,
            case '0':  case '1':  case '2':  case '3':  case '4':
            case '5':  case '6':  case '7':
              *q = 0;
-             while ((*p >= '0') && (*p <= '7'))
+             octal = p;
+             while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
                {
                  *q = (*q * 8) + (*p - '0');
                  p++;
@@ -1124,17 +1144,24 @@ g_strccpy (gchar       *dest,
       p++;
     }
   *q = 0;
+  
   return dest;
 }
 
 gchar *
-g_strecpy (gchar       *dest,
-          const gchar *src,
-          const gchar *exceptions)
+g_strescape (const gchar *source,
+            const gchar *exceptions)
 {
-  const guchar *p = (guchar *) src;
-  gchar *q = dest;
+  const guchar *p;
+  gchar *dest;
+  gchar *q;
   guchar excmap[256];
+  
+  g_return_val_if_fail (source != NULL, NULL);
+
+  p = (guchar *) source;
+  /* Each source byte needs maximally four destination chars (\777) */
+  q = dest = g_malloc (strlen (source) * 4 + 1);
 
   memset (excmap, 0, 256);
   if (exceptions)
@@ -1188,9 +1215,9 @@ g_strecpy (gchar       *dest,
              if ((*p < ' ') || (*p >= 0177))
                {
                  *q++ = '\\';
-                 *q++ = '0' + (((*p) >> 6)&07);
-                 *q++ = '0' + (((*p) >> 3)&07);
-                 *q++ = '0' + ((*p)&07);
+                 *q++ = '0' + (((*p) >> 6) & 07);
+                 *q++ = '0' + (((*p) >> 3) & 07);
+                 *q++ = '0' + ((*p) & 07);
                }
              else
                *q++ = *p;
@@ -1204,54 +1231,16 @@ g_strecpy (gchar       *dest,
 }
 
 gchar*
-g_strescape (gchar *string)
-{
-  gchar *q;
-  gchar *escaped;
-  guint escapes_needed = 0;
-  gchar *p = string;
-
-  g_message ("g_strescape() is deprecated");
-
-  g_return_val_if_fail (string != NULL, NULL);
-
-  while (*p != '\000')
-    {
-      escapes_needed += (*p == '\\' || *p == '"');
-      p++;
-    }
-
-  if (!escapes_needed)
-    return g_strdup (string);
-
-  escaped = g_new (gchar, strlen (string) + escapes_needed + 1);
-
-  p = string;
-  q = escaped;
-
-  while (*p != '\000')
-    {
-      if (*p == '\\' || *p == '"')
-       *q++ = '\\';
-      *q++ = *p++;
-    }
-  *q = '\000';
-
-  return escaped;
-}
-
-/* blame Elliot for these next five routines */
-gchar*
 g_strchug (gchar *string)
 {
   guchar *start;
 
   g_return_val_if_fail (string != NULL, NULL);
 
-  for (start = string; *start && isspace (*start); start++)
+  for (start = (guchar*) string; *start && isspace (*start); start++)
     ;
 
-  g_memmove(string, start, strlen(start) + 1);
+  g_memmove (string, start, strlen ((gchar *) start) + 1);
 
   return string;
 }
@@ -1280,7 +1269,7 @@ g_strsplit (const gchar *string,
 {
   GSList *string_list = NULL, *slist;
   gchar **str_array, *s;
-  guint i, n = 1;
+  guint n = 1;
 
   g_return_val_if_fail (string != NULL, NULL);
   g_return_val_if_fail (delimiter != NULL, NULL);
@@ -1309,19 +1298,13 @@ g_strsplit (const gchar *string,
        }
       while (--max_tokens && s);
     }
-  if (*string)
-    {
-      n++;
-      string_list = g_slist_prepend (string_list, g_strdup (string));
-    }
-
-  str_array = g_new (gchar*, n);
+  string_list = g_slist_prepend (string_list, g_strdup (string));
 
-  i = n - 1;
+  str_array = g_new (gchar*, n + 1);
 
-  str_array[i--] = NULL;
+  str_array[n--] = NULL;
   for (slist = string_list; slist; slist = slist->next)
-    str_array[i--] = slist->data;
+    str_array[n--] = slist->data;
 
   g_slist_free (string_list);
 
@@ -1342,6 +1325,45 @@ g_strfreev (gchar **str_array)
     }
 }
 
+/**
+ * g_strdupv:
+ * @str_array: %NULL-terminated array of strings
+ * 
+ * Copies %NULL-terminated array of strings. The copy is a deep copy;
+ * the new array should be freed by first freeing each string, then
+ * the array itself. g_strfreev() does this for you. If called
+ * on a %NULL value, g_strdupv() simply returns %NULL.
+ * 
+ * Return value: a new %NULL-terminated array of strings
+ **/
+gchar**
+g_strdupv (gchar **str_array)
+{
+  if (str_array)
+    {
+      gint i;
+      gchar **retval;
+
+      i = 0;
+      while (str_array[i])
+        ++i;
+          
+      retval = g_new (gchar*, i + 1);
+
+      i = 0;
+      while (str_array[i])
+        {
+          retval[i] = g_strdup (str_array[i]);
+          ++i;
+        }
+      retval[i] = NULL;
+
+      return retval;
+    }
+  else
+    return NULL;
+}
+
 gchar*
 g_strjoinv (const gchar  *separator,
            gchar       **str_array)