changed prototype of g_boxed_type_register_static() to contain an optional
[platform/upstream/glib.git] / gstring.c
index 8350552..a720ac7 100644 (file)
--- a/gstring.c
+++ b/gstring.c
@@ -2,27 +2,45 @@
  * 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.
  */
-#include <glib.h>
+
+/*
+ * 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/. 
+ */
+
+/* 
+ * MT safe
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
-
+#include "glib.h"
 
 typedef struct _GRealStringChunk GRealStringChunk;
 typedef struct _GRealString      GRealString;
@@ -43,35 +61,34 @@ struct _GRealString
   gint   alloc;
 };
 
-
+G_LOCK_DEFINE_STATIC (string_mem_chunk);
 static GMemChunk *string_mem_chunk = NULL;
 
 /* Hash Functions.
  */
 
-gint
-g_str_equal (gconstpointer v, gconstpointer v2)
+gboolean
+g_str_equal (gconstpointer v1,
+            gconstpointer v2)
 {
-  return strcmp ((const gchar*) v, (const gchar*)v2) == 0;
+  const gchar *string1 = v1;
+  const gchar *string2 = v2;
+  
+  return strcmp (string1, string2) == 0;
 }
 
-/* a char* hash function from ASU */
+/* 31 bit hash function */
 guint
-g_str_hash (gconstpointer v)
+g_str_hash (gconstpointer key)
 {
-  const char *s = (char*)v;
-  const char *p;
-  guint h=0, g;
-
-  for(p = s; *p != '\0'; p += 1) {
-    h = ( h << 4 ) + *p;
-    if ( ( g = h & 0xf0000000 ) ) {
-      h = h ^ (g >> 24);
-      h = h ^ g;
-    }
-  }
+  const char *p = key;
+  guint h = *p;
 
-  return h /* % M */;
+  if (h)
+    for (p += 1; *p != '\0'; p++)
+      h = (h << 5) - h + *p;
+
+  return h;
 }
 
 
@@ -106,14 +123,10 @@ g_string_chunk_free (GStringChunk *fchunk)
 
   if (chunk->storage_list)
     {
-      GListAllocator *tmp_allocator = g_slist_set_allocator (NULL);
-
       for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
        g_free (tmp_list->data);
 
       g_slist_free (chunk->storage_list);
-
-      g_slist_set_allocator (tmp_allocator);
     }
 
   if (chunk->const_table)
@@ -134,7 +147,6 @@ g_string_chunk_insert (GStringChunk *fchunk,
 
   if ((chunk->storage_next + len + 1) > chunk->this_size)
     {
-      GListAllocator *tmp_allocator = g_slist_set_allocator (NULL);
       gint new_size = chunk->default_size;
 
       while (new_size < len+1)
@@ -145,11 +157,9 @@ g_string_chunk_insert (GStringChunk *fchunk,
 
       chunk->this_size = new_size;
       chunk->storage_next = 0;
-
-      g_slist_set_allocator (tmp_allocator);
     }
 
-  pos = ((char*)chunk->storage_list->data) + chunk->storage_next;
+  pos = ((char *) chunk->storage_list->data) + chunk->storage_next;
 
   strcpy (pos, string);
 
@@ -183,8 +193,8 @@ g_string_chunk_insert_const (GStringChunk *fchunk,
 
 /* Strings.
  */
-static gint
-nearest_pow (gint num)
+static inline gint
+nearest_power (gint num)
 {
   gint n = 1;
 
@@ -199,7 +209,7 @@ g_string_maybe_expand (GRealString* string, gint len)
 {
   if (string->len + len >= string->alloc)
     {
-      string->alloc = nearest_pow (string->len + len + 1);
+      string->alloc = nearest_power (string->len + len + 1);
       string->str = g_realloc (string->str, string->alloc);
     }
 }
@@ -209,12 +219,14 @@ g_string_sized_new (guint dfl_size)
 {
   GRealString *string;
 
+  G_LOCK (string_mem_chunk);
   if (!string_mem_chunk)
     string_mem_chunk = g_mem_chunk_new ("string mem chunk",
                                        sizeof (GRealString),
                                        1024, G_ALLOC_AND_FREE);
 
   string = g_chunk_new (GRealString, string_mem_chunk);
+  G_UNLOCK (string_mem_chunk);
 
   string->alloc = 0;
   string->len   = 0;
@@ -231,7 +243,7 @@ g_string_new (const gchar *init)
 {
   GString *string;
 
-  string = g_string_sized_new (2);
+  string = g_string_sized_new (init ? strlen (init) + 2 : 2);
 
   if (init)
     g_string_append (string, init);
@@ -239,94 +251,146 @@ g_string_new (const gchar *init)
   return string;
 }
 
-void
+GString*
+g_string_new_len (const gchar *init,
+                  gint         len)
+{
+  GString *string;
+
+  if (len < 0)
+    return g_string_new (init);
+  else
+    {
+      string = g_string_sized_new (len);
+      
+      if (init)
+        g_string_append_len (string, init, len);
+      
+      return string;
+    }
+}
+
+gchar*
 g_string_free (GString *string,
-              gint free_segment)
+              gboolean free_segment)
 {
-  g_return_if_fail (string != NULL);
+  gchar *segment;
+
+  g_return_val_if_fail (string != NULL, NULL);
 
   if (free_segment)
-    g_free (string->str);
+    {
+      g_free (string->str);
+      segment = NULL;
+    }
+  else
+    segment = string->str;
 
+  G_LOCK (string_mem_chunk);
   g_mem_chunk_free (string_mem_chunk, string);
+  G_UNLOCK (string_mem_chunk);
+
+  return segment;
 }
 
-GString*
-g_string_assign (GString *lval,
-                const gchar *rval)
+gboolean
+g_string_equal (const GString *v,
+                const GString *v2)
 {
-  g_string_truncate (lval, 0);
-  g_string_append (lval, rval);
+  gchar *p, *q;
+  GRealString *string1 = (GRealString *) v;
+  GRealString *string2 = (GRealString *) v2;
+  gint i = string1->len;
+
+  if (i != string2->len)
+    return FALSE;
 
-  return lval;
+  p = string1->str;
+  q = string2->str;
+  while (i)
+    {
+      if (*p != *q)
+       return FALSE;
+      p++;
+      q++;
+      i--;
+    }
+  return TRUE;
 }
 
-GString*
-g_string_truncate (GString* fstring,
-                  gint len)
+/* 31 bit hash function */
+guint
+g_string_hash (const GString *str)
 {
-  GRealString *string = (GRealString*)fstring;
+  const gchar *p = str->str;
+  gint n = str->len;
+  guint h = 0;
 
-  g_return_val_if_fail (string != NULL, NULL);
-
-  string->len = len;
-
-  string->str[len] = 0;
+  while (n--)
+    {
+      h = (h << 5) - h + *p;
+      p++;
+    }
 
-  return fstring;
+  return h;
 }
 
 GString*
-g_string_append (GString *fstring,
-                const gchar *val)
+g_string_assign (GString     *string,
+                const gchar *rval)
 {
-  GRealString *string = (GRealString*)fstring;
-  int len;
-
   g_return_val_if_fail (string != NULL, NULL);
-  g_return_val_if_fail (val != NULL, fstring);
+  g_return_val_if_fail (rval != NULL, string);
   
-  len = strlen (val);
-  g_string_maybe_expand (string, len);
-
-  strcpy (string->str + string->len, val);
-
-  string->len += len;
+  g_string_truncate (string, 0);
+  g_string_append (string, rval);
 
-  return fstring;
+  return string;
 }
 
 GString*
-g_string_append_c (GString *fstring,
-                  gchar c)
+g_string_truncate (GString *fstring,
+                  guint    len)
 {
-  GRealString *string = (GRealString*)fstring;
+  GRealString *string = (GRealString *) fstring;
 
   g_return_val_if_fail (string != NULL, NULL);
-  g_string_maybe_expand (string, 1);
 
-  string->str[string->len++] = c;
+  string->len = MIN (len, string->len);
+
   string->str[string->len] = 0;
 
   return fstring;
 }
 
 GString*
-g_string_prepend (GString *fstring,
-                 const gchar *val)
+g_string_insert_len (GString     *fstring,
+                    gint         pos,
+                    const gchar *val,
+                    gint         len)
 {
-  GRealString *string = (GRealString*)fstring;
-  gint len;
+  GRealString *string = (GRealString *) fstring;
 
   g_return_val_if_fail (string != NULL, NULL);
   g_return_val_if_fail (val != NULL, fstring);
+  g_return_val_if_fail (pos <= string->len, fstring);
 
-  len = strlen (val);
-  g_string_maybe_expand (string, len);
+  if (len < 0)
+    len = strlen (val);
 
-  g_memmove (string->str + len, string->str, string->len);
+  if (pos < 0)
+    pos = string->len;
+  
+  g_string_maybe_expand (string, len);
 
-  strncpy (string->str, val, len);
+  /* If we aren't appending at the end, move a hunk
+   * of the old string to the end, opening up space
+   */
+  if (pos < string->len)
+    g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
+  
+  /* insert the new string */
+  g_memmove (string->str + pos, val, len);
 
   string->len += len;
 
@@ -336,23 +400,63 @@ g_string_prepend (GString *fstring,
 }
 
 GString*
-g_string_prepend_c (GString *fstring,
-                   gchar    c)
-{
-  GRealString *string = (GRealString*)fstring;
+g_string_append (GString     *fstring,
+                const gchar *val)
+{  
+  g_return_val_if_fail (fstring != NULL, NULL);
+  g_return_val_if_fail (val != NULL, fstring);
+
+  return g_string_insert_len (fstring, -1, val, -1);
+}
 
+GString*
+g_string_append_len (GString    *string,
+                     const gchar *val,
+                     gint         len)
+{
   g_return_val_if_fail (string != NULL, NULL);
-  g_string_maybe_expand (string, 1);
+  g_return_val_if_fail (val != NULL, string);
 
-  g_memmove (string->str + 1, string->str, string->len);
+  return g_string_insert_len (string, -1, val, len);
+}
 
-  string->str[0] = c;
+GString*
+g_string_append_c (GString *fstring,
+                  gchar    c)
+{
+  g_return_val_if_fail (fstring != NULL, NULL);
 
-  string->len += 1;
+  return g_string_insert_c (fstring, -1, c);
+}
 
-  string->str[string->len] = 0;
+GString*
+g_string_prepend (GString     *fstring,
+                 const gchar *val)
+{
+  g_return_val_if_fail (fstring != NULL, NULL);
+  g_return_val_if_fail (val != NULL, fstring);
+  
+  return g_string_insert_len (fstring, 0, val, -1);
+}
 
-  return fstring;
+GString*
+g_string_prepend_len (GString    *string,
+                      const gchar *val,
+                      gint         len)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (val != NULL, string);
+
+  return g_string_insert_len (string, 0, val, len);
+}
+
+GString*
+g_string_prepend_c (GString *fstring,
+                   gchar    c)
+{  
+  g_return_val_if_fail (fstring != NULL, NULL);
+  
+  return g_string_insert_c (fstring, 0, c);
 }
 
 GString*
@@ -360,41 +464,31 @@ g_string_insert (GString     *fstring,
                 gint         pos,
                 const gchar *val)
 {
-  GRealString *string = (GRealString*)fstring;
-  gint len;
-
-  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (fstring != NULL, NULL);
   g_return_val_if_fail (val != NULL, fstring);
-  g_return_val_if_fail (pos >= 0, fstring);
-  g_return_val_if_fail (pos <= string->len, fstring);
-
-  len = strlen (val);
-  g_string_maybe_expand (string, len);
-
-  g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
-
-  strncpy (string->str + pos, val, len);
-
-  string->len += len;
-
-  string->str[string->len] = 0;
-
-  return fstring;
+  g_return_val_if_fail (pos <= fstring->len, fstring);
+  
+  return g_string_insert_len (fstring, pos, val, -1);
 }
 
-GString *
+GString*
 g_string_insert_c (GString *fstring,
                   gint     pos,
                   gchar    c)
 {
-  GRealString *string = (GRealString*)fstring;
+  GRealString *string = (GRealString *) fstring;
 
   g_return_val_if_fail (string != NULL, NULL);
   g_return_val_if_fail (pos <= string->len, fstring);
 
   g_string_maybe_expand (string, 1);
 
-  g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
+  if (pos < 0)
+    pos = string->len;
+  
+  /* If not just an append, move the old stuff */
+  if (pos < string->len)
+    g_memmove (string->str + pos + 1, string->str + pos, string->len - pos);
 
   string->str[pos] = c;
 
@@ -407,8 +501,8 @@ g_string_insert_c (GString *fstring,
 
 GString*
 g_string_erase (GString *fstring,
-               gint pos,
-               gint len)
+               gint     pos,
+               gint     len)
 {
   GRealString *string = (GRealString*)fstring;
 
@@ -431,17 +525,19 @@ g_string_erase (GString *fstring,
 GString*
 g_string_down (GString *fstring)
 {
-  GRealString *string = (GRealString*)fstring;
-  gchar *s;
+  GRealString *string = (GRealString *) fstring;
+  guchar *s;
+  gint n = string->len;
 
   g_return_val_if_fail (string != NULL, NULL);
 
-  s = string->str;
+  s = (guchar *) string->str;
 
-  while (*s)
+  while (n)
     {
       *s = tolower (*s);
       s++;
+      n--;
     }
 
   return fstring;
@@ -450,198 +546,58 @@ g_string_down (GString *fstring)
 GString*
 g_string_up (GString *fstring)
 {
-  GRealString *string = (GRealString*)fstring;
-  gchar *s;
+  GRealString *string = (GRealString *) fstring;
+  guchar *s;
+  gint n = string->len;
 
   g_return_val_if_fail (string != NULL, NULL);
 
-  s = string->str;
+  s = (guchar *) string->str;
 
-  while (*s)
+  while (n)
     {
       *s = toupper (*s);
       s++;
+      n--;
     }
 
   return fstring;
 }
 
-static int
-get_length_upper_bound (const gchar* fmt, va_list *args)
-{
-  int len = 0;
-  int short_int;
-  int long_int;
-  int done;
-  char *tmp;
-
-  while (*fmt)
-    {
-      char c = *fmt++;
-
-      short_int = FALSE;
-      long_int = FALSE;
-
-      if (c == '%')
-       {
-         done = FALSE;
-         while (*fmt && !done)
-           {
-             switch (*fmt++)
-               {
-               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':
-                 fmt -= 1;
-                 len += strtol (fmt, (char **)&fmt, 10);
-                 break;
-               case 'h':
-                 short_int = TRUE;
-                 break;
-               case 'l':
-                 long_int = TRUE;
-                 break;
-
-                 /* I ignore 'q' and 'L', they're not portable anyway. */
-
-               case 's':
-                 tmp = va_arg(*args, char *);
-                 if(tmp)
-                   len += strlen (tmp);
-                 else
-                   len += strlen ("(null)");
-                 done = TRUE;
-                 break;
-               case 'd':
-               case 'i':
-               case 'o':
-               case 'u':
-               case 'x':
-               case 'X':
-                 if (long_int)
-                   (void)va_arg (*args, long);
-                 else if (short_int)
-                   (void)va_arg (*args, int);
-                 else
-                   (void)va_arg (*args, int);
-                 len += 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':
-                 (void)va_arg (*args, double);
-                 len += 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:
-                 break;
-               }
-           }
-       }
-      else
-       len += 1;
-    }
-
-  return len;
-}
-
-char*
-g_vsprintf (const gchar *fmt,
-           va_list *args,
-           va_list *args2)
-{
-  static gchar *buf = NULL;
-  static gint   alloc = 0;
-
-  gint len = get_length_upper_bound (fmt, args);
-
-  if (len >= alloc)
-    {
-      if (buf)
-       g_free (buf);
-
-      alloc = nearest_pow (MAX(len + 1, 1024));
-
-      buf = g_new (char, alloc);
-    }
-
-  vsprintf (buf, fmt, *args2);
-
-  return buf;
-}
-
 static void
-g_string_sprintfa_int (GString *string,
-                      const gchar *fmt,
-                      va_list *args,
-                      va_list *args2)
+g_string_printfa_internal (GString     *string,
+                          const gchar *fmt,
+                          va_list      args)
 {
-  g_string_append (string, g_vsprintf (fmt, args, args2));
+  gchar *buffer;
+
+  buffer = g_strdup_vprintf (fmt, args);
+  g_string_append (string, buffer);
+  g_free (buffer);
 }
 
 void
-g_string_sprintf (GString *string,
-                 const gchar *fmt,
-                 ...)
+g_string_printf (GString *string,
+                const gchar *fmt,
+                ...)
 {
-  va_list args, args2;
-
-  va_start(args, fmt);
-  va_start(args2, fmt);
+  va_list args;
 
   g_string_truncate (string, 0);
 
-  g_string_sprintfa_int (string, fmt, &args, &args2);
-
-  va_end(args);
-  va_end(args2);
+  va_start (args, fmt);
+  g_string_printfa_internal (string, fmt, args);
+  va_end (args);
 }
 
 void
-g_string_sprintfa (GString *string,
-                  const gchar *fmt,
-                  ...)
+g_string_printfa (GString *string,
+                 const gchar *fmt,
+                 ...)
 {
-  va_list args, args2;
-
-  va_start(args, fmt);
-  va_start(args2, fmt);
-
-  g_string_sprintfa_int (string, fmt, &args, &args2);
+  va_list args;
 
-  va_end(args);
-  va_end(args2);
+  va_start (args, fmt);
+  g_string_printfa_internal (string, fmt, args);
+  va_end (args);
 }