Add:Core:Added required stuff from glib 2.18.1
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Sat, 18 Oct 2008 16:31:04 +0000 (16:31 +0000)
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Sat, 18 Oct 2008 16:31:04 +0000 (16:31 +0000)
git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@1484 ffa7fe5e-494d-0410-b361-a75ebd5db220

27 files changed:
navit/navit/support/glib/gatomic.c [new file with mode: 0644]
navit/navit/support/glib/gerror.c [new file with mode: 0644]
navit/navit/support/glib/gerror.h [new file with mode: 0644]
navit/navit/support/glib/ghash.c [new file with mode: 0644]
navit/navit/support/glib/ghash.h [new file with mode: 0644]
navit/navit/support/glib/glibconfig.h [new file with mode: 0644]
navit/navit/support/glib/glibintl.h [new file with mode: 0644]
navit/navit/support/glib/glist.c [new file with mode: 0644]
navit/navit/support/glib/glist.h [new file with mode: 0644]
navit/navit/support/glib/gmacros.h [new file with mode: 0644]
navit/navit/support/glib/gmem.c [new file with mode: 0644]
navit/navit/support/glib/gmem.h [new file with mode: 0644]
navit/navit/support/glib/gmessages.c [new file with mode: 0644]
navit/navit/support/glib/gmessages.h [new file with mode: 0644]
navit/navit/support/glib/gprimes.c [new file with mode: 0644]
navit/navit/support/glib/gprintf.c [new file with mode: 0644]
navit/navit/support/glib/gprintf.h [new file with mode: 0644]
navit/navit/support/glib/gprintfint.h [new file with mode: 0644]
navit/navit/support/glib/gquark.h [new file with mode: 0644]
navit/navit/support/glib/gslice.c [new file with mode: 0644]
navit/navit/support/glib/gslice.h [new file with mode: 0644]
navit/navit/support/glib/gstrfuncs.c [new file with mode: 0644]
navit/navit/support/glib/gstrfuncs.h [new file with mode: 0644]
navit/navit/support/glib/gstring.c [new file with mode: 0644]
navit/navit/support/glib/gthreadprivate.h [new file with mode: 0644]
navit/navit/support/glib/gtypes.h [new file with mode: 0644]
navit/navit/support/glib/gutils.c [new file with mode: 0644]

diff --git a/navit/navit/support/glib/gatomic.c b/navit/navit/support/glib/gatomic.c
new file mode 100644 (file)
index 0000000..b75a8c5
--- /dev/null
@@ -0,0 +1,936 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * g_atomic_*: atomic operations.
+ * Copyright (C) 2003 Sebastian Wilhelmi
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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 "config.h"
+
+#if defined (G_ATOMIC_ARM)
+#include <sched.h>
+#endif
+
+#include "glib.h"
+#include "gthreadprivate.h"
+#include "galias.h"
+
+#if defined (__GNUC__)
+# if defined (G_ATOMIC_I486)
+/* Adapted from CVS version 1.10 of glibc's sysdeps/i386/i486/bits/atomic.h 
+ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+                              gint           val)
+{
+  gint result;
+
+  __asm__ __volatile__ ("lock; xaddl %0,%1"
+                        : "=r" (result), "=m" (*atomic) 
+                       : "0" (val), "m" (*atomic));
+  return result;
+}
+void
+g_atomic_int_add (volatile gint *atomic, 
+                 gint           val)
+{
+  __asm__ __volatile__ ("lock; addl %1,%0"
+                       : "=m" (*atomic) 
+                       : "ir" (val), "m" (*atomic));
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  gint result;
+  __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+                       : "=a" (result), "=m" (*atomic)
+                       : "r" (newval), "m" (*atomic), "0" (oldval)); 
+
+  return result == oldval;
+}
+
+/* The same code as above, as on i386 gpointer is 32 bit as well.
+ * Duplicating the code here seems more natural than casting the
+ * arguments and calling the former function */
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gpointer result;
+  __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+                       : "=a" (result), "=m" (*atomic)
+                       : "r" (newval), "m" (*atomic), "0" (oldval)); 
+
+  return result == oldval;
+}
+
+# elif defined (G_ATOMIC_SPARCV9)
+/* Adapted from CVS version 1.3 of glibc's sysdeps/sparc/sparc64/bits/atomic.h
+ */
+#  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)                  \
+  ({                                                                   \
+     gint __result;                                                    \
+     __asm__ __volatile__ ("cas [%4], %2, %0"                          \
+                           : "=r" (__result), "=m" (*(atomic))         \
+                           : "r" (oldval), "m" (*(atomic)), "r" (atomic),\
+                           "0" (newval));                              \
+     __result == oldval;                                               \
+  })
+
+#  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gpointer result;
+  __asm__ __volatile__ ("cas [%4], %2, %0"
+                       : "=r" (result), "=m" (*atomic)
+                       : "r" (oldval), "m" (*atomic), "r" (atomic),
+                       "0" (newval));
+  return result == oldval;
+}
+#  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gpointer result;
+  gpointer *a = atomic;
+  __asm__ __volatile__ ("casx [%4], %2, %0"
+                       : "=r" (result), "=m" (*a)
+                       : "r" (oldval), "m" (*a), "r" (a),
+                       "0" (newval));
+  return result == oldval;
+}
+#  else /* What's that */
+#    error "Your system has an unsupported pointer size"
+#  endif /* GLIB_SIZEOF_VOID_P */
+#  define G_ATOMIC_MEMORY_BARRIER                                      \
+  __asm__ __volatile__ ("membar #LoadLoad | #LoadStore"                        \
+                        " | #StoreLoad | #StoreStore" : : : "memory")
+
+# elif defined (G_ATOMIC_ALPHA)
+/* Adapted from CVS version 1.3 of glibc's sysdeps/alpha/bits/atomic.h
+ */
+#  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)                  \
+  ({                                                                   \
+     gint __result;                                                    \
+     gint __prev;                                                      \
+     __asm__ __volatile__ (                                            \
+        "       mb\n"                                                  \
+        "1:     ldl_l   %0,%2\n"                                       \
+        "       cmpeq   %0,%3,%1\n"                                    \
+        "       beq     %1,2f\n"                                       \
+        "       mov     %4,%1\n"                                       \
+        "       stl_c   %1,%2\n"                                       \
+        "       beq     %1,1b\n"                                       \
+        "       mb\n"                                                  \
+        "2:"                                                           \
+        : "=&r" (__prev),                                              \
+          "=&r" (__result)                                             \
+        : "m" (*(atomic)),                                             \
+          "Ir" (oldval),                                               \
+          "Ir" (newval)                                                        \
+        : "memory");                                                   \
+     __result != 0;                                                    \
+  })
+#  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gint result;
+  gpointer prev;
+  __asm__ __volatile__ (
+        "       mb\n"
+        "1:     ldl_l   %0,%2\n"
+        "       cmpeq   %0,%3,%1\n"
+        "       beq     %1,2f\n"
+        "       mov     %4,%1\n"
+        "       stl_c   %1,%2\n"
+        "       beq     %1,1b\n"
+        "       mb\n"
+        "2:"
+        : "=&r" (prev), 
+          "=&r" (result)
+        : "m" (*atomic),
+          "Ir" (oldval),
+          "Ir" (newval)
+        : "memory");
+  return result != 0;
+}
+#  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gint result;
+  gpointer prev;
+  __asm__ __volatile__ (
+        "       mb\n"
+        "1:     ldq_l   %0,%2\n"
+        "       cmpeq   %0,%3,%1\n"
+        "       beq     %1,2f\n"
+        "       mov     %4,%1\n"
+        "       stq_c   %1,%2\n"
+        "       beq     %1,1b\n"
+        "       mb\n"
+        "2:"
+        : "=&r" (prev), 
+          "=&r" (result)
+        : "m" (*atomic),
+          "Ir" (oldval),
+          "Ir" (newval)
+        : "memory");
+  return result != 0;
+}
+#  else /* What's that */
+#   error "Your system has an unsupported pointer size"
+#  endif /* GLIB_SIZEOF_VOID_P */
+#  define G_ATOMIC_MEMORY_BARRIER  __asm__ ("mb" : : : "memory")
+# elif defined (G_ATOMIC_X86_64)
+/* Adapted from CVS version 1.9 of glibc's sysdeps/x86_64/bits/atomic.h 
+ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+                              gint           val)
+{
+  gint result;
+
+  __asm__ __volatile__ ("lock; xaddl %0,%1"
+                        : "=r" (result), "=m" (*atomic) 
+                       : "0" (val), "m" (*atomic));
+  return result;
+}
+void
+g_atomic_int_add (volatile gint *atomic, 
+                 gint           val)
+{
+  __asm__ __volatile__ ("lock; addl %1,%0"
+                       : "=m" (*atomic) 
+                       : "ir" (val), "m" (*atomic));
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  gint result;
+  __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+                       : "=a" (result), "=m" (*atomic)
+                       : "r" (newval), "m" (*atomic), "0" (oldval)); 
+
+  return result == oldval;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gpointer result;
+  __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
+                       : "=a" (result), "=m" (*atomic)
+                       : "r" (newval), "m" (*atomic), "0" (oldval)); 
+
+  return result == oldval;
+}
+
+# elif defined (G_ATOMIC_POWERPC)
+/* Adapted from CVS version 1.16 of glibc's sysdeps/powerpc/bits/atomic.h 
+ * and CVS version 1.4 of glibc's sysdeps/powerpc/powerpc32/bits/atomic.h 
+ * and CVS version 1.7 of glibc's sysdeps/powerpc/powerpc64/bits/atomic.h 
+ */
+#   ifdef __OPTIMIZE__
+/* Non-optimizing compile bails on the following two asm statements
+ * for reasons unknown to the author */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+                              gint           val)
+{
+  gint result, temp;
+#if ASM_NUMERIC_LABELS
+  __asm__ __volatile__ ("1:       lwarx   %0,0,%3\n"
+                       "         add     %1,%0,%4\n"
+                       "         stwcx.  %1,0,%3\n"
+                       "         bne-    1b"
+                       : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+                       : "b" (atomic), "r" (val), "m" (*atomic)
+                       : "cr0", "memory");
+#else
+  __asm__ __volatile__ (".Lieaa%=:       lwarx   %0,0,%3\n"
+                       "         add     %1,%0,%4\n"
+                       "         stwcx.  %1,0,%3\n"
+                       "         bne-    .Lieaa%="
+                       : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+                       : "b" (atomic), "r" (val), "m" (*atomic)
+                       : "cr0", "memory");
+#endif
+  return result;
+}
+/* The same as above, to save a function call repeated here */
+void
+g_atomic_int_add (volatile gint *atomic, 
+                 gint           val)
+{
+  gint result, temp;  
+#if ASM_NUMERIC_LABELS
+  __asm__ __volatile__ ("1:       lwarx   %0,0,%3\n"
+                       "         add     %1,%0,%4\n"
+                       "         stwcx.  %1,0,%3\n"
+                       "         bne-    1b"
+                       : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+                       : "b" (atomic), "r" (val), "m" (*atomic)
+                       : "cr0", "memory");
+#else
+  __asm__ __volatile__ (".Lia%=:       lwarx   %0,0,%3\n"
+                       "         add     %1,%0,%4\n"
+                       "         stwcx.  %1,0,%3\n"
+                       "         bne-    .Lia%="
+                       : "=&b" (result), "=&r" (temp), "=m" (*atomic)
+                       : "b" (atomic), "r" (val), "m" (*atomic)
+                       : "cr0", "memory");
+#endif
+}
+#   else /* !__OPTIMIZE__ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+                              gint           val)
+{
+  gint result;
+  do
+    result = *atomic;
+  while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
+
+  return result;
+}
+void
+g_atomic_int_add (volatile gint *atomic,
+                 gint           val)
+{
+  gint result;
+  do
+    result = *atomic;
+  while (!g_atomic_int_compare_and_exchange (atomic, result, result + val));
+}
+#   endif /* !__OPTIMIZE__ */
+
+#   if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  gint result;
+#if ASM_NUMERIC_LABELS
+  __asm__ __volatile__ ("sync\n"
+                       "1: lwarx   %0,0,%1\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     2f\n"
+                       "   stwcx.  %3,0,%1\n"
+                       "   bne-    1b\n"
+                       "2: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#else
+  __asm__ __volatile__ ("sync\n"
+                       ".L1icae%=: lwarx   %0,0,%1\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     .L2icae%=\n"
+                       "   stwcx.  %3,0,%1\n"
+                       "   bne-    .L1icae%=\n"
+                       ".L2icae%=: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#endif
+  return result == 0;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gpointer result;
+#if ASM_NUMERIC_LABELS
+  __asm__ __volatile__ ("sync\n"
+                       "1: lwarx   %0,0,%1\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     2f\n"
+                       "   stwcx.  %3,0,%1\n"
+                       "   bne-    1b\n"
+                       "2: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#else
+  __asm__ __volatile__ ("sync\n"
+                       ".L1pcae%=: lwarx   %0,0,%1\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     .L2pcae%=\n"
+                       "   stwcx.  %3,0,%1\n"
+                       "   bne-    .L1pcae%=\n"
+                       ".L2pcae%=: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#endif
+  return result == 0;
+}
+#   elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  gpointer result;
+#if ASM_NUMERIC_LABELS
+  __asm__ __volatile__ ("sync\n"
+                       "1: lwarx   %0,0,%1\n"
+                       "   extsw   %0,%0\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     2f\n"
+                       "   stwcx.  %3,0,%1\n"
+                       "   bne-    1b\n"
+                       "2: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#else
+  __asm__ __volatile__ ("sync\n"
+                       ".L1icae%=: lwarx   %0,0,%1\n"
+                       "   extsw   %0,%0\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     .L2icae%=\n"
+                       "   stwcx.  %3,0,%1\n"
+                       "   bne-    .L1icae%=\n"
+                       ".L2icae%=: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#endif
+  return result == 0;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gpointer result;
+#if ASM_NUMERIC_LABELS
+  __asm__ __volatile__ ("sync\n"
+                       "1: ldarx   %0,0,%1\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     2f\n"
+                       "   stdcx.  %3,0,%1\n"
+                       "   bne-    1b\n"
+                       "2: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#else
+  __asm__ __volatile__ ("sync\n"
+                       ".L1pcae%=: ldarx   %0,0,%1\n"
+                       "   subf.   %0,%2,%0\n"
+                       "   bne     .L2pcae%=\n"
+                       "   stdcx.  %3,0,%1\n"
+                       "   bne-    .L1pcae%=\n"
+                       ".L2pcae%=: isync"
+                       : "=&r" (result)
+                       : "b" (atomic), "r" (oldval), "r" (newval)
+                       : "cr0", "memory"); 
+#endif
+  return result == 0;
+}
+#  else /* What's that */
+#   error "Your system has an unsupported pointer size"
+#  endif /* GLIB_SIZEOF_VOID_P */
+
+#  define G_ATOMIC_MEMORY_BARRIER __asm__ ("sync" : : : "memory")
+
+# elif defined (G_ATOMIC_IA64)
+/* Adapted from CVS version 1.8 of glibc's sysdeps/ia64/bits/atomic.h
+ */
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+                              gint           val)
+{
+  return __sync_fetch_and_add (atomic, val);
+}
+void
+g_atomic_int_add (volatile gint *atomic, 
+                 gint val)
+{
+  __sync_fetch_and_add (atomic, val);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  return __sync_bool_compare_and_swap (atomic, oldval, newval);
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  return __sync_bool_compare_and_swap ((long *)atomic, 
+                                      (long)oldval, (long)newval);
+}
+
+#  define G_ATOMIC_MEMORY_BARRIER __sync_synchronize ()
+# elif defined (G_ATOMIC_S390)
+/* Adapted from glibc's sysdeps/s390/bits/atomic.h
+ */
+#  define ATOMIC_INT_CMP_XCHG(atomic, oldval, newval)                  \
+  ({                                                                   \
+     gint __result = oldval;                                   \
+     __asm__ __volatile__ ("cs %0, %2, %1"                             \
+                           : "+d" (__result), "=Q" (*(atomic))         \
+                           : "d" (newval), "m" (*(atomic)) : "cc" );   \
+     __result == oldval;                                               \
+  })
+
+#  if GLIB_SIZEOF_VOID_P == 4 /* 32-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+                                      gpointer           oldval,
+                                      gpointer           newval)
+{
+  gpointer result = oldval;
+  __asm__ __volatile__ ("cs %0, %2, %1"
+                       : "+d" (result), "=Q" (*(atomic))
+                       : "d" (newval), "m" (*(atomic)) : "cc" );
+  return result == oldval;
+}
+#  elif GLIB_SIZEOF_VOID_P == 8 /* 64-bit system */
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+                                      gpointer           oldval,
+                                      gpointer           newval)
+{
+  gpointer result = oldval;
+  gpointer *a = atomic;
+  __asm__ __volatile__ ("csg %0, %2, %1"
+                       : "+d" (result), "=Q" (*a)
+                       : "d" ((long)(newval)), "m" (*a) : "cc" );
+  return result == oldval;
+}
+#  else /* What's that */
+#    error "Your system has an unsupported pointer size"
+#  endif /* GLIB_SIZEOF_VOID_P */
+# elif defined (G_ATOMIC_ARM)
+static volatile int atomic_spin = 0;
+
+static int atomic_spin_trylock (void)
+{
+  int result;
+
+  asm volatile (
+    "swp %0, %1, [%2]\n"
+    : "=&r,&r" (result)
+    : "r,0" (1), "r,r" (&atomic_spin)
+    : "memory");
+  if (result == 0)
+    return 0;
+  else
+    return -1;
+}
+
+static void atomic_spin_lock (void)
+{
+  while (atomic_spin_trylock())
+    sched_yield();
+}
+
+static void atomic_spin_unlock (void)
+{
+  atomic_spin = 0;
+}
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+                              gint           val)
+{
+  gint result;
+  atomic_spin_lock();  
+  result = *atomic;
+  *atomic += val;
+  atomic_spin_unlock();
+
+  return result;
+}
+
+void
+g_atomic_int_add (volatile gint *atomic,
+                 gint           val)
+{
+  atomic_spin_lock();
+  *atomic += val;
+  atomic_spin_unlock();
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  gboolean result;
+
+  atomic_spin_lock();
+  if (*atomic == oldval)
+    {
+      result = TRUE;
+      *atomic = newval;
+    }
+  else
+    result = FALSE;
+  atomic_spin_unlock();
+
+  return result;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gboolean result;
+  atomic_spin_lock();
+  if (*atomic == oldval)
+    {
+      result = TRUE;
+      *atomic = newval;
+    }
+  else
+    result = FALSE;
+  atomic_spin_unlock();
+
+  return result;
+}
+# else /* !G_ATOMIC_ARM */
+#  define DEFINE_WITH_MUTEXES
+# endif /* G_ATOMIC_IA64 */
+#else /* !__GNUC__ */
+# ifdef G_PLATFORM_WIN32
+#  define DEFINE_WITH_WIN32_INTERLOCKED
+# else
+#  define DEFINE_WITH_MUTEXES
+# endif
+#endif /* __GNUC__ */
+
+#ifdef DEFINE_WITH_WIN32_INTERLOCKED
+# include <windows.h>
+/* Following indicates that InterlockedCompareExchangePointer is
+ * declared in winbase.h (included by windows.h) and needs to be
+ * commented out if not true. It is defined iff WINVER > 0x0400,
+ * which is usually correct but can be wrong if WINVER is set before
+ * windows.h is included.
+ */
+# if WINVER > 0x0400
+#  define HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
+# endif
+
+gint32
+g_atomic_int_exchange_and_add (volatile gint32 *atomic,
+                              gint32           val)
+{
+  return InterlockedExchangeAdd (atomic, val);
+}
+
+void     
+g_atomic_int_add (volatile gint32 *atomic, 
+                 gint32           val)
+{
+  InterlockedExchangeAdd (atomic, val);
+}
+
+gboolean 
+g_atomic_int_compare_and_exchange (volatile gint32 *atomic,
+                                  gint32           oldval,
+                                  gint32           newval)
+{
+#ifndef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
+  return (guint32) InterlockedCompareExchange ((PVOID*)atomic, 
+                                               (PVOID)newval, 
+                                               (PVOID)oldval) == oldval;
+#else
+  return InterlockedCompareExchange (atomic, 
+                                     newval, 
+                                     oldval) == oldval;
+#endif
+}
+
+gboolean 
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic,
+                                      gpointer           oldval,
+                                      gpointer           newval)
+{
+# ifdef HAVE_INTERLOCKED_COMPARE_EXCHANGE_POINTER
+  return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
+# else
+#  if GLIB_SIZEOF_VOID_P != 4 /* no 32-bit system */
+#   error "InterlockedCompareExchangePointer needed"
+#  else
+   return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
+#  endif
+# endif
+}
+#endif /* DEFINE_WITH_WIN32_INTERLOCKED */
+
+#ifdef DEFINE_WITH_MUTEXES
+/* We have to use the slow, but safe locking method */
+static GMutex *g_atomic_mutex; 
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic, 
+                              gint           val)
+{
+  gint result;
+    
+  g_mutex_lock (g_atomic_mutex);
+  result = *atomic;
+  *atomic += val;
+  g_mutex_unlock (g_atomic_mutex);
+
+  return result;
+}
+
+
+void
+g_atomic_int_add (volatile gint *atomic,
+                 gint           val)
+{
+  g_mutex_lock (g_atomic_mutex);
+  *atomic += val;
+  g_mutex_unlock (g_atomic_mutex);
+}
+
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic, 
+                                  gint           oldval, 
+                                  gint           newval)
+{
+  gboolean result;
+    
+  g_mutex_lock (g_atomic_mutex);
+  if (*atomic == oldval)
+    {
+      result = TRUE;
+      *atomic = newval;
+    }
+  else
+    result = FALSE;
+  g_mutex_unlock (g_atomic_mutex);
+
+  return result;
+}
+
+gboolean
+g_atomic_pointer_compare_and_exchange (volatile gpointer *atomic, 
+                                      gpointer           oldval, 
+                                      gpointer           newval)
+{
+  gboolean result;
+    
+  g_mutex_lock (g_atomic_mutex);
+  if (*atomic == oldval)
+    {
+      result = TRUE;
+      *atomic = newval;
+    }
+  else
+    result = FALSE;
+  g_mutex_unlock (g_atomic_mutex);
+
+  return result;
+}
+
+#ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+gint
+g_atomic_int_get (volatile gint *atomic)
+{
+  gint result;
+
+  g_mutex_lock (g_atomic_mutex);
+  result = *atomic;
+  g_mutex_unlock (g_atomic_mutex);
+
+  return result;
+}
+
+void
+g_atomic_int_set (volatile gint *atomic,
+                  gint           newval)
+{
+  g_mutex_lock (g_atomic_mutex);
+  *atomic = newval;
+  g_mutex_unlock (g_atomic_mutex);
+}
+
+gpointer
+g_atomic_pointer_get (volatile gpointer *atomic)
+{
+  gpointer result;
+
+  g_mutex_lock (g_atomic_mutex);
+  result = *atomic;
+  g_mutex_unlock (g_atomic_mutex);
+
+  return result;
+}
+
+void
+g_atomic_pointer_set (volatile gpointer *atomic,
+                      gpointer           newval)
+{
+  g_mutex_lock (g_atomic_mutex);
+  *atomic = newval;
+  g_mutex_unlock (g_atomic_mutex);
+}
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */   
+#elif defined (G_ATOMIC_OP_MEMORY_BARRIER_NEEDED)
+gint
+g_atomic_int_get (volatile gint *atomic)
+{
+  G_ATOMIC_MEMORY_BARRIER;
+  return *atomic;
+}
+
+void
+g_atomic_int_set (volatile gint *atomic,
+                  gint           newval)
+{
+  *atomic = newval;
+  G_ATOMIC_MEMORY_BARRIER; 
+}
+
+gpointer
+g_atomic_pointer_get (volatile gpointer *atomic)
+{
+  G_ATOMIC_MEMORY_BARRIER;
+  return *atomic;
+}   
+
+void
+g_atomic_pointer_set (volatile gpointer *atomic,
+                      gpointer           newval)
+{
+  *atomic = newval;
+  G_ATOMIC_MEMORY_BARRIER; 
+}
+#endif /* DEFINE_WITH_MUTEXES || G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+#ifdef ATOMIC_INT_CMP_XCHG
+gboolean
+g_atomic_int_compare_and_exchange (volatile gint *atomic,
+                                  gint           oldval,
+                                  gint           newval)
+{
+  return ATOMIC_INT_CMP_XCHG (atomic, oldval, newval);
+}
+
+gint
+g_atomic_int_exchange_and_add (volatile gint *atomic,
+                              gint           val)
+{
+  gint result;
+  do
+    result = *atomic;
+  while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
+
+  return result;
+}
+void
+g_atomic_int_add (volatile gint *atomic,
+                 gint           val)
+{
+  gint result;
+  do
+    result = *atomic;
+  while (!ATOMIC_INT_CMP_XCHG (atomic, result, result + val));
+}
+#endif /* ATOMIC_INT_CMP_XCHG */
+
+void 
+_g_atomic_thread_init (void)
+{
+#ifdef DEFINE_WITH_MUTEXES
+  g_atomic_mutex = g_mutex_new ();
+#endif /* DEFINE_WITH_MUTEXES */
+}
+
+#ifndef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED
+gint
+(g_atomic_int_get) (volatile gint *atomic)
+{
+  return g_atomic_int_get (atomic);
+}
+
+void
+(g_atomic_int_set) (volatile gint *atomic,
+                   gint           newval)
+{
+  g_atomic_int_set (atomic, newval);
+}
+
+gpointer
+(g_atomic_pointer_get) (volatile gpointer *atomic)
+{
+  return g_atomic_pointer_get (atomic);
+}
+
+void
+(g_atomic_pointer_set) (volatile gpointer *atomic,
+                       gpointer           newval)
+{
+  g_atomic_pointer_set (atomic, newval);
+}
+#endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
+
+#define __G_ATOMIC_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gerror.c b/navit/navit/support/glib/gerror.c
new file mode 100644 (file)
index 0000000..9408560
--- /dev/null
@@ -0,0 +1,375 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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 "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+static GError* 
+g_error_new_valist (GQuark         domain,
+                    gint           code,
+                    const gchar   *format,
+                    va_list        args)
+{
+  GError *error;
+  
+  error = g_slice_new (GError);
+  
+  error->domain = domain;
+  error->code = code;
+  error->message = g_strdup_vprintf (format, args);
+  
+  return error;
+}
+
+/**
+ * g_error_new:
+ * @domain: error domain 
+ * @code: error code
+ * @format: printf()-style format for error message
+ * @Varargs: parameters for message format
+ * 
+ * Creates a new #GError with the given @domain and @code,
+ * and a message formatted with @format.
+ * 
+ * Return value: a new #GError
+ **/
+GError*
+g_error_new (GQuark       domain,
+             gint         code,
+             const gchar *format,
+             ...)
+{
+  GError* error;
+  va_list args;
+
+  g_return_val_if_fail (format != NULL, NULL);
+  g_return_val_if_fail (domain != 0, NULL);
+
+  va_start (args, format);
+  error = g_error_new_valist (domain, code, format, args);
+  va_end (args);
+
+  return error;
+}
+
+/**
+ * g_error_new_literal:
+ * @domain: error domain
+ * @code: error code
+ * @message: error message
+ * 
+ * Creates a new #GError; unlike g_error_new(), @message is not
+ * a printf()-style format string. Use this 
+ * function if @message contains text you don't have control over, 
+ * that could include printf() escape sequences.
+ * 
+ * Return value: a new #GError
+ **/
+GError*
+g_error_new_literal (GQuark         domain,
+                     gint           code,
+                     const gchar   *message)
+{
+  GError* err;
+
+  g_return_val_if_fail (message != NULL, NULL);
+  g_return_val_if_fail (domain != 0, NULL);
+
+  err = g_slice_new (GError);
+
+  err->domain = domain;
+  err->code = code;
+  err->message = g_strdup (message);
+  
+  return err;
+}
+
+/**
+ * g_error_free:
+ * @error: a #GError
+ *
+ * Frees a #GError and associated resources.
+ * 
+ **/
+void
+g_error_free (GError *error)
+{
+  g_return_if_fail (error != NULL);  
+
+  g_free (error->message);
+
+  g_slice_free (GError, error);
+}
+
+/**
+ * g_error_copy:
+ * @error: a #GError
+ * 
+ * Makes a copy of @error.
+ * 
+ * Return value: a new #GError
+ **/
+GError*
+g_error_copy (const GError *error)
+{
+  GError *copy;
+  
+  g_return_val_if_fail (error != NULL, NULL);
+
+  copy = g_slice_new (GError);
+
+  *copy = *error;
+
+  copy->message = g_strdup (error->message);
+
+  return copy;
+}
+
+/**
+ * g_error_matches:
+ * @error: a #GError
+ * @domain: an error domain
+ * @code: an error code
+ * 
+ * Returns %TRUE if @error matches @domain and @code, %FALSE
+ * otherwise.
+ * 
+ * Return value: whether @error has @domain and @code
+ **/
+gboolean
+g_error_matches (const GError *error,
+                 GQuark        domain,
+                 gint          code)
+{
+  return error &&
+    error->domain == domain &&
+    error->code == code;
+}
+
+#define ERROR_OVERWRITTEN_WARNING "GError set over the top of a previous GError or uninitialized memory.\n" \
+               "This indicates a bug in someone's code. You must ensure an error is NULL before it's set.\n" \
+               "The overwriting error message was: %s"
+
+/**
+ * g_set_error:
+ * @err: a return location for a #GError, or %NULL
+ * @domain: error domain
+ * @code: error code 
+ * @format: printf()-style format
+ * @Varargs: args for @format 
+ * 
+ * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err must
+ * be %NULL. A new #GError is created and assigned to *@err.
+ **/
+void
+g_set_error (GError      **err,
+             GQuark        domain,
+             gint          code,
+             const gchar  *format,
+             ...)
+{
+  GError *new;
+  
+  va_list args;
+
+  if (err == NULL)
+    return;
+  
+  va_start (args, format);
+  new = g_error_new_valist (domain, code, format, args);
+  va_end (args);
+
+  if (*err == NULL)
+    *err = new;
+  else
+    g_warning (ERROR_OVERWRITTEN_WARNING, new->message);    
+}
+
+/**
+ * g_set_error_literal:
+ * @err: a return location for a #GError, or %NULL
+ * @domain: error domain
+ * @code: error code 
+ * @message: error message
+ *
+ * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err must
+ * be %NULL. A new #GError is created and assigned to *@err.
+ * Unlike g_set_error(), @message is not a printf()-style format string.
+ * Use this function if @message contains text you don't have control over,
+ * that could include printf() escape sequences.
+ *
+ * Since: 2.18
+ **/
+void
+g_set_error_literal (GError      **err,
+                     GQuark        domain,
+                     gint          code,
+                     const gchar  *message)
+{
+  GError *new;
+  
+  if (err == NULL)
+    return;
+
+  new = g_error_new_literal (domain, code, message);
+  if (*err == NULL)
+    *err = new;
+  else
+    g_warning (ERROR_OVERWRITTEN_WARNING, new->message);    
+}
+
+/**
+ * g_propagate_error:
+ * @dest: error return location
+ * @src: error to move into the return location
+ *
+ * If @dest is %NULL, free @src; otherwise, moves @src into *@dest.
+ * The error variable @dest points to must be %NULL.
+ **/
+void
+g_propagate_error (GError       **dest,
+                  GError        *src)
+{
+  g_return_if_fail (src != NULL);
+  
+  if (dest == NULL)
+    {
+      if (src)
+        g_error_free (src);
+      return;
+    }
+  else
+    {
+      if (*dest != NULL)
+        g_warning (ERROR_OVERWRITTEN_WARNING, src->message);
+      else
+        *dest = src;
+    }
+}
+
+/**
+ * g_clear_error:
+ * @err: a #GError return location
+ * 
+ * If @err is %NULL, does nothing. If @err is non-%NULL,
+ * calls g_error_free() on *@err and sets *@err to %NULL.
+ **/
+void
+g_clear_error (GError **err)
+{
+  if (err && *err)
+    {
+      g_error_free (*err);
+      *err = NULL;
+    }
+}
+
+static void
+g_error_add_prefix (gchar       **string,
+                    const gchar  *format,
+                    va_list       ap)
+{
+  gchar *oldstring;
+  gchar *prefix;
+
+  prefix = g_strdup_vprintf (format, ap);
+  oldstring = *string;
+  *string = g_strconcat (prefix, oldstring, NULL);
+  g_free (oldstring);
+  g_free (prefix);
+}
+
+/**
+ * g_prefix_error:
+ * @err: a return location for a #GError, or %NULL
+ * @format: printf()-style format string
+ * @...: arguments to @format
+ *
+ * Formats a string according to @format and
+ * prefix it to an existing error message.  If
+ * @err is %NULL (ie: no error variable) then do
+ * nothing.
+ *
+ * If *@err is %NULL (ie: an error variable is
+ * present but there is no error condition) then
+ * also do nothing.  Whether or not it makes
+ * sense to take advantage of this feature is up
+ * to you.
+ *
+ * Since: 2.16
+ **/
+void
+g_prefix_error (GError      **err,
+                const gchar  *format,
+                ...)
+{
+  if (err && *err)
+    {
+      va_list ap;
+
+      va_start (ap, format);
+      g_error_add_prefix (&(*err)->message, format, ap);
+      va_end (ap);
+    }
+}
+
+/**
+ * g_propagate_prefixed_error:
+ * @dest: error return location
+ * @src: error to move into the return location
+ * @format: printf()-style format string
+ * @...: arguments to @format
+ * 
+ * If @dest is %NULL, free @src; otherwise,
+ * moves @src into *@dest. *@dest must be %NULL.
+ * After the move, add a prefix as with 
+ * g_prefix_error().
+ *
+ * Since: 2.16
+ **/
+void
+g_propagate_prefixed_error (GError      **dest,
+                            GError       *src,
+                            const gchar  *format,
+                            ...)
+{
+  g_propagate_error (dest, src);
+
+  if (dest && *dest)
+    {
+      va_list ap;
+
+      va_start (ap, format);
+      g_error_add_prefix (&(*dest)->message, format, ap);
+      va_end (ap);
+    }
+}
+
+#define __G_ERROR_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gerror.h b/navit/navit/support/glib/gerror.h
new file mode 100644 (file)
index 0000000..d3d42d5
--- /dev/null
@@ -0,0 +1,92 @@
+/* gerror.h - Error reporting system
+ *
+ *  Copyright 2000 Red Hat, Inc.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * 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.
+ *
+ * The Gnome 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *   Boston, MA 02111-1307, USA.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_ERROR_H__
+#define __G_ERROR_H__
+
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GError GError;
+
+struct _GError
+{
+  GQuark       domain;
+  gint         code;
+  gchar       *message;
+};
+
+GError*  g_error_new           (GQuark         domain,
+                                gint           code,
+                                const gchar   *format,
+                                ...) G_GNUC_PRINTF (3, 4);
+
+GError*  g_error_new_literal   (GQuark         domain,
+                                gint           code,
+                                const gchar   *message);
+
+void     g_error_free          (GError        *error);
+GError*  g_error_copy          (const GError  *error);
+
+gboolean g_error_matches       (const GError  *error,
+                                GQuark         domain,
+                                gint           code);
+
+/* if (err) *err = g_error_new(domain, code, format, ...), also has
+ * some sanity checks.
+ */
+void     g_set_error           (GError       **err,
+                                GQuark         domain,
+                                gint           code,
+                                const gchar   *format,
+                                ...) G_GNUC_PRINTF (4, 5);
+
+void     g_set_error_literal   (GError       **err,
+                                GQuark         domain,
+                                gint           code,
+                                const gchar   *message);
+
+/* if (dest) *dest = src; also has some sanity checks.
+ */
+void     g_propagate_error     (GError       **dest,
+                               GError        *src);
+
+/* if (err && *err) { g_error_free(*err); *err = NULL; } */
+void     g_clear_error         (GError       **err);
+
+/* if (err) prefix the formatted string to the ->message */
+void     g_prefix_error               (GError       **err,
+                                       const gchar   *format,
+                                       ...) G_GNUC_PRINTF (2, 3);
+
+/* g_propagate_error then g_error_prefix on dest */
+void     g_propagate_prefixed_error   (GError       **dest,
+                                       GError        *src,
+                                       const gchar   *format,
+                                       ...) G_GNUC_PRINTF (3, 4);
+
+G_END_DECLS
+
+#endif /* __G_ERROR_H__ */
diff --git a/navit/navit/support/glib/ghash.c b/navit/navit/support/glib/ghash.c
new file mode 100644 (file)
index 0000000..e00b4c4
--- /dev/null
@@ -0,0 +1,1202 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+#define HASH_TABLE_MIN_SIZE 11
+#define HASH_TABLE_MAX_SIZE 13845163
+
+
+typedef struct _GHashNode      GHashNode;
+
+struct _GHashNode
+{
+  gpointer   key;
+  gpointer   value;
+  GHashNode *next;
+  guint      key_hash;
+};
+
+struct _GHashTable
+{
+  gint             size;
+  gint             nnodes;
+  GHashNode      **nodes;
+  GHashFunc        hash_func;
+  GEqualFunc       key_equal_func;
+  volatile gint    ref_count;
+#ifndef G_DISABLE_ASSERT
+  /*
+   * Tracks the structure of the hash table, not its contents: is only
+   * incremented when a node is added or removed (is not incremented
+   * when the key or data of a node is modified).
+   */
+  int              version;
+#endif
+  GDestroyNotify   key_destroy_func;
+  GDestroyNotify   value_destroy_func;
+};
+
+typedef struct
+{
+  GHashTable   *hash_table;
+  GHashNode    *prev_node;
+  GHashNode    *node;
+  int          position;
+  gboolean     pre_advanced;
+  int          version;
+} RealIter;
+
+/*
+ * g_hash_table_lookup_node:
+ * @hash_table: our #GHashTable
+ * @key: the key to lookup against
+ * @hash_return: optional key hash return location
+ * Return value: a pointer to the described #GHashNode pointer
+ *
+ * Performs a lookup in the hash table.  Virtually all hash operations
+ * will use this function internally.
+ *
+ * This function first computes the hash value of the key using the
+ * user's hash function.
+ *
+ * If an entry in the table matching @key is found then this function
+ * returns a pointer to the pointer to that entry in the table.  In
+ * the case that the entry is at the head of a chain, this pointer
+ * will be an item in the nodes[] array.  In the case that the entry
+ * is not at the head of a chain, this pointer will be the ->next
+ * pointer on the node that preceeds it.
+ *
+ * In the case that no matching entry exists in the table, a pointer
+ * to a %NULL pointer will be returned.  To insert a item, this %NULL
+ * pointer should be updated to point to the new #GHashNode.
+ *
+ * If @hash_return is a pass-by-reference parameter.  If it is
+ * non-%NULL then the computed hash value is returned.  This is to
+ * save insertions from having to compute the hash record again for
+ * the new record.
+ */
+static inline GHashNode **
+g_hash_table_lookup_node (GHashTable    *hash_table,
+                          gconstpointer  key,
+                          guint         *hash_return)
+{
+  GHashNode **node_ptr, *node;
+  guint hash_value;
+
+  hash_value = (* hash_table->hash_func) (key);
+  node_ptr = &hash_table->nodes[hash_value % hash_table->size];
+
+  if (hash_return)
+    *hash_return = hash_value;
+
+  /* Hash table lookup needs to be fast.
+   *  We therefore remove the extra conditional of testing
+   *  whether to call the key_equal_func or not from
+   *  the inner loop.
+   *
+   *  Additional optimisation: first check if our full hash
+   *  values are equal so we can avoid calling the full-blown
+   *  key equality function in most cases.
+   */
+  if (hash_table->key_equal_func)
+    {
+      while ((node = *node_ptr))
+        {
+          if (node->key_hash == hash_value &&
+              hash_table->key_equal_func (node->key, key))
+            break;
+
+          node_ptr = &(*node_ptr)->next;
+        }
+    }
+  else
+    {
+      while ((node = *node_ptr))
+        {
+          if (node->key == key)
+            break;
+
+          node_ptr = &(*node_ptr)->next;
+        }
+    }
+
+  return node_ptr;
+}
+
+/*
+ * g_hash_table_remove_node:
+ * @hash_table: our #GHashTable
+ * @node_ptr_ptr: a pointer to the return value from
+ *   g_hash_table_lookup_node()
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ *
+ * Removes a node from the hash table and updates the node count.  The
+ * node is freed.  No table resize is performed.
+ *
+ * If @notify is %TRUE then the destroy notify functions are called
+ * for the key and value of the hash node.
+ *
+ * @node_ptr_ptr is a pass-by-reference in/out parameter.  When the
+ * function is called, it should point to the pointer to the node to
+ * remove.  This level of indirection is required so that the pointer
+ * may be updated appropriately once the node has been removed.
+ *
+ * Before the function returns, the pointer at @node_ptr_ptr will be
+ * updated to point to the position in the table that contains the
+ * pointer to the "next" node in the chain.  This makes this function
+ * convenient to use from functions that iterate over the entire
+ * table.  If there is no further item in the chain then the
+ * #GHashNode pointer will be %NULL (ie: **node_ptr_ptr == %NULL).
+ *
+ * Since the pointer in the table to the removed node is replaced with
+ * either a pointer to the next node or a %NULL pointer as
+ * appropriate, the pointer at the end of @node_ptr_ptr will never be
+ * modified at all.  Stay tuned. :)
+ */
+static void
+g_hash_table_remove_node (GHashTable   *hash_table,
+                          GHashNode  ***node_ptr_ptr,
+                          gboolean      notify)
+{
+  GHashNode **node_ptr, *node;
+
+  node_ptr = *node_ptr_ptr;
+  node = *node_ptr;
+
+  *node_ptr = node->next;
+
+  if (notify && hash_table->key_destroy_func)
+    hash_table->key_destroy_func (node->key);
+
+  if (notify && hash_table->value_destroy_func)
+    hash_table->value_destroy_func (node->value);
+
+  g_slice_free (GHashNode, node);
+
+  hash_table->nnodes--;
+}
+
+/*
+ * g_hash_table_remove_all_nodes:
+ * @hash_table: our #GHashTable
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ *
+ * Removes all nodes from the table.  Since this may be a precursor to
+ * freeing the table entirely, no resize is performed.
+ *
+ * If @notify is %TRUE then the destroy notify functions are called
+ * for the key and value of the hash node.
+ */
+static void
+g_hash_table_remove_all_nodes (GHashTable *hash_table,
+                               gboolean    notify)
+{
+  GHashNode **node_ptr;
+  int i;
+
+  for (i = 0; i < hash_table->size; i++)
+    for (node_ptr = &hash_table->nodes[i]; *node_ptr != NULL;)
+      g_hash_table_remove_node (hash_table, &node_ptr, notify);
+
+  hash_table->nnodes = 0;
+}
+
+/*
+ * g_hash_table_resize:
+ * @hash_table: our #GHashTable
+ *
+ * Resizes the hash table to the optimal size based on the number of
+ * nodes currently held.  If you call this function then a resize will
+ * occur, even if one does not need to occur.  Use
+ * g_hash_table_maybe_resize() instead.
+ */
+static void
+g_hash_table_resize (GHashTable *hash_table)
+{
+  GHashNode **new_nodes;
+  GHashNode *node;
+  GHashNode *next;
+  guint hash_val;
+  gint new_size;
+  gint i;
+
+  new_size = g_spaced_primes_closest (hash_table->nnodes);
+  new_size = CLAMP (new_size, HASH_TABLE_MIN_SIZE, HASH_TABLE_MAX_SIZE);
+
+  new_nodes = g_new0 (GHashNode*, new_size);
+
+  for (i = 0; i < hash_table->size; i++)
+    for (node = hash_table->nodes[i]; node; node = next)
+      {
+       next = node->next;
+
+       hash_val = node->key_hash % new_size;
+
+       node->next = new_nodes[hash_val];
+       new_nodes[hash_val] = node;
+      }
+
+  g_free (hash_table->nodes);
+  hash_table->nodes = new_nodes;
+  hash_table->size = new_size;
+}
+
+/*
+ * g_hash_table_maybe_resize:
+ * @hash_table: our #GHashTable
+ *
+ * Resizes the hash table, if needed.
+ *
+ * Essentially, calls g_hash_table_resize() if the table has strayed
+ * too far from its ideal size for its number of nodes.
+ */
+static inline void
+g_hash_table_maybe_resize (GHashTable *hash_table)
+{
+  gint nnodes = hash_table->nnodes;
+  gint size = hash_table->size;
+
+  if ((size >= 3 * nnodes && size > HASH_TABLE_MIN_SIZE) ||
+      (3 * size <= nnodes && size < HASH_TABLE_MAX_SIZE))
+    g_hash_table_resize (hash_table);
+}
+
+/**
+ * g_hash_table_new:
+ * @hash_func: a function to create a hash value from a key.
+ *   Hash values are used to determine where keys are stored within the
+ *   #GHashTable data structure. The g_direct_hash(), g_int_hash() and
+ *   g_str_hash() functions are provided for some common types of keys.
+ *   If hash_func is %NULL, g_direct_hash() is used.
+ * @key_equal_func: a function to check two keys for equality.  This is
+ *   used when looking up keys in the #GHashTable.  The g_direct_equal(),
+ *   g_int_equal() and g_str_equal() functions are provided for the most
+ *   common types of keys. If @key_equal_func is %NULL, keys are compared
+ *   directly in a similar fashion to g_direct_equal(), but without the
+ *   overhead of a function call.
+ *
+ * Creates a new #GHashTable with a reference count of 1.
+ *
+ * Return value: a new #GHashTable.
+ **/
+GHashTable*
+g_hash_table_new (GHashFunc    hash_func,
+                  GEqualFunc   key_equal_func)
+{
+  return g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
+}
+
+
+/**
+ * g_hash_table_new_full:
+ * @hash_func: a function to create a hash value from a key.
+ * @key_equal_func: a function to check two keys for equality.
+ * @key_destroy_func: a function to free the memory allocated for the key
+ *   used when removing the entry from the #GHashTable or %NULL if you
+ *   don't want to supply such a function.
+ * @value_destroy_func: a function to free the memory allocated for the
+ *   value used when removing the entry from the #GHashTable or %NULL if
+ *   you don't want to supply such a function.
+ *
+ * Creates a new #GHashTable like g_hash_table_new() with a reference count
+ * of 1 and allows to specify functions to free the memory allocated for the
+ * key and value that get called when removing the entry from the #GHashTable.
+ *
+ * Return value: a new #GHashTable.
+ **/
+GHashTable*
+g_hash_table_new_full (GHashFunc       hash_func,
+                       GEqualFunc      key_equal_func,
+                       GDestroyNotify  key_destroy_func,
+                       GDestroyNotify  value_destroy_func)
+{
+  GHashTable *hash_table;
+
+  hash_table = g_slice_new (GHashTable);
+  hash_table->size               = HASH_TABLE_MIN_SIZE;
+  hash_table->nnodes             = 0;
+  hash_table->hash_func          = hash_func ? hash_func : g_direct_hash;
+  hash_table->key_equal_func     = key_equal_func;
+  hash_table->ref_count          = 1;
+#ifndef G_DISABLE_ASSERT
+  hash_table->version            = 0;
+#endif
+  hash_table->key_destroy_func   = key_destroy_func;
+  hash_table->value_destroy_func = value_destroy_func;
+  hash_table->nodes              = g_new0 (GHashNode*, hash_table->size);
+
+  return hash_table;
+}
+
+/**
+ * g_hash_table_iter_init:
+ * @iter: an uninitialized #GHashTableIter.
+ * @hash_table: a #GHashTable.
+ *
+ * Initializes a key/value pair iterator and associates it with
+ * @hash_table. Modifying the hash table after calling this function
+ * invalidates the returned iterator.
+ * |[
+ * GHashTableIter iter;
+ * gpointer key, value;
+ *
+ * g_hash_table_iter_init (&iter, hash_table);
+ * while (g_hash_table_iter_next (&iter, &key, &value)) 
+ *   {
+ *     /&ast; do something with key and value &ast;/
+ *   }
+ * ]|
+ *
+ * Since: 2.16
+ **/
+void
+g_hash_table_iter_init (GHashTableIter *iter,
+                       GHashTable     *hash_table)
+{
+  RealIter *ri = (RealIter *) iter;
+
+  g_return_if_fail (iter != NULL);
+  g_return_if_fail (hash_table != NULL);
+
+  ri->hash_table = hash_table;
+  ri->prev_node = NULL;
+  ri->node = NULL;
+  ri->position = -1;
+  ri->pre_advanced = FALSE;
+#ifndef G_DISABLE_ASSERT
+  ri->version = hash_table->version;
+#endif
+}
+
+/**
+ * g_hash_table_iter_next:
+ * @iter: an initialized #GHashTableIter.
+ * @key: a location to store the key, or %NULL.
+ * @value: a location to store the value, or %NULL.
+ *
+ * Advances @iter and retrieves the key and/or value that are now
+ * pointed to as a result of this advancement. If %FALSE is returned,
+ * @key and @value are not set, and the iterator becomes invalid.
+ *
+ * Return value: %FALSE if the end of the #GHashTable has been reached.
+ *
+ * Since: 2.16
+ **/
+gboolean
+g_hash_table_iter_next (GHashTableIter *iter,
+                       gpointer       *key,
+                       gpointer       *value)
+{
+  RealIter *ri = (RealIter *) iter;
+
+  g_return_val_if_fail (iter != NULL, FALSE);
+#ifndef G_DISABLE_ASSERT
+  g_return_val_if_fail (ri->version == ri->hash_table->version, FALSE);
+#endif
+
+  if (ri->pre_advanced)
+    {
+      ri->pre_advanced = FALSE;
+
+      if (ri->node == NULL)
+       return FALSE;
+    }
+  else
+    {
+      if (ri->node != NULL)
+       {
+         ri->prev_node = ri->node;
+         ri->node = ri->node->next;
+       }
+
+      while (ri->node == NULL)
+       {
+         ri->position++;
+         if (ri->position >= ri->hash_table->size)
+           return FALSE;
+
+         ri->prev_node = NULL;
+         ri->node = ri->hash_table->nodes[ri->position];
+       }
+    }
+
+  if (key != NULL)
+    *key = ri->node->key;
+  if (value != NULL)
+    *value = ri->node->value;
+
+  return TRUE;
+}
+
+/**
+ * g_hash_table_iter_get_hash_table:
+ * @iter: an initialized #GHashTableIter.
+ *
+ * Returns the #GHashTable associated with @iter.
+ *
+ * Return value: the #GHashTable associated with @iter.
+ *
+ * Since: 2.16
+ **/
+GHashTable *
+g_hash_table_iter_get_hash_table (GHashTableIter *iter)
+{
+  g_return_val_if_fail (iter != NULL, NULL);
+
+  return ((RealIter *) iter)->hash_table;
+}
+
+static void
+iter_remove_or_steal (RealIter *ri, gboolean notify)
+{
+  GHashNode *prev;
+  GHashNode *node;
+  int position;
+
+  g_return_if_fail (ri != NULL);
+#ifndef G_DISABLE_ASSERT
+  g_return_if_fail (ri->version == ri->hash_table->version);
+#endif
+  g_return_if_fail (ri->node != NULL);
+
+  prev = ri->prev_node;
+  node = ri->node;
+  position = ri->position;
+
+  /* pre-advance the iterator since we will remove the node */
+
+  ri->node = ri->node->next;
+  /* ri->prev_node is still the correct previous node */
+
+  while (ri->node == NULL)
+    {
+      ri->position++;
+      if (ri->position >= ri->hash_table->size)
+       break;
+
+      ri->prev_node = NULL;
+      ri->node = ri->hash_table->nodes[ri->position];
+    }
+
+  ri->pre_advanced = TRUE;
+
+  /* remove the node */
+
+  if (prev != NULL)
+    prev->next = node->next;
+  else
+    ri->hash_table->nodes[position] = node->next;
+
+  if (notify)
+    {
+      if (ri->hash_table->key_destroy_func)
+       ri->hash_table->key_destroy_func(node->key);
+      if (ri->hash_table->value_destroy_func)
+       ri->hash_table->value_destroy_func(node->value);
+    }
+
+  g_slice_free (GHashNode, node);
+
+  ri->hash_table->nnodes--;
+
+#ifndef G_DISABLE_ASSERT
+  ri->version++;
+  ri->hash_table->version++;
+#endif
+}
+
+/**
+ * g_hash_table_iter_remove():
+ * @iter: an initialized #GHashTableIter.
+ *
+ * Removes the key/value pair currently pointed to by the iterator
+ * from its associated #GHashTable. Can only be called after
+ * g_hash_table_iter_next() returned %TRUE, and cannot be called more
+ * than once for the same key/value pair.
+ *
+ * If the #GHashTable was created using g_hash_table_new_full(), the
+ * key and value are freed using the supplied destroy functions, otherwise
+ * you have to make sure that any dynamically allocated values are freed 
+ * yourself.
+ *
+ * Since: 2.16
+ **/
+void
+g_hash_table_iter_remove (GHashTableIter *iter)
+{
+  iter_remove_or_steal ((RealIter *) iter, TRUE);
+}
+
+/**
+ * g_hash_table_iter_steal():
+ * @iter: an initialized #GHashTableIter.
+ *
+ * Removes the key/value pair currently pointed to by the iterator
+ * from its associated #GHashTable, without calling the key and value
+ * destroy functions. Can only be called after
+ * g_hash_table_iter_next() returned %TRUE, and cannot be called more
+ * than once for the same key/value pair.
+ *
+ * Since: 2.16
+ **/
+void
+g_hash_table_iter_steal (GHashTableIter *iter)
+{
+  iter_remove_or_steal ((RealIter *) iter, FALSE);
+}
+
+
+/**
+ * g_hash_table_ref:
+ * @hash_table: a valid #GHashTable.
+ *
+ * Atomically increments the reference count of @hash_table by one.
+ * This function is MT-safe and may be called from any thread.
+ *
+ * Return value: the passed in #GHashTable.
+ *
+ * Since: 2.10
+ **/
+GHashTable*
+g_hash_table_ref (GHashTable *hash_table)
+{
+  g_return_val_if_fail (hash_table != NULL, NULL);
+  g_return_val_if_fail (hash_table->ref_count > 0, hash_table);
+
+  g_atomic_int_add (&hash_table->ref_count, 1);
+  return hash_table;
+}
+
+/**
+ * g_hash_table_unref:
+ * @hash_table: a valid #GHashTable.
+ *
+ * Atomically decrements the reference count of @hash_table by one.
+ * If the reference count drops to 0, all keys and values will be
+ * destroyed, and all memory allocated by the hash table is released.
+ * This function is MT-safe and may be called from any thread.
+ *
+ * Since: 2.10
+ **/
+void
+g_hash_table_unref (GHashTable *hash_table)
+{
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (hash_table->ref_count > 0);
+
+  if (g_atomic_int_exchange_and_add (&hash_table->ref_count, -1) - 1 == 0)
+    {
+      g_hash_table_remove_all_nodes (hash_table, TRUE);
+      g_free (hash_table->nodes);
+      g_slice_free (GHashTable, hash_table);
+    }
+}
+
+/**
+ * g_hash_table_destroy:
+ * @hash_table: a #GHashTable.
+ *
+ * Destroys all keys and values in the #GHashTable and decrements its
+ * reference count by 1. If keys and/or values are dynamically allocated,
+ * you should either free them first or create the #GHashTable with destroy
+ * notifiers using g_hash_table_new_full(). In the latter case the destroy
+ * functions you supplied will be called on all keys and values during the
+ * destruction phase.
+ **/
+void
+g_hash_table_destroy (GHashTable *hash_table)
+{
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (hash_table->ref_count > 0);
+
+  g_hash_table_remove_all (hash_table);
+  g_hash_table_unref (hash_table);
+}
+
+/**
+ * g_hash_table_lookup:
+ * @hash_table: a #GHashTable.
+ * @key: the key to look up.
+ *
+ * Looks up a key in a #GHashTable. Note that this function cannot
+ * distinguish between a key that is not present and one which is present
+ * and has the value %NULL. If you need this distinction, use
+ * g_hash_table_lookup_extended().
+ *
+ * Return value: the associated value, or %NULL if the key is not found.
+ **/
+gpointer
+g_hash_table_lookup (GHashTable   *hash_table,
+                     gconstpointer key)
+{
+  GHashNode *node;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+
+  node = *g_hash_table_lookup_node (hash_table, key, NULL);
+
+  return node ? node->value : NULL;
+}
+
+/**
+ * g_hash_table_lookup_extended:
+ * @hash_table: a #GHashTable.
+ * @lookup_key: the key to look up.
+ * @orig_key: returns the original key.
+ * @value: returns the value associated with the key.
+ *
+ * Looks up a key in the #GHashTable, returning the original key and the
+ * associated value and a #gboolean which is %TRUE if the key was found. This
+ * is useful if you need to free the memory allocated for the original key,
+ * for example before calling g_hash_table_remove().
+ *
+ * Return value: %TRUE if the key was found in the #GHashTable.
+ **/
+gboolean
+g_hash_table_lookup_extended (GHashTable    *hash_table,
+                              gconstpointer  lookup_key,
+                              gpointer      *orig_key,
+                              gpointer      *value)
+{
+  GHashNode *node;
+
+  g_return_val_if_fail (hash_table != NULL, FALSE);
+
+  node = *g_hash_table_lookup_node (hash_table, lookup_key, NULL);
+
+  if (node == NULL)
+    return FALSE;
+
+  if (orig_key)
+    *orig_key = node->key;
+
+  if (value)
+    *value = node->value;
+
+  return TRUE;
+}
+
+/*
+ * g_hash_table_insert_internal:
+ * @hash_table: our #GHashTable
+ * @key: the key to insert
+ * @value: the value to insert
+ * @keep_new_key: if %TRUE and this key already exists in the table
+ *   then call the destroy notify function on the old key.  If %FALSE
+ *   then call the destroy notify function on the new key.
+ *
+ * Implements the common logic for the g_hash_table_insert() and
+ * g_hash_table_replace() functions.
+ *
+ * Do a lookup of @key.  If it is found, replace it with the new
+ * @value (and perhaps the new @key).  If it is not found, create a
+ * new node.
+ */
+static void
+g_hash_table_insert_internal (GHashTable *hash_table,
+                              gpointer    key,
+                              gpointer    value,
+                              gboolean    keep_new_key)
+{
+  GHashNode **node_ptr, *node;
+  guint key_hash;
+
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (hash_table->ref_count > 0);
+
+  node_ptr = g_hash_table_lookup_node (hash_table, key, &key_hash);
+
+  if ((node = *node_ptr))
+    {
+      if (keep_new_key)
+        {
+          if (hash_table->key_destroy_func)
+            hash_table->key_destroy_func (node->key);
+          node->key = key;
+        }
+      else
+        {
+          if (hash_table->key_destroy_func)
+            hash_table->key_destroy_func (key);
+        }
+
+      if (hash_table->value_destroy_func)
+        hash_table->value_destroy_func (node->value);
+
+      node->value = value;
+    }
+  else
+    {
+      node = g_slice_new (GHashNode);
+
+      node->key = key;
+      node->value = value;
+      node->key_hash = key_hash;
+      node->next = NULL;
+
+      *node_ptr = node;
+      hash_table->nnodes++;
+      g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+      hash_table->version++;
+#endif
+    }
+}
+
+/**
+ * g_hash_table_insert:
+ * @hash_table: a #GHashTable.
+ * @key: a key to insert.
+ * @value: the value to associate with the key.
+ *
+ * Inserts a new key and value into a #GHashTable.
+ *
+ * If the key already exists in the #GHashTable its current value is replaced
+ * with the new value. If you supplied a @value_destroy_func when creating the
+ * #GHashTable, the old value is freed using that function. If you supplied
+ * a @key_destroy_func when creating the #GHashTable, the passed key is freed
+ * using that function.
+ **/
+void
+g_hash_table_insert (GHashTable *hash_table,
+                     gpointer    key,
+                     gpointer    value)
+{
+  g_hash_table_insert_internal (hash_table, key, value, FALSE);
+}
+
+/**
+ * g_hash_table_replace:
+ * @hash_table: a #GHashTable.
+ * @key: a key to insert.
+ * @value: the value to associate with the key.
+ *
+ * Inserts a new key and value into a #GHashTable similar to
+ * g_hash_table_insert(). The difference is that if the key already exists
+ * in the #GHashTable, it gets replaced by the new key. If you supplied a
+ * @value_destroy_func when creating the #GHashTable, the old value is freed
+ * using that function. If you supplied a @key_destroy_func when creating the
+ * #GHashTable, the old key is freed using that function.
+ **/
+void
+g_hash_table_replace (GHashTable *hash_table,
+                      gpointer    key,
+                      gpointer    value)
+{
+  g_hash_table_insert_internal (hash_table, key, value, TRUE);
+}
+
+/*
+ * g_hash_table_remove_internal:
+ * @hash_table: our #GHashTable
+ * @key: the key to remove
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ * Return value: %TRUE if a node was found and removed, else %FALSE
+ *
+ * Implements the common logic for the g_hash_table_remove() and
+ * g_hash_table_steal() functions.
+ *
+ * Do a lookup of @key and remove it if it is found, calling the
+ * destroy notify handlers only if @notify is %TRUE.
+ */
+static gboolean
+g_hash_table_remove_internal (GHashTable    *hash_table,
+                              gconstpointer  key,
+                              gboolean       notify)
+{
+  GHashNode **node_ptr;
+
+  g_return_val_if_fail (hash_table != NULL, FALSE);
+
+  node_ptr = g_hash_table_lookup_node (hash_table, key, NULL);
+  if (*node_ptr == NULL)
+    return FALSE;
+
+  g_hash_table_remove_node (hash_table, &node_ptr, notify);
+  g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+  hash_table->version++;
+#endif
+
+  return TRUE;
+}
+
+/**
+ * g_hash_table_remove:
+ * @hash_table: a #GHashTable.
+ * @key: the key to remove.
+ *
+ * Removes a key and its associated value from a #GHashTable.
+ *
+ * If the #GHashTable was created using g_hash_table_new_full(), the
+ * key and value are freed using the supplied destroy functions, otherwise
+ * you have to make sure that any dynamically allocated values are freed
+ * yourself.
+ *
+ * Return value: %TRUE if the key was found and removed from the #GHashTable.
+ **/
+gboolean
+g_hash_table_remove (GHashTable    *hash_table,
+                     gconstpointer  key)
+{
+  return g_hash_table_remove_internal (hash_table, key, TRUE);
+}
+
+/**
+ * g_hash_table_steal:
+ * @hash_table: a #GHashTable.
+ * @key: the key to remove.
+ *
+ * Removes a key and its associated value from a #GHashTable without
+ * calling the key and value destroy functions.
+ *
+ * Return value: %TRUE if the key was found and removed from the #GHashTable.
+ **/
+gboolean
+g_hash_table_steal (GHashTable    *hash_table,
+                    gconstpointer  key)
+{
+  return g_hash_table_remove_internal (hash_table, key, FALSE);
+}
+
+/**
+ * g_hash_table_remove_all:
+ * @hash_table: a #GHashTable
+ *
+ * Removes all keys and their associated values from a #GHashTable.
+ *
+ * If the #GHashTable was created using g_hash_table_new_full(), the keys
+ * and values are freed using the supplied destroy functions, otherwise you
+ * have to make sure that any dynamically allocated values are freed
+ * yourself.
+ *
+ * Since: 2.12
+ **/
+void
+g_hash_table_remove_all (GHashTable *hash_table)
+{
+  g_return_if_fail (hash_table != NULL);
+
+#ifndef G_DISABLE_ASSERT
+  if (hash_table->nnodes != 0)
+    hash_table->version++;
+#endif
+
+  g_hash_table_remove_all_nodes (hash_table, TRUE);
+  g_hash_table_maybe_resize (hash_table);
+}
+
+/**
+ * g_hash_table_steal_all:
+ * @hash_table: a #GHashTable.
+ *
+ * Removes all keys and their associated values from a #GHashTable
+ * without calling the key and value destroy functions.
+ *
+ * Since: 2.12
+ **/
+void
+g_hash_table_steal_all (GHashTable *hash_table)
+{
+  g_return_if_fail (hash_table != NULL);
+
+#ifndef G_DISABLE_ASSERT
+  if (hash_table->nnodes != 0)
+    hash_table->version++;
+#endif
+
+  g_hash_table_remove_all_nodes (hash_table, FALSE);
+  g_hash_table_maybe_resize (hash_table);
+}
+
+/*
+ * g_hash_table_foreach_remove_or_steal:
+ * @hash_table: our #GHashTable
+ * @func: the user's callback function
+ * @user_data: data for @func
+ * @notify: %TRUE if the destroy notify handlers are to be called
+ *
+ * Implements the common logic for g_hash_table_foreach_remove() and
+ * g_hash_table_foreach_steal().
+ *
+ * Iterates over every node in the table, calling @func with the key
+ * and value of the node (and @user_data).  If @func returns %TRUE the
+ * node is removed from the table.
+ *
+ * If @notify is true then the destroy notify handlers will be called
+ * for each removed node.
+ */
+static guint
+g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
+                                      GHRFunc    func,
+                                      gpointer    user_data,
+                                      gboolean    notify)
+{
+  GHashNode *node, **node_ptr;
+  guint deleted = 0;
+  gint i;
+
+  for (i = 0; i < hash_table->size; i++)
+    for (node_ptr = &hash_table->nodes[i]; (node = *node_ptr) != NULL;)
+      if ((* func) (node->key, node->value, user_data))
+        {
+          g_hash_table_remove_node (hash_table, &node_ptr, notify);
+          deleted++;
+        }
+      else
+        node_ptr = &node->next;
+
+  g_hash_table_maybe_resize (hash_table);
+
+#ifndef G_DISABLE_ASSERT
+  if (deleted > 0)
+    hash_table->version++;
+#endif
+
+  return deleted;
+}
+
+/**
+ * g_hash_table_foreach_remove:
+ * @hash_table: a #GHashTable.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each key/value pair in the #GHashTable.
+ * If the function returns %TRUE, then the key/value pair is removed from the
+ * #GHashTable. If you supplied key or value destroy functions when creating
+ * the #GHashTable, they are used to free the memory allocated for the removed
+ * keys and values.
+ *
+ * See #GHashTableIterator for an alternative way to loop over the 
+ * key/value pairs in the hash table.
+ *
+ * Return value: the number of key/value pairs removed.
+ **/
+guint
+g_hash_table_foreach_remove (GHashTable *hash_table,
+                             GHRFunc     func,
+                             gpointer    user_data)
+{
+  g_return_val_if_fail (hash_table != NULL, 0);
+  g_return_val_if_fail (func != NULL, 0);
+
+  return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, TRUE);
+}
+
+/**
+ * g_hash_table_foreach_steal:
+ * @hash_table: a #GHashTable.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each key/value pair in the #GHashTable.
+ * If the function returns %TRUE, then the key/value pair is removed from the
+ * #GHashTable, but no key or value destroy functions are called.
+ *
+ * See #GHashTableIterator for an alternative way to loop over the 
+ * key/value pairs in the hash table.
+ *
+ * Return value: the number of key/value pairs removed.
+ **/
+guint
+g_hash_table_foreach_steal (GHashTable *hash_table,
+                            GHRFunc     func,
+                            gpointer    user_data)
+{
+  g_return_val_if_fail (hash_table != NULL, 0);
+  g_return_val_if_fail (func != NULL, 0);
+
+  return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, FALSE);
+}
+
+/**
+ * g_hash_table_foreach:
+ * @hash_table: a #GHashTable.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each of the key/value pairs in the
+ * #GHashTable.  The function is passed the key and value of each
+ * pair, and the given @user_data parameter.  The hash table may not
+ * be modified while iterating over it (you can't add/remove
+ * items). To remove all items matching a predicate, use
+ * g_hash_table_foreach_remove().
+ *
+ * See g_hash_table_find() for performance caveats for linear
+ * order searches in contrast to g_hash_table_lookup().
+ **/
+void
+g_hash_table_foreach (GHashTable *hash_table,
+                      GHFunc      func,
+                      gpointer    user_data)
+{
+  GHashNode *node;
+  gint i;
+
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (func != NULL);
+
+  for (i = 0; i < hash_table->size; i++)
+    for (node = hash_table->nodes[i]; node; node = node->next)
+      (* func) (node->key, node->value, user_data);
+}
+
+/**
+ * g_hash_table_find:
+ * @hash_table: a #GHashTable.
+ * @predicate:  function to test the key/value pairs for a certain property.
+ * @user_data:  user data to pass to the function.
+ *
+ * Calls the given function for key/value pairs in the #GHashTable until
+ * @predicate returns %TRUE.  The function is passed the key and value of
+ * each pair, and the given @user_data parameter. The hash table may not
+ * be modified while iterating over it (you can't add/remove items).
+ *
+ * Note, that hash tables are really only optimized for forward lookups,
+ * i.e. g_hash_table_lookup().
+ * So code that frequently issues g_hash_table_find() or
+ * g_hash_table_foreach() (e.g. in the order of once per every entry in a
+ * hash table) should probably be reworked to use additional or different
+ * data structures for reverse lookups (keep in mind that an O(n) find/foreach
+ * operation issued for all n values in a hash table ends up needing O(n*n)
+ * operations).
+ *
+ * Return value: The value of the first key/value pair is returned, for which
+ * func evaluates to %TRUE. If no pair with the requested property is found,
+ * %NULL is returned.
+ *
+ * Since: 2.4
+ **/
+gpointer
+g_hash_table_find (GHashTable      *hash_table,
+                   GHRFunc          predicate,
+                   gpointer         user_data)
+{
+  GHashNode *node;
+  gint i;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+  g_return_val_if_fail (predicate != NULL, NULL);
+
+  for (i = 0; i < hash_table->size; i++)
+    for (node = hash_table->nodes[i]; node; node = node->next)
+      if (predicate (node->key, node->value, user_data))
+        return node->value;
+  return NULL;
+}
+
+/**
+ * g_hash_table_size:
+ * @hash_table: a #GHashTable.
+ *
+ * Returns the number of elements contained in the #GHashTable.
+ *
+ * Return value: the number of key/value pairs in the #GHashTable.
+ **/
+guint
+g_hash_table_size (GHashTable *hash_table)
+{
+  g_return_val_if_fail (hash_table != NULL, 0);
+
+  return hash_table->nnodes;
+}
+
+/**
+ * g_hash_table_get_keys:
+ * @hash_table: a #GHashTable
+ *
+ * Retrieves every key inside @hash_table. The returned data is valid
+ * until @hash_table is modified.
+ *
+ * Return value: a #GList containing all the keys inside the hash
+ *   table. The content of the list is owned by the hash table and
+ *   should not be modified or freed. Use g_list_free() when done
+ *   using the list.
+ *
+ * Since: 2.14
+ */
+GList *
+g_hash_table_get_keys (GHashTable *hash_table)
+{
+  GHashNode *node;
+  gint i;
+  GList *retval;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+
+  retval = NULL;
+  for (i = 0; i < hash_table->size; i++)
+    for (node = hash_table->nodes[i]; node; node = node->next)
+      retval = g_list_prepend (retval, node->key);
+
+  return retval;
+}
+
+/**
+ * g_hash_table_get_values:
+ * @hash_table: a #GHashTable
+ *
+ * Retrieves every value inside @hash_table. The returned data is
+ * valid until @hash_table is modified.
+ *
+ * Return value: a #GList containing all the values inside the hash
+ *   table. The content of the list is owned by the hash table and
+ *   should not be modified or freed. Use g_list_free() when done
+ *   using the list.
+ *
+ * Since: 2.14
+ */
+GList *
+g_hash_table_get_values (GHashTable *hash_table)
+{
+  GHashNode *node;
+  gint i;
+  GList *retval;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+
+  retval = NULL;
+  for (i = 0; i < hash_table->size; i++)
+    for (node = hash_table->nodes[i]; node; node = node->next)
+      retval = g_list_prepend (retval, node->value);
+
+  return retval;
+}
+
+#define __G_HASH_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/ghash.h b/navit/navit/support/glib/ghash.h
new file mode 100644 (file)
index 0000000..afdd072
--- /dev/null
@@ -0,0 +1,145 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_HASH_H__
+#define __G_HASH_H__
+
+#include <glib/gtypes.h>
+#include <glib/glist.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GHashTable  GHashTable;
+
+typedef gboolean  (*GHRFunc)  (gpointer  key,
+                               gpointer  value,
+                               gpointer  user_data);
+
+typedef struct _GHashTableIter GHashTableIter;
+
+struct _GHashTableIter
+{
+  /*< private >*/
+  gpointer     dummy1;
+  gpointer     dummy2;
+  gpointer     dummy3;
+  int          dummy4;
+  gboolean     dummy5;
+  gpointer     dummy6;
+};
+
+/* Hash tables
+ */
+GHashTable* g_hash_table_new              (GHashFunc       hash_func,
+                                           GEqualFunc      key_equal_func);
+GHashTable* g_hash_table_new_full                 (GHashFunc       hash_func,
+                                           GEqualFunc      key_equal_func,
+                                           GDestroyNotify  key_destroy_func,
+                                           GDestroyNotify  value_destroy_func);
+void       g_hash_table_destroy           (GHashTable     *hash_table);
+void       g_hash_table_insert            (GHashTable     *hash_table,
+                                           gpointer        key,
+                                           gpointer        value);
+void        g_hash_table_replace           (GHashTable     *hash_table,
+                                           gpointer        key,
+                                           gpointer        value);
+gboolean    g_hash_table_remove                   (GHashTable     *hash_table,
+                                           gconstpointer   key);
+void        g_hash_table_remove_all        (GHashTable     *hash_table);
+gboolean    g_hash_table_steal             (GHashTable     *hash_table,
+                                           gconstpointer   key);
+void        g_hash_table_steal_all         (GHashTable     *hash_table);
+gpointer    g_hash_table_lookup                   (GHashTable     *hash_table,
+                                           gconstpointer   key);
+gboolean    g_hash_table_lookup_extended   (GHashTable    *hash_table,
+                                           gconstpointer   lookup_key,
+                                           gpointer       *orig_key,
+                                           gpointer       *value);
+void       g_hash_table_foreach           (GHashTable     *hash_table,
+                                           GHFunc          func,
+                                           gpointer        user_data);
+gpointer    g_hash_table_find             (GHashTable     *hash_table,
+                                           GHRFunc         predicate,
+                                           gpointer        user_data);
+guint      g_hash_table_foreach_remove    (GHashTable     *hash_table,
+                                           GHRFunc         func,
+                                           gpointer        user_data);
+guint      g_hash_table_foreach_steal     (GHashTable     *hash_table,
+                                           GHRFunc         func,
+                                           gpointer        user_data);
+guint      g_hash_table_size              (GHashTable     *hash_table);
+GList *     g_hash_table_get_keys          (GHashTable     *hash_table);
+GList *     g_hash_table_get_values        (GHashTable     *hash_table);
+
+void        g_hash_table_iter_init         (GHashTableIter *iter,
+                                           GHashTable     *hash_table);
+gboolean    g_hash_table_iter_next         (GHashTableIter *iter,
+                                           gpointer       *key,
+                                           gpointer       *value);
+GHashTable* g_hash_table_iter_get_hash_table (GHashTableIter *iter);
+void        g_hash_table_iter_remove       (GHashTableIter *iter);
+void        g_hash_table_iter_steal        (GHashTableIter *iter);
+
+/* keeping hash tables alive */
+GHashTable* g_hash_table_ref                      (GHashTable     *hash_table);
+void        g_hash_table_unref             (GHashTable     *hash_table);
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following two functions are deprecated and will be removed in
+ * the next major release. They do no good. */
+#define g_hash_table_freeze(hash_table) ((void)0)
+#define g_hash_table_thaw(hash_table) ((void)0)
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* Hash Functions
+ */
+gboolean g_str_equal (gconstpointer  v1,
+                      gconstpointer  v2);
+guint    g_str_hash  (gconstpointer  v);
+
+gboolean g_int_equal (gconstpointer  v1,
+                      gconstpointer  v2);
+guint    g_int_hash  (gconstpointer  v);
+
+/* This "hash" function will just return the key's address as an
+ * unsigned integer. Useful for hashing on plain addresses or
+ * simple integer values.
+ * Passing NULL into g_hash_table_new() as GHashFunc has the
+ * same effect as passing g_direct_hash().
+ */
+guint    g_direct_hash  (gconstpointer  v) G_GNUC_CONST;
+gboolean g_direct_equal (gconstpointer  v1,
+                         gconstpointer  v2) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_HASH_H__ */
diff --git a/navit/navit/support/glib/glibconfig.h b/navit/navit/support/glib/glibconfig.h
new file mode 100644 (file)
index 0000000..db380a6
--- /dev/null
@@ -0,0 +1,255 @@
+/* glibconfig.h.win32.in Merged from two versions generated by configure for gcc and MSVC.  */
+/* glibconfig.h
+ *
+ * This is a generated file.  Please modify 'configure.in'
+ */
+
+#ifndef __G_LIBCONFIG_H__
+#define __G_LIBCONFIG_H__
+
+#include <glib/gmacros.h>
+
+#include <limits.h>
+#include <float.h>
+
+G_BEGIN_DECLS
+
+#define G_MINFLOAT     FLT_MIN
+#define G_MAXFLOAT     FLT_MAX
+#define G_MINDOUBLE    DBL_MIN
+#define G_MAXDOUBLE    DBL_MAX
+#define G_MINSHORT     SHRT_MIN
+#define G_MAXSHORT     SHRT_MAX
+#define G_MAXUSHORT    USHRT_MAX
+#define G_MININT       INT_MIN
+#define G_MAXINT       INT_MAX
+#define G_MAXUINT      UINT_MAX
+#define G_MINLONG      LONG_MIN
+#define G_MAXLONG      LONG_MAX
+#define G_MAXULONG     ULONG_MAX
+
+typedef signed char gint8;
+typedef unsigned char guint8;
+typedef signed short gint16;
+typedef unsigned short guint16;
+#define G_GINT16_MODIFIER "h"
+#define G_GINT16_FORMAT "hi"
+#define G_GUINT16_FORMAT "hu"
+typedef signed int gint32;
+typedef unsigned int guint32;
+#define G_GINT32_MODIFIER ""
+#define G_GINT32_FORMAT "i"
+#define G_GUINT32_FORMAT "u"
+#define G_HAVE_GINT64 1          /* deprecated, always true */
+
+#ifndef _MSC_VER
+G_GNUC_EXTENSION typedef signed long long gint64;
+G_GNUC_EXTENSION typedef unsigned long long guint64;
+#else /* _MSC_VER */
+typedef signed __int64 gint64;
+typedef unsigned __int64 guint64;
+#endif /* _MSC_VER */
+
+#ifndef _MSC_VER
+#define G_GINT64_CONSTANT(val) (G_GNUC_EXTENSION (val##LL))
+#else /* _MSC_VER */
+#define G_GINT64_CONSTANT(val) (val##i64)
+#endif /* _MSC_VER */
+#ifndef _MSC_VER
+#define G_GUINT64_CONSTANT(val)        (G_GNUC_EXTENSION (val##ULL))
+#else /* _MSC_VER */
+#define G_GUINT64_CONSTANT(val)        (val##Ui64)
+#endif /* _MSC_VER */
+#define G_GINT64_MODIFIER "I64"
+#define G_GINT64_FORMAT "I64i"
+#define G_GUINT64_FORMAT "I64u"
+
+#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
+
+#define GLIB_SIZEOF_VOID_P 8
+#define GLIB_SIZEOF_LONG   4
+#define GLIB_SIZEOF_SIZE_T 8
+
+typedef signed long long gssize;
+typedef unsigned long long gsize;
+#define G_GSIZE_MODIFIER "I64"
+#define G_GSSIZE_FORMAT "I64d"
+#define G_GSIZE_FORMAT "I64u"
+
+#define G_MAXSIZE      G_MAXUINT64
+#define G_MINSSIZE     G_MININT64
+#define G_MAXSSIZE     G_MAXINT64
+
+#else
+
+#define GLIB_SIZEOF_VOID_P 4
+#define GLIB_SIZEOF_LONG   4
+#define GLIB_SIZEOF_SIZE_T 4
+
+typedef signed int gssize;
+typedef unsigned int gsize;
+#define G_GSIZE_MODIFIER ""
+#define G_GSSIZE_FORMAT "i"
+#define G_GSIZE_FORMAT "u"
+
+#define G_MAXSIZE      G_MAXUINT
+#define G_MINSSIZE     G_MININT
+#define G_MAXSSIZE     G_MAXINT
+
+#endif
+
+typedef gint64 goffset;
+#define G_MINOFFSET    G_MININT64
+#define G_MAXOFFSET    G_MAXINT64
+
+#ifndef _WIN64
+
+#define GPOINTER_TO_INT(p)     ((gint)   (p))
+#define GPOINTER_TO_UINT(p)    ((guint)  (p))
+
+#define GINT_TO_POINTER(i)     ((gpointer)  (i))
+#define GUINT_TO_POINTER(u)    ((gpointer)  (u))
+
+typedef signed int gintptr;
+typedef unsigned int guintptr;
+
+#else
+
+#define GPOINTER_TO_INT(p)     ((gint)  (gint64) (p))
+#define GPOINTER_TO_UINT(p)    ((guint) (guint64) (p))
+
+#define GINT_TO_POINTER(i)     ((gpointer) (gint64) (i))
+#define GUINT_TO_POINTER(u)    ((gpointer) (guint64) (u))
+
+#ifndef _MSC_VER
+typedef signed long long gintptr;
+typedef unsigned long long guintptr;
+#else
+typedef signed __int64 gintptr;
+typedef unsigned __int64 guintptr;
+#endif
+
+#endif
+
+#ifdef NeXT /* @#%@! NeXTStep */
+# define g_ATEXIT(proc)        (!atexit (proc))
+#else
+# define g_ATEXIT(proc)        (atexit (proc))
+#endif
+
+#define g_memmove(dest,src,len) G_STMT_START { memmove ((dest), (src), (len)); } G_STMT_END
+
+#define GLIB_MAJOR_VERSION 2
+#define GLIB_MINOR_VERSION 18
+#define GLIB_MICRO_VERSION 1
+
+#define G_OS_WIN32
+#define G_PLATFORM_WIN32
+
+
+#ifndef _MSC_VER
+#define G_VA_COPY      va_copy
+#endif /* not _MSC_VER */
+
+#ifdef __cplusplus
+#define        G_HAVE_INLINE   1
+#else  /* !__cplusplus */
+#ifndef _MSC_VER
+#define G_HAVE_INLINE 1
+#endif /* _MSC_VER */
+#define G_HAVE___INLINE 1
+#if !defined(_MSC_VER) && !defined(__DMC__)
+#define G_HAVE___INLINE__ 1
+#endif /* !_MSC_VER and !__DMC__ */
+#endif /* !__cplusplus */
+
+#define G_CAN_INLINE   1
+
+#ifndef _MSC_VER
+#define G_HAVE_ISO_VARARGS 1
+
+/* gcc-2.95.x supports both gnu style and ISO varargs, but if -ansi
+ * is passed ISO vararg support is turned off, and there is no work
+ * around to turn it on, so we unconditionally turn it off.
+ */
+#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
+#  undef G_HAVE_ISO_VARARGS
+#endif
+
+#define G_HAVE_GNUC_VARARGS 1
+#else /* _MSC_VER */
+/* varargs macros available since msvc8 (vs2005) */
+#  if _MSC_VER >= 1400
+#    define G_HAVE_ISO_VARARGS 1
+#   endif
+#endif /* not _MSC_VER */
+#define G_HAVE_GROWING_STACK 0
+
+#define G_GNUC_INTERNAL
+
+#define G_THREADS_ENABLED
+#define G_THREADS_IMPL_WIN32
+typedef struct _GMutex* GStaticMutex;
+#define G_STATIC_MUTEX_INIT NULL
+#define g_static_mutex_get_mutex(mutex) \
+  (g_static_mutex_get_mutex_impl_shortcut (mutex))
+/* This represents a system thread as used by the implementation. An
+ * alien implementaion, as loaded by g_thread_init can only count on
+ * "sizeof (gpointer)" bytes to store their info. We however need more
+ * for some of our native implementations. */
+typedef union _GSystemThread GSystemThread;
+union _GSystemThread
+{
+#ifndef _WIN64
+  char   data[4];
+#else
+  char   data[8];
+#endif
+  double dummy_double;
+  void  *dummy_pointer;
+  long   dummy_long;
+};
+
+#define GINT16_TO_LE(val)      ((gint16) (val))
+#define GUINT16_TO_LE(val)     ((guint16) (val))
+#define GINT16_TO_BE(val)      ((gint16) GUINT16_SWAP_LE_BE (val))
+#define GUINT16_TO_BE(val)     (GUINT16_SWAP_LE_BE (val))
+#define GINT32_TO_LE(val)      ((gint32) (val))
+#define GUINT32_TO_LE(val)     ((guint32) (val))
+#define GINT32_TO_BE(val)      ((gint32) GUINT32_SWAP_LE_BE (val))
+#define GUINT32_TO_BE(val)     (GUINT32_SWAP_LE_BE (val))
+#define GINT64_TO_LE(val)      ((gint64) (val))
+#define GUINT64_TO_LE(val)     ((guint64) (val))
+#define GINT64_TO_BE(val)      ((gint64) GUINT64_SWAP_LE_BE (val))
+#define GUINT64_TO_BE(val)     (GUINT64_SWAP_LE_BE (val))
+#define GLONG_TO_LE(val)       ((glong) GINT32_TO_LE (val))
+#define GULONG_TO_LE(val)      ((gulong) GUINT32_TO_LE (val))
+#define GLONG_TO_BE(val)       ((glong) GINT32_TO_BE (val))
+#define GULONG_TO_BE(val)      ((gulong) GUINT32_TO_BE (val))
+#define GINT_TO_LE(val)                ((gint) GINT32_TO_LE (val))
+#define GUINT_TO_LE(val)       ((guint) GUINT32_TO_LE (val))
+#define GINT_TO_BE(val)                ((gint) GINT32_TO_BE (val))
+#define GUINT_TO_BE(val)       ((guint) GUINT32_TO_BE (val))
+#define G_BYTE_ORDER G_LITTLE_ENDIAN
+
+#define GLIB_SYSDEF_POLLIN =1
+#define GLIB_SYSDEF_POLLOUT =4
+#define GLIB_SYSDEF_POLLPRI =2
+#define GLIB_SYSDEF_POLLHUP =16
+#define GLIB_SYSDEF_POLLERR =8
+#define GLIB_SYSDEF_POLLNVAL =32
+
+#define G_MODULE_SUFFIX "dll"
+
+/* A GPid is an abstraction for a process "handle". It is *not* an
+ * abstraction for a process identifier in general. GPid is used in
+ * GLib only for descendant processes spawned with the g_spawn*
+ * functions. On POSIX there is no "process handle" concept as such,
+ * but on Windows a GPid is a handle to a process, a kind of pointer,
+ * not a process identifier.
+ */
+typedef void * GPid;
+
+G_END_DECLS
+
+#endif /* GLIBCONFIG_H */
diff --git a/navit/navit/support/glib/glibintl.h b/navit/navit/support/glib/glibintl.h
new file mode 100644 (file)
index 0000000..4bed7c1
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __GLIBINTL_H__
+#define __GLIBINTL_H__
+
+#ifndef SIZEOF_CHAR
+#error "config.h must be included prior to glibintl.h"
+#endif
+
+G_CONST_RETURN gchar *glib_gettext (const gchar *str);
+
+#ifdef ENABLE_NLS
+
+#include <libintl.h>
+#define _(String) glib_gettext(String)
+/* Split out this in the code, but keep it in the same domain for now */
+#define P_(String) glib_gettext(String)
+
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#else /* NLS is disabled */
+#define _(String) (String)
+#define N_(String) (String)
+#define P_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define dngettext(Domain,String1,String2,N) ((N) == 1 ? (String1) : (String2))
+#define bindtextdomain(Domain,Directory) (Domain) 
+#endif
+
+/* not really I18N-related, but also a string marker macro */
+#define I_(string) g_intern_static_string (string)
+
+#endif /* __GLIBINTL_H__ */
diff --git a/navit/navit/support/glib/glist.c b/navit/navit/support/glib/glist.c
new file mode 100644 (file)
index 0000000..b607abd
--- /dev/null
@@ -0,0 +1,999 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+void g_list_push_allocator (gpointer dummy) { /* present for binary compat only */ }
+void g_list_pop_allocator  (void)           { /* present for binary compat only */ }
+
+#define _g_list_alloc()         g_slice_new (GList)
+#define _g_list_alloc0()        g_slice_new0 (GList)
+#define _g_list_free1(list)     g_slice_free (GList, list)
+
+GList*
+g_list_alloc (void)
+{
+  return _g_list_alloc0 ();
+}
+
+/**
+ * g_list_free: 
+ * @list: a #GList
+ *
+ * Frees all of the memory used by a #GList.
+ * The freed elements are returned to the slice allocator.
+ *
+ * <note><para>
+ * If list elements contain dynamically-allocated memory, 
+ * they should be freed first.
+ * </para></note>
+ */
+void
+g_list_free (GList *list)
+{
+  g_slice_free_chain (GList, list, next);
+}
+
+/**
+ * g_list_free_1:
+ * @list: a #GList element
+ *
+ * Frees one #GList element.
+ * It is usually used after g_list_remove_link().
+ */
+void
+g_list_free_1 (GList *list)
+{
+  _g_list_free1 (list);
+}
+
+/**
+ * g_list_append:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the end of the list.
+ *
+ * <note><para>
+ * The return value is the new start of the list, which 
+ * may have changed, so make sure you store the new value.
+ * </para></note>
+ *
+ * <note><para>
+ * Note that g_list_append() has to traverse the entire list 
+ * to find the end, which is inefficient when adding multiple 
+ * elements. A common idiom to avoid the inefficiency is to prepend 
+ * the elements and reverse the list when all elements have been added.
+ * </para></note>
+ *
+ * |[
+ * /&ast; Notice that these are initialized to the empty list. &ast;/
+ * GList *list = NULL, *number_list = NULL;
+ *
+ * /&ast; This is a list of strings. &ast;/
+ * list = g_list_append (list, "first");
+ * list = g_list_append (list, "second");
+ * 
+ * /&ast; This is a list of integers. &ast;/
+ * number_list = g_list_append (number_list, GINT_TO_POINTER (27));
+ * number_list = g_list_append (number_list, GINT_TO_POINTER (14));
+ * ]|
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_append (GList   *list,
+              gpointer  data)
+{
+  GList *new_list;
+  GList *last;
+  
+  new_list = _g_list_alloc ();
+  new_list->data = data;
+  new_list->next = NULL;
+  
+  if (list)
+    {
+      last = g_list_last (list);
+      /* g_assert (last != NULL); */
+      last->next = new_list;
+      new_list->prev = last;
+
+      return list;
+    }
+  else
+    {
+      new_list->prev = NULL;
+      return new_list;
+    }
+}
+
+/**
+ * g_list_prepend:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the start of the list.
+ *
+ * <note><para>
+ * The return value is the new start of the list, which 
+ * may have changed, so make sure you store the new value.
+ * </para></note>
+ *
+ * |[ 
+ * /&ast; Notice that it is initialized to the empty list. &ast;/
+ * GList *list = NULL;
+ * list = g_list_prepend (list, "last");
+ * list = g_list_prepend (list, "first");
+ * ]|
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_prepend (GList   *list,
+               gpointer  data)
+{
+  GList *new_list;
+  
+  new_list = _g_list_alloc ();
+  new_list->data = data;
+  new_list->next = list;
+  
+  if (list)
+    {
+      new_list->prev = list->prev;
+      if (list->prev)
+       list->prev->next = new_list;
+      list->prev = new_list;
+    }
+  else
+    new_list->prev = NULL;
+  
+  return new_list;
+}
+
+/**
+ * g_list_insert:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ * @position: the position to insert the element. If this is 
+ *     negative, or is larger than the number of elements in the 
+ *     list, the new element is added on to the end of the list.
+ * 
+ * Inserts a new element into the list at the given position.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_insert (GList   *list,
+              gpointer  data,
+              gint      position)
+{
+  GList *new_list;
+  GList *tmp_list;
+  
+  if (position < 0)
+    return g_list_append (list, data);
+  else if (position == 0)
+    return g_list_prepend (list, data);
+  
+  tmp_list = g_list_nth (list, position);
+  if (!tmp_list)
+    return g_list_append (list, data);
+  
+  new_list = _g_list_alloc ();
+  new_list->data = data;
+  new_list->prev = tmp_list->prev;
+  if (tmp_list->prev)
+    tmp_list->prev->next = new_list;
+  new_list->next = tmp_list;
+  tmp_list->prev = new_list;
+  
+  if (tmp_list == list)
+    return new_list;
+  else
+    return list;
+}
+
+/**
+ * g_list_insert_before:
+ * @list: a pointer to a #GList
+ * @sibling: the list element before which the new element 
+ *     is inserted or %NULL to insert at the end of the list
+ * @data: the data for the new element
+ *
+ * Inserts a new element into the list before the given position.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_insert_before (GList   *list,
+                     GList   *sibling,
+                     gpointer data)
+{
+  if (!list)
+    {
+      list = g_list_alloc ();
+      list->data = data;
+      g_return_val_if_fail (sibling == NULL, list);
+      return list;
+    }
+  else if (sibling)
+    {
+      GList *node;
+
+      node = _g_list_alloc ();
+      node->data = data;
+      node->prev = sibling->prev;
+      node->next = sibling;
+      sibling->prev = node;
+      if (node->prev)
+       {
+         node->prev->next = node;
+         return list;
+       }
+      else
+       {
+         g_return_val_if_fail (sibling == list, node);
+         return node;
+       }
+    }
+  else
+    {
+      GList *last;
+
+      last = list;
+      while (last->next)
+       last = last->next;
+
+      last->next = _g_list_alloc ();
+      last->next->data = data;
+      last->next->prev = last;
+      last->next->next = NULL;
+
+      return list;
+    }
+}
+
+/**
+ * g_list_concat:
+ * @list1: a #GList
+ * @list2: the #GList to add to the end of the first #GList
+ *
+ * Adds the second #GList onto the end of the first #GList.
+ * Note that the elements of the second #GList are not copied.
+ * They are used directly.
+ *
+ * Returns: the start of the new #GList
+ */
+GList *
+g_list_concat (GList *list1, GList *list2)
+{
+  GList *tmp_list;
+  
+  if (list2)
+    {
+      tmp_list = g_list_last (list1);
+      if (tmp_list)
+       tmp_list->next = list2;
+      else
+       list1 = list2;
+      list2->prev = tmp_list;
+    }
+  
+  return list1;
+}
+
+/**
+ * g_list_remove:
+ * @list: a #GList
+ * @data: the data of the element to remove
+ *
+ * Removes an element from a #GList.
+ * If two elements contain the same data, only the first is removed.
+ * If none of the elements contain the data, the #GList is unchanged.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_remove (GList        *list,
+              gconstpointer  data)
+{
+  GList *tmp;
+  
+  tmp = list;
+  while (tmp)
+    {
+      if (tmp->data != data)
+       tmp = tmp->next;
+      else
+       {
+         if (tmp->prev)
+           tmp->prev->next = tmp->next;
+         if (tmp->next)
+           tmp->next->prev = tmp->prev;
+         
+         if (list == tmp)
+           list = list->next;
+         
+         _g_list_free1 (tmp);
+         
+         break;
+       }
+    }
+  return list;
+}
+
+/**
+ * g_list_remove_all:
+ * @list: a #GList
+ * @data: data to remove
+ *
+ * Removes all list nodes with data equal to @data. 
+ * Returns the new head of the list. Contrast with 
+ * g_list_remove() which removes only the first node 
+ * matching the given data.
+ *
+ * Returns: new head of @list
+ */
+GList*
+g_list_remove_all (GList       *list,
+                  gconstpointer data)
+{
+  GList *tmp = list;
+
+  while (tmp)
+    {
+      if (tmp->data != data)
+       tmp = tmp->next;
+      else
+       {
+         GList *next = tmp->next;
+
+         if (tmp->prev)
+           tmp->prev->next = next;
+         else
+           list = next;
+         if (next)
+           next->prev = tmp->prev;
+
+         _g_list_free1 (tmp);
+         tmp = next;
+       }
+    }
+  return list;
+}
+
+static inline GList*
+_g_list_remove_link (GList *list,
+                    GList *link)
+{
+  if (link)
+    {
+      if (link->prev)
+       link->prev->next = link->next;
+      if (link->next)
+       link->next->prev = link->prev;
+      
+      if (link == list)
+       list = list->next;
+      
+      link->next = NULL;
+      link->prev = NULL;
+    }
+  
+  return list;
+}
+
+/**
+ * g_list_remove_link:
+ * @list: a #GList
+ * @llink: an element in the #GList
+ *
+ * Removes an element from a #GList, without freeing the element.
+ * The removed element's prev and next links are set to %NULL, so 
+ * that it becomes a self-contained list with one element.
+ *
+ * Returns: the new start of the #GList, without the element
+ */
+GList*
+g_list_remove_link (GList *list,
+                   GList *llink)
+{
+  return _g_list_remove_link (list, llink);
+}
+
+/**
+ * g_list_delete_link:
+ * @list: a #GList
+ * @link_: node to delete from @list
+ *
+ * Removes the node link_ from the list and frees it. 
+ * Compare this to g_list_remove_link() which removes the node 
+ * without freeing it.
+ *
+ * Returns: the new head of @list
+ */
+GList*
+g_list_delete_link (GList *list,
+                   GList *link_)
+{
+  list = _g_list_remove_link (list, link_);
+  _g_list_free1 (link_);
+
+  return list;
+}
+
+/**
+ * g_list_copy:
+ * @list: a #GList
+ *
+ * Copies a #GList.
+ *
+ * <note><para>
+ * Note that this is a "shallow" copy. If the list elements 
+ * consist of pointers to data, the pointers are copied but 
+ * the actual data is not.
+ * </para></note>
+ *
+ * Returns: a copy of @list
+ */
+GList*
+g_list_copy (GList *list)
+{
+  GList *new_list = NULL;
+
+  if (list)
+    {
+      GList *last;
+
+      new_list = _g_list_alloc ();
+      new_list->data = list->data;
+      new_list->prev = NULL;
+      last = new_list;
+      list = list->next;
+      while (list)
+       {
+         last->next = _g_list_alloc ();
+         last->next->prev = last;
+         last = last->next;
+         last->data = list->data;
+         list = list->next;
+       }
+      last->next = NULL;
+    }
+
+  return new_list;
+}
+
+/**
+ * g_list_reverse:
+ * @list: a #GList
+ *
+ * Reverses a #GList.
+ * It simply switches the next and prev pointers of each element.
+ *
+ * Returns: the start of the reversed #GList
+ */
+GList*
+g_list_reverse (GList *list)
+{
+  GList *last;
+  
+  last = NULL;
+  while (list)
+    {
+      last = list;
+      list = last->next;
+      last->next = last->prev;
+      last->prev = list;
+    }
+  
+  return last;
+}
+
+/**
+ * g_list_nth:
+ * @list: a #GList
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element at the given position in a #GList.
+ *
+ * Returns: the element, or %NULL if the position is off 
+ *     the end of the #GList
+ */
+GList*
+g_list_nth (GList *list,
+           guint  n)
+{
+  while ((n-- > 0) && list)
+    list = list->next;
+  
+  return list;
+}
+
+/**
+ * g_list_nth_prev:
+ * @list: a #GList
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element @n places before @list.
+ *
+ * Returns: the element, or %NULL if the position is 
+ *     off the end of the #GList
+ */
+GList*
+g_list_nth_prev (GList *list,
+                guint  n)
+{
+  while ((n-- > 0) && list)
+    list = list->prev;
+  
+  return list;
+}
+
+/**
+ * g_list_nth_data:
+ * @list: a #GList
+ * @n: the position of the element
+ *
+ * Gets the data of the element at the given position.
+ *
+ * Returns: the element's data, or %NULL if the position 
+ *     is off the end of the #GList
+ */
+gpointer
+g_list_nth_data (GList     *list,
+                guint      n)
+{
+  while ((n-- > 0) && list)
+    list = list->next;
+  
+  return list ? list->data : NULL;
+}
+
+/**
+ * g_list_find:
+ * @list: a #GList
+ * @data: the element data to find
+ *
+ * Finds the element in a #GList which 
+ * contains the given data.
+ *
+ * Returns: the found #GList element, 
+ *     or %NULL if it is not found
+ */
+GList*
+g_list_find (GList         *list,
+            gconstpointer  data)
+{
+  while (list)
+    {
+      if (list->data == data)
+       break;
+      list = list->next;
+    }
+  
+  return list;
+}
+
+/**
+ * g_list_find_custom:
+ * @list: a #GList
+ * @data: user data passed to the function
+ * @func: the function to call for each element. 
+ *     It should return 0 when the desired element is found
+ *
+ * Finds an element in a #GList, using a supplied function to 
+ * find the desired element. It iterates over the list, calling 
+ * the given function which should return 0 when the desired 
+ * element is found. The function takes two #gconstpointer arguments, 
+ * the #GList element's data as the first argument and the 
+ * given user data.
+ *
+ * Returns: the found #GList element, or %NULL if it is not found
+ */
+GList*
+g_list_find_custom (GList         *list,
+                   gconstpointer  data,
+                   GCompareFunc   func)
+{
+  g_return_val_if_fail (func != NULL, list);
+
+  while (list)
+    {
+      if (! func (list->data, data))
+       return list;
+      list = list->next;
+    }
+
+  return NULL;
+}
+
+
+/**
+ * g_list_position:
+ * @list: a #GList
+ * @llink: an element in the #GList
+ *
+ * Gets the position of the given element 
+ * in the #GList (starting from 0).
+ *
+ * Returns: the position of the element in the #GList, 
+ *     or -1 if the element is not found
+ */
+gint
+g_list_position (GList *list,
+                GList *llink)
+{
+  gint i;
+
+  i = 0;
+  while (list)
+    {
+      if (list == llink)
+       return i;
+      i++;
+      list = list->next;
+    }
+
+  return -1;
+}
+
+/**
+ * g_list_index:
+ * @list: a #GList
+ * @data: the data to find
+ *
+ * Gets the position of the element containing 
+ * the given data (starting from 0).
+ *
+ * Returns: the index of the element containing the data, 
+ *     or -1 if the data is not found
+ */
+gint
+g_list_index (GList         *list,
+             gconstpointer  data)
+{
+  gint i;
+
+  i = 0;
+  while (list)
+    {
+      if (list->data == data)
+       return i;
+      i++;
+      list = list->next;
+    }
+
+  return -1;
+}
+
+/**
+ * g_list_last:
+ * @list: a #GList
+ *
+ * Gets the last element in a #GList.
+ *
+ * Returns: the last element in the #GList, 
+ *     or %NULL if the #GList has no elements
+ */
+GList*
+g_list_last (GList *list)
+{
+  if (list)
+    {
+      while (list->next)
+       list = list->next;
+    }
+  
+  return list;
+}
+
+/**
+ * g_list_first:
+ * @list: a #GList
+ *
+ * Gets the first element in a #GList.
+ *
+ * Returns: the first element in the #GList, 
+ *     or %NULL if the #GList has no elements
+ */
+GList*
+g_list_first (GList *list)
+{
+  if (list)
+    {
+      while (list->prev)
+       list = list->prev;
+    }
+  
+  return list;
+}
+
+/**
+ * g_list_length:
+ * @list: a #GList
+ *
+ * Gets the number of elements in a #GList.
+ *
+ * <note><para>
+ * This function iterates over the whole list to 
+ * count its elements.
+ * </para></note>
+ *
+ * Returns: the number of elements in the #GList
+ */
+guint
+g_list_length (GList *list)
+{
+  guint length;
+  
+  length = 0;
+  while (list)
+    {
+      length++;
+      list = list->next;
+    }
+  
+  return length;
+}
+
+/**
+ * g_list_foreach:
+ * @list: a #GList
+ * @func: the function to call with each element's data
+ * @user_data: user data to pass to the function
+ *
+ * Calls a function for each element of a #GList.
+ */
+void
+g_list_foreach (GList   *list,
+               GFunc     func,
+               gpointer  user_data)
+{
+  while (list)
+    {
+      GList *next = list->next;
+      (*func) (list->data, user_data);
+      list = next;
+    }
+}
+
+static GList*
+g_list_insert_sorted_real (GList    *list,
+                          gpointer  data,
+                          GFunc     func,
+                          gpointer  user_data)
+{
+  GList *tmp_list = list;
+  GList *new_list;
+  gint cmp;
+
+  g_return_val_if_fail (func != NULL, list);
+  
+  if (!list) 
+    {
+      new_list = _g_list_alloc0 ();
+      new_list->data = data;
+      return new_list;
+    }
+  
+  cmp = ((GCompareDataFunc) func) (data, tmp_list->data, user_data);
+
+  while ((tmp_list->next) && (cmp > 0))
+    {
+      tmp_list = tmp_list->next;
+
+      cmp = ((GCompareDataFunc) func) (data, tmp_list->data, user_data);
+    }
+
+  new_list = _g_list_alloc0 ();
+  new_list->data = data;
+
+  if ((!tmp_list->next) && (cmp > 0))
+    {
+      tmp_list->next = new_list;
+      new_list->prev = tmp_list;
+      return list;
+    }
+   
+  if (tmp_list->prev)
+    {
+      tmp_list->prev->next = new_list;
+      new_list->prev = tmp_list->prev;
+    }
+  new_list->next = tmp_list;
+  tmp_list->prev = new_list;
+  if (tmp_list == list)
+    return new_list;
+  else
+    return list;
+}
+
+/**
+ * g_list_insert_sorted:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ * @func: the function to compare elements in the list. It should 
+ *     return a number > 0 if the first parameter comes after the 
+ *     second parameter in the sort order.
+ *
+ * Inserts a new element into the list, using the given comparison 
+ * function to determine its position.
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_insert_sorted (GList        *list,
+                     gpointer      data,
+                     GCompareFunc  func)
+{
+  return g_list_insert_sorted_real (list, data, (GFunc) func, NULL);
+}
+
+/**
+ * g_list_insert_sorted_with_data:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ * @func: the function to compare elements in the list. 
+ *     It should return a number > 0 if the first parameter 
+ *     comes after the second parameter in the sort order.
+ * @user_data: user data to pass to comparison function.
+ *
+ * Inserts a new element into the list, using the given comparison 
+ * function to determine its position.
+ *
+ * Returns: the new start of the #GList
+ *
+ * Since: 2.10
+ */
+GList*
+g_list_insert_sorted_with_data (GList            *list,
+                               gpointer          data,
+                               GCompareDataFunc  func,
+                               gpointer          user_data)
+{
+  return g_list_insert_sorted_real (list, data, (GFunc) func, user_data);
+}
+
+static GList *
+g_list_sort_merge (GList     *l1, 
+                  GList     *l2,
+                  GFunc     compare_func,
+                  gpointer  user_data)
+{
+  GList list, *l, *lprev;
+  gint cmp;
+
+  l = &list; 
+  lprev = NULL;
+
+  while (l1 && l2)
+    {
+      cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
+
+      if (cmp <= 0)
+        {
+         l->next = l1;
+         l1 = l1->next;
+        } 
+      else 
+       {
+         l->next = l2;
+         l2 = l2->next;
+        }
+      l = l->next;
+      l->prev = lprev; 
+      lprev = l;
+    }
+  l->next = l1 ? l1 : l2;
+  l->next->prev = l;
+
+  return list.next;
+}
+
+static GList* 
+g_list_sort_real (GList    *list,
+                 GFunc     compare_func,
+                 gpointer  user_data)
+{
+  GList *l1, *l2;
+  
+  if (!list) 
+    return NULL;
+  if (!list->next) 
+    return list;
+  
+  l1 = list; 
+  l2 = list->next;
+
+  while ((l2 = l2->next) != NULL)
+    {
+      if ((l2 = l2->next) == NULL) 
+       break;
+      l1 = l1->next;
+    }
+  l2 = l1->next; 
+  l1->next = NULL; 
+
+  return g_list_sort_merge (g_list_sort_real (list, compare_func, user_data),
+                           g_list_sort_real (l2, compare_func, user_data),
+                           compare_func,
+                           user_data);
+}
+
+/**
+ * g_list_sort:
+ * @list: a #GList
+ * @compare_func: the comparison function used to sort the #GList.
+ *     This function is passed the data from 2 elements of the #GList 
+ *     and should return 0 if they are equal, a negative value if the 
+ *     first element comes before the second, or a positive value if 
+ *     the first element comes after the second.
+ *
+ * Sorts a #GList using the given comparison function.
+ *
+ * Returns: the start of the sorted #GList
+ */
+GList *
+g_list_sort (GList        *list,
+            GCompareFunc  compare_func)
+{
+  return g_list_sort_real (list, (GFunc) compare_func, NULL);
+                           
+}
+
+/**
+ * g_list_sort_with_data:
+ * @list: a #GList
+ * @compare_func: comparison function
+ * @user_data: user data to pass to comparison function
+ *
+ * Like g_list_sort(), but the comparison function accepts 
+ * a user data argument.
+ *
+ * Returns: the new head of @list
+ */
+GList *
+g_list_sort_with_data (GList            *list,
+                      GCompareDataFunc  compare_func,
+                      gpointer          user_data)
+{
+  return g_list_sort_real (list, (GFunc) compare_func, user_data);
+}
+
+#define __G_LIST_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/glist.h b/navit/navit/support/glib/glist.h
new file mode 100644 (file)
index 0000000..e74ed96
--- /dev/null
@@ -0,0 +1,120 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_LIST_H__
+#define __G_LIST_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GList GList;
+
+struct _GList
+{
+  gpointer data;
+  GList *next;
+  GList *prev;
+};
+
+/* Doubly linked lists
+ */
+GList*   g_list_alloc                   (void) G_GNUC_WARN_UNUSED_RESULT;
+void     g_list_free                    (GList            *list);
+void     g_list_free_1                  (GList            *list);
+#define  g_list_free1                   g_list_free_1
+GList*   g_list_append                  (GList            *list,
+                                        gpointer          data) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_prepend                 (GList            *list,
+                                        gpointer          data) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_insert                  (GList            *list,
+                                        gpointer          data,
+                                        gint              position) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_insert_sorted           (GList            *list,
+                                        gpointer          data,
+                                        GCompareFunc      func) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_insert_sorted_with_data (GList            *list,
+                                        gpointer          data,
+                                        GCompareDataFunc  func,
+                                        gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_insert_before           (GList            *list,
+                                        GList            *sibling,
+                                        gpointer          data) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_concat                  (GList            *list1,
+                                        GList            *list2) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_remove                  (GList            *list,
+                                        gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_remove_all              (GList            *list,
+                                        gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_remove_link             (GList            *list,
+                                        GList            *llink) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_delete_link             (GList            *list,
+                                        GList            *link_) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_reverse                 (GList            *list) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_copy                    (GList            *list) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_nth                     (GList            *list,
+                                        guint             n);
+GList*   g_list_nth_prev                (GList            *list,
+                                        guint             n);
+GList*   g_list_find                    (GList            *list,
+                                        gconstpointer     data);
+GList*   g_list_find_custom             (GList            *list,
+                                        gconstpointer     data,
+                                        GCompareFunc      func);
+gint     g_list_position                (GList            *list,
+                                        GList            *llink);
+gint     g_list_index                   (GList            *list,
+                                        gconstpointer     data);
+GList*   g_list_last                    (GList            *list);
+GList*   g_list_first                   (GList            *list);
+guint    g_list_length                  (GList            *list);
+void     g_list_foreach                 (GList            *list,
+                                        GFunc             func,
+                                        gpointer          user_data);
+GList*   g_list_sort                    (GList            *list,
+                                        GCompareFunc      compare_func) G_GNUC_WARN_UNUSED_RESULT;
+GList*   g_list_sort_with_data          (GList            *list,
+                                        GCompareDataFunc  compare_func,
+                                        gpointer          user_data)  G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_list_nth_data                (GList            *list,
+                                        guint             n);
+
+
+#define g_list_previous(list)          ((list) ? (((GList *)(list))->prev) : NULL)
+#define g_list_next(list)              ((list) ? (((GList *)(list))->next) : NULL)
+
+#ifndef G_DISABLE_DEPRECATED
+void     g_list_push_allocator          (gpointer          allocator);
+void     g_list_pop_allocator           (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_LIST_H__ */
diff --git a/navit/navit/support/glib/gmacros.h b/navit/navit/support/glib/gmacros.h
new file mode 100644 (file)
index 0000000..f87e932
--- /dev/null
@@ -0,0 +1,273 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+/* This file must not include any other glib header file and must thus
+ * not refer to variables from glibconfig.h
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MACROS_H__
+#define __G_MACROS_H__
+
+/* We include stddef.h to get the system's definition of NULL
+ */
+#include <stddef.h>
+
+/* Here we provide G_GNUC_EXTENSION as an alias for __extension__,
+ * where this is valid. This allows for warningless compilation of
+ * "long long" types even in the presence of '-ansi -pedantic'. 
+ */
+#if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+#  define G_GNUC_EXTENSION __extension__
+#else
+#  define G_GNUC_EXTENSION
+#endif
+
+/* Provide macros to feature the GCC function attribute.
+ */
+#if    __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#define G_GNUC_PURE                            \
+  __attribute__((__pure__))
+#define G_GNUC_MALLOC                          \
+  __attribute__((__malloc__))
+#else
+#define G_GNUC_PURE
+#define G_GNUC_MALLOC
+#endif
+
+#if     __GNUC__ >= 4
+#define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
+#else
+#define G_GNUC_NULL_TERMINATED
+#endif
+
+#if     (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+#define G_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+#define G_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y)))
+#else
+#define G_GNUC_ALLOC_SIZE(x)
+#define G_GNUC_ALLOC_SIZE2(x,y)
+#endif
+
+#if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define G_GNUC_PRINTF( format_idx, arg_idx )    \
+  __attribute__((__format__ (__printf__, format_idx, arg_idx)))
+#define G_GNUC_SCANF( format_idx, arg_idx )     \
+  __attribute__((__format__ (__scanf__, format_idx, arg_idx)))
+#define G_GNUC_FORMAT( arg_idx )                \
+  __attribute__((__format_arg__ (arg_idx)))
+#define G_GNUC_NORETURN                         \
+  __attribute__((__noreturn__))
+#define G_GNUC_CONST                            \
+  __attribute__((__const__))
+#define G_GNUC_UNUSED                           \
+  __attribute__((__unused__))
+#define G_GNUC_NO_INSTRUMENT                   \
+  __attribute__((__no_instrument_function__))
+#else   /* !__GNUC__ */
+#define G_GNUC_PRINTF( format_idx, arg_idx )
+#define G_GNUC_SCANF( format_idx, arg_idx )
+#define G_GNUC_FORMAT( arg_idx )
+#define G_GNUC_NORETURN
+#define G_GNUC_CONST
+#define G_GNUC_UNUSED
+#define G_GNUC_NO_INSTRUMENT
+#endif  /* !__GNUC__ */
+
+#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define G_GNUC_DEPRECATED                            \
+  __attribute__((__deprecated__))
+#else
+#define G_GNUC_DEPRECATED
+#endif /* __GNUC__ */
+
+#if     __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+#  define G_GNUC_MAY_ALIAS __attribute__((may_alias))
+#else
+#  define G_GNUC_MAY_ALIAS
+#endif
+
+#if    __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define G_GNUC_WARN_UNUSED_RESULT              \
+  __attribute__((warn_unused_result))
+#else
+#define G_GNUC_WARN_UNUSED_RESULT
+#endif /* __GNUC__ */
+
+#ifndef G_DISABLE_DEPRECATED
+/* Wrap the gcc __PRETTY_FUNCTION__ and __FUNCTION__ variables with
+ * macros, so we can refer to them as strings unconditionally.
+ * usage not-recommended since gcc-3.0
+ */
+#if defined (__GNUC__) && (__GNUC__ < 3)
+#define G_GNUC_FUNCTION         __FUNCTION__
+#define G_GNUC_PRETTY_FUNCTION  __PRETTY_FUNCTION__
+#else   /* !__GNUC__ */
+#define G_GNUC_FUNCTION         ""
+#define G_GNUC_PRETTY_FUNCTION  ""
+#endif  /* !__GNUC__ */
+#endif  /* !G_DISABLE_DEPRECATED */
+
+#define G_STRINGIFY(macro_or_string)   G_STRINGIFY_ARG (macro_or_string)
+#define        G_STRINGIFY_ARG(contents)       #contents
+
+/* Provide a string identifying the current code position */
+#if defined(__GNUC__) && (__GNUC__ < 3) && !defined(__cplusplus)
+#  define G_STRLOC     __FILE__ ":" G_STRINGIFY (__LINE__) ":" __PRETTY_FUNCTION__ "()"
+#else
+#  define G_STRLOC     __FILE__ ":" G_STRINGIFY (__LINE__)
+#endif
+
+/* Provide a string identifying the current function, non-concatenatable */
+#if defined (__GNUC__)
+#  define G_STRFUNC     ((const char*) (__PRETTY_FUNCTION__))
+#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 19901L
+#  define G_STRFUNC     ((const char*) (__func__))
+#else
+#  define G_STRFUNC     ((const char*) ("???"))
+#endif
+
+/* Guard C code in headers, while including them from C++ */
+#ifdef  __cplusplus
+# define G_BEGIN_DECLS  extern "C" {
+# define G_END_DECLS    }
+#else
+# define G_BEGIN_DECLS
+# define G_END_DECLS
+#endif
+
+/* Provide definitions for some commonly used macros.
+ *  Some of them are only provided if they haven't already
+ *  been defined. It is assumed that if they are already
+ *  defined then the current definition is correct.
+ */
+#ifndef NULL
+#  ifdef __cplusplus
+#    define NULL        (0L)
+#  else /* !__cplusplus */
+#    define NULL        ((void*) 0)
+#  endif /* !__cplusplus */
+#endif
+
+#ifndef        FALSE
+#define        FALSE   (0)
+#endif
+
+#ifndef        TRUE
+#define        TRUE    (!FALSE)
+#endif
+
+#undef MAX
+#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
+
+#undef MIN
+#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
+
+#undef ABS
+#define ABS(a)    (((a) < 0) ? -(a) : (a))
+
+#undef CLAMP
+#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
+/* Count the number of elements in an array. The array must be defined
+ * as such; using this with a dynamically allocated array will give
+ * incorrect results.
+ */
+#define G_N_ELEMENTS(arr)              (sizeof (arr) / sizeof ((arr)[0]))
+
+/* Macros by analogy to GINT_TO_POINTER, GPOINTER_TO_INT
+ */
+#define GPOINTER_TO_SIZE(p)    ((gsize) (p))
+#define GSIZE_TO_POINTER(s)    ((gpointer) (gsize) (s))
+
+/* Provide convenience macros for handling structure
+ * fields through their offsets.
+ */
+
+#if defined(__GNUC__)  && __GNUC__ >= 4
+#  define G_STRUCT_OFFSET(struct_type, member) \
+      ((glong) __builtin_offsetof (struct_type, member))
+#else
+#  define G_STRUCT_OFFSET(struct_type, member) \
+      ((glong) ((guint8*) &((struct_type*) 0)->member))
+#endif
+
+#define G_STRUCT_MEMBER_P(struct_p, struct_offset)   \
+    ((gpointer) ((guint8*) (struct_p) + (glong) (struct_offset)))
+#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset)   \
+    (*(member_type*) G_STRUCT_MEMBER_P ((struct_p), (struct_offset)))
+
+/* Provide simple macro statement wrappers:
+ *   G_STMT_START { statements; } G_STMT_END;
+ * This can be used as a single statement, like:
+ *   if (x) G_STMT_START { ... } G_STMT_END; else ...
+ * This intentionally does not use compiler extensions like GCC's '({...})' to
+ * avoid portability issue or side effects when compiled with different compilers.
+ */
+#if !(defined (G_STMT_START) && defined (G_STMT_END))
+#  define G_STMT_START  do
+#  define G_STMT_END    while (0)
+#endif
+
+/* Allow the app programmer to select whether or not return values
+ * (usually char*) are const or not.  Don't try using this feature for
+ * functions with C++ linkage.
+ */
+#ifdef G_DISABLE_CONST_RETURNS
+#define G_CONST_RETURN
+#else
+#define G_CONST_RETURN const
+#endif
+
+/*
+ * The G_LIKELY and G_UNLIKELY macros let the programmer give hints to 
+ * the compiler about the expected result of an expression. Some compilers
+ * can use this information for optimizations.
+ *
+ * The _G_BOOLEAN_EXPR macro is intended to trigger a gcc warning when
+ * putting assignments in g_return_if_fail ().  
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _G_BOOLEAN_EXPR(expr)                   \
+ __extension__ ({                               \
+   int _g_boolean_var_;                         \
+   if (expr)                                    \
+      _g_boolean_var_ = 1;                      \
+   else                                         \
+      _g_boolean_var_ = 0;                      \
+   _g_boolean_var_;                             \
+})
+#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
+#define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))
+#else
+#define G_LIKELY(expr) (expr)
+#define G_UNLIKELY(expr) (expr)
+#endif
+
+#endif /* __G_MACROS_H__ */
diff --git a/navit/navit/support/glib/gmem.c b/navit/navit/support/glib/gmem.c
new file mode 100644 (file)
index 0000000..b9ce0a6
--- /dev/null
@@ -0,0 +1,730 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "glib.h"
+#include "gthreadprivate.h"
+#include "galias.h"
+
+#define MEM_PROFILE_TABLE_SIZE 4096
+
+
+/* notes on macros:
+ * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
+ * g_mem_profile().
+ * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works.
+ * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions
+ * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here.
+ * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped.
+ */
+
+/* --- prototypes --- */
+static gboolean g_mem_initialized = FALSE;
+static void     g_mem_init_nomessage (void);
+
+
+/* --- malloc wrappers --- */
+#ifndef        REALLOC_0_WORKS
+static gpointer
+standard_realloc (gpointer mem,
+                 gsize    n_bytes)
+{
+  if (!mem)
+    return malloc (n_bytes);
+  else
+    return realloc (mem, n_bytes);
+}
+#endif /* !REALLOC_0_WORKS */
+
+#ifdef SANE_MALLOC_PROTOS
+#  define standard_malloc      malloc
+#  ifdef REALLOC_0_WORKS
+#    define standard_realloc   realloc
+#  endif /* REALLOC_0_WORKS */
+#  define standard_free                free
+#  define standard_calloc      calloc
+#  define standard_try_malloc  malloc
+#  define standard_try_realloc realloc
+#else  /* !SANE_MALLOC_PROTOS */
+static gpointer
+standard_malloc (gsize n_bytes)
+{
+  return malloc (n_bytes);
+}
+#  ifdef REALLOC_0_WORKS
+static gpointer
+standard_realloc (gpointer mem,
+                 gsize    n_bytes)
+{
+  return realloc (mem, n_bytes);
+}
+#  endif /* REALLOC_0_WORKS */
+static void
+standard_free (gpointer mem)
+{
+  free (mem);
+}
+static gpointer
+standard_calloc (gsize n_blocks,
+                gsize n_bytes)
+{
+  return calloc (n_blocks, n_bytes);
+}
+#define        standard_try_malloc     standard_malloc
+#define        standard_try_realloc    standard_realloc
+#endif /* !SANE_MALLOC_PROTOS */
+
+
+/* --- variables --- */
+static GMemVTable glib_mem_vtable = {
+  standard_malloc,
+  standard_realloc,
+  standard_free,
+  standard_calloc,
+  standard_try_malloc,
+  standard_try_realloc,
+};
+
+
+/* --- functions --- */
+gpointer
+g_malloc (gsize n_bytes)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    {
+      gpointer mem;
+
+      mem = glib_mem_vtable.malloc (n_bytes);
+      if (mem)
+       return mem;
+
+      g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_bytes);
+    }
+
+  return NULL;
+}
+
+gpointer
+g_malloc0 (gsize n_bytes)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    {
+      gpointer mem;
+
+      mem = glib_mem_vtable.calloc (1, n_bytes);
+      if (mem)
+       return mem;
+
+      g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_bytes);
+    }
+
+  return NULL;
+}
+
+gpointer
+g_realloc (gpointer mem,
+          gsize    n_bytes)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    {
+      mem = glib_mem_vtable.realloc (mem, n_bytes);
+      if (mem)
+       return mem;
+
+      g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_bytes);
+    }
+
+  if (mem)
+    glib_mem_vtable.free (mem);
+
+  return NULL;
+}
+
+void
+g_free (gpointer mem)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (mem))
+    glib_mem_vtable.free (mem);
+}
+
+gpointer
+g_try_malloc (gsize n_bytes)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    return glib_mem_vtable.try_malloc (n_bytes);
+  else
+    return NULL;
+}
+
+gpointer
+g_try_malloc0 (gsize n_bytes)
+{ 
+  gpointer mem;
+
+  mem = g_try_malloc (n_bytes);
+  
+  if (mem)
+    memset (mem, 0, n_bytes);
+
+  return mem;
+}
+
+gpointer
+g_try_realloc (gpointer mem,
+              gsize    n_bytes)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    return glib_mem_vtable.try_realloc (mem, n_bytes);
+
+  if (mem)
+    glib_mem_vtable.free (mem);
+
+  return NULL;
+}
+
+static gpointer
+fallback_calloc (gsize n_blocks,
+                gsize n_block_bytes)
+{
+  gsize l = n_blocks * n_block_bytes;
+  gpointer mem = glib_mem_vtable.malloc (l);
+
+  if (mem)
+    memset (mem, 0, l);
+
+  return mem;
+}
+
+static gboolean vtable_set = FALSE;
+
+/**
+ * g_mem_is_system_malloc
+ * 
+ * Checks whether the allocator used by g_malloc() is the system's
+ * malloc implementation. If it returns %TRUE memory allocated with
+ * malloc() can be used interchangeable with memory allocated using g_malloc(). 
+ * This function is useful for avoiding an extra copy of allocated memory returned
+ * by a non-GLib-based API.
+ *
+ * A different allocator can be set using g_mem_set_vtable().
+ *
+ * Return value: if %TRUE, malloc() and g_malloc() can be mixed.
+ **/
+gboolean
+g_mem_is_system_malloc (void)
+{
+  return !vtable_set;
+}
+
+void
+g_mem_set_vtable (GMemVTable *vtable)
+{
+  if (!vtable_set)
+    {
+      if (vtable->malloc && vtable->realloc && vtable->free)
+       {
+         glib_mem_vtable.malloc = vtable->malloc;
+         glib_mem_vtable.realloc = vtable->realloc;
+         glib_mem_vtable.free = vtable->free;
+         glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc;
+         glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc;
+         glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc;
+         vtable_set = TRUE;
+       }
+      else
+       g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
+    }
+  else
+    g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
+}
+
+
+/* --- memory profiling and checking --- */
+#ifdef G_DISABLE_CHECKS
+GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
+void
+g_mem_profile (void)
+{
+}
+#else  /* !G_DISABLE_CHECKS */
+typedef enum {
+  PROFILER_FREE                = 0,
+  PROFILER_ALLOC       = 1,
+  PROFILER_RELOC       = 2,
+  PROFILER_ZINIT       = 4
+} ProfilerJob;
+static guint *profile_data = NULL;
+static gsize profile_allocs = 0;
+static gsize profile_zinit = 0;
+static gsize profile_frees = 0;
+static GMutex *gmem_profile_mutex = NULL;
+#ifdef  G_ENABLE_DEBUG
+static volatile gsize g_trap_free_size = 0;
+static volatile gsize g_trap_realloc_size = 0;
+static volatile gsize g_trap_malloc_size = 0;
+#endif  /* G_ENABLE_DEBUG */
+
+#define        PROFILE_TABLE(f1,f2,f3)   ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1))
+
+static void
+profiler_log (ProfilerJob job,
+             gsize       n_bytes,
+             gboolean    success)
+{
+  g_mutex_lock (gmem_profile_mutex);
+  if (!profile_data)
+    {
+      profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8, 
+                                      sizeof (profile_data[0]));
+      if (!profile_data)       /* memory system kiddin' me, eh? */
+       {
+         g_mutex_unlock (gmem_profile_mutex);
+         return;
+       }
+    }
+
+  if (n_bytes < MEM_PROFILE_TABLE_SIZE)
+    profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
+                                          (job & PROFILER_RELOC) != 0,
+                                          success != 0)] += 1;
+  else
+    profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
+                                                         (job & PROFILER_RELOC) != 0,
+                                                         success != 0)] += 1;
+  if (success)
+    {
+      if (job & PROFILER_ALLOC)
+        {
+          profile_allocs += n_bytes;
+          if (job & PROFILER_ZINIT)
+            profile_zinit += n_bytes;
+        }
+      else
+        profile_frees += n_bytes;
+    }
+  g_mutex_unlock (gmem_profile_mutex);
+}
+
+static void
+profile_print_locked (guint   *local_data,
+                     gboolean success)
+{
+  gboolean need_header = TRUE;
+  guint i;
+
+  for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
+    {
+      glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
+      glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
+      glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
+      glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
+      
+      if (!t_malloc && !t_realloc && !t_free && !t_refree)
+       continue;
+      else if (need_header)
+       {
+         need_header = FALSE;
+         g_print (" blocks of | allocated  | freed      | allocated  | freed      | n_bytes   \n");
+         g_print ("  n_bytes  | n_times by | n_times by | n_times by | n_times by | remaining \n");
+         g_print ("           | malloc()   | free()     | realloc()  | realloc()  |           \n");
+         g_print ("===========|============|============|============|============|===========\n");
+       }
+      if (i < MEM_PROFILE_TABLE_SIZE)
+       g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
+                i, t_malloc, t_free, t_realloc, t_refree,
+                (t_malloc - t_free + t_realloc - t_refree) * i);
+      else if (i >= MEM_PROFILE_TABLE_SIZE)
+       g_print ("   >%6u | %10ld | %10ld | %10ld | %10ld |        ***\n",
+                i, t_malloc, t_free, t_realloc, t_refree);
+    }
+  if (need_header)
+    g_print (" --- none ---\n");
+}
+
+void
+g_mem_profile (void)
+{
+  guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])];
+  gsize local_allocs;
+  gsize local_zinit;
+  gsize local_frees;
+
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+
+  g_mutex_lock (gmem_profile_mutex);
+
+  local_allocs = profile_allocs;
+  local_zinit = profile_zinit;
+  local_frees = profile_frees;
+
+  if (!profile_data)
+    {
+      g_mutex_unlock (gmem_profile_mutex);
+      return;
+    }
+
+  memcpy (local_data, profile_data, 
+         (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
+  
+  g_mutex_unlock (gmem_profile_mutex);
+
+  g_print ("GLib Memory statistics (successful operations):\n");
+  profile_print_locked (local_data, TRUE);
+  g_print ("GLib Memory statistics (failing operations):\n");
+  profile_print_locked (local_data, FALSE);
+  g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
+           "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
+           "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
+           "remaining=%"G_GSIZE_FORMAT"\n",
+          local_allocs,
+          local_zinit,
+          ((gdouble) local_zinit) / local_allocs * 100.0,
+          local_frees,
+          ((gdouble) local_frees) / local_allocs * 100.0,
+          local_allocs - local_frees);
+}
+
+static gpointer
+profiler_try_malloc (gsize n_bytes)
+{
+  gsize *p;
+
+#ifdef  G_ENABLE_DEBUG
+  if (g_trap_malloc_size == n_bytes)
+    G_BREAKPOINT ();
+#endif  /* G_ENABLE_DEBUG */
+
+  p = standard_malloc (sizeof (gsize) * 2 + n_bytes);
+
+  if (p)
+    {
+      p[0] = 0;                /* free count */
+      p[1] = n_bytes;  /* length */
+      profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
+      p += 2;
+    }
+  else
+    profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
+  
+  return p;
+}
+
+static gpointer
+profiler_malloc (gsize n_bytes)
+{
+  gpointer mem = profiler_try_malloc (n_bytes);
+
+  if (!mem)
+    g_mem_profile ();
+
+  return mem;
+}
+
+static gpointer
+profiler_calloc (gsize n_blocks,
+                gsize n_block_bytes)
+{
+  gsize l = n_blocks * n_block_bytes;
+  gsize *p;
+
+#ifdef  G_ENABLE_DEBUG
+  if (g_trap_malloc_size == l)
+    G_BREAKPOINT ();
+#endif  /* G_ENABLE_DEBUG */
+  
+  p = standard_calloc (1, sizeof (gsize) * 2 + l);
+
+  if (p)
+    {
+      p[0] = 0;                /* free count */
+      p[1] = l;                /* length */
+      profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
+      p += 2;
+    }
+  else
+    {
+      profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
+      g_mem_profile ();
+    }
+
+  return p;
+}
+
+static void
+profiler_free (gpointer mem)
+{
+  gsize *p = mem;
+
+  p -= 2;
+  if (p[0])    /* free count */
+    {
+      g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
+                 p + 2, p[0]);
+      profiler_log (PROFILER_FREE,
+                   p[1],       /* length */
+                   FALSE);
+    }
+  else
+    {
+#ifdef  G_ENABLE_DEBUG
+      if (g_trap_free_size == p[1])
+       G_BREAKPOINT ();
+#endif  /* G_ENABLE_DEBUG */
+
+      profiler_log (PROFILER_FREE,
+                   p[1],       /* length */
+                   TRUE);
+      memset (p + 2, 0xaa, p[1]);
+
+      /* for all those that miss standard_free (p); in this place, yes,
+       * we do leak all memory when profiling, and that is intentional
+       * to catch double frees. patch submissions are futile.
+       */
+    }
+  p[0] += 1;
+}
+
+static gpointer
+profiler_try_realloc (gpointer mem,
+                     gsize    n_bytes)
+{
+  gsize *p = mem;
+
+  p -= 2;
+
+#ifdef  G_ENABLE_DEBUG
+  if (g_trap_realloc_size == n_bytes)
+    G_BREAKPOINT ();
+#endif  /* G_ENABLE_DEBUG */
+  
+  if (mem && p[0])     /* free count */
+    {
+      g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
+                 "memory has been freed %"G_GSIZE_FORMAT" times already",
+                 p + 2, (gsize) n_bytes, p[0]);
+      profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
+
+      return NULL;
+    }
+  else
+    {
+      p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
+
+      if (p)
+       {
+         if (mem)
+           profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
+         p[0] = 0;
+         p[1] = n_bytes;
+         profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
+         p += 2;
+       }
+      else
+       profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
+
+      return p;
+    }
+}
+
+static gpointer
+profiler_realloc (gpointer mem,
+                 gsize    n_bytes)
+{
+  mem = profiler_try_realloc (mem, n_bytes);
+
+  if (!mem)
+    g_mem_profile ();
+
+  return mem;
+}
+
+static GMemVTable profiler_table = {
+  profiler_malloc,
+  profiler_realloc,
+  profiler_free,
+  profiler_calloc,
+  profiler_try_malloc,
+  profiler_try_realloc,
+};
+GMemVTable *glib_mem_profiler_table = &profiler_table;
+
+#endif /* !G_DISABLE_CHECKS */
+
+/* --- MemChunks --- */
+#ifndef G_ALLOC_AND_FREE
+typedef struct _GAllocator GAllocator;
+typedef struct _GMemChunk  GMemChunk;
+#define G_ALLOC_ONLY     1
+#define G_ALLOC_AND_FREE  2
+#endif
+
+struct _GMemChunk {
+  guint alloc_size;           /* the size of an atom */
+};
+
+GMemChunk*
+g_mem_chunk_new (const gchar  *name,
+                gint          atom_size,
+                gsize         area_size,
+                gint          type)
+{
+  GMemChunk *mem_chunk;
+  g_return_val_if_fail (atom_size > 0, NULL);
+
+  mem_chunk = g_slice_new (GMemChunk);
+  mem_chunk->alloc_size = atom_size;
+  return mem_chunk;
+}
+
+void
+g_mem_chunk_destroy (GMemChunk *mem_chunk)
+{
+  g_return_if_fail (mem_chunk != NULL);
+  
+  g_slice_free (GMemChunk, mem_chunk);
+}
+
+gpointer
+g_mem_chunk_alloc (GMemChunk *mem_chunk)
+{
+  g_return_val_if_fail (mem_chunk != NULL, NULL);
+  
+  return g_slice_alloc (mem_chunk->alloc_size);
+}
+
+gpointer
+g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
+{
+  g_return_val_if_fail (mem_chunk != NULL, NULL);
+  
+  return g_slice_alloc0 (mem_chunk->alloc_size);
+}
+
+void
+g_mem_chunk_free (GMemChunk *mem_chunk,
+                 gpointer   mem)
+{
+  g_return_if_fail (mem_chunk != NULL);
+  
+  g_slice_free1 (mem_chunk->alloc_size, mem);
+}
+
+void   g_mem_chunk_clean       (GMemChunk *mem_chunk)  {}
+void   g_mem_chunk_reset       (GMemChunk *mem_chunk)  {}
+void   g_mem_chunk_print       (GMemChunk *mem_chunk)  {}
+void   g_mem_chunk_info        (void)                  {}
+void   g_blow_chunks           (void)                  {}
+
+GAllocator*
+g_allocator_new (const gchar *name,
+                guint        n_preallocs)
+{
+  static struct _GAllocator {
+    gchar      *name;
+    guint16     n_preallocs;
+    guint       is_unused : 1;
+    guint       type : 4;
+    GAllocator *last;
+    GMemChunk  *mem_chunk;
+    gpointer    free_list;
+  } dummy = {
+    "GAllocator is deprecated", 1, TRUE, 0, NULL, NULL, NULL,
+  };
+  /* some (broken) GAllocator uses depend on non-NULL allocators */
+  return (void*) &dummy;
+}
+
+void
+g_allocator_free (GAllocator *allocator)
+{
+}
+
+#ifdef ENABLE_GC_FRIENDLY_DEFAULT
+gboolean g_mem_gc_friendly = TRUE;
+#else
+gboolean g_mem_gc_friendly = FALSE;
+#endif
+
+static void
+g_mem_init_nomessage (void)
+{
+  gchar buffer[1024];
+  const gchar *val;
+  const GDebugKey keys[] = {
+    { "gc-friendly", 1 },
+  };
+  gint flags;
+  if (g_mem_initialized)
+    return;
+  /* don't use g_malloc/g_message here */
+  val = _g_getenv_nomalloc ("G_DEBUG", buffer);
+  flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+  if (flags & 1)        /* gc-friendly */
+    {
+      g_mem_gc_friendly = TRUE;
+    }
+  g_mem_initialized = TRUE;
+}
+
+void
+_g_mem_thread_init_noprivate_nomessage (void)
+{
+  /* we may only create mutexes here, locking/
+   * unlocking a mutex does not yet work.
+   */
+  g_mem_init_nomessage();
+#ifndef G_DISABLE_CHECKS
+  gmem_profile_mutex = g_mutex_new ();
+#endif
+}
+
+#define __G_MEM_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gmem.h b/navit/navit/support/glib/gmem.h
new file mode 100644 (file)
index 0000000..8cb050e
--- /dev/null
@@ -0,0 +1,152 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MEM_H__
+#define __G_MEM_H__
+
+#include <glib/gslice.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GMemVTable GMemVTable;
+
+
+#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
+#  define G_MEM_ALIGN  GLIB_SIZEOF_VOID_P
+#else  /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */
+#  define G_MEM_ALIGN  GLIB_SIZEOF_LONG
+#endif /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */
+
+
+/* Memory allocation functions
+ */
+gpointer g_malloc         (gsize        n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_malloc0        (gsize        n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_realloc        (gpointer     mem,
+                          gsize         n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+void    g_free           (gpointer      mem);
+gpointer g_try_malloc     (gsize        n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_try_malloc0    (gsize        n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_try_realloc    (gpointer     mem,
+                          gsize         n_bytes) G_GNUC_WARN_UNUSED_RESULT;
+
+
+/* Convenience memory allocators
+ */
+#define g_new(struct_type, n_structs)          \
+    ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_new0(struct_type, n_structs)         \
+    ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_renew(struct_type, mem, n_structs)   \
+    ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+
+#define g_try_new(struct_type, n_structs)              \
+    ((struct_type *) g_try_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_new0(struct_type, n_structs)             \
+    ((struct_type *) g_try_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_renew(struct_type, mem, n_structs)       \
+    ((struct_type *) g_try_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+
+
+/* Memory allocation virtualization for debugging purposes
+ * g_mem_set_vtable() has to be the very first GLib function called
+ * if being used
+ */
+struct _GMemVTable
+{
+  gpointer (*malloc)      (gsize    n_bytes);
+  gpointer (*realloc)     (gpointer mem,
+                          gsize    n_bytes);
+  void     (*free)        (gpointer mem);
+  /* optional; set to NULL if not used ! */
+  gpointer (*calloc)      (gsize    n_blocks,
+                          gsize    n_block_bytes);
+  gpointer (*try_malloc)  (gsize    n_bytes);
+  gpointer (*try_realloc) (gpointer mem,
+                          gsize    n_bytes);
+};
+void    g_mem_set_vtable (GMemVTable   *vtable);
+gboolean g_mem_is_system_malloc (void);
+
+GLIB_VAR gboolean g_mem_gc_friendly;
+
+/* Memory profiler and checker, has to be enabled via g_mem_set_vtable()
+ */
+GLIB_VAR GMemVTable    *glib_mem_profiler_table;
+void   g_mem_profile   (void);
+
+
+/* deprecated memchunks and allocators */
+#if !defined (G_DISABLE_DEPRECATED) || defined (GTK_COMPILATION) || defined (GDK_COMPILATION)
+typedef struct _GAllocator GAllocator;
+typedef struct _GMemChunk  GMemChunk;
+#define g_mem_chunk_create(type, pre_alloc, alloc_type)        ( \
+  g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \
+                  sizeof (type), \
+                  sizeof (type) * (pre_alloc), \
+                  (alloc_type)) \
+)
+#define g_chunk_new(type, chunk)       ( \
+  (type *) g_mem_chunk_alloc (chunk) \
+)
+#define g_chunk_new0(type, chunk)      ( \
+  (type *) g_mem_chunk_alloc0 (chunk) \
+)
+#define g_chunk_free(mem, mem_chunk)   G_STMT_START { \
+  g_mem_chunk_free ((mem_chunk), (mem)); \
+} G_STMT_END
+#define G_ALLOC_ONLY     1
+#define G_ALLOC_AND_FREE  2
+GMemChunk* g_mem_chunk_new     (const gchar *name,
+                               gint         atom_size,
+                               gsize        area_size,
+                               gint         type);
+void       g_mem_chunk_destroy (GMemChunk   *mem_chunk);
+gpointer   g_mem_chunk_alloc   (GMemChunk   *mem_chunk);
+gpointer   g_mem_chunk_alloc0  (GMemChunk   *mem_chunk);
+void       g_mem_chunk_free    (GMemChunk   *mem_chunk,
+                               gpointer     mem);
+void       g_mem_chunk_clean   (GMemChunk   *mem_chunk);
+void       g_mem_chunk_reset   (GMemChunk   *mem_chunk);
+void       g_mem_chunk_print   (GMemChunk   *mem_chunk);
+void       g_mem_chunk_info    (void);
+void      g_blow_chunks       (void);
+GAllocator*g_allocator_new     (const gchar  *name,
+                               guint         n_preallocs);
+void       g_allocator_free    (GAllocator   *allocator);
+#define        G_ALLOCATOR_LIST       (1)
+#define        G_ALLOCATOR_SLIST      (2)
+#define        G_ALLOCATOR_NODE       (3)
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_MEM_H__ */
diff --git a/navit/navit/support/glib/gmessages.c b/navit/navit/support/glib/gmessages.c
new file mode 100644 (file)
index 0000000..7b90a02
--- /dev/null
@@ -0,0 +1,1114 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <locale.h>
+#include <errno.h>
+
+#include "glib.h"
+#include "gdebug.h"
+#include "gprintfint.h"
+#include "gthreadprivate.h"
+#include "galias.h"
+
+#ifdef G_OS_WIN32
+#include <process.h>           /* For getpid() */
+#include <io.h>
+#  define STRICT               /* Strict typing, please */
+#  define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
+#  include <windows.h>
+#  undef STRICT
+#endif
+
+/* --- structures --- */
+typedef struct _GLogDomain     GLogDomain;
+typedef struct _GLogHandler    GLogHandler;
+struct _GLogDomain
+{
+  gchar                *log_domain;
+  GLogLevelFlags fatal_mask;
+  GLogHandler  *handlers;
+  GLogDomain   *next;
+};
+struct _GLogHandler
+{
+  guint                 id;
+  GLogLevelFlags log_level;
+  GLogFunc      log_func;
+  gpointer      data;
+  GLogHandler  *next;
+};
+
+
+/* --- variables --- */
+static GMutex        *g_messages_lock = NULL;
+static GLogDomain    *g_log_domains = NULL;
+static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
+static GPrintFunc     glib_print_func = NULL;
+static GPrintFunc     glib_printerr_func = NULL;
+static GPrivate             *g_log_depth = NULL;
+static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
+static GLogFunc       default_log_func = g_log_default_handler;
+static gpointer       default_log_data = NULL;
+
+/* --- functions --- */
+#ifdef G_OS_WIN32
+#  define STRICT
+#  include <windows.h>
+#  undef STRICT
+static gboolean win32_keep_fatal_message = FALSE;
+
+/* This default message will usually be overwritten. */
+/* Yes, a fixed size buffer is bad. So sue me. But g_error() is never
+ * called with huge strings, is it?
+ */
+static gchar  fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
+static gchar *fatal_msg_ptr = fatal_msg_buf;
+
+#undef write
+static inline int
+dowrite (int          fd,
+        const void  *buf,
+        unsigned int len)
+{
+  if (win32_keep_fatal_message)
+    {
+      memcpy (fatal_msg_ptr, buf, len);
+      fatal_msg_ptr += len;
+      *fatal_msg_ptr = 0;
+      return len;
+    }
+
+  write (fd, buf, len);
+
+  return len;
+}
+#define write(fd, buf, len) dowrite(fd, buf, len)
+
+#endif
+
+static void
+write_string (int          fd,
+             const gchar *string)
+{
+  write (fd, string, strlen (string));
+}
+
+static void
+g_messages_prefixed_init (void)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      const gchar *val;
+
+      initialized = TRUE;
+      val = g_getenv ("G_MESSAGES_PREFIXED");
+      
+      if (val)
+       {
+         const GDebugKey keys[] = {
+           { "error", G_LOG_LEVEL_ERROR },
+           { "critical", G_LOG_LEVEL_CRITICAL },
+           { "warning", G_LOG_LEVEL_WARNING },
+           { "message", G_LOG_LEVEL_MESSAGE },
+           { "info", G_LOG_LEVEL_INFO },
+           { "debug", G_LOG_LEVEL_DEBUG }
+         };
+         
+         g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+       }
+    }
+}
+
+static GLogDomain*
+g_log_find_domain_L (const gchar *log_domain)
+{
+  register GLogDomain *domain;
+  
+  domain = g_log_domains;
+  while (domain)
+    {
+      if (strcmp (domain->log_domain, log_domain) == 0)
+       return domain;
+      domain = domain->next;
+    }
+  return NULL;
+}
+
+static GLogDomain*
+g_log_domain_new_L (const gchar *log_domain)
+{
+  register GLogDomain *domain;
+
+  domain = g_new (GLogDomain, 1);
+  domain->log_domain = g_strdup (log_domain);
+  domain->fatal_mask = G_LOG_FATAL_MASK;
+  domain->handlers = NULL;
+  
+  domain->next = g_log_domains;
+  g_log_domains = domain;
+  
+  return domain;
+}
+
+static void
+g_log_domain_check_free_L (GLogDomain *domain)
+{
+  if (domain->fatal_mask == G_LOG_FATAL_MASK &&
+      domain->handlers == NULL)
+    {
+      register GLogDomain *last, *work;
+      
+      last = NULL;  
+
+      work = g_log_domains;
+      while (work)
+       {
+         if (work == domain)
+           {
+             if (last)
+               last->next = domain->next;
+             else
+               g_log_domains = domain->next;
+             g_free (domain->log_domain);
+             g_free (domain);
+             break;
+           }
+         last = work;
+         work = last->next;
+       }  
+    }
+}
+
+static GLogFunc
+g_log_domain_get_handler_L (GLogDomain *domain,
+                           GLogLevelFlags log_level,
+                           gpointer    *data)
+{
+  if (domain && log_level)
+    {
+      register GLogHandler *handler;
+      
+      handler = domain->handlers;
+      while (handler)
+       {
+         if ((handler->log_level & log_level) == log_level)
+           {
+             *data = handler->data;
+             return handler->log_func;
+           }
+         handler = handler->next;
+       }
+    }
+
+  *data = default_log_data;
+  return default_log_func;
+}
+
+GLogLevelFlags
+g_log_set_always_fatal (GLogLevelFlags fatal_mask)
+{
+  GLogLevelFlags old_mask;
+
+  /* restrict the global mask to levels that are known to glib
+   * since this setting applies to all domains
+   */
+  fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
+  /* force errors to be fatal */
+  fatal_mask |= G_LOG_LEVEL_ERROR;
+  /* remove bogus flag */
+  fatal_mask &= ~G_LOG_FLAG_FATAL;
+
+  g_mutex_lock (g_messages_lock);
+  old_mask = g_log_always_fatal;
+  g_log_always_fatal = fatal_mask;
+  g_mutex_unlock (g_messages_lock);
+
+  return old_mask;
+}
+
+GLogLevelFlags
+g_log_set_fatal_mask (const gchar   *log_domain,
+                     GLogLevelFlags fatal_mask)
+{
+  GLogLevelFlags old_flags;
+  register GLogDomain *domain;
+  
+  if (!log_domain)
+    log_domain = "";
+  
+  /* force errors to be fatal */
+  fatal_mask |= G_LOG_LEVEL_ERROR;
+  /* remove bogus flag */
+  fatal_mask &= ~G_LOG_FLAG_FATAL;
+  
+  g_mutex_lock (g_messages_lock);
+
+  domain = g_log_find_domain_L (log_domain);
+  if (!domain)
+    domain = g_log_domain_new_L (log_domain);
+  old_flags = domain->fatal_mask;
+  
+  domain->fatal_mask = fatal_mask;
+  g_log_domain_check_free_L (domain);
+
+  g_mutex_unlock (g_messages_lock);
+
+  return old_flags;
+}
+
+guint
+g_log_set_handler (const gchar  *log_domain,
+                  GLogLevelFlags log_levels,
+                  GLogFunc       log_func,
+                  gpointer       user_data)
+{
+  static guint handler_id = 0;
+  GLogDomain *domain;
+  GLogHandler *handler;
+  
+  g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
+  g_return_val_if_fail (log_func != NULL, 0);
+  
+  if (!log_domain)
+    log_domain = "";
+
+  handler = g_new (GLogHandler, 1);
+
+  g_mutex_lock (g_messages_lock);
+
+  domain = g_log_find_domain_L (log_domain);
+  if (!domain)
+    domain = g_log_domain_new_L (log_domain);
+  
+  handler->id = ++handler_id;
+  handler->log_level = log_levels;
+  handler->log_func = log_func;
+  handler->data = user_data;
+  handler->next = domain->handlers;
+  domain->handlers = handler;
+
+  g_mutex_unlock (g_messages_lock);
+  
+  return handler_id;
+}
+
+GLogFunc
+g_log_set_default_handler (GLogFunc log_func,
+                          gpointer user_data)
+{
+  GLogFunc old_log_func;
+  
+  g_mutex_lock (g_messages_lock);
+  old_log_func = default_log_func;
+  default_log_func = log_func;
+  default_log_data = user_data;
+  g_mutex_unlock (g_messages_lock);
+  
+  return old_log_func;
+}
+
+void
+g_log_remove_handler (const gchar *log_domain,
+                     guint        handler_id)
+{
+  register GLogDomain *domain;
+  
+  g_return_if_fail (handler_id > 0);
+  
+  if (!log_domain)
+    log_domain = "";
+  
+  g_mutex_lock (g_messages_lock);
+  domain = g_log_find_domain_L (log_domain);
+  if (domain)
+    {
+      GLogHandler *work, *last;
+      
+      last = NULL;
+      work = domain->handlers;
+      while (work)
+       {
+         if (work->id == handler_id)
+           {
+             if (last)
+               last->next = work->next;
+             else
+               domain->handlers = work->next;
+             g_log_domain_check_free_L (domain); 
+             g_mutex_unlock (g_messages_lock);
+             g_free (work);
+             return;
+           }
+         last = work;
+         work = last->next;
+       }
+    } 
+  g_mutex_unlock (g_messages_lock);
+  g_warning ("%s: could not find handler with id `%d' for domain \"%s\"",
+            G_STRLOC, handler_id, log_domain);
+}
+
+void
+g_logv (const gchar   *log_domain,
+       GLogLevelFlags log_level,
+       const gchar   *format,
+       va_list        args1)
+{
+  gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+  gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
+  gint i;
+
+  log_level &= G_LOG_LEVEL_MASK;
+  if (!log_level)
+    return;
+  
+  for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
+    {
+      register GLogLevelFlags test_level;
+      
+      test_level = 1 << i;
+      if (log_level & test_level)
+       {
+         guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
+         GLogDomain *domain;
+         GLogFunc log_func;
+         GLogLevelFlags domain_fatal_mask;
+         gpointer data = NULL;
+
+         if (was_fatal)
+           test_level |= G_LOG_FLAG_FATAL;
+         if (was_recursion)
+           test_level |= G_LOG_FLAG_RECURSION;
+
+         /* check recursion and lookup handler */
+         g_mutex_lock (g_messages_lock);
+         domain = g_log_find_domain_L (log_domain ? log_domain : "");
+         if (depth)
+           test_level |= G_LOG_FLAG_RECURSION;
+         depth++;
+         domain_fatal_mask = domain ? domain->fatal_mask : G_LOG_FATAL_MASK;
+         if ((domain_fatal_mask | g_log_always_fatal) & test_level)
+           test_level |= G_LOG_FLAG_FATAL;
+         if (test_level & G_LOG_FLAG_RECURSION)
+           log_func = _g_log_fallback_handler;
+         else
+           log_func = g_log_domain_get_handler_L (domain, test_level, &data);
+         domain = NULL;
+         g_mutex_unlock (g_messages_lock);
+
+         g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
+
+         /* had to defer debug initialization until we can keep track of recursion */
+         if (!(test_level & G_LOG_FLAG_RECURSION) && !_g_debug_initialized)
+           {
+             GLogLevelFlags orig_test_level = test_level;
+
+             _g_debug_init ();
+             if ((domain_fatal_mask | g_log_always_fatal) & test_level)
+               test_level |= G_LOG_FLAG_FATAL;
+             if (test_level != orig_test_level)
+               {
+                 /* need a relookup, not nice, but not too bad either */
+                 g_mutex_lock (g_messages_lock);
+                 domain = g_log_find_domain_L (log_domain ? log_domain : "");
+                 log_func = g_log_domain_get_handler_L (domain, test_level, &data);
+                 domain = NULL;
+                 g_mutex_unlock (g_messages_lock);
+               }
+           }
+
+         if (test_level & G_LOG_FLAG_RECURSION)
+           {
+             /* we use a stack buffer of fixed size, since we're likely
+              * in an out-of-memory situation
+              */
+             gchar buffer[1025];
+             gint size;
+             size = _g_vsnprintf (buffer, 1024, format, args1);
+
+             log_func (log_domain, test_level, buffer, data);
+           }
+         else
+           {
+             gchar *msg = g_strdup_vprintf (format, args1);
+
+             log_func (log_domain, test_level, msg, data);
+
+             g_free (msg);
+           }
+
+         if (test_level & G_LOG_FLAG_FATAL)
+           {
+#ifdef G_OS_WIN32
+             gchar *locale_msg = g_locale_from_utf8 (fatal_msg_buf, -1, NULL, NULL, NULL);
+             
+             MessageBox (NULL, locale_msg, NULL,
+                         MB_ICONERROR|MB_SETFOREGROUND);
+             if (IsDebuggerPresent () && !(test_level & G_LOG_FLAG_RECURSION))
+               G_BREAKPOINT ();
+             else
+               abort ();
+#else
+#if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
+             if (!(test_level & G_LOG_FLAG_RECURSION))
+               G_BREAKPOINT ();
+             else
+               abort ();
+#else /* !G_ENABLE_DEBUG || !SIGTRAP */
+             abort ();
+#endif /* !G_ENABLE_DEBUG || !SIGTRAP */
+#endif /* !G_OS_WIN32 */
+           }
+         
+         depth--;
+         g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
+       }
+    }
+}
+
+void
+g_log (const gchar   *log_domain,
+       GLogLevelFlags log_level,
+       const gchar   *format,
+       ...)
+{
+  va_list args;
+  
+  va_start (args, format);
+  g_logv (log_domain, log_level, format, args);
+  va_end (args);
+}
+
+void
+g_return_if_fail_warning (const char *log_domain,
+                         const char *pretty_function,
+                         const char *expression)
+{
+  /*
+   * Omit the prefix used by the PLT-reduction
+   * technique used in GTK+. 
+   */
+  if (g_str_has_prefix (pretty_function, "IA__"))
+    pretty_function += 4;
+  g_log (log_domain,
+        G_LOG_LEVEL_CRITICAL,
+        "%s: assertion `%s' failed",
+        pretty_function,
+        expression);
+}
+
+void
+g_warn_message (const char     *domain,
+                const char     *file,
+                int             line,
+                const char     *func,
+                const char     *warnexpr)
+{
+  char *s, lstr[32];
+  g_snprintf (lstr, 32, "%d", line);
+  if (warnexpr)
+    s = g_strconcat ("(", file, ":", lstr, "):",
+                     func, func[0] ? ":" : "",
+                     " runtime check failed: (", warnexpr, ")", NULL);
+  else
+    s = g_strconcat ("(", file, ":", lstr, "):",
+                     func, func[0] ? ":" : "",
+                     " ", "code should not be reached", NULL);
+  g_log (domain, G_LOG_LEVEL_WARNING, "%s", s);
+  g_free (s);
+}
+
+void
+g_assert_warning (const char *log_domain,
+                 const char *file,
+                 const int   line,
+                 const char *pretty_function,
+                 const char *expression)
+{
+  /*
+   * Omit the prefix used by the PLT-reduction
+   * technique used in GTK+. 
+   */
+  if (g_str_has_prefix (pretty_function, "IA__"))
+    pretty_function += 4;
+  g_log (log_domain,
+        G_LOG_LEVEL_ERROR,
+        expression 
+        ? "file %s: line %d (%s): assertion failed: (%s)"
+        : "file %s: line %d (%s): should not be reached",
+        file, 
+        line, 
+        pretty_function,
+        expression);
+  abort ();
+}
+
+#define CHAR_IS_SAFE(wc) (!((wc < 0x20 && wc != '\t' && wc != '\n' && wc != '\r') || \
+                           (wc == 0x7f) || \
+                           (wc >= 0x80 && wc < 0xa0)))
+     
+static gchar*
+strdup_convert (const gchar *string,
+               const gchar *charset)
+{
+  if (!g_utf8_validate (string, -1, NULL))
+    {
+      GString *gstring = g_string_new ("[Invalid UTF-8] ");
+      guchar *p;
+
+      for (p = (guchar *)string; *p; p++)
+       {
+         if (CHAR_IS_SAFE(*p) &&
+             !(*p == '\r' && *(p + 1) != '\n') &&
+             *p < 0x80)
+           g_string_append_c (gstring, *p);
+         else
+           g_string_append_printf (gstring, "\\x%02x", (guint)(guchar)*p);
+       }
+      
+      return g_string_free (gstring, FALSE);
+    }
+  else
+    {
+      GError *err = NULL;
+      
+      gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err);
+      if (result)
+       return result;
+      else
+       {
+         /* Not thread-safe, but doesn't matter if we print the warning twice
+          */
+         static gboolean warned = FALSE; 
+         if (!warned)
+           {
+             warned = TRUE;
+             _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
+           }
+         g_error_free (err);
+         
+         return g_strdup (string);
+       }
+    }
+}
+
+/* For a radix of 8 we need at most 3 output bytes for 1 input
+ * byte. Additionally we might need up to 2 output bytes for the
+ * readix prefix and 1 byte for the trailing NULL.
+ */
+#define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)
+
+static void
+format_unsigned (gchar  *buf,
+                gulong  num,
+                guint   radix)
+{
+  gulong tmp;
+  gchar c;
+  gint i, n;
+
+  /* we may not call _any_ GLib functions here (or macros like g_return_if_fail()) */
+
+  if (radix != 8 && radix != 10 && radix != 16)
+    {
+      *buf = '\000';
+      return;
+    }
+  
+  if (!num)
+    {
+      *buf++ = '0';
+      *buf = '\000';
+      return;
+    } 
+  
+  if (radix == 16)
+    {
+      *buf++ = '0';
+      *buf++ = 'x';
+    }
+  else if (radix == 8)
+    {
+      *buf++ = '0';
+    }
+       
+  n = 0;
+  tmp = num;
+  while (tmp)
+    {
+      tmp /= radix;
+      n++;
+    }
+
+  i = n;
+
+  /* Again we can't use g_assert; actually this check should _never_ fail. */
+  if (n > FORMAT_UNSIGNED_BUFSIZE - 3)
+    {
+      *buf = '\000';
+      return;
+    }
+
+  while (num)
+    {
+      i--;
+      c = (num % radix);
+      if (c < 10)
+       buf[i] = c + '0';
+      else
+       buf[i] = c + 'a' - 10;
+      num /= radix;
+    }
+  
+  buf[n] = '\000';
+}
+
+/* string size big enough to hold level prefix */
+#define        STRING_BUFFER_SIZE      (FORMAT_UNSIGNED_BUFSIZE + 32)
+
+#define        ALERT_LEVELS            (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)
+
+static int
+mklevel_prefix (gchar          level_prefix[STRING_BUFFER_SIZE],
+               GLogLevelFlags log_level)
+{
+  gboolean to_stdout = TRUE;
+
+  /* we may not call _any_ GLib functions here */
+
+  switch (log_level & G_LOG_LEVEL_MASK)
+    {
+    case G_LOG_LEVEL_ERROR:
+      strcpy (level_prefix, "ERROR");
+      to_stdout = FALSE;
+      break;
+    case G_LOG_LEVEL_CRITICAL:
+      strcpy (level_prefix, "CRITICAL");
+      to_stdout = FALSE;
+      break;
+    case G_LOG_LEVEL_WARNING:
+      strcpy (level_prefix, "WARNING");
+      to_stdout = FALSE;
+      break;
+    case G_LOG_LEVEL_MESSAGE:
+      strcpy (level_prefix, "Message");
+      to_stdout = FALSE;
+      break;
+    case G_LOG_LEVEL_INFO:
+      strcpy (level_prefix, "INFO");
+      break;
+    case G_LOG_LEVEL_DEBUG:
+      strcpy (level_prefix, "DEBUG");
+      break;
+    default:
+      if (log_level)
+       {
+         strcpy (level_prefix, "LOG-");
+         format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16);
+       }
+      else
+       strcpy (level_prefix, "LOG");
+      break;
+    }
+  if (log_level & G_LOG_FLAG_RECURSION)
+    strcat (level_prefix, " (recursed)");
+  if (log_level & ALERT_LEVELS)
+    strcat (level_prefix, " **");
+
+#ifdef G_OS_WIN32
+  win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
+#endif
+  return to_stdout ? 1 : 2;
+}
+
+void
+_g_log_fallback_handler (const gchar   *log_domain,
+                        GLogLevelFlags log_level,
+                        const gchar   *message,
+                        gpointer       unused_data)
+{
+  gchar level_prefix[STRING_BUFFER_SIZE];
+#ifndef G_OS_WIN32
+  gchar pid_string[FORMAT_UNSIGNED_BUFSIZE];
+#endif
+  gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+  int fd;
+
+  /* we can not call _any_ GLib functions in this fallback handler,
+   * which is why we skip UTF-8 conversion, etc.
+   * since we either recursed or ran out of memory, we're in a pretty
+   * pathologic situation anyways, what we can do is giving the
+   * the process ID unconditionally however.
+   */
+
+  fd = mklevel_prefix (level_prefix, log_level);
+  if (!message)
+    message = "(NULL) message";
+
+#ifndef G_OS_WIN32
+  format_unsigned (pid_string, getpid (), 10);
+#endif
+
+  if (log_domain)
+    write_string (fd, "\n");
+  else
+    write_string (fd, "\n** ");
+
+#ifndef G_OS_WIN32
+  write_string (fd, "(process:");
+  write_string (fd, pid_string);
+  write_string (fd, "): ");
+#endif
+
+  if (log_domain)
+    {
+      write_string (fd, log_domain);
+      write_string (fd, "-");
+    }
+  write_string (fd, level_prefix);
+  write_string (fd, ": ");
+  write_string (fd, message);
+  if (is_fatal)
+    write_string (fd, "\naborting...\n");
+  else
+    write_string (fd, "\n");
+}
+
+static void
+escape_string (GString *string)
+{
+  const char *p = string->str;
+  gunichar wc;
+
+  while (p < string->str + string->len)
+    {
+      gboolean safe;
+           
+      wc = g_utf8_get_char_validated (p, -1);
+      if (wc == (gunichar)-1 || wc == (gunichar)-2)  
+       {
+         gchar *tmp;
+         guint pos;
+
+         pos = p - string->str;
+
+         /* Emit invalid UTF-8 as hex escapes 
+           */
+         tmp = g_strdup_printf ("\\x%02x", (guint)(guchar)*p);
+         g_string_erase (string, pos, 1);
+         g_string_insert (string, pos, tmp);
+
+         p = string->str + (pos + 4); /* Skip over escape sequence */
+
+         g_free (tmp);
+         continue;
+       }
+      if (wc == '\r')
+       {
+         safe = *(p + 1) == '\n';
+       }
+      else
+       {
+         safe = CHAR_IS_SAFE (wc);
+       }
+      
+      if (!safe)
+       {
+         gchar *tmp;
+         guint pos;
+
+         pos = p - string->str;
+         
+         /* Largest char we escape is 0x0a, so we don't have to worry
+          * about 8-digit \Uxxxxyyyy
+          */
+         tmp = g_strdup_printf ("\\u%04x", wc); 
+         g_string_erase (string, pos, g_utf8_next_char (p) - p);
+         g_string_insert (string, pos, tmp);
+         g_free (tmp);
+
+         p = string->str + (pos + 6); /* Skip over escape sequence */
+       }
+      else
+       p = g_utf8_next_char (p);
+    }
+}
+
+void
+g_log_default_handler (const gchar   *log_domain,
+                      GLogLevelFlags log_level,
+                      const gchar   *message,
+                      gpointer       unused_data)
+{
+  gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+  gchar level_prefix[STRING_BUFFER_SIZE], *string;
+  GString *gstring;
+  int fd;
+
+  /* we can be called externally with recursion for whatever reason */
+  if (log_level & G_LOG_FLAG_RECURSION)
+    {
+      _g_log_fallback_handler (log_domain, log_level, message, unused_data);
+      return;
+    }
+
+  g_messages_prefixed_init ();
+
+  fd = mklevel_prefix (level_prefix, log_level);
+
+  gstring = g_string_new (NULL);
+  if (log_level & ALERT_LEVELS)
+    g_string_append (gstring, "\n");
+  if (!log_domain)
+    g_string_append (gstring, "** ");
+
+  if ((g_log_msg_prefix & log_level) == log_level)
+    {
+      const gchar *prg_name = g_get_prgname ();
+      
+      if (!prg_name)
+       g_string_append_printf (gstring, "(process:%lu): ", (gulong)getpid ());
+      else
+       g_string_append_printf (gstring, "(%s:%lu): ", prg_name, (gulong)getpid ());
+    }
+
+  if (log_domain)
+    {
+      g_string_append (gstring, log_domain);
+      g_string_append_c (gstring, '-');
+    }
+  g_string_append (gstring, level_prefix);
+
+  g_string_append (gstring, ": ");
+  if (!message)
+    g_string_append (gstring, "(NULL) message");
+  else
+    {
+      GString *msg;
+      const gchar *charset;
+
+      msg = g_string_new (message);
+      escape_string (msg);
+
+      if (g_get_charset (&charset))
+       g_string_append (gstring, msg->str);    /* charset is UTF-8 already */
+      else
+       {
+         string = strdup_convert (msg->str, charset);
+         g_string_append (gstring, string);
+         g_free (string);
+       }
+
+      g_string_free (msg, TRUE);
+    }
+  if (is_fatal)
+    g_string_append (gstring, "\naborting...\n");
+  else
+    g_string_append (gstring, "\n");
+
+  string = g_string_free (gstring, FALSE);
+
+  write_string (fd, string);
+  g_free (string);
+}
+
+GPrintFunc
+g_set_print_handler (GPrintFunc func)
+{
+  GPrintFunc old_print_func;
+  
+  g_mutex_lock (g_messages_lock);
+  old_print_func = glib_print_func;
+  glib_print_func = func;
+  g_mutex_unlock (g_messages_lock);
+  
+  return old_print_func;
+}
+
+void
+g_print (const gchar *format,
+        ...)
+{
+  va_list args;
+  gchar *string;
+  GPrintFunc local_glib_print_func;
+  
+  g_return_if_fail (format != NULL);
+  
+  va_start (args, format);
+  string = g_strdup_vprintf (format, args);
+  va_end (args);
+  
+  g_mutex_lock (g_messages_lock);
+  local_glib_print_func = glib_print_func;
+  g_mutex_unlock (g_messages_lock);
+  
+  if (local_glib_print_func)
+    local_glib_print_func (string);
+  else
+    {
+      const gchar *charset;
+
+      if (g_get_charset (&charset))
+       fputs (string, stdout); /* charset is UTF-8 already */
+      else
+       {
+         gchar *lstring = strdup_convert (string, charset);
+
+         fputs (lstring, stdout);
+         g_free (lstring);
+       }
+      fflush (stdout);
+    }
+  g_free (string);
+}
+
+GPrintFunc
+g_set_printerr_handler (GPrintFunc func)
+{
+  GPrintFunc old_printerr_func;
+  
+  g_mutex_lock (g_messages_lock);
+  old_printerr_func = glib_printerr_func;
+  glib_printerr_func = func;
+  g_mutex_unlock (g_messages_lock);
+  
+  return old_printerr_func;
+}
+
+void
+g_printerr (const gchar *format,
+           ...)
+{
+  va_list args;
+  gchar *string;
+  GPrintFunc local_glib_printerr_func;
+  
+  g_return_if_fail (format != NULL);
+  
+  va_start (args, format);
+  string = g_strdup_vprintf (format, args);
+  va_end (args);
+  
+  g_mutex_lock (g_messages_lock);
+  local_glib_printerr_func = glib_printerr_func;
+  g_mutex_unlock (g_messages_lock);
+  
+  if (local_glib_printerr_func)
+    local_glib_printerr_func (string);
+  else
+    {
+      const gchar *charset;
+
+      if (g_get_charset (&charset))
+       fputs (string, stderr); /* charset is UTF-8 already */
+      else
+       {
+         gchar *lstring = strdup_convert (string, charset);
+
+         fputs (lstring, stderr);
+         g_free (lstring);
+       }
+      fflush (stderr);
+    }
+  g_free (string);
+}
+
+gsize
+g_printf_string_upper_bound (const gchar *format,
+                            va_list      args)
+{
+  gchar c;
+  return _g_vsnprintf (&c, 1, format, args) + 1;
+}
+
+void
+_g_messages_thread_init_nomessage (void)
+{
+  g_messages_lock = g_mutex_new ();
+  g_log_depth = g_private_new (NULL);
+  g_messages_prefixed_init ();
+  _g_debug_init ();
+}
+
+gboolean _g_debug_initialized = FALSE;
+guint _g_debug_flags = 0;
+
+void
+_g_debug_init (void) 
+{
+  const gchar *val;
+  
+  _g_debug_initialized = TRUE;
+  
+  val = g_getenv ("G_DEBUG");
+  if (val != NULL)
+    {
+      const GDebugKey keys[] = {
+       {"fatal_warnings", G_DEBUG_FATAL_WARNINGS},
+       {"fatal_criticals", G_DEBUG_FATAL_CRITICALS}
+      };
+      
+      _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+    }
+  
+  if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS) 
+    {
+      GLogLevelFlags fatal_mask;
+      
+      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+      fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+      g_log_set_always_fatal (fatal_mask);
+    }
+  
+  if (_g_debug_flags & G_DEBUG_FATAL_CRITICALS) 
+    {
+      GLogLevelFlags fatal_mask;
+      
+      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+      fatal_mask |= G_LOG_LEVEL_CRITICAL;
+      g_log_set_always_fatal (fatal_mask);
+    }
+}
+
+#define __G_MESSAGES_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gmessages.h b/navit/navit/support/glib/gmessages.h
new file mode 100644 (file)
index 0000000..af5a826
--- /dev/null
@@ -0,0 +1,341 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_MESSAGES_H__
+#define __G_MESSAGES_H__
+
+#include <stdarg.h>
+#include <glib/gtypes.h>
+#include <glib/gmacros.h>
+
+/* Suppress warnings when GCC is in -pedantic mode and not -std=c99
+ */
+#if (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+#pragma GCC system_header
+#endif
+
+G_BEGIN_DECLS
+
+/* calculate a string size, guaranteed to fit format + args.
+ */
+gsize  g_printf_string_upper_bound (const gchar* format,
+                                    va_list      args);
+
+/* Log level shift offset for user defined
+ * log levels (0-7 are used by GLib).
+ */
+#define G_LOG_LEVEL_USER_SHIFT  (8)
+
+/* Glib log levels and flags.
+ */
+typedef enum
+{
+  /* log flags */
+  G_LOG_FLAG_RECURSION          = 1 << 0,
+  G_LOG_FLAG_FATAL              = 1 << 1,
+
+  /* GLib log levels */
+  G_LOG_LEVEL_ERROR             = 1 << 2,       /* always fatal */
+  G_LOG_LEVEL_CRITICAL          = 1 << 3,
+  G_LOG_LEVEL_WARNING           = 1 << 4,
+  G_LOG_LEVEL_MESSAGE           = 1 << 5,
+  G_LOG_LEVEL_INFO              = 1 << 6,
+  G_LOG_LEVEL_DEBUG             = 1 << 7,
+
+  G_LOG_LEVEL_MASK              = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL)
+} GLogLevelFlags;
+
+/* GLib log levels that are considered fatal by default */
+#define G_LOG_FATAL_MASK        (G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR)
+
+typedef void            (*GLogFunc)             (const gchar   *log_domain,
+                                                 GLogLevelFlags log_level,
+                                                 const gchar   *message,
+                                                 gpointer       user_data);
+
+/* Logging mechanism
+ */
+guint           g_log_set_handler       (const gchar    *log_domain,
+                                         GLogLevelFlags  log_levels,
+                                         GLogFunc        log_func,
+                                         gpointer        user_data);
+void            g_log_remove_handler    (const gchar    *log_domain,
+                                         guint           handler_id);
+void            g_log_default_handler   (const gchar    *log_domain,
+                                         GLogLevelFlags  log_level,
+                                         const gchar    *message,
+                                         gpointer        unused_data);
+GLogFunc        g_log_set_default_handler (GLogFunc      log_func,
+                                          gpointer      user_data);
+void            g_log                   (const gchar    *log_domain,
+                                         GLogLevelFlags  log_level,
+                                         const gchar    *format,
+                                         ...) G_GNUC_PRINTF (3, 4);
+void            g_logv                  (const gchar    *log_domain,
+                                         GLogLevelFlags  log_level,
+                                         const gchar    *format,
+                                         va_list         args);
+GLogLevelFlags  g_log_set_fatal_mask    (const gchar    *log_domain,
+                                         GLogLevelFlags  fatal_mask);
+GLogLevelFlags  g_log_set_always_fatal  (GLogLevelFlags  fatal_mask);
+
+/* internal */
+G_GNUC_INTERNAL void   _g_log_fallback_handler (const gchar   *log_domain,
+                                                GLogLevelFlags log_level,
+                                                const gchar   *message,
+                                                gpointer       unused_data);
+
+/* Internal functions, used to implement the following macros */
+void g_return_if_fail_warning (const char *log_domain,
+                              const char *pretty_function,
+                              const char *expression);
+void g_warn_message           (const char     *domain,
+                               const char     *file,
+                               int             line,
+                               const char     *func,
+                               const char     *warnexpr);
+#ifndef G_DISABLE_DEPRECATED
+void g_assert_warning         (const char *log_domain,
+                              const char *file,
+                              const int   line,
+                              const char *pretty_function,
+                              const char *expression) G_GNUC_NORETURN;
+#endif /* !G_DISABLE_DEPRECATED */
+
+
+#ifndef G_LOG_DOMAIN
+#define G_LOG_DOMAIN    ((gchar*) 0)
+#endif  /* G_LOG_DOMAIN */
+#ifdef G_HAVE_ISO_VARARGS
+/* for(;;); so that GCC knows that control doesn't go past g_error() */
+#define g_error(...)  G_STMT_START {                 \
+                        g_log (G_LOG_DOMAIN,         \
+                               G_LOG_LEVEL_ERROR,    \
+                               __VA_ARGS__);         \
+                        for (;;);                    \
+                      } G_STMT_END
+                        
+#define g_message(...)  g_log (G_LOG_DOMAIN,         \
+                               G_LOG_LEVEL_MESSAGE,  \
+                               __VA_ARGS__)
+#define g_critical(...) g_log (G_LOG_DOMAIN,         \
+                               G_LOG_LEVEL_CRITICAL, \
+                               __VA_ARGS__)
+#define g_warning(...)  g_log (G_LOG_DOMAIN,         \
+                               G_LOG_LEVEL_WARNING,  \
+                               __VA_ARGS__)
+#define g_debug(...)    g_log (G_LOG_DOMAIN,         \
+                               G_LOG_LEVEL_DEBUG,    \
+                               __VA_ARGS__)
+#elif defined(G_HAVE_GNUC_VARARGS)
+#define g_error(format...)    G_STMT_START {                 \
+                                g_log (G_LOG_DOMAIN,         \
+                                       G_LOG_LEVEL_ERROR,    \
+                                       format);              \
+                                for (;;);                    \
+                              } G_STMT_END
+                              
+#define g_message(format...)    g_log (G_LOG_DOMAIN,         \
+                                       G_LOG_LEVEL_MESSAGE,  \
+                                       format)
+#define g_critical(format...)   g_log (G_LOG_DOMAIN,         \
+                                       G_LOG_LEVEL_CRITICAL, \
+                                       format)
+#define g_warning(format...)    g_log (G_LOG_DOMAIN,         \
+                                       G_LOG_LEVEL_WARNING,  \
+                                       format)
+#define g_debug(format...)      g_log (G_LOG_DOMAIN,         \
+                                       G_LOG_LEVEL_DEBUG,    \
+                                       format)
+#else   /* no varargs macros */
+static void
+g_error (const gchar *format,
+         ...)
+{
+  va_list args;
+  va_start (args, format);
+  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, format, args);
+  va_end (args);
+
+  for(;;);
+}
+static void
+g_message (const gchar *format,
+           ...)
+{
+  va_list args;
+  va_start (args, format);
+  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, args);
+  va_end (args);
+}
+static void
+g_critical (const gchar *format,
+            ...)
+{
+  va_list args;
+  va_start (args, format);
+  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args);
+  va_end (args);
+}
+static void
+g_warning (const gchar *format,
+           ...)
+{
+  va_list args;
+  va_start (args, format);
+  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
+  va_end (args);
+}
+static void
+g_debug (const gchar *format,
+         ...)
+{
+  va_list args;
+  va_start (args, format);
+  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
+  va_end (args);
+}
+#endif  /* !__GNUC__ */
+
+typedef void    (*GPrintFunc)           (const gchar    *string);
+void            g_print                 (const gchar    *format,
+                                         ...) G_GNUC_PRINTF (1, 2);
+GPrintFunc      g_set_print_handler     (GPrintFunc      func);
+void            g_printerr              (const gchar    *format,
+                                         ...) G_GNUC_PRINTF (1, 2);
+GPrintFunc      g_set_printerr_handler  (GPrintFunc      func);
+
+
+/* Provide macros for graceful error handling.
+ * The "return" macros will return from the current function.
+ * Two different definitions are given for the macros in
+ * order to support gcc's __PRETTY_FUNCTION__ capability.
+ */
+
+#define g_warn_if_reached()     do { g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } while (0)
+#define g_warn_if_fail(expr)    do { if G_LIKELY (expr) ; else \
+                                       g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, #expr); } while (0)
+
+#ifdef G_DISABLE_CHECKS
+
+#define g_return_if_fail(expr)                 G_STMT_START{ (void)0; }G_STMT_END
+#define g_return_val_if_fail(expr,val)         G_STMT_START{ (void)0; }G_STMT_END
+#define g_return_if_reached()                  G_STMT_START{ return; }G_STMT_END
+#define g_return_val_if_reached(val)           G_STMT_START{ return (val); }G_STMT_END
+
+#else /* !G_DISABLE_CHECKS */
+
+#ifdef __GNUC__
+
+#define g_return_if_fail(expr)         G_STMT_START{                   \
+     if G_LIKELY(expr) { } else                                        \
+       {                                                               \
+        g_return_if_fail_warning (G_LOG_DOMAIN,                        \
+                                  __PRETTY_FUNCTION__,                 \
+                                  #expr);                              \
+        return;                                                        \
+       };                              }G_STMT_END
+
+#define g_return_val_if_fail(expr,val) G_STMT_START{                   \
+     if G_LIKELY(expr) { } else                                                \
+       {                                                               \
+        g_return_if_fail_warning (G_LOG_DOMAIN,                        \
+                                  __PRETTY_FUNCTION__,                 \
+                                  #expr);                              \
+        return (val);                                                  \
+       };                              }G_STMT_END
+
+#define g_return_if_reached()          G_STMT_START{                   \
+     g_log (G_LOG_DOMAIN,                                              \
+           G_LOG_LEVEL_CRITICAL,                                       \
+           "file %s: line %d (%s): should not be reached",             \
+           __FILE__,                                                   \
+           __LINE__,                                                   \
+           __PRETTY_FUNCTION__);                                       \
+     return;                           }G_STMT_END
+
+#define g_return_val_if_reached(val)   G_STMT_START{                   \
+     g_log (G_LOG_DOMAIN,                                              \
+           G_LOG_LEVEL_CRITICAL,                                       \
+           "file %s: line %d (%s): should not be reached",             \
+           __FILE__,                                                   \
+           __LINE__,                                                   \
+           __PRETTY_FUNCTION__);                                       \
+     return (val);                     }G_STMT_END
+
+#else /* !__GNUC__ */
+
+#define g_return_if_fail(expr)         G_STMT_START{           \
+     if (expr) { } else                                                \
+       {                                                       \
+        g_log (G_LOG_DOMAIN,                                   \
+               G_LOG_LEVEL_CRITICAL,                           \
+               "file %s: line %d: assertion `%s' failed",      \
+               __FILE__,                                       \
+               __LINE__,                                       \
+               #expr);                                         \
+        return;                                                \
+       };                              }G_STMT_END
+
+#define g_return_val_if_fail(expr, val)        G_STMT_START{           \
+     if (expr) { } else                                                \
+       {                                                       \
+        g_log (G_LOG_DOMAIN,                                   \
+               G_LOG_LEVEL_CRITICAL,                           \
+               "file %s: line %d: assertion `%s' failed",      \
+               __FILE__,                                       \
+               __LINE__,                                       \
+               #expr);                                         \
+        return (val);                                          \
+       };                              }G_STMT_END
+
+#define g_return_if_reached()          G_STMT_START{           \
+     g_log (G_LOG_DOMAIN,                                      \
+           G_LOG_LEVEL_CRITICAL,                               \
+           "file %s: line %d: should not be reached",          \
+           __FILE__,                                           \
+           __LINE__);                                          \
+     return;                           }G_STMT_END
+
+#define g_return_val_if_reached(val)   G_STMT_START{           \
+     g_log (G_LOG_DOMAIN,                                      \
+           G_LOG_LEVEL_CRITICAL,                               \
+           "file %s: line %d: should not be reached",          \
+           __FILE__,                                           \
+           __LINE__);                                          \
+     return (val);                     }G_STMT_END
+
+#endif /* !__GNUC__ */
+
+#endif /* !G_DISABLE_CHECKS */
+
+G_END_DECLS
+
+#endif /* __G_MESSAGES_H__ */
diff --git a/navit/navit/support/glib/gprimes.c b/navit/navit/support/glib/gprimes.c
new file mode 100644 (file)
index 0000000..7beca71
--- /dev/null
@@ -0,0 +1,90 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "galias.h"
+
+
+static const guint g_primes[] =
+{
+  11,
+  19,
+  37,
+  73,
+  109,
+  163,
+  251,
+  367,
+  557,
+  823,
+  1237,
+  1861,
+  2777,
+  4177,
+  6247,
+  9371,
+  14057,
+  21089,
+  31627,
+  47431,
+  71143,
+  106721,
+  160073,
+  240101,
+  360163,
+  540217,
+  810343,
+  1215497,
+  1823231,
+  2734867,
+  4102283,
+  6153409,
+  9230113,
+  13845163,
+};
+
+static const guint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]);
+
+guint
+g_spaced_primes_closest (guint num)
+{
+  gint i;
+
+  for (i = 0; i < g_nprimes; i++)
+    if (g_primes[i] > num)
+      return g_primes[i];
+
+  return g_primes[g_nprimes - 1];
+}
+
+#define __G_PRIMES_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gprintf.c b/navit/navit/support/glib/gprintf.c
new file mode 100644 (file)
index 0000000..6cbb214
--- /dev/null
@@ -0,0 +1,342 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 2002  Peter Mattis, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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 "config.h"
+
+#define _GNU_SOURCE            /* For vasprintf */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "glib.h"
+#include "gprintf.h"
+#include "gprintfint.h"
+
+#include "galias.h"
+
+/**
+ * g_printf:
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * An implementation of the standard printf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_printf (gchar const *format,
+         ...)
+{
+  va_list args;
+  gint retval;
+
+  va_start (args, format);
+  retval = g_vprintf (format, args);
+  va_end (args);
+  
+  return retval;
+}
+
+/**
+ * g_fprintf:
+ * @file: the stream to write to.
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * An implementation of the standard fprintf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_fprintf (FILE        *file, 
+           gchar const *format,
+          ...)
+{
+  va_list args;
+  gint retval;
+
+  va_start (args, format);
+  retval = g_vfprintf (file, format, args);
+  va_end (args);
+  
+  return retval;
+}
+
+/**
+ * g_sprintf:
+ * @string: A pointer to a memory buffer to contain the resulting string. It 
+ *          is up to the caller to ensure that the allocated buffer is large 
+ *          enough to hold the formatted result
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * An implementation of the standard sprintf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_sprintf (gchar       *string,
+          gchar const *format,
+          ...)
+{
+  va_list args;
+  gint retval;
+
+  va_start (args, format);
+  retval = g_vsprintf (string, format, args);
+  va_end (args);
+  
+  return retval;
+}
+
+/**
+ * g_snprintf:
+ * @string: the buffer to hold the output.
+ * @n: the maximum number of bytes to produce (including the 
+ *     terminating nul character).
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @Varargs: the arguments to insert in the output.
+ *
+ * A safer form of the standard sprintf() function. The output is guaranteed
+ * to not exceed @n characters (including the terminating nul character), so 
+ * it is easy to ensure that a buffer overflow cannot occur.
+ * 
+ * See also g_strdup_printf().
+ *
+ * In versions of GLib prior to 1.2.3, this function may return -1 if the 
+ * output was truncated, and the truncated string may not be nul-terminated. 
+ * In versions prior to 1.3.12, this function returns the length of the output 
+ * string.
+ *
+ * The return value of g_snprintf() conforms to the snprintf()
+ * function as standardized in ISO C99. Note that this is different from 
+ * traditional snprintf(), which returns the length of the output string.
+ *
+ * The format string may contain positional parameters, as specified in 
+ * the Single Unix Specification.
+ *
+ * Returns: the number of bytes which would be produced if the buffer 
+ *     was large enough.
+ **/
+gint
+g_snprintf (gchar      *string,
+           gulong       n,
+           gchar const *format,
+           ...)
+{
+  va_list args;
+  gint retval;
+
+  va_start (args, format);
+  retval = g_vsnprintf (string, n, format, args);
+  va_end (args);
+  
+  return retval;
+}
+
+/**
+ * g_vprintf:
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the standard vprintf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_vprintf (gchar const *format,
+          va_list      args)
+{
+  g_return_val_if_fail (format != NULL, -1);
+
+  return _g_vprintf (format, args);
+}
+
+/**
+ * g_vfprintf:
+ * @file: the stream to write to.
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the standard fprintf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_vfprintf (FILE        *file,
+            gchar const *format,
+           va_list      args)
+{
+  g_return_val_if_fail (format != NULL, -1);
+
+  return _g_vfprintf (file, format, args);
+}
+
+/**
+ * g_vsprintf:
+ * @string: the buffer to hold the output.
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the standard vsprintf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.2
+ **/
+gint
+g_vsprintf (gchar       *string,
+           gchar const *format,
+           va_list      args)
+{
+  g_return_val_if_fail (string != NULL, -1);
+  g_return_val_if_fail (format != NULL, -1);
+
+  return _g_vsprintf (string, format, args);
+}
+
+/** 
+ * g_vsnprintf:
+ * @string: the buffer to hold the output.
+ * @n: the maximum number of bytes to produce (including the 
+ *     terminating nul character).
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * A safer form of the standard vsprintf() function. The output is guaranteed
+ * to not exceed @n characters (including the terminating nul character), so 
+ * it is easy to ensure that a buffer overflow cannot occur.
+ *
+ * See also g_strdup_vprintf().
+ *
+ * In versions of GLib prior to 1.2.3, this function may return -1 if the 
+ * output was truncated, and the truncated string may not be nul-terminated.
+ * In versions prior to 1.3.12, this function returns the length of the output 
+ * string.
+ *
+ * The return value of g_vsnprintf() conforms to the vsnprintf() function 
+ * as standardized in ISO C99. Note that this is different from traditional 
+ * vsnprintf(), which returns the length of the output string.
+ *
+ * The format string may contain positional parameters, as specified in 
+ * the Single Unix Specification.
+ *
+ * Returns: the number of bytes which would be produced if the buffer 
+ *  was large enough.
+ */
+gint
+g_vsnprintf (gchar      *string,
+            gulong       n,
+            gchar const *format,
+            va_list      args)
+{
+  g_return_val_if_fail (n == 0 || string != NULL, -1);
+  g_return_val_if_fail (format != NULL, -1);
+
+  return _g_vsnprintf (string, n, format, args);
+}
+
+/**
+ * g_vasprintf:
+ * @string: the return location for the newly-allocated string.
+ * @format: a standard printf() format string, but notice
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @args: the list of arguments to insert in the output.
+ *
+ * An implementation of the GNU vasprintf() function which supports 
+ * positional parameters, as specified in the Single Unix Specification.
+ * This function is similar to g_vsprintf(), except that it allocates a 
+ * string to hold the output, instead of putting the output in a buffer 
+ * you allocate in advance.
+ *
+ * Returns: the number of bytes printed.
+ *
+ * Since: 2.4
+ **/
+gint 
+g_vasprintf (gchar      **string,
+            gchar const *format,
+            va_list      args)
+{
+  gint len;
+  g_return_val_if_fail (string != NULL, -1);
+
+#if !defined(HAVE_GOOD_PRINTF)
+
+  len = _g_gnulib_vasprintf (string, format, args);
+  if (len < 0)
+    *string = NULL;
+
+#elif defined (HAVE_VASPRINTF)
+
+  len = vasprintf (string, format, args);
+  if (len < 0)
+    *string = NULL;
+  else if (!g_mem_is_system_malloc ()) 
+    {
+      /* vasprintf returns malloc-allocated memory */
+      gchar *string1 = g_strndup (*string, len);
+      free (*string);
+      *string = string1;
+    }
+
+#else
+
+  {
+    va_list args2;
+
+    G_VA_COPY (args2, args);
+
+    *string = g_new (gchar, g_printf_string_upper_bound (format, args));
+
+    len = _g_vsprintf (*string, format, args2);
+    va_end (args2);
+  }
+#endif
+
+  return len;
+}
+
+#define __G_PRINTF_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gprintf.h b/navit/navit/support/glib/gprintf.h
new file mode 100644 (file)
index 0000000..d96870f
--- /dev/null
@@ -0,0 +1,52 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997, 2002  Peter Mattis, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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.
+ */
+
+#ifndef __G_PRINTF_H__
+#define __G_PRINTF_H__
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+G_BEGIN_DECLS
+
+gint                  g_printf    (gchar const *format,
+                                   ...) G_GNUC_PRINTF (1, 2);
+gint                  g_fprintf   (FILE        *file,
+                                  gchar const *format,
+                                  ...) G_GNUC_PRINTF (2, 3);
+gint                  g_sprintf   (gchar       *string,
+                                  gchar const *format,
+                                  ...) G_GNUC_PRINTF (2, 3);
+
+gint                  g_vprintf   (gchar const *format,
+                                   va_list      args);
+gint                  g_vfprintf  (FILE        *file,
+                                  gchar const *format,
+                                  va_list      args);
+gint                  g_vsprintf  (gchar       *string,
+                                  gchar const *format,
+                                  va_list      args);
+gint                  g_vasprintf (gchar      **string,
+                                  gchar const *format,
+                                  va_list      args);
+
+G_END_DECLS
+
+#endif /* __G_PRINTF_H__ */
diff --git a/navit/navit/support/glib/gprintfint.h b/navit/navit/support/glib/gprintfint.h
new file mode 100644 (file)
index 0000000..0c975a1
--- /dev/null
@@ -0,0 +1,59 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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 2002.  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/. 
+ */
+
+#ifndef __G_PRINTFINT_H__
+#define __G_PRINTFINT_H__
+
+#ifdef HAVE_GOOD_PRINTF
+
+#define _g_printf    printf
+#define _g_fprintf   fprintf
+#define _g_sprintf   sprintf
+#define _g_snprintf  snprintf
+
+#define _g_vprintf   vprintf
+#define _g_vfprintf  vfprintf
+#define _g_vsprintf  vsprintf
+#define _g_vsnprintf vsnprintf
+
+#else
+
+#include "gnulib/printf.h"
+
+#define _g_printf    _g_gnulib_printf
+#define _g_fprintf   _g_gnulib_fprintf
+#define _g_sprintf   _g_gnulib_sprintf
+#define _g_snprintf  _g_gnulib_snprintf
+
+#define _g_vprintf   _g_gnulib_vprintf
+#define _g_vfprintf  _g_gnulib_vfprintf
+#define _g_vsprintf  _g_gnulib_vsprintf
+#define _g_vsnprintf _g_gnulib_vsnprintf
+
+#endif
+
+#endif /* __G_PRINTF_H__ */
+
diff --git a/navit/navit/support/glib/gquark.h b/navit/navit/support/glib/gquark.h
new file mode 100644 (file)
index 0000000..a0cbe2f
--- /dev/null
@@ -0,0 +1,52 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_QUARK_H__
+#define __G_QUARK_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef guint32 GQuark;
+
+/* Quarks (string<->id association)
+ */
+GQuark                g_quark_try_string         (const gchar *string);
+GQuark                g_quark_from_static_string (const gchar *string);
+GQuark                g_quark_from_string        (const gchar *string);
+G_CONST_RETURN gchar* g_quark_to_string          (GQuark       quark) G_GNUC_CONST;
+
+G_CONST_RETURN gchar* g_intern_string            (const gchar *string);
+G_CONST_RETURN gchar* g_intern_static_string     (const gchar *string);
+
+G_END_DECLS
+
+#endif /* __G_QUARK_H__ */
diff --git a/navit/navit/support/glib/gslice.c b/navit/navit/support/glib/gslice.c
new file mode 100644 (file)
index 0000000..70f9efa
--- /dev/null
@@ -0,0 +1,1476 @@
+/* GLIB sliced memory - fast concurrent memory chunk allocator
+ * Copyright (C) 2005 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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.
+ */
+/* MT safe */
+
+#include "config.h"
+
+#if     defined HAVE_POSIX_MEMALIGN && defined POSIX_MEMALIGN_WITH_COMPLIANT_ALLOCS
+#  define HAVE_COMPLIANT_POSIX_MEMALIGN 1
+#endif
+
+#ifdef HAVE_COMPLIANT_POSIX_MEMALIGN
+#define _XOPEN_SOURCE 600       /* posix_memalign() */
+#endif
+#include <stdlib.h>             /* posix_memalign() */
+#include <string.h>
+#include <errno.h>
+#include "gmem.h"               /* gslice.h */
+#include "gthreadprivate.h"
+#include "glib.h"
+#include "galias.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>             /* sysconf() */
+#endif
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <process.h>
+#endif
+
+#include <stdio.h>              /* fputs/fprintf */
+
+
+/* the GSlice allocator is split up into 4 layers, roughly modelled after the slab
+ * allocator and magazine extensions as outlined in:
+ * + [Bonwick94] Jeff Bonwick, The slab allocator: An object-caching kernel
+ *   memory allocator. USENIX 1994, http://citeseer.ist.psu.edu/bonwick94slab.html
+ * + [Bonwick01] Bonwick and Jonathan Adams, Magazines and vmem: Extending the
+ *   slab allocator to many cpu's and arbitrary resources.
+ *   USENIX 2001, http://citeseer.ist.psu.edu/bonwick01magazines.html
+ * the layers are:
+ * - the thread magazines. for each (aligned) chunk size, a magazine (a list)
+ *   of recently freed and soon to be allocated chunks is maintained per thread.
+ *   this way, most alloc/free requests can be quickly satisfied from per-thread
+ *   free lists which only require one g_private_get() call to retrive the
+ *   thread handle.
+ * - the magazine cache. allocating and freeing chunks to/from threads only
+ *   occours at magazine sizes from a global depot of magazines. the depot
+ *   maintaines a 15 second working set of allocated magazines, so full
+ *   magazines are not allocated and released too often.
+ *   the chunk size dependent magazine sizes automatically adapt (within limits,
+ *   see [3]) to lock contention to properly scale performance across a variety
+ *   of SMP systems.
+ * - the slab allocator. this allocator allocates slabs (blocks of memory) close
+ *   to the system page size or multiples thereof which have to be page aligned.
+ *   the blocks are divided into smaller chunks which are used to satisfy
+ *   allocations from the upper layers. the space provided by the reminder of
+ *   the chunk size division is used for cache colorization (random distribution
+ *   of chunk addresses) to improve processor cache utilization. multiple slabs
+ *   with the same chunk size are kept in a partially sorted ring to allow O(1)
+ *   freeing and allocation of chunks (as long as the allocation of an entirely
+ *   new slab can be avoided).
+ * - the page allocator. on most modern systems, posix_memalign(3) or
+ *   memalign(3) should be available, so this is used to allocate blocks with
+ *   system page size based alignments and sizes or multiples thereof.
+ *   if no memalign variant is provided, valloc() is used instead and
+ *   block sizes are limited to the system page size (no multiples thereof).
+ *   as a fallback, on system without even valloc(), a malloc(3)-based page
+ *   allocator with alloc-only behaviour is used.
+ *
+ * NOTES:
+ * [1] some systems memalign(3) implementations may rely on boundary tagging for
+ *     the handed out memory chunks. to avoid excessive page-wise fragmentation,
+ *     we reserve 2 * sizeof (void*) per block size for the systems memalign(3),
+ *     specified in NATIVE_MALLOC_PADDING.
+ * [2] using the slab allocator alone already provides for a fast and efficient
+ *     allocator, it doesn't properly scale beyond single-threaded uses though.
+ *     also, the slab allocator implements eager free(3)-ing, i.e. does not
+ *     provide any form of caching or working set maintenance. so if used alone,
+ *     it's vulnerable to trashing for sequences of balanced (alloc, free) pairs
+ *     at certain thresholds.
+ * [3] magazine sizes are bound by an implementation specific minimum size and
+ *     a chunk size specific maximum to limit magazine storage sizes to roughly
+ *     16KB.
+ * [4] allocating ca. 8 chunks per block/page keeps a good balance between
+ *     external and internal fragmentation (<= 12.5%). [Bonwick94]
+ */
+
+/* --- macros and constants --- */
+#define LARGEALIGNMENT          (256)
+#define P2ALIGNMENT             (2 * sizeof (gsize))                            /* fits 2 pointers (assumed to be 2 * GLIB_SIZEOF_SIZE_T below) */
+#define ALIGN(size, base)       ((base) * (gsize) (((size) + (base) - 1) / (base)))
+#define NATIVE_MALLOC_PADDING   P2ALIGNMENT                                     /* per-page padding left for native malloc(3) see [1] */
+#define SLAB_INFO_SIZE          P2ALIGN (sizeof (SlabInfo) + NATIVE_MALLOC_PADDING)
+#define MAX_MAGAZINE_SIZE       (256)                                           /* see [3] and allocator_get_magazine_threshold() for this */
+#define MIN_MAGAZINE_SIZE       (4)
+#define MAX_STAMP_COUNTER       (7)                                             /* distributes the load of gettimeofday() */
+#define MAX_SLAB_CHUNK_SIZE(al) (((al)->max_page_size - SLAB_INFO_SIZE) / 8)    /* we want at last 8 chunks per page, see [4] */
+#define MAX_SLAB_INDEX(al)      (SLAB_INDEX (al, MAX_SLAB_CHUNK_SIZE (al)) + 1)
+#define SLAB_INDEX(al, asize)   ((asize) / P2ALIGNMENT - 1)                     /* asize must be P2ALIGNMENT aligned */
+#define SLAB_CHUNK_SIZE(al, ix) (((ix) + 1) * P2ALIGNMENT)
+#define SLAB_BPAGE_SIZE(al,csz) (8 * (csz) + SLAB_INFO_SIZE)
+
+/* optimized version of ALIGN (size, P2ALIGNMENT) */
+#if     GLIB_SIZEOF_SIZE_T * 2 == 8  /* P2ALIGNMENT */
+#define P2ALIGN(size)   (((size) + 0x7) & ~(gsize) 0x7)
+#elif   GLIB_SIZEOF_SIZE_T * 2 == 16 /* P2ALIGNMENT */
+#define P2ALIGN(size)   (((size) + 0xf) & ~(gsize) 0xf)
+#else
+#define P2ALIGN(size)   ALIGN (size, P2ALIGNMENT)
+#endif
+
+/* special helpers to avoid gmessage.c dependency */
+static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2);
+#define mem_assert(cond)    do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0)
+
+/* --- structures --- */
+typedef struct _ChunkLink      ChunkLink;
+typedef struct _SlabInfo       SlabInfo;
+typedef struct _CachedMagazine CachedMagazine;
+struct _ChunkLink {
+  ChunkLink *next;
+  ChunkLink *data;
+};
+struct _SlabInfo {
+  ChunkLink *chunks;
+  guint n_allocated;
+  SlabInfo *next, *prev;
+};
+typedef struct {
+  ChunkLink *chunks;
+  gsize      count;                     /* approximative chunks list length */
+} Magazine;
+typedef struct {
+  Magazine   *magazine1;                /* array of MAX_SLAB_INDEX (allocator) */
+  Magazine   *magazine2;                /* array of MAX_SLAB_INDEX (allocator) */
+} ThreadMemory;
+typedef struct {
+  gboolean always_malloc;
+  gboolean bypass_magazines;
+  gboolean debug_blocks;
+  gsize    working_set_msecs;
+  guint    color_increment;
+} SliceConfig;
+typedef struct {
+  /* const after initialization */
+  gsize         min_page_size, max_page_size;
+  SliceConfig   config;
+  gsize         max_slab_chunk_size_for_magazine_cache;
+  /* magazine cache */
+  GMutex       *magazine_mutex;
+  ChunkLink   **magazines;                /* array of MAX_SLAB_INDEX (allocator) */
+  guint        *contention_counters;      /* array of MAX_SLAB_INDEX (allocator) */
+  gint          mutex_counter;
+  guint         stamp_counter;
+  guint         last_stamp;
+  /* slab allocator */
+  GMutex       *slab_mutex;
+  SlabInfo    **slab_stack;                /* array of MAX_SLAB_INDEX (allocator) */
+  guint        color_accu;
+} Allocator;
+
+/* --- g-slice prototypes --- */
+static gpointer     slab_allocator_alloc_chunk       (gsize      chunk_size);
+static void         slab_allocator_free_chunk        (gsize      chunk_size,
+                                                      gpointer   mem);
+static void         private_thread_memory_cleanup    (gpointer   data);
+static gpointer     allocator_memalign               (gsize      alignment,
+                                                      gsize      memsize);
+static void         allocator_memfree                (gsize      memsize,
+                                                      gpointer   mem);
+static inline void  magazine_cache_update_stamp      (void);
+static inline gsize allocator_get_magazine_threshold (Allocator *allocator,
+                                                      guint      ix);
+
+/* --- g-slice memory checker --- */
+static void     smc_notify_alloc  (void   *pointer,
+                                   size_t  size);
+static int      smc_notify_free   (void   *pointer,
+                                   size_t  size);
+
+/* --- variables --- */
+static GPrivate   *private_thread_memory = NULL;
+static gsize       sys_page_size = 0;
+static Allocator   allocator[1] = { { 0, }, };
+static SliceConfig slice_config = {
+  FALSE,        /* always_malloc */
+  FALSE,        /* bypass_magazines */
+  FALSE,        /* debug_blocks */
+  15 * 1000,    /* working_set_msecs */
+  1,            /* color increment, alt: 0x7fffffff */
+};
+static GMutex     *smc_tree_mutex = NULL; /* mutex for G_SLICE=debug-blocks */
+
+/* --- auxillary funcitons --- */
+void
+g_slice_set_config (GSliceConfig ckey,
+                    gint64       value)
+{
+  g_return_if_fail (sys_page_size == 0);
+  switch (ckey)
+    {
+    case G_SLICE_CONFIG_ALWAYS_MALLOC:
+      slice_config.always_malloc = value != 0;
+      break;
+    case G_SLICE_CONFIG_BYPASS_MAGAZINES:
+      slice_config.bypass_magazines = value != 0;
+      break;
+    case G_SLICE_CONFIG_WORKING_SET_MSECS:
+      slice_config.working_set_msecs = value;
+      break;
+    case G_SLICE_CONFIG_COLOR_INCREMENT:
+      slice_config.color_increment = value;
+    default: ;
+    }
+}
+
+gint64
+g_slice_get_config (GSliceConfig ckey)
+{
+  switch (ckey)
+    {
+    case G_SLICE_CONFIG_ALWAYS_MALLOC:
+      return slice_config.always_malloc;
+    case G_SLICE_CONFIG_BYPASS_MAGAZINES:
+      return slice_config.bypass_magazines;
+    case G_SLICE_CONFIG_WORKING_SET_MSECS:
+      return slice_config.working_set_msecs;
+    case G_SLICE_CONFIG_CHUNK_SIZES:
+      return MAX_SLAB_INDEX (allocator);
+    case G_SLICE_CONFIG_COLOR_INCREMENT:
+      return slice_config.color_increment;
+    default:
+      return 0;
+    }
+}
+
+gint64*
+g_slice_get_config_state (GSliceConfig ckey,
+                          gint64       address,
+                          guint       *n_values)
+{
+  guint i = 0;
+  g_return_val_if_fail (n_values != NULL, NULL);
+  *n_values = 0;
+  switch (ckey)
+    {
+      gint64 array[64];
+    case G_SLICE_CONFIG_CONTENTION_COUNTER:
+      array[i++] = SLAB_CHUNK_SIZE (allocator, address);
+      array[i++] = allocator->contention_counters[address];
+      array[i++] = allocator_get_magazine_threshold (allocator, address);
+      *n_values = i;
+      return g_memdup (array, sizeof (array[0]) * *n_values);
+    default:
+      return NULL;
+    }
+}
+
+static void
+slice_config_init (SliceConfig *config)
+{
+  /* don't use g_malloc/g_message here */
+  gchar buffer[1024];
+  const gchar *val = _g_getenv_nomalloc ("G_SLICE", buffer);
+  const GDebugKey keys[] = {
+    { "always-malloc", 1 << 0 },
+    { "debug-blocks",  1 << 1 },
+  };
+  gint flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+  *config = slice_config;
+  if (flags & (1 << 0))         /* always-malloc */
+    config->always_malloc = TRUE;
+  if (flags & (1 << 1))         /* debug-blocks */
+    config->debug_blocks = TRUE;
+}
+
+static void
+g_slice_init_nomessage (void)
+{
+  /* we may not use g_error() or friends here */
+  mem_assert (sys_page_size == 0);
+  mem_assert (MIN_MAGAZINE_SIZE >= 4);
+
+#ifdef G_OS_WIN32
+  {
+    SYSTEM_INFO system_info;
+    GetSystemInfo (&system_info);
+    sys_page_size = system_info.dwPageSize;
+  }
+#else
+  sys_page_size = sysconf (_SC_PAGESIZE); /* = sysconf (_SC_PAGE_SIZE); = getpagesize(); */
+#endif
+  mem_assert (sys_page_size >= 2 * LARGEALIGNMENT);
+  mem_assert ((sys_page_size & (sys_page_size - 1)) == 0);
+  slice_config_init (&allocator->config);
+  allocator->min_page_size = sys_page_size;
+#if HAVE_COMPLIANT_POSIX_MEMALIGN || HAVE_MEMALIGN
+  /* allow allocation of pages up to 8KB (with 8KB alignment).
+   * this is useful because many medium to large sized structures
+   * fit less than 8 times (see [4]) into 4KB pages.
+   * we allow very small page sizes here, to reduce wastage in
+   * threads if only small allocations are required (this does
+   * bear the risk of incresing allocation times and fragmentation
+   * though).
+   */
+  allocator->min_page_size = MAX (allocator->min_page_size, 4096);
+  allocator->max_page_size = MAX (allocator->min_page_size, 8192);
+  allocator->min_page_size = MIN (allocator->min_page_size, 128);
+#else
+  /* we can only align to system page size */
+  allocator->max_page_size = sys_page_size;
+#endif
+  allocator->magazine_mutex = NULL;     /* _g_slice_thread_init_nomessage() */
+  allocator->magazines = g_new0 (ChunkLink*, MAX_SLAB_INDEX (allocator));
+  allocator->contention_counters = g_new0 (guint, MAX_SLAB_INDEX (allocator));
+  allocator->mutex_counter = 0;
+  allocator->stamp_counter = MAX_STAMP_COUNTER; /* force initial update */
+  allocator->last_stamp = 0;
+  allocator->slab_mutex = NULL;         /* _g_slice_thread_init_nomessage() */
+  allocator->slab_stack = g_new0 (SlabInfo*, MAX_SLAB_INDEX (allocator));
+  allocator->color_accu = 0;
+  magazine_cache_update_stamp();
+  /* values cached for performance reasons */
+  allocator->max_slab_chunk_size_for_magazine_cache = MAX_SLAB_CHUNK_SIZE (allocator);
+  if (allocator->config.always_malloc || allocator->config.bypass_magazines)
+    allocator->max_slab_chunk_size_for_magazine_cache = 0;      /* non-optimized cases */
+  /* at this point, g_mem_gc_friendly() should be initialized, this
+   * should have been accomplished by the above g_malloc/g_new calls
+   */
+}
+
+static inline guint
+allocator_categorize (gsize aligned_chunk_size)
+{
+  /* speed up the likely path */
+  if (G_LIKELY (aligned_chunk_size && aligned_chunk_size <= allocator->max_slab_chunk_size_for_magazine_cache))
+    return 1;           /* use magazine cache */
+
+  /* the above will fail (max_slab_chunk_size_for_magazine_cache == 0) if the
+   * allocator is still uninitialized, or if we are not configured to use the
+   * magazine cache.
+   */
+  if (!sys_page_size)
+    g_slice_init_nomessage ();
+  if (!allocator->config.always_malloc &&
+      aligned_chunk_size &&
+      aligned_chunk_size <= MAX_SLAB_CHUNK_SIZE (allocator))
+    {
+      if (allocator->config.bypass_magazines)
+        return 2;       /* use slab allocator, see [2] */
+      return 1;         /* use magazine cache */
+    }
+  return 0;             /* use malloc() */
+}
+
+void
+_g_slice_thread_init_nomessage (void)
+{
+  /* we may not use g_error() or friends here */
+  if (!sys_page_size)
+    g_slice_init_nomessage();
+  else
+    {
+      /* g_slice_init_nomessage() has been called already, probably due
+       * to a g_slice_alloc1() before g_thread_init().
+       */
+    }
+  private_thread_memory = g_private_new (private_thread_memory_cleanup);
+  allocator->magazine_mutex = g_mutex_new();
+  allocator->slab_mutex = g_mutex_new();
+  if (allocator->config.debug_blocks)
+    smc_tree_mutex = g_mutex_new();
+}
+
+static inline void
+g_mutex_lock_a (GMutex *mutex,
+                guint  *contention_counter)
+{
+  gboolean contention = FALSE;
+  if (!g_mutex_trylock (mutex))
+    {
+      g_mutex_lock (mutex);
+      contention = TRUE;
+    }
+  if (contention)
+    {
+      allocator->mutex_counter++;
+      if (allocator->mutex_counter >= 1)        /* quickly adapt to contention */
+        {
+          allocator->mutex_counter = 0;
+          *contention_counter = MIN (*contention_counter + 1, MAX_MAGAZINE_SIZE);
+        }
+    }
+  else /* !contention */
+    {
+      allocator->mutex_counter--;
+      if (allocator->mutex_counter < -11)       /* moderately recover magazine sizes */
+        {
+          allocator->mutex_counter = 0;
+          *contention_counter = MAX (*contention_counter, 1) - 1;
+        }
+    }
+}
+
+static inline ThreadMemory*
+thread_memory_from_self (void)
+{
+  ThreadMemory *tmem = g_private_get (private_thread_memory);
+  if (G_UNLIKELY (!tmem))
+    {
+      static ThreadMemory *single_thread_memory = NULL;   /* remember single-thread info for multi-threaded case */
+      if (single_thread_memory && g_thread_supported ())
+        {
+          g_mutex_lock (allocator->slab_mutex);
+          if (single_thread_memory)
+            {
+              /* GSlice has been used before g_thread_init(), and now
+               * we are running threaded. to cope with it, use the saved
+               * thread memory structure from when we weren't threaded.
+               */
+              tmem = single_thread_memory;
+              single_thread_memory = NULL;      /* slab_mutex protected when multi-threaded */
+            }
+          g_mutex_unlock (allocator->slab_mutex);
+        }
+      if (!tmem)
+       {
+          const guint n_magazines = MAX_SLAB_INDEX (allocator);
+         tmem = g_malloc0 (sizeof (ThreadMemory) + sizeof (Magazine) * 2 * n_magazines);
+         tmem->magazine1 = (Magazine*) (tmem + 1);
+         tmem->magazine2 = &tmem->magazine1[n_magazines];
+       }
+      /* g_private_get/g_private_set works in the single-threaded xor the multi-
+       * threaded case. but not *across* g_thread_init(), after multi-thread
+       * initialization it returns NULL for previously set single-thread data.
+       */
+      g_private_set (private_thread_memory, tmem);
+      /* save single-thread thread memory structure, in case we need to
+       * pick it up again after multi-thread initialization happened.
+       */
+      if (!single_thread_memory && !g_thread_supported ())
+        single_thread_memory = tmem;            /* no slab_mutex created yet */
+    }
+  return tmem;
+}
+
+static inline ChunkLink*
+magazine_chain_pop_head (ChunkLink **magazine_chunks)
+{
+  /* magazine chains are linked via ChunkLink->next.
+   * each ChunkLink->data of the toplevel chain may point to a subchain,
+   * linked via ChunkLink->next. ChunkLink->data of the subchains just
+   * contains uninitialized junk.
+   */
+  ChunkLink *chunk = (*magazine_chunks)->data;
+  if (G_UNLIKELY (chunk))
+    {
+      /* allocating from freed list */
+      (*magazine_chunks)->data = chunk->next;
+    }
+  else
+    {
+      chunk = *magazine_chunks;
+      *magazine_chunks = chunk->next;
+    }
+  return chunk;
+}
+
+#if 0 /* useful for debugging */
+static guint
+magazine_count (ChunkLink *head)
+{
+  guint count = 0;
+  if (!head)
+    return 0;
+  while (head)
+    {
+      ChunkLink *child = head->data;
+      count += 1;
+      for (child = head->data; child; child = child->next)
+        count += 1;
+      head = head->next;
+    }
+  return count;
+}
+#endif
+
+static inline gsize
+allocator_get_magazine_threshold (Allocator *allocator,
+                                  guint      ix)
+{
+  /* the magazine size calculated here has a lower bound of MIN_MAGAZINE_SIZE,
+   * which is required by the implementation. also, for moderately sized chunks
+   * (say >= 64 bytes), magazine sizes shouldn't be much smaller then the number
+   * of chunks available per page/2 to avoid excessive traffic in the magazine
+   * cache for small to medium sized structures.
+   * the upper bound of the magazine size is effectively provided by
+   * MAX_MAGAZINE_SIZE. for larger chunks, this number is scaled down so that
+   * the content of a single magazine doesn't exceed ca. 16KB.
+   */
+  gsize chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+  guint threshold = MAX (MIN_MAGAZINE_SIZE, allocator->max_page_size / MAX (5 * chunk_size, 5 * 32));
+  guint contention_counter = allocator->contention_counters[ix];
+  if (G_UNLIKELY (contention_counter))  /* single CPU bias */
+    {
+      /* adapt contention counter thresholds to chunk sizes */
+      contention_counter = contention_counter * 64 / chunk_size;
+      threshold = MAX (threshold, contention_counter);
+    }
+  return threshold;
+}
+
+/* --- magazine cache --- */
+static inline void
+magazine_cache_update_stamp (void)
+{
+  if (allocator->stamp_counter >= MAX_STAMP_COUNTER)
+    {
+      GTimeVal tv;
+      g_get_current_time (&tv);
+      allocator->last_stamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; /* milli seconds */
+      allocator->stamp_counter = 0;
+    }
+  else
+    allocator->stamp_counter++;
+}
+
+static inline ChunkLink*
+magazine_chain_prepare_fields (ChunkLink *magazine_chunks)
+{
+  ChunkLink *chunk1;
+  ChunkLink *chunk2;
+  ChunkLink *chunk3;
+  ChunkLink *chunk4;
+  /* checked upon initialization: mem_assert (MIN_MAGAZINE_SIZE >= 4); */
+  /* ensure a magazine with at least 4 unused data pointers */
+  chunk1 = magazine_chain_pop_head (&magazine_chunks);
+  chunk2 = magazine_chain_pop_head (&magazine_chunks);
+  chunk3 = magazine_chain_pop_head (&magazine_chunks);
+  chunk4 = magazine_chain_pop_head (&magazine_chunks);
+  chunk4->next = magazine_chunks;
+  chunk3->next = chunk4;
+  chunk2->next = chunk3;
+  chunk1->next = chunk2;
+  return chunk1;
+}
+
+/* access the first 3 fields of a specially prepared magazine chain */
+#define magazine_chain_prev(mc)         ((mc)->data)
+#define magazine_chain_stamp(mc)        ((mc)->next->data)
+#define magazine_chain_uint_stamp(mc)   GPOINTER_TO_UINT ((mc)->next->data)
+#define magazine_chain_next(mc)         ((mc)->next->next->data)
+#define magazine_chain_count(mc)        ((mc)->next->next->next->data)
+
+static void
+magazine_cache_trim (Allocator *allocator,
+                     guint      ix,
+                     guint      stamp)
+{
+  /* g_mutex_lock (allocator->mutex); done by caller */
+  /* trim magazine cache from tail */
+  ChunkLink *current = magazine_chain_prev (allocator->magazines[ix]);
+  ChunkLink *trash = NULL;
+  while (ABS (stamp - magazine_chain_uint_stamp (current)) >= allocator->config.working_set_msecs)
+    {
+      /* unlink */
+      ChunkLink *prev = magazine_chain_prev (current);
+      ChunkLink *next = magazine_chain_next (current);
+      magazine_chain_next (prev) = next;
+      magazine_chain_prev (next) = prev;
+      /* clear special fields, put on trash stack */
+      magazine_chain_next (current) = NULL;
+      magazine_chain_count (current) = NULL;
+      magazine_chain_stamp (current) = NULL;
+      magazine_chain_prev (current) = trash;
+      trash = current;
+      /* fixup list head if required */
+      if (current == allocator->magazines[ix])
+        {
+          allocator->magazines[ix] = NULL;
+          break;
+        }
+      current = prev;
+    }
+  g_mutex_unlock (allocator->magazine_mutex);
+  /* free trash */
+  if (trash)
+    {
+      const gsize chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+      g_mutex_lock (allocator->slab_mutex);
+      while (trash)
+        {
+          current = trash;
+          trash = magazine_chain_prev (current);
+          magazine_chain_prev (current) = NULL; /* clear special field */
+          while (current)
+            {
+              ChunkLink *chunk = magazine_chain_pop_head (&current);
+              slab_allocator_free_chunk (chunk_size, chunk);
+            }
+        }
+      g_mutex_unlock (allocator->slab_mutex);
+    }
+}
+
+static void
+magazine_cache_push_magazine (guint      ix,
+                              ChunkLink *magazine_chunks,
+                              gsize      count) /* must be >= MIN_MAGAZINE_SIZE */
+{
+  ChunkLink *current = magazine_chain_prepare_fields (magazine_chunks);
+  ChunkLink *next, *prev;
+  g_mutex_lock (allocator->magazine_mutex);
+  /* add magazine at head */
+  next = allocator->magazines[ix];
+  if (next)
+    prev = magazine_chain_prev (next);
+  else
+    next = prev = current;
+  magazine_chain_next (prev) = current;
+  magazine_chain_prev (next) = current;
+  magazine_chain_prev (current) = prev;
+  magazine_chain_next (current) = next;
+  magazine_chain_count (current) = (gpointer) count;
+  /* stamp magazine */
+  magazine_cache_update_stamp();
+  magazine_chain_stamp (current) = GUINT_TO_POINTER (allocator->last_stamp);
+  allocator->magazines[ix] = current;
+  /* free old magazines beyond a certain threshold */
+  magazine_cache_trim (allocator, ix, allocator->last_stamp);
+  /* g_mutex_unlock (allocator->mutex); was done by magazine_cache_trim() */
+}
+
+static ChunkLink*
+magazine_cache_pop_magazine (guint  ix,
+                             gsize *countp)
+{
+  g_mutex_lock_a (allocator->magazine_mutex, &allocator->contention_counters[ix]);
+  if (!allocator->magazines[ix])
+    {
+      guint magazine_threshold = allocator_get_magazine_threshold (allocator, ix);
+      gsize i, chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+      ChunkLink *chunk, *head;
+      g_mutex_unlock (allocator->magazine_mutex);
+      g_mutex_lock (allocator->slab_mutex);
+      head = slab_allocator_alloc_chunk (chunk_size);
+      head->data = NULL;
+      chunk = head;
+      for (i = 1; i < magazine_threshold; i++)
+        {
+          chunk->next = slab_allocator_alloc_chunk (chunk_size);
+          chunk = chunk->next;
+          chunk->data = NULL;
+        }
+      chunk->next = NULL;
+      g_mutex_unlock (allocator->slab_mutex);
+      *countp = i;
+      return head;
+    }
+  else
+    {
+      ChunkLink *current = allocator->magazines[ix];
+      ChunkLink *prev = magazine_chain_prev (current);
+      ChunkLink *next = magazine_chain_next (current);
+      /* unlink */
+      magazine_chain_next (prev) = next;
+      magazine_chain_prev (next) = prev;
+      allocator->magazines[ix] = next == current ? NULL : next;
+      g_mutex_unlock (allocator->magazine_mutex);
+      /* clear special fields and hand out */
+      *countp = (gsize) magazine_chain_count (current);
+      magazine_chain_prev (current) = NULL;
+      magazine_chain_next (current) = NULL;
+      magazine_chain_count (current) = NULL;
+      magazine_chain_stamp (current) = NULL;
+      return current;
+    }
+}
+
+/* --- thread magazines --- */
+static void
+private_thread_memory_cleanup (gpointer data)
+{
+  ThreadMemory *tmem = data;
+  const guint n_magazines = MAX_SLAB_INDEX (allocator);
+  guint ix;
+  for (ix = 0; ix < n_magazines; ix++)
+    {
+      Magazine *mags[2];
+      guint j;
+      mags[0] = &tmem->magazine1[ix];
+      mags[1] = &tmem->magazine2[ix];
+      for (j = 0; j < 2; j++)
+        {
+          Magazine *mag = mags[j];
+          if (mag->count >= MIN_MAGAZINE_SIZE)
+            magazine_cache_push_magazine (ix, mag->chunks, mag->count);
+          else
+            {
+              const gsize chunk_size = SLAB_CHUNK_SIZE (allocator, ix);
+              g_mutex_lock (allocator->slab_mutex);
+              while (mag->chunks)
+                {
+                  ChunkLink *chunk = magazine_chain_pop_head (&mag->chunks);
+                  slab_allocator_free_chunk (chunk_size, chunk);
+                }
+              g_mutex_unlock (allocator->slab_mutex);
+            }
+        }
+    }
+  g_free (tmem);
+}
+
+static void
+thread_memory_magazine1_reload (ThreadMemory *tmem,
+                                guint         ix)
+{
+  Magazine *mag = &tmem->magazine1[ix];
+  mem_assert (mag->chunks == NULL); /* ensure that we may reset mag->count */
+  mag->count = 0;
+  mag->chunks = magazine_cache_pop_magazine (ix, &mag->count);
+}
+
+static void
+thread_memory_magazine2_unload (ThreadMemory *tmem,
+                                guint         ix)
+{
+  Magazine *mag = &tmem->magazine2[ix];
+  magazine_cache_push_magazine (ix, mag->chunks, mag->count);
+  mag->chunks = NULL;
+  mag->count = 0;
+}
+
+static inline void
+thread_memory_swap_magazines (ThreadMemory *tmem,
+                              guint         ix)
+{
+  Magazine xmag = tmem->magazine1[ix];
+  tmem->magazine1[ix] = tmem->magazine2[ix];
+  tmem->magazine2[ix] = xmag;
+}
+
+static inline gboolean
+thread_memory_magazine1_is_empty (ThreadMemory *tmem,
+                                  guint         ix)
+{
+  return tmem->magazine1[ix].chunks == NULL;
+}
+
+static inline gboolean
+thread_memory_magazine2_is_full (ThreadMemory *tmem,
+                                 guint         ix)
+{
+  return tmem->magazine2[ix].count >= allocator_get_magazine_threshold (allocator, ix);
+}
+
+static inline gpointer
+thread_memory_magazine1_alloc (ThreadMemory *tmem,
+                               guint         ix)
+{
+  Magazine *mag = &tmem->magazine1[ix];
+  ChunkLink *chunk = magazine_chain_pop_head (&mag->chunks);
+  if (G_LIKELY (mag->count > 0))
+    mag->count--;
+  return chunk;
+}
+
+static inline void
+thread_memory_magazine2_free (ThreadMemory *tmem,
+                              guint         ix,
+                              gpointer      mem)
+{
+  Magazine *mag = &tmem->magazine2[ix];
+  ChunkLink *chunk = mem;
+  chunk->data = NULL;
+  chunk->next = mag->chunks;
+  mag->chunks = chunk;
+  mag->count++;
+}
+
+/* --- API functions --- */
+gpointer
+g_slice_alloc (gsize mem_size)
+{
+  gsize chunk_size;
+  gpointer mem;
+  guint acat;
+  chunk_size = P2ALIGN (mem_size);
+  acat = allocator_categorize (chunk_size);
+  if (G_LIKELY (acat == 1))     /* allocate through magazine layer */
+    {
+      ThreadMemory *tmem = thread_memory_from_self();
+      guint ix = SLAB_INDEX (allocator, chunk_size);
+      if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
+        {
+          thread_memory_swap_magazines (tmem, ix);
+          if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
+            thread_memory_magazine1_reload (tmem, ix);
+        }
+      mem = thread_memory_magazine1_alloc (tmem, ix);
+    }
+  else if (acat == 2)           /* allocate through slab allocator */
+    {
+      g_mutex_lock (allocator->slab_mutex);
+      mem = slab_allocator_alloc_chunk (chunk_size);
+      g_mutex_unlock (allocator->slab_mutex);
+    }
+  else                          /* delegate to system malloc */
+    mem = g_malloc (mem_size);
+  if (G_UNLIKELY (allocator->config.debug_blocks))
+    smc_notify_alloc (mem, mem_size);
+  return mem;
+}
+
+gpointer
+g_slice_alloc0 (gsize mem_size)
+{
+  gpointer mem = g_slice_alloc (mem_size);
+  if (mem)
+    memset (mem, 0, mem_size);
+  return mem;
+}
+
+gpointer
+g_slice_copy (gsize         mem_size,
+              gconstpointer mem_block)
+{
+  gpointer mem = g_slice_alloc (mem_size);
+  if (mem)
+    memcpy (mem, mem_block, mem_size);
+  return mem;
+}
+
+void
+g_slice_free1 (gsize    mem_size,
+               gpointer mem_block)
+{
+  gsize chunk_size = P2ALIGN (mem_size);
+  guint acat = allocator_categorize (chunk_size);
+  if (G_UNLIKELY (!mem_block))
+    return;
+  if (G_UNLIKELY (allocator->config.debug_blocks) &&
+      !smc_notify_free (mem_block, mem_size))
+    abort();
+  if (G_LIKELY (acat == 1))             /* allocate through magazine layer */
+    {
+      ThreadMemory *tmem = thread_memory_from_self();
+      guint ix = SLAB_INDEX (allocator, chunk_size);
+      if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+        {
+          thread_memory_swap_magazines (tmem, ix);
+          if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+            thread_memory_magazine2_unload (tmem, ix);
+        }
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        memset (mem_block, 0, chunk_size);
+      thread_memory_magazine2_free (tmem, ix, mem_block);
+    }
+  else if (acat == 2)                   /* allocate through slab allocator */
+    {
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        memset (mem_block, 0, chunk_size);
+      g_mutex_lock (allocator->slab_mutex);
+      slab_allocator_free_chunk (chunk_size, mem_block);
+      g_mutex_unlock (allocator->slab_mutex);
+    }
+  else                                  /* delegate to system malloc */
+    {
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        memset (mem_block, 0, mem_size);
+      g_free (mem_block);
+    }
+}
+
+void
+g_slice_free_chain_with_offset (gsize    mem_size,
+                                gpointer mem_chain,
+                                gsize    next_offset)
+{
+  gpointer slice = mem_chain;
+  /* while the thread magazines and the magazine cache are implemented so that
+   * they can easily be extended to allow for free lists containing more free
+   * lists for the first level nodes, which would allow O(1) freeing in this
+   * function, the benefit of such an extension is questionable, because:
+   * - the magazine size counts will become mere lower bounds which confuses
+   *   the code adapting to lock contention;
+   * - freeing a single node to the thread magazines is very fast, so this
+   *   O(list_length) operation is multiplied by a fairly small factor;
+   * - memory usage histograms on larger applications seem to indicate that
+   *   the amount of released multi node lists is negligible in comparison
+   *   to single node releases.
+   * - the major performance bottle neck, namely g_private_get() or
+   *   g_mutex_lock()/g_mutex_unlock() has already been moved out of the
+   *   inner loop for freeing chained slices.
+   */
+  gsize chunk_size = P2ALIGN (mem_size);
+  guint acat = allocator_categorize (chunk_size);
+  if (G_LIKELY (acat == 1))             /* allocate through magazine layer */
+    {
+      ThreadMemory *tmem = thread_memory_from_self();
+      guint ix = SLAB_INDEX (allocator, chunk_size);
+      while (slice)
+        {
+          guint8 *current = slice;
+          slice = *(gpointer*) (current + next_offset);
+          if (G_UNLIKELY (allocator->config.debug_blocks) &&
+              !smc_notify_free (current, mem_size))
+            abort();
+          if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+            {
+              thread_memory_swap_magazines (tmem, ix);
+              if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+                thread_memory_magazine2_unload (tmem, ix);
+            }
+          if (G_UNLIKELY (g_mem_gc_friendly))
+            memset (current, 0, chunk_size);
+          thread_memory_magazine2_free (tmem, ix, current);
+        }
+    }
+  else if (acat == 2)                   /* allocate through slab allocator */
+    {
+      g_mutex_lock (allocator->slab_mutex);
+      while (slice)
+        {
+          guint8 *current = slice;
+          slice = *(gpointer*) (current + next_offset);
+          if (G_UNLIKELY (allocator->config.debug_blocks) &&
+              !smc_notify_free (current, mem_size))
+            abort();
+          if (G_UNLIKELY (g_mem_gc_friendly))
+            memset (current, 0, chunk_size);
+          slab_allocator_free_chunk (chunk_size, current);
+        }
+      g_mutex_unlock (allocator->slab_mutex);
+    }
+  else                                  /* delegate to system malloc */
+    while (slice)
+      {
+        guint8 *current = slice;
+        slice = *(gpointer*) (current + next_offset);
+        if (G_UNLIKELY (allocator->config.debug_blocks) &&
+            !smc_notify_free (current, mem_size))
+          abort();
+        if (G_UNLIKELY (g_mem_gc_friendly))
+          memset (current, 0, mem_size);
+        g_free (current);
+      }
+}
+
+/* --- single page allocator --- */
+static void
+allocator_slab_stack_push (Allocator *allocator,
+                           guint      ix,
+                           SlabInfo  *sinfo)
+{
+  /* insert slab at slab ring head */
+  if (!allocator->slab_stack[ix])
+    {
+      sinfo->next = sinfo;
+      sinfo->prev = sinfo;
+    }
+  else
+    {
+      SlabInfo *next = allocator->slab_stack[ix], *prev = next->prev;
+      next->prev = sinfo;
+      prev->next = sinfo;
+      sinfo->next = next;
+      sinfo->prev = prev;
+    }
+  allocator->slab_stack[ix] = sinfo;
+}
+
+static gsize
+allocator_aligned_page_size (Allocator *allocator,
+                             gsize      n_bytes)
+{
+  gsize val = 1 << g_bit_storage (n_bytes - 1);
+  val = MAX (val, allocator->min_page_size);
+  return val;
+}
+
+static void
+allocator_add_slab (Allocator *allocator,
+                    guint      ix,
+                    gsize      chunk_size)
+{
+  ChunkLink *chunk;
+  SlabInfo *sinfo;
+  gsize addr, padding, n_chunks, color = 0;
+  gsize page_size = allocator_aligned_page_size (allocator, SLAB_BPAGE_SIZE (allocator, chunk_size));
+  /* allocate 1 page for the chunks and the slab */
+  gpointer aligned_memory = allocator_memalign (page_size, page_size - NATIVE_MALLOC_PADDING);
+  guint8 *mem = aligned_memory;
+  guint i;
+  if (!mem)
+    {
+      const gchar *syserr = "unknown error";
+#if HAVE_STRERROR
+      syserr = strerror (errno);
+#endif
+      mem_error ("failed to allocate %u bytes (alignment: %u): %s\n",
+                 (guint) (page_size - NATIVE_MALLOC_PADDING), (guint) page_size, syserr);
+    }
+  /* mask page adress */
+  addr = ((gsize) mem / page_size) * page_size;
+  /* assert alignment */
+  mem_assert (aligned_memory == (gpointer) addr);
+  /* basic slab info setup */
+  sinfo = (SlabInfo*) (mem + page_size - SLAB_INFO_SIZE);
+  sinfo->n_allocated = 0;
+  sinfo->chunks = NULL;
+  /* figure cache colorization */
+  n_chunks = ((guint8*) sinfo - mem) / chunk_size;
+  padding = ((guint8*) sinfo - mem) - n_chunks * chunk_size;
+  if (padding)
+    {
+      color = (allocator->color_accu * P2ALIGNMENT) % padding;
+      allocator->color_accu += allocator->config.color_increment;
+    }
+  /* add chunks to free list */
+  chunk = (ChunkLink*) (mem + color);
+  sinfo->chunks = chunk;
+  for (i = 0; i < n_chunks - 1; i++)
+    {
+      chunk->next = (ChunkLink*) ((guint8*) chunk + chunk_size);
+      chunk = chunk->next;
+    }
+  chunk->next = NULL;   /* last chunk */
+  /* add slab to slab ring */
+  allocator_slab_stack_push (allocator, ix, sinfo);
+}
+
+static gpointer
+slab_allocator_alloc_chunk (gsize chunk_size)
+{
+  ChunkLink *chunk;
+  guint ix = SLAB_INDEX (allocator, chunk_size);
+  /* ensure non-empty slab */
+  if (!allocator->slab_stack[ix] || !allocator->slab_stack[ix]->chunks)
+    allocator_add_slab (allocator, ix, chunk_size);
+  /* allocate chunk */
+  chunk = allocator->slab_stack[ix]->chunks;
+  allocator->slab_stack[ix]->chunks = chunk->next;
+  allocator->slab_stack[ix]->n_allocated++;
+  /* rotate empty slabs */
+  if (!allocator->slab_stack[ix]->chunks)
+    allocator->slab_stack[ix] = allocator->slab_stack[ix]->next;
+  return chunk;
+}
+
+static void
+slab_allocator_free_chunk (gsize    chunk_size,
+                           gpointer mem)
+{
+  ChunkLink *chunk;
+  gboolean was_empty;
+  guint ix = SLAB_INDEX (allocator, chunk_size);
+  gsize page_size = allocator_aligned_page_size (allocator, SLAB_BPAGE_SIZE (allocator, chunk_size));
+  gsize addr = ((gsize) mem / page_size) * page_size;
+  /* mask page adress */
+  guint8 *page = (guint8*) addr;
+  SlabInfo *sinfo = (SlabInfo*) (page + page_size - SLAB_INFO_SIZE);
+  /* assert valid chunk count */
+  mem_assert (sinfo->n_allocated > 0);
+  /* add chunk to free list */
+  was_empty = sinfo->chunks == NULL;
+  chunk = (ChunkLink*) mem;
+  chunk->next = sinfo->chunks;
+  sinfo->chunks = chunk;
+  sinfo->n_allocated--;
+  /* keep slab ring partially sorted, empty slabs at end */
+  if (was_empty)
+    {
+      /* unlink slab */
+      SlabInfo *next = sinfo->next, *prev = sinfo->prev;
+      next->prev = prev;
+      prev->next = next;
+      if (allocator->slab_stack[ix] == sinfo)
+        allocator->slab_stack[ix] = next == sinfo ? NULL : next;
+      /* insert slab at head */
+      allocator_slab_stack_push (allocator, ix, sinfo);
+    }
+  /* eagerly free complete unused slabs */
+  if (!sinfo->n_allocated)
+    {
+      /* unlink slab */
+      SlabInfo *next = sinfo->next, *prev = sinfo->prev;
+      next->prev = prev;
+      prev->next = next;
+      if (allocator->slab_stack[ix] == sinfo)
+        allocator->slab_stack[ix] = next == sinfo ? NULL : next;
+      /* free slab */
+      allocator_memfree (page_size, page);
+    }
+}
+
+/* --- memalign implementation --- */
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>             /* memalign() */
+#endif
+
+/* from config.h:
+ * define HAVE_POSIX_MEMALIGN           1 // if free(posix_memalign(3)) works, <stdlib.h>
+ * define HAVE_COMPLIANT_POSIX_MEMALIGN 1 // if free(posix_memalign(3)) works for sizes != 2^n, <stdlib.h>
+ * define HAVE_MEMALIGN                 1 // if free(memalign(3)) works, <malloc.h>
+ * define HAVE_VALLOC                   1 // if free(valloc(3)) works, <stdlib.h> or <malloc.h>
+ * if none is provided, we implement malloc(3)-based alloc-only page alignment
+ */
+
+#if !(HAVE_COMPLIANT_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_VALLOC)
+static GTrashStack *compat_valloc_trash = NULL;
+#endif
+
+static gpointer
+allocator_memalign (gsize alignment,
+                    gsize memsize)
+{
+  gpointer aligned_memory = NULL;
+  gint err = ENOMEM;
+#if     HAVE_COMPLIANT_POSIX_MEMALIGN
+  err = posix_memalign (&aligned_memory, alignment, memsize);
+#elif   HAVE_MEMALIGN
+  errno = 0;
+  aligned_memory = memalign (alignment, memsize);
+  err = errno;
+#elif   HAVE_VALLOC
+  errno = 0;
+  aligned_memory = valloc (memsize);
+  err = errno;
+#else
+  /* simplistic non-freeing page allocator */
+  mem_assert (alignment == sys_page_size);
+  mem_assert (memsize <= sys_page_size);
+  if (!compat_valloc_trash)
+    {
+      const guint n_pages = 16;
+      guint8 *mem = malloc (n_pages * sys_page_size);
+      err = errno;
+      if (mem)
+        {
+          gint i = n_pages;
+          guint8 *amem = (guint8*) ALIGN ((gsize) mem, sys_page_size);
+          if (amem != mem)
+            i--;        /* mem wasn't page aligned */
+          while (--i >= 0)
+            g_trash_stack_push (&compat_valloc_trash, amem + i * sys_page_size);
+        }
+    }
+  aligned_memory = g_trash_stack_pop (&compat_valloc_trash);
+#endif
+  if (!aligned_memory)
+    errno = err;
+  return aligned_memory;
+}
+
+static void
+allocator_memfree (gsize    memsize,
+                   gpointer mem)
+{
+#if     HAVE_COMPLIANT_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_VALLOC
+  free (mem);
+#else
+  mem_assert (memsize <= sys_page_size);
+  g_trash_stack_push (&compat_valloc_trash, mem);
+#endif
+}
+
+static void
+mem_error (const char *format,
+           ...)
+{
+  const char *pname;
+  va_list args;
+  /* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */
+  fputs ("\n***MEMORY-ERROR***: ", stderr);
+  pname = g_get_prgname();
+  fprintf (stderr, "%s[%ld]: GSlice: ", pname ? pname : "", (long)getpid());
+  va_start (args, format);
+  vfprintf (stderr, format, args);
+  va_end (args);
+  fputs ("\n", stderr);
+  abort();
+  _exit (1);
+}
+
+/* --- g-slice memory checker tree --- */
+typedef size_t SmcKType;                /* key type */
+typedef size_t SmcVType;                /* value type */
+typedef struct {
+  SmcKType key;
+  SmcVType value;
+} SmcEntry;
+static void             smc_tree_insert      (SmcKType  key,
+                                              SmcVType  value);
+static gboolean         smc_tree_lookup      (SmcKType  key,
+                                              SmcVType *value_p);
+static gboolean         smc_tree_remove      (SmcKType  key);
+
+
+/* --- g-slice memory checker implementation --- */
+static void
+smc_notify_alloc (void   *pointer,
+                  size_t  size)
+{
+  size_t adress = (size_t) pointer;
+  if (pointer)
+    smc_tree_insert (adress, size);
+}
+
+#if 0
+static void
+smc_notify_ignore (void *pointer)
+{
+  size_t adress = (size_t) pointer;
+  if (pointer)
+    smc_tree_remove (adress);
+}
+#endif
+
+static int
+smc_notify_free (void   *pointer,
+                 size_t  size)
+{
+  size_t adress = (size_t) pointer;
+  SmcVType real_size;
+  gboolean found_one;
+
+  if (!pointer)
+    return 1; /* ignore */
+  found_one = smc_tree_lookup (adress, &real_size);
+  if (!found_one)
+    {
+      fprintf (stderr, "GSlice: MemChecker: attempt to release non-allocated block: %p size=%" G_GSIZE_FORMAT "\n", pointer, size);
+      return 0;
+    }
+  if (real_size != size && (real_size || size))
+    {
+      fprintf (stderr, "GSlice: MemChecker: attempt to release block with invalid size: %p size=%" G_GSIZE_FORMAT " invalid-size=%" G_GSIZE_FORMAT "\n", pointer, real_size, size);
+      return 0;
+    }
+  if (!smc_tree_remove (adress))
+    {
+      fprintf (stderr, "GSlice: MemChecker: attempt to release non-allocated block: %p size=%" G_GSIZE_FORMAT "\n", pointer, size);
+      return 0;
+    }
+  return 1; /* all fine */
+}
+
+/* --- g-slice memory checker tree implementation --- */
+#define SMC_TRUNK_COUNT     (4093 /* 16381 */)          /* prime, to distribute trunk collisions (big, allocated just once) */
+#define SMC_BRANCH_COUNT    (511)                       /* prime, to distribute branch collisions */
+#define SMC_TRUNK_EXTENT    (SMC_BRANCH_COUNT * 2039)   /* key adress space per trunk, should distribute uniformly across BRANCH_COUNT */
+#define SMC_TRUNK_HASH(k)   ((k / SMC_TRUNK_EXTENT) % SMC_TRUNK_COUNT)  /* generate new trunk hash per megabyte (roughly) */
+#define SMC_BRANCH_HASH(k)  (k % SMC_BRANCH_COUNT)
+
+typedef struct {
+  SmcEntry    *entries;
+  unsigned int n_entries;
+} SmcBranch;
+
+static SmcBranch     **smc_tree_root = NULL;
+
+static void
+smc_tree_abort (int errval)
+{
+  const char *syserr = "unknown error";
+#if HAVE_STRERROR
+  syserr = strerror (errval);
+#endif
+  mem_error ("MemChecker: failure in debugging tree: %s", syserr);
+}
+
+static inline SmcEntry*
+smc_tree_branch_grow_L (SmcBranch   *branch,
+                        unsigned int index)
+{
+  unsigned int old_size = branch->n_entries * sizeof (branch->entries[0]);
+  unsigned int new_size = old_size + sizeof (branch->entries[0]);
+  SmcEntry *entry;
+  mem_assert (index <= branch->n_entries);
+  branch->entries = (SmcEntry*) realloc (branch->entries, new_size);
+  if (!branch->entries)
+    smc_tree_abort (errno);
+  entry = branch->entries + index;
+  g_memmove (entry + 1, entry, (branch->n_entries - index) * sizeof (entry[0]));
+  branch->n_entries += 1;
+  return entry;
+}
+
+static inline SmcEntry*
+smc_tree_branch_lookup_nearest_L (SmcBranch *branch,
+                                  SmcKType   key)
+{
+  unsigned int n_nodes = branch->n_entries, offs = 0;
+  SmcEntry *check = branch->entries;
+  int cmp = 0;
+  while (offs < n_nodes)
+    {
+      unsigned int i = (offs + n_nodes) >> 1;
+      check = branch->entries + i;
+      cmp = key < check->key ? -1 : key != check->key;
+      if (cmp == 0)
+        return check;                   /* return exact match */
+      else if (cmp < 0)
+        n_nodes = i;
+      else /* (cmp > 0) */
+        offs = i + 1;
+    }
+  /* check points at last mismatch, cmp > 0 indicates greater key */
+  return cmp > 0 ? check + 1 : check;   /* return insertion position for inexact match */
+}
+
+static void
+smc_tree_insert (SmcKType key,
+                 SmcVType value)
+{
+  unsigned int ix0, ix1;
+  SmcEntry *entry;
+
+  g_mutex_lock (smc_tree_mutex);
+  ix0 = SMC_TRUNK_HASH (key);
+  ix1 = SMC_BRANCH_HASH (key);
+  if (!smc_tree_root)
+    {
+      smc_tree_root = calloc (SMC_TRUNK_COUNT, sizeof (smc_tree_root[0]));
+      if (!smc_tree_root)
+        smc_tree_abort (errno);
+    }
+  if (!smc_tree_root[ix0])
+    {
+      smc_tree_root[ix0] = calloc (SMC_BRANCH_COUNT, sizeof (smc_tree_root[0][0]));
+      if (!smc_tree_root[ix0])
+        smc_tree_abort (errno);
+    }
+  entry = smc_tree_branch_lookup_nearest_L (&smc_tree_root[ix0][ix1], key);
+  if (!entry ||                                                                         /* need create */
+      entry >= smc_tree_root[ix0][ix1].entries + smc_tree_root[ix0][ix1].n_entries ||   /* need append */
+      entry->key != key)                                                                /* need insert */
+    entry = smc_tree_branch_grow_L (&smc_tree_root[ix0][ix1], entry - smc_tree_root[ix0][ix1].entries);
+  entry->key = key;
+  entry->value = value;
+  g_mutex_unlock (smc_tree_mutex);
+}
+
+static gboolean
+smc_tree_lookup (SmcKType  key,
+                 SmcVType *value_p)
+{
+  SmcEntry *entry = NULL;
+  unsigned int ix0 = SMC_TRUNK_HASH (key), ix1 = SMC_BRANCH_HASH (key);
+  gboolean found_one = FALSE;
+  *value_p = 0;
+  g_mutex_lock (smc_tree_mutex);
+  if (smc_tree_root && smc_tree_root[ix0])
+    {
+      entry = smc_tree_branch_lookup_nearest_L (&smc_tree_root[ix0][ix1], key);
+      if (entry &&
+          entry < smc_tree_root[ix0][ix1].entries + smc_tree_root[ix0][ix1].n_entries &&
+          entry->key == key)
+        {
+          found_one = TRUE;
+          *value_p = entry->value;
+        }
+    }
+  g_mutex_unlock (smc_tree_mutex);
+  return found_one;
+}
+
+static gboolean
+smc_tree_remove (SmcKType key)
+{
+  unsigned int ix0 = SMC_TRUNK_HASH (key), ix1 = SMC_BRANCH_HASH (key);
+  gboolean found_one = FALSE;
+  g_mutex_lock (smc_tree_mutex);
+  if (smc_tree_root && smc_tree_root[ix0])
+    {
+      SmcEntry *entry = smc_tree_branch_lookup_nearest_L (&smc_tree_root[ix0][ix1], key);
+      if (entry &&
+          entry < smc_tree_root[ix0][ix1].entries + smc_tree_root[ix0][ix1].n_entries &&
+          entry->key == key)
+        {
+          unsigned int i = entry - smc_tree_root[ix0][ix1].entries;
+          smc_tree_root[ix0][ix1].n_entries -= 1;
+          g_memmove (entry, entry + 1, (smc_tree_root[ix0][ix1].n_entries - i) * sizeof (entry[0]));
+          if (!smc_tree_root[ix0][ix1].n_entries)
+            {
+              /* avoid useless pressure on the memory system */
+              free (smc_tree_root[ix0][ix1].entries);
+              smc_tree_root[ix0][ix1].entries = NULL;
+            }
+          found_one = TRUE;
+        }
+    }
+  g_mutex_unlock (smc_tree_mutex);
+  return found_one;
+}
+
+#ifdef G_ENABLE_DEBUG
+void
+g_slice_debug_tree_statistics (void)
+{
+  g_mutex_lock (smc_tree_mutex);
+  if (smc_tree_root)
+    {
+      unsigned int i, j, t = 0, o = 0, b = 0, su = 0, ex = 0, en = 4294967295u;
+      double tf, bf;
+      for (i = 0; i < SMC_TRUNK_COUNT; i++)
+        if (smc_tree_root[i])
+          {
+            t++;
+            for (j = 0; j < SMC_BRANCH_COUNT; j++)
+              if (smc_tree_root[i][j].n_entries)
+                {
+                  b++;
+                  su += smc_tree_root[i][j].n_entries;
+                  en = MIN (en, smc_tree_root[i][j].n_entries);
+                  ex = MAX (ex, smc_tree_root[i][j].n_entries);
+                }
+              else if (smc_tree_root[i][j].entries)
+                o++; /* formerly used, now empty */
+          }
+      en = b ? en : 0;
+      tf = MAX (t, 1.0); /* max(1) to be a valid divisor */
+      bf = MAX (b, 1.0); /* max(1) to be a valid divisor */
+      fprintf (stderr, "GSlice: MemChecker: %u trunks, %u branches, %u old branches\n", t, b, o);
+      fprintf (stderr, "GSlice: MemChecker: %f branches per trunk, %.2f%% utilization\n",
+               b / tf,
+               100.0 - (SMC_BRANCH_COUNT - b / tf) / (0.01 * SMC_BRANCH_COUNT));
+      fprintf (stderr, "GSlice: MemChecker: %f entries per branch, %u minimum, %u maximum\n",
+               su / bf, en, ex);
+    }
+  else
+    fprintf (stderr, "GSlice: MemChecker: root=NULL\n");
+  g_mutex_unlock (smc_tree_mutex);
+  
+  /* sample statistics (beast + GSLice + 24h scripted core & GUI activity):
+   *  PID %CPU %MEM   VSZ  RSS      COMMAND
+   * 8887 30.3 45.8 456068 414856   beast-0.7.1 empty.bse
+   * $ cat /proc/8887/statm # total-program-size resident-set-size shared-pages text/code data/stack library dirty-pages
+   * 114017 103714 2354 344 0 108676 0
+   * $ cat /proc/8887/status 
+   * Name:   beast-0.7.1
+   * VmSize:   456068 kB
+   * VmLck:         0 kB
+   * VmRSS:    414856 kB
+   * VmData:   434620 kB
+   * VmStk:        84 kB
+   * VmExe:      1376 kB
+   * VmLib:     13036 kB
+   * VmPTE:       456 kB
+   * Threads:        3
+   * (gdb) print g_slice_debug_tree_statistics ()
+   * GSlice: MemChecker: 422 trunks, 213068 branches, 0 old branches
+   * GSlice: MemChecker: 504.900474 branches per trunk, 98.81% utilization
+   * GSlice: MemChecker: 4.965039 entries per branch, 1 minimum, 37 maximum
+   */
+}
+#endif /* G_ENABLE_DEBUG */
+
+#define __G_SLICE_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gslice.h b/navit/navit/support/glib/gslice.h
new file mode 100644 (file)
index 0000000..f9cc644
--- /dev/null
@@ -0,0 +1,90 @@
+/* GLIB sliced memory - fast threaded memory chunk allocator
+ * Copyright (C) 2005 Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_SLICE_H__
+#define __G_SLICE_H__
+
+#ifndef __G_MEM_H__
+#error Include <glib.h> instead of <gslice.h>
+#endif
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* slices - fast allocation/release of small memory blocks
+ */
+gpointer g_slice_alloc                 (gsize         block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_slice_alloc0                (gsize         block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+gpointer g_slice_copy                   (gsize         block_size,
+                                         gconstpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
+void     g_slice_free1                 (gsize         block_size,
+                                        gpointer      mem_block);
+void     g_slice_free_chain_with_offset (gsize         block_size,
+                                        gpointer      mem_chain,
+                                        gsize         next_offset);
+#define  g_slice_new(type)      ((type*) g_slice_alloc (sizeof (type)))
+#define  g_slice_new0(type)     ((type*) g_slice_alloc0 (sizeof (type)))
+/* MemoryBlockType *
+ *       g_slice_dup                    (MemoryBlockType,
+ *                                      MemoryBlockType *mem_block);
+ *       g_slice_free                   (MemoryBlockType,
+ *                                      MemoryBlockType *mem_block);
+ *       g_slice_free_chain             (MemoryBlockType,
+ *                                       MemoryBlockType *first_chain_block,
+ *                                       memory_block_next_field);
+ * pseudo prototypes for the macro
+ * definitions following below.
+ */
+
+/* we go through extra hoops to ensure type safety */
+#define g_slice_dup(type, mem)                                  \
+  (1 ? (type*) g_slice_copy (sizeof (type), (mem))              \
+     : ((void) ((type*) 0 == (mem)), (type*) 0))
+#define g_slice_free(type, mem)                                do {    \
+  if (1) g_slice_free1 (sizeof (type), (mem));                 \
+  else   (void) ((type*) 0 == (mem));                          \
+} while (0)
+#define g_slice_free_chain(type, mem_chain, next)      do {    \
+  if (1) g_slice_free_chain_with_offset (sizeof (type),                \
+                 (mem_chain), G_STRUCT_OFFSET (type, next));   \
+  else   (void) ((type*) 0 == (mem_chain));                    \
+} while (0)
+
+
+/* --- internal debugging API --- */
+typedef enum {
+  G_SLICE_CONFIG_ALWAYS_MALLOC = 1,
+  G_SLICE_CONFIG_BYPASS_MAGAZINES,
+  G_SLICE_CONFIG_WORKING_SET_MSECS,
+  G_SLICE_CONFIG_COLOR_INCREMENT,
+  G_SLICE_CONFIG_CHUNK_SIZES,
+  G_SLICE_CONFIG_CONTENTION_COUNTER
+} GSliceConfig;
+void     g_slice_set_config       (GSliceConfig ckey, gint64 value);
+gint64   g_slice_get_config       (GSliceConfig ckey);
+gint64*  g_slice_get_config_state  (GSliceConfig ckey, gint64 address, guint *n_values);
+
+G_END_DECLS
+
+#endif /* __G_SLICE_H__ */
diff --git a/navit/navit/support/glib/gstrfuncs.c b/navit/navit/support/glib/gstrfuncs.c
new file mode 100644 (file)
index 0000000..f45bbf7
--- /dev/null
@@ -0,0 +1,3103 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#define _GNU_SOURCE            /* For stpcpy */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <ctype.h>             /* For tolower() */
+#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
+#include <signal.h>
+#endif
+
+#include "glib.h"
+#include "gprintf.h"
+#include "gprintfint.h"
+#include "glibintl.h"
+
+#include "galias.h"
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#endif
+
+/* do not include <unistd.h> in this place since it
+ * interferes with g_strsignal() on some OSes
+ */
+
+static const guint16 ascii_table_data[256] = {
+  0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+  0x004, 0x104, 0x104, 0x004, 0x104, 0x104, 0x004, 0x004,
+  0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+  0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+  0x140, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+  0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+  0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459,
+  0x459, 0x459, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+  0x0d0, 0x653, 0x653, 0x653, 0x653, 0x653, 0x653, 0x253,
+  0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253,
+  0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253,
+  0x253, 0x253, 0x253, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0,
+  0x0d0, 0x473, 0x473, 0x473, 0x473, 0x473, 0x473, 0x073,
+  0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073,
+  0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073,
+  0x073, 0x073, 0x073, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x004
+  /* the upper 128 are all zeroes */
+};
+
+const guint16 * const g_ascii_table = ascii_table_data;
+
+gchar*
+g_strdup (const gchar *str)
+{
+  gchar *new_str;
+  gsize length;
+
+  if (str)
+    {
+      length = strlen (str) + 1;
+      new_str = g_new (char, length);
+      memcpy (new_str, str, length);
+    }
+  else
+    new_str = NULL;
+
+  return new_str;
+}
+
+gpointer
+g_memdup (gconstpointer mem,
+         guint         byte_size)
+{
+  gpointer new_mem;
+
+  if (mem)
+    {
+      new_mem = g_malloc (byte_size);
+      memcpy (new_mem, mem, byte_size);
+    }
+  else
+    new_mem = NULL;
+
+  return new_mem;
+}
+
+/**
+ * g_strndup:
+ * @str: the string to duplicate
+ * @n: the maximum number of bytes to copy from @str
+ *
+ * Duplicates the first @n bytes of a string, returning a newly-allocated
+ * buffer @n + 1 bytes long which will always be nul-terminated.
+ * If @str is less than @n bytes long the buffer is padded with nuls.
+ * If @str is %NULL it returns %NULL.
+ * The returned value should be freed when no longer needed.
+ * 
+ * <note><para>
+ * To copy a number of characters from a UTF-8 encoded string, use
+ * g_utf8_strncpy() instead.
+ * </para></note>
+ * 
+ * Returns: a newly-allocated buffer containing the first @n bytes 
+ *          of @str, nul-terminated 
+ */
+gchar*
+g_strndup (const gchar *str,
+          gsize        n)    
+{
+  gchar *new_str;
+
+  if (str)
+    {
+      new_str = g_new (gchar, n + 1);
+      strncpy (new_str, str, n);
+      new_str[n] = '\0';
+    }
+  else
+    new_str = NULL;
+
+  return new_str;
+}
+
+/**
+ * g_strnfill:
+ * @length: the length of the new string
+ * @fill_char: the byte to fill the string with
+ *
+ * Creates a new string @length bytes long filled with @fill_char.
+ * The returned string should be freed when no longer needed.
+ * 
+ * Returns: a newly-allocated string filled the @fill_char
+ */
+gchar*
+g_strnfill (gsize length,     
+           gchar fill_char)
+{
+  gchar *str;
+
+  str = g_new (gchar, length + 1);
+  memset (str, (guchar)fill_char, length);
+  str[length] = '\0';
+
+  return str;
+}
+
+/**
+ * g_stpcpy:
+ * @dest: destination buffer.
+ * @src: source string.
+ * 
+ * Copies a nul-terminated string into the dest buffer, include the
+ * trailing nul, and return a pointer to the trailing nul byte.
+ * This is useful for concatenating multiple strings together
+ * without having to repeatedly scan for the end.
+ * 
+ * Return value: a pointer to trailing nul byte.
+ **/
+gchar *
+g_stpcpy (gchar       *dest,
+          const gchar *src)
+{
+#ifdef HAVE_STPCPY
+  g_return_val_if_fail (dest != NULL, NULL);
+  g_return_val_if_fail (src != NULL, NULL);
+  return stpcpy (dest, src);
+#else
+  register gchar *d = dest;
+  register const gchar *s = src;
+
+  g_return_val_if_fail (dest != NULL, NULL);
+  g_return_val_if_fail (src != NULL, NULL);
+  do
+    *d++ = *s;
+  while (*s++ != '\0');
+
+  return d - 1;
+#endif
+}
+
+gchar*
+g_strdup_vprintf (const gchar *format,
+                 va_list      args)
+{
+  gchar *string = NULL;
+
+  g_vasprintf (&string, format, args);
+
+  return string;
+}
+
+gchar*
+g_strdup_printf (const gchar *format,
+                ...)
+{
+  gchar *buffer;
+  va_list args;
+
+  va_start (args, format);
+  buffer = g_strdup_vprintf (format, args);
+  va_end (args);
+
+  return buffer;
+}
+
+gchar*
+g_strconcat (const gchar *string1, ...)
+{
+  gsize          l;     
+  va_list args;
+  gchar          *s;
+  gchar          *concat;
+  gchar   *ptr;
+
+  if (!string1)
+    return NULL;
+
+  l = 1 + strlen (string1);
+  va_start (args, string1);
+  s = va_arg (args, gchar*);
+  while (s)
+    {
+      l += strlen (s);
+      s = va_arg (args, gchar*);
+    }
+  va_end (args);
+
+  concat = g_new (gchar, l);
+  ptr = concat;
+
+  ptr = g_stpcpy (ptr, string1);
+  va_start (args, string1);
+  s = va_arg (args, gchar*);
+  while (s)
+    {
+      ptr = g_stpcpy (ptr, s);
+      s = va_arg (args, gchar*);
+    }
+  va_end (args);
+
+  return concat;
+}
+
+/**
+ * g_strtod:
+ * @nptr:    the string to convert to a numeric value.
+ * @endptr:  if non-%NULL, it returns the character after
+ *           the last character used in the conversion.
+ * 
+ * Converts a string to a #gdouble value.
+ * It calls the standard strtod() function to handle the conversion, but
+ * if the string is not completely converted it attempts the conversion
+ * again with g_ascii_strtod(), and returns the best match.
+ *
+ * This function should seldomly be used. The normal situation when reading
+ * numbers not for human consumption is to use g_ascii_strtod(). Only when
+ * you know that you must expect both locale formatted and C formatted numbers
+ * should you use this. Make sure that you don't pass strings such as comma
+ * separated lists of values, since the commas may be interpreted as a decimal
+ * point in some locales, causing unexpected results.
+ * 
+ * Return value: the #gdouble value.
+ **/
+gdouble
+g_strtod (const gchar *nptr,
+         gchar      **endptr)
+{
+  gchar *fail_pos_1;
+  gchar *fail_pos_2;
+  gdouble val_1;
+  gdouble val_2 = 0;
+
+  g_return_val_if_fail (nptr != NULL, 0);
+
+  fail_pos_1 = NULL;
+  fail_pos_2 = NULL;
+
+  val_1 = strtod (nptr, &fail_pos_1);
+
+  if (fail_pos_1 && fail_pos_1[0] != 0)
+    val_2 = g_ascii_strtod (nptr, &fail_pos_2);
+
+  if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
+    {
+      if (endptr)
+       *endptr = fail_pos_1;
+      return val_1;
+    }
+  else
+    {
+      if (endptr)
+       *endptr = fail_pos_2;
+      return val_2;
+    }
+}
+
+/**
+ * g_ascii_strtod:
+ * @nptr:    the string to convert to a numeric value.
+ * @endptr:  if non-%NULL, it returns the character after
+ *           the last character used in the conversion.
+ * 
+ * Converts a string to a #gdouble value.
+ *
+ * This function behaves like the standard strtod() function
+ * does in the C locale. It does this without actually changing 
+ * the current locale, since that would not be thread-safe. 
+ * A limitation of the implementation is that this function
+ * will still accept localized versions of infinities and NANs. 
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtod() function.
+ *
+ * To convert from a #gdouble to a string in a locale-insensitive
+ * way, use g_ascii_dtostr().
+ *
+ * If the correct value would cause overflow, plus or minus %HUGE_VAL
+ * is returned (according to the sign of the value), and %ERANGE is
+ * stored in %errno. If the correct value would cause underflow,
+ * zero is returned and %ERANGE is stored in %errno.
+ * 
+ * This function resets %errno before calling strtod() so that
+ * you can reliably detect overflow and underflow.
+ *
+ * Return value: the #gdouble value.
+ **/
+gdouble
+g_ascii_strtod (const gchar *nptr,
+               gchar      **endptr)
+{
+  gchar *fail_pos;
+  gdouble val;
+  struct lconv *locale_data;
+  const char *decimal_point;
+  int decimal_point_len;
+  const char *p, *decimal_point_pos;
+  const char *end = NULL; /* Silence gcc */
+  int strtod_errno;
+
+  g_return_val_if_fail (nptr != NULL, 0);
+
+  fail_pos = NULL;
+
+  locale_data = localeconv ();
+  decimal_point = locale_data->decimal_point;
+  decimal_point_len = strlen (decimal_point);
+
+  g_assert (decimal_point_len != 0);
+  
+  decimal_point_pos = NULL;
+  end = NULL;
+
+  if (decimal_point[0] != '.' || 
+      decimal_point[1] != 0)
+    {
+      p = nptr;
+      /* Skip leading space */
+      while (g_ascii_isspace (*p))
+       p++;
+      
+      /* Skip leading optional sign */
+      if (*p == '+' || *p == '-')
+       p++;
+      
+      if (p[0] == '0' && 
+         (p[1] == 'x' || p[1] == 'X'))
+       {
+         p += 2;
+         /* HEX - find the (optional) decimal point */
+         
+         while (g_ascii_isxdigit (*p))
+           p++;
+         
+         if (*p == '.')
+           decimal_point_pos = p++;
+             
+         while (g_ascii_isxdigit (*p))
+           p++;
+         
+         if (*p == 'p' || *p == 'P')
+           p++;
+         if (*p == '+' || *p == '-')
+           p++;
+         while (g_ascii_isdigit (*p))
+           p++;
+
+         end = p;
+       }
+      else if (g_ascii_isdigit (*p) || *p == '.')
+       {
+         while (g_ascii_isdigit (*p))
+           p++;
+         
+         if (*p == '.')
+           decimal_point_pos = p++;
+         
+         while (g_ascii_isdigit (*p))
+           p++;
+         
+         if (*p == 'e' || *p == 'E')
+           p++;
+         if (*p == '+' || *p == '-')
+           p++;
+         while (g_ascii_isdigit (*p))
+           p++;
+
+         end = p;
+       }
+      /* For the other cases, we need not convert the decimal point */
+    }
+
+  if (decimal_point_pos)
+    {
+      char *copy, *c;
+
+      /* We need to convert the '.' to the locale specific decimal point */
+      copy = g_malloc (end - nptr + 1 + decimal_point_len);
+      
+      c = copy;
+      memcpy (c, nptr, decimal_point_pos - nptr);
+      c += decimal_point_pos - nptr;
+      memcpy (c, decimal_point, decimal_point_len);
+      c += decimal_point_len;
+      memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
+      c += end - (decimal_point_pos + 1);
+      *c = 0;
+
+      errno = 0;
+      val = strtod (copy, &fail_pos);
+      strtod_errno = errno;
+
+      if (fail_pos)
+       {
+         if (fail_pos - copy > decimal_point_pos - nptr)
+           fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
+         else
+           fail_pos = (char *)nptr + (fail_pos - copy);
+       }
+      
+      g_free (copy);
+         
+    }
+  else if (end)
+    {
+      char *copy;
+      
+      copy = g_malloc (end - (char *)nptr + 1);
+      memcpy (copy, nptr, end - nptr);
+      *(copy + (end - (char *)nptr)) = 0;
+      
+      errno = 0;
+      val = strtod (copy, &fail_pos);
+      strtod_errno = errno;
+
+      if (fail_pos)
+       {
+         fail_pos = (char *)nptr + (fail_pos - copy);
+       }
+      
+      g_free (copy);
+    }
+  else
+    {
+      errno = 0;
+      val = strtod (nptr, &fail_pos);
+      strtod_errno = errno;
+    }
+
+  if (endptr)
+    *endptr = fail_pos;
+
+  errno = strtod_errno;
+
+  return val;
+}
+
+
+/**
+ * g_ascii_dtostr:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @d: The #gdouble to convert
+ *
+ * Converts a #gdouble to a string, using the '.' as
+ * decimal point. 
+ * 
+ * This functions generates enough precision that converting
+ * the string back using g_ascii_strtod() gives the same machine-number
+ * (on machines with IEEE compatible 64bit doubles). It is
+ * guaranteed that the size of the resulting string will never
+ * be larger than @G_ASCII_DTOSTR_BUF_SIZE bytes.
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_dtostr (gchar       *buffer,
+               gint         buf_len,
+               gdouble      d)
+{
+  return g_ascii_formatd (buffer, buf_len, "%.17g", d);
+}
+
+/**
+ * g_ascii_formatd:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @format: The printf()-style format to use for the
+ *          code to use for converting. 
+ * @d: The #gdouble to convert
+ *
+ * Converts a #gdouble to a string, using the '.' as
+ * decimal point. To format the number you pass in
+ * a printf()-style format string. Allowed conversion
+ * specifiers are 'e', 'E', 'f', 'F', 'g' and 'G'. 
+ * 
+ * If you just want to want to serialize the value into a
+ * string, use g_ascii_dtostr().
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_formatd (gchar       *buffer,
+                gint         buf_len,
+                const gchar *format,
+                gdouble      d)
+{
+  struct lconv *locale_data;
+  const char *decimal_point;
+  int decimal_point_len;
+  gchar *p;
+  int rest_len;
+  gchar format_char;
+
+  g_return_val_if_fail (buffer != NULL, NULL);
+  g_return_val_if_fail (format[0] == '%', NULL);
+  g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL);
+  format_char = format[strlen (format) - 1];
+  
+  g_return_val_if_fail (format_char == 'e' || format_char == 'E' ||
+                       format_char == 'f' || format_char == 'F' ||
+                       format_char == 'g' || format_char == 'G',
+                       NULL);
+
+  if (format[0] != '%')
+    return NULL;
+
+  if (strpbrk (format + 1, "'l%"))
+    return NULL;
+
+  if (!(format_char == 'e' || format_char == 'E' ||
+       format_char == 'f' || format_char == 'F' ||
+       format_char == 'g' || format_char == 'G'))
+    return NULL;
+
+      
+  _g_snprintf (buffer, buf_len, format, d);
+
+  locale_data = localeconv ();
+  decimal_point = locale_data->decimal_point;
+  decimal_point_len = strlen (decimal_point);
+
+  g_assert (decimal_point_len != 0);
+
+  if (decimal_point[0] != '.' ||
+      decimal_point[1] != 0)
+    {
+      p = buffer;
+
+      while (g_ascii_isspace (*p))
+       p++;
+
+      if (*p == '+' || *p == '-')
+       p++;
+
+      while (isdigit ((guchar)*p))
+       p++;
+
+      if (strncmp (p, decimal_point, decimal_point_len) == 0)
+       {
+         *p = '.';
+         p++;
+         if (decimal_point_len > 1) 
+            {
+             rest_len = strlen (p + (decimal_point_len-1));
+             memmove (p, p + (decimal_point_len-1), rest_len);
+             p[rest_len] = 0;
+           }
+       }
+    }
+  
+  return buffer;
+}
+
+static guint64
+g_parse_long_long (const gchar  *nptr,
+                  const gchar **endptr,
+                  guint         base,
+                  gboolean     *negative)
+{
+  /* this code is based on on the strtol(3) code from GNU libc released under
+   * the GNU Lesser General Public License.
+   *
+   * Copyright (C) 1991,92,94,95,96,97,98,99,2000,01,02
+   *        Free Software Foundation, Inc.
+   */
+#define ISSPACE(c)             ((c) == ' ' || (c) == '\f' || (c) == '\n' || \
+                                (c) == '\r' || (c) == '\t' || (c) == '\v')
+#define ISUPPER(c)             ((c) >= 'A' && (c) <= 'Z')
+#define ISLOWER(c)             ((c) >= 'a' && (c) <= 'z')
+#define ISALPHA(c)             (ISUPPER (c) || ISLOWER (c))
+#define        TOUPPER(c)              (ISLOWER (c) ? (c) - 'a' + 'A' : (c))
+#define        TOLOWER(c)              (ISUPPER (c) ? (c) - 'A' + 'a' : (c))
+  gboolean overflow;
+  guint64 cutoff;
+  guint64 cutlim;
+  guint64 ui64;
+  const gchar *s, *save;
+  guchar c;
+  
+  g_return_val_if_fail (nptr != NULL, 0);
+  
+  *negative = FALSE;
+  if (base == 1 || base > 36)
+    {
+      errno = EINVAL;
+      if (endptr)
+       *endptr = nptr;
+      return 0;
+    }
+  
+  save = s = nptr;
+  
+  /* Skip white space.  */
+  while (ISSPACE (*s))
+    ++s;
+
+  if (G_UNLIKELY (!*s))
+    goto noconv;
+  
+  /* Check for a sign.  */
+  if (*s == '-')
+    {
+      *negative = TRUE;
+      ++s;
+    }
+  else if (*s == '+')
+    ++s;
+  
+  /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */
+  if (*s == '0')
+    {
+      if ((base == 0 || base == 16) && TOUPPER (s[1]) == 'X')
+       {
+         s += 2;
+         base = 16;
+       }
+      else if (base == 0)
+       base = 8;
+    }
+  else if (base == 0)
+    base = 10;
+  
+  /* Save the pointer so we can check later if anything happened.  */
+  save = s;
+  cutoff = G_MAXUINT64 / base;
+  cutlim = G_MAXUINT64 % base;
+  
+  overflow = FALSE;
+  ui64 = 0;
+  c = *s;
+  for (; c; c = *++s)
+    {
+      if (c >= '0' && c <= '9')
+       c -= '0';
+      else if (ISALPHA (c))
+       c = TOUPPER (c) - 'A' + 10;
+      else
+       break;
+      if (c >= base)
+       break;
+      /* Check for overflow.  */
+      if (ui64 > cutoff || (ui64 == cutoff && c > cutlim))
+       overflow = TRUE;
+      else
+       {
+         ui64 *= base;
+         ui64 += c;
+       }
+    }
+  
+  /* Check if anything actually happened.  */
+  if (s == save)
+    goto noconv;
+  
+  /* Store in ENDPTR the address of one character
+     past the last character we converted.  */
+  if (endptr)
+    *endptr = s;
+  
+  if (G_UNLIKELY (overflow))
+    {
+      errno = ERANGE;
+      return G_MAXUINT64;
+    }
+
+  return ui64;
+  
+ noconv:
+  /* We must handle a special case here: the base is 0 or 16 and the
+     first two characters are '0' and 'x', but the rest are no
+     hexadecimal digits.  This is no error case.  We return 0 and
+     ENDPTR points to the `x`.  */
+  if (endptr)
+    {
+      if (save - nptr >= 2 && TOUPPER (save[-1]) == 'X'
+         && save[-2] == '0')
+       *endptr = &save[-1];
+      else
+       /*  There was no number to convert.  */
+       *endptr = nptr;
+    }
+  return 0;
+}
+
+/**
+ * g_ascii_strtoull:
+ * @nptr:    the string to convert to a numeric value.
+ * @endptr:  if non-%NULL, it returns the character after
+ *           the last character used in the conversion.
+ * @base:    to be used for the conversion, 2..36 or 0
+ *
+ * Converts a string to a #guint64 value.
+ * This function behaves like the standard strtoull() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtoull() function.
+ *
+ * If the correct value would cause overflow, %G_MAXUINT64
+ * is returned, and %ERANGE is stored in %errno.  If the base is
+ * outside the valid range, zero is returned, and %EINVAL is stored
+ * in %errno.  If the string conversion fails, zero is returned, and
+ * @endptr returns @nptr (if @endptr is non-%NULL).
+ *
+ * Return value: the #guint64 value or zero on error.
+ *
+ * Since: 2.2
+ **/
+guint64
+g_ascii_strtoull (const gchar *nptr,
+                 gchar      **endptr,
+                 guint        base)
+{
+  gboolean negative;
+  guint64 result;
+
+  result = g_parse_long_long (nptr, (const gchar **) endptr, base, &negative);
+
+  /* Return the result of the appropriate sign.  */
+  return negative ? -result : result;
+}
+
+/**
+ * g_ascii_strtoll:
+ * @nptr:    the string to convert to a numeric value.
+ * @endptr:  if non-%NULL, it returns the character after
+ *           the last character used in the conversion.
+ * @base:    to be used for the conversion, 2..36 or 0
+ *
+ * Converts a string to a #gint64 value.
+ * This function behaves like the standard strtoll() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale independent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtoll() function.
+ *
+ * If the correct value would cause overflow, %G_MAXINT64 or %G_MININT64
+ * is returned, and %ERANGE is stored in %errno.  If the base is
+ * outside the valid range, zero is returned, and %EINVAL is stored
+ * in %errno.  If the string conversion fails, zero is returned, and
+ * @endptr returns @nptr (if @endptr is non-%NULL).
+ *
+ * Return value: the #gint64 value or zero on error.
+ *
+ * Since: 2.12
+ **/
+gint64 
+g_ascii_strtoll (const gchar *nptr,
+                gchar      **endptr,
+                guint        base)
+{
+  gboolean negative;
+  guint64 result;
+
+  result = g_parse_long_long (nptr, (const gchar **) endptr, base, &negative);
+
+  if (negative && result > (guint64) G_MININT64)
+    {
+      errno = ERANGE;
+      return G_MININT64;
+    }
+  else if (!negative && result > (guint64) G_MAXINT64)
+    {
+      errno = ERANGE;
+      return G_MAXINT64;
+    }
+  else if (negative)
+    return - (gint64) result;
+  else
+    return (gint64) result;
+}
+
+G_CONST_RETURN gchar*
+g_strerror (gint errnum)
+{
+  static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+  char *msg;
+  int saved_errno = errno;
+
+#ifdef HAVE_STRERROR
+  const char *msg_locale;
+
+  msg_locale = strerror (errnum);
+  if (g_get_charset (NULL))
+    {
+      errno = saved_errno;
+      return msg_locale;
+    }
+  else
+    {
+      gchar *msg_utf8 = g_locale_to_utf8 (msg_locale, -1, NULL, NULL, NULL);
+      if (msg_utf8)
+       {
+         /* Stick in the quark table so that we can return a static result
+          */
+         GQuark msg_quark = g_quark_from_string (msg_utf8);
+         g_free (msg_utf8);
+         
+         msg_utf8 = (gchar *) g_quark_to_string (msg_quark);
+         errno = saved_errno;
+         return msg_utf8;
+       }
+    }
+#elif NO_SYS_ERRLIST
+  switch (errnum)
+    {
+#ifdef E2BIG
+    case E2BIG: return "argument list too long";
+#endif
+#ifdef EACCES
+    case EACCES: return "permission denied";
+#endif
+#ifdef EADDRINUSE
+    case EADDRINUSE: return "address already in use";
+#endif
+#ifdef EADDRNOTAVAIL
+    case EADDRNOTAVAIL: return "can't assign requested address";
+#endif
+#ifdef EADV
+    case EADV: return "advertise error";
+#endif
+#ifdef EAFNOSUPPORT
+    case EAFNOSUPPORT: return "address family not supported by protocol family";
+#endif
+#ifdef EAGAIN
+    case EAGAIN: return "try again";
+#endif
+#ifdef EALIGN
+    case EALIGN: return "EALIGN";
+#endif
+#ifdef EALREADY
+    case EALREADY: return "operation already in progress";
+#endif
+#ifdef EBADE
+    case EBADE: return "bad exchange descriptor";
+#endif
+#ifdef EBADF
+    case EBADF: return "bad file number";
+#endif
+#ifdef EBADFD
+    case EBADFD: return "file descriptor in bad state";
+#endif
+#ifdef EBADMSG
+    case EBADMSG: return "not a data message";
+#endif
+#ifdef EBADR
+    case EBADR: return "bad request descriptor";
+#endif
+#ifdef EBADRPC
+    case EBADRPC: return "RPC structure is bad";
+#endif
+#ifdef EBADRQC
+    case EBADRQC: return "bad request code";
+#endif
+#ifdef EBADSLT
+    case EBADSLT: return "invalid slot";
+#endif
+#ifdef EBFONT
+    case EBFONT: return "bad font file format";
+#endif
+#ifdef EBUSY
+    case EBUSY: return "mount device busy";
+#endif
+#ifdef ECHILD
+    case ECHILD: return "no children";
+#endif
+#ifdef ECHRNG
+    case ECHRNG: return "channel number out of range";
+#endif
+#ifdef ECOMM
+    case ECOMM: return "communication error on send";
+#endif
+#ifdef ECONNABORTED
+    case ECONNABORTED: return "software caused connection abort";
+#endif
+#ifdef ECONNREFUSED
+    case ECONNREFUSED: return "connection refused";
+#endif
+#ifdef ECONNRESET
+    case ECONNRESET: return "connection reset by peer";
+#endif
+#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
+    case EDEADLK: return "resource deadlock avoided";
+#endif
+#ifdef EDEADLOCK
+    case EDEADLOCK: return "resource deadlock avoided";
+#endif
+#ifdef EDESTADDRREQ
+    case EDESTADDRREQ: return "destination address required";
+#endif
+#ifdef EDIRTY
+    case EDIRTY: return "mounting a dirty fs w/o force";
+#endif
+#ifdef EDOM
+    case EDOM: return "math argument out of range";
+#endif
+#ifdef EDOTDOT
+    case EDOTDOT: return "cross mount point";
+#endif
+#ifdef EDQUOT
+    case EDQUOT: return "disk quota exceeded";
+#endif
+#ifdef EDUPPKG
+    case EDUPPKG: return "duplicate package name";
+#endif
+#ifdef EEXIST
+    case EEXIST: return "file already exists";
+#endif
+#ifdef EFAULT
+    case EFAULT: return "bad address in system call argument";
+#endif
+#ifdef EFBIG
+    case EFBIG: return "file too large";
+#endif
+#ifdef EHOSTDOWN
+    case EHOSTDOWN: return "host is down";
+#endif
+#ifdef EHOSTUNREACH
+    case EHOSTUNREACH: return "host is unreachable";
+#endif
+#ifdef EIDRM
+    case EIDRM: return "identifier removed";
+#endif
+#ifdef EINIT
+    case EINIT: return "initialization error";
+#endif
+#ifdef EINPROGRESS
+    case EINPROGRESS: return "operation now in progress";
+#endif
+#ifdef EINTR
+    case EINTR: return "interrupted system call";
+#endif
+#ifdef EINVAL
+    case EINVAL: return "invalid argument";
+#endif
+#ifdef EIO
+    case EIO: return "I/O error";
+#endif
+#ifdef EISCONN
+    case EISCONN: return "socket is already connected";
+#endif
+#ifdef EISDIR
+    case EISDIR: return "is a directory";
+#endif
+#ifdef EISNAME
+    case EISNAM: return "is a name file";
+#endif
+#ifdef ELBIN
+    case ELBIN: return "ELBIN";
+#endif
+#ifdef EL2HLT
+    case EL2HLT: return "level 2 halted";
+#endif
+#ifdef EL2NSYNC
+    case EL2NSYNC: return "level 2 not synchronized";
+#endif
+#ifdef EL3HLT
+    case EL3HLT: return "level 3 halted";
+#endif
+#ifdef EL3RST
+    case EL3RST: return "level 3 reset";
+#endif
+#ifdef ELIBACC
+    case ELIBACC: return "can not access a needed shared library";
+#endif
+#ifdef ELIBBAD
+    case ELIBBAD: return "accessing a corrupted shared library";
+#endif
+#ifdef ELIBEXEC
+    case ELIBEXEC: return "can not exec a shared library directly";
+#endif
+#ifdef ELIBMAX
+    case ELIBMAX: return "attempting to link in more shared libraries than system limit";
+#endif
+#ifdef ELIBSCN
+    case ELIBSCN: return ".lib section in a.out corrupted";
+#endif
+#ifdef ELNRNG
+    case ELNRNG: return "link number out of range";
+#endif
+#ifdef ELOOP
+    case ELOOP: return "too many levels of symbolic links";
+#endif
+#ifdef EMFILE
+    case EMFILE: return "too many open files";
+#endif
+#ifdef EMLINK
+    case EMLINK: return "too many links";
+#endif
+#ifdef EMSGSIZE
+    case EMSGSIZE: return "message too long";
+#endif
+#ifdef EMULTIHOP
+    case EMULTIHOP: return "multihop attempted";
+#endif
+#ifdef ENAMETOOLONG
+    case ENAMETOOLONG: return "file name too long";
+#endif
+#ifdef ENAVAIL
+    case ENAVAIL: return "not available";
+#endif
+#ifdef ENET
+    case ENET: return "ENET";
+#endif
+#ifdef ENETDOWN
+    case ENETDOWN: return "network is down";
+#endif
+#ifdef ENETRESET
+    case ENETRESET: return "network dropped connection on reset";
+#endif
+#ifdef ENETUNREACH
+    case ENETUNREACH: return "network is unreachable";
+#endif
+#ifdef ENFILE
+    case ENFILE: return "file table overflow";
+#endif
+#ifdef ENOANO
+    case ENOANO: return "anode table overflow";
+#endif
+#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
+    case ENOBUFS: return "no buffer space available";
+#endif
+#ifdef ENOCSI
+    case ENOCSI: return "no CSI structure available";
+#endif
+#ifdef ENODATA
+    case ENODATA: return "no data available";
+#endif
+#ifdef ENODEV
+    case ENODEV: return "no such device";
+#endif
+#ifdef ENOENT
+    case ENOENT: return "no such file or directory";
+#endif
+#ifdef ENOEXEC
+    case ENOEXEC: return "exec format error";
+#endif
+#ifdef ENOLCK
+    case ENOLCK: return "no locks available";
+#endif
+#ifdef ENOLINK
+    case ENOLINK: return "link has be severed";
+#endif
+#ifdef ENOMEM
+    case ENOMEM: return "not enough memory";
+#endif
+#ifdef ENOMSG
+    case ENOMSG: return "no message of desired type";
+#endif
+#ifdef ENONET
+    case ENONET: return "machine is not on the network";
+#endif
+#ifdef ENOPKG
+    case ENOPKG: return "package not installed";
+#endif
+#ifdef ENOPROTOOPT
+    case ENOPROTOOPT: return "bad proocol option";
+#endif
+#ifdef ENOSPC
+    case ENOSPC: return "no space left on device";
+#endif
+#ifdef ENOSR
+    case ENOSR: return "out of stream resources";
+#endif
+#ifdef ENOSTR
+    case ENOSTR: return "not a stream device";
+#endif
+#ifdef ENOSYM
+    case ENOSYM: return "unresolved symbol name";
+#endif
+#ifdef ENOSYS
+    case ENOSYS: return "function not implemented";
+#endif
+#ifdef ENOTBLK
+    case ENOTBLK: return "block device required";
+#endif
+#ifdef ENOTCONN
+    case ENOTCONN: return "socket is not connected";
+#endif
+#ifdef ENOTDIR
+    case ENOTDIR: return "not a directory";
+#endif
+#ifdef ENOTEMPTY
+    case ENOTEMPTY: return "directory not empty";
+#endif
+#ifdef ENOTNAM
+    case ENOTNAM: return "not a name file";
+#endif
+#ifdef ENOTSOCK
+    case ENOTSOCK: return "socket operation on non-socket";
+#endif
+#ifdef ENOTTY
+    case ENOTTY: return "inappropriate device for ioctl";
+#endif
+#ifdef ENOTUNIQ
+    case ENOTUNIQ: return "name not unique on network";
+#endif
+#ifdef ENXIO
+    case ENXIO: return "no such device or address";
+#endif
+#ifdef EOPNOTSUPP
+    case EOPNOTSUPP: return "operation not supported on socket";
+#endif
+#ifdef EPERM
+    case EPERM: return "not owner";
+#endif
+#ifdef EPFNOSUPPORT
+    case EPFNOSUPPORT: return "protocol family not supported";
+#endif
+#ifdef EPIPE
+    case EPIPE: return "broken pipe";
+#endif
+#ifdef EPROCLIM
+    case EPROCLIM: return "too many processes";
+#endif
+#ifdef EPROCUNAVAIL
+    case EPROCUNAVAIL: return "bad procedure for program";
+#endif
+#ifdef EPROGMISMATCH
+    case EPROGMISMATCH: return "program version wrong";
+#endif
+#ifdef EPROGUNAVAIL
+    case EPROGUNAVAIL: return "RPC program not available";
+#endif
+#ifdef EPROTO
+    case EPROTO: return "protocol error";
+#endif
+#ifdef EPROTONOSUPPORT
+    case EPROTONOSUPPORT: return "protocol not suppored";
+#endif
+#ifdef EPROTOTYPE
+    case EPROTOTYPE: return "protocol wrong type for socket";
+#endif
+#ifdef ERANGE
+    case ERANGE: return "math result unrepresentable";
+#endif
+#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
+    case EREFUSED: return "EREFUSED";
+#endif
+#ifdef EREMCHG
+    case EREMCHG: return "remote address changed";
+#endif
+#ifdef EREMDEV
+    case EREMDEV: return "remote device";
+#endif
+#ifdef EREMOTE
+    case EREMOTE: return "pathname hit remote file system";
+#endif
+#ifdef EREMOTEIO
+    case EREMOTEIO: return "remote i/o error";
+#endif
+#ifdef EREMOTERELEASE
+    case EREMOTERELEASE: return "EREMOTERELEASE";
+#endif
+#ifdef EROFS
+    case EROFS: return "read-only file system";
+#endif
+#ifdef ERPCMISMATCH
+    case ERPCMISMATCH: return "RPC version is wrong";
+#endif
+#ifdef ERREMOTE
+    case ERREMOTE: return "object is remote";
+#endif
+#ifdef ESHUTDOWN
+    case ESHUTDOWN: return "can't send afer socket shutdown";
+#endif
+#ifdef ESOCKTNOSUPPORT
+    case ESOCKTNOSUPPORT: return "socket type not supported";
+#endif
+#ifdef ESPIPE
+    case ESPIPE: return "invalid seek";
+#endif
+#ifdef ESRCH
+    case ESRCH: return "no such process";
+#endif
+#ifdef ESRMNT
+    case ESRMNT: return "srmount error";
+#endif
+#ifdef ESTALE
+    case ESTALE: return "stale remote file handle";
+#endif
+#ifdef ESUCCESS
+    case ESUCCESS: return "Error 0";
+#endif
+#ifdef ETIME
+    case ETIME: return "timer expired";
+#endif
+#ifdef ETIMEDOUT
+    case ETIMEDOUT: return "connection timed out";
+#endif
+#ifdef ETOOMANYREFS
+    case ETOOMANYREFS: return "too many references: can't splice";
+#endif
+#ifdef ETXTBSY
+    case ETXTBSY: return "text file or pseudo-device busy";
+#endif
+#ifdef EUCLEAN
+    case EUCLEAN: return "structure needs cleaning";
+#endif
+#ifdef EUNATCH
+    case EUNATCH: return "protocol driver not attached";
+#endif
+#ifdef EUSERS
+    case EUSERS: return "too many users";
+#endif
+#ifdef EVERSION
+    case EVERSION: return "version mismatch";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+    case EWOULDBLOCK: return "operation would block";
+#endif
+#ifdef EXDEV
+    case EXDEV: return "cross-domain link";
+#endif
+#ifdef EXFULL
+    case EXFULL: return "message tables full";
+#endif
+    }
+#else /* NO_SYS_ERRLIST */
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+
+  if ((errnum > 0) && (errnum <= sys_nerr))
+    return sys_errlist [errnum];
+#endif /* NO_SYS_ERRLIST */
+
+  msg = g_static_private_get (&msg_private);
+  if (!msg)
+    {
+      msg = g_new (gchar, 64);
+      g_static_private_set (&msg_private, msg, g_free);
+    }
+
+  _g_sprintf (msg, "unknown error (%d)", errnum);
+
+  errno = saved_errno;
+  return msg;
+}
+
+G_CONST_RETURN gchar*
+g_strsignal (gint signum)
+{
+  static GStaticPrivate msg_private = G_STATIC_PRIVATE_INIT;
+  char *msg;
+
+#ifdef HAVE_STRSIGNAL
+  const char *msg_locale;
+  
+#if defined(G_OS_BEOS) || defined(G_WITH_CYGWIN)
+extern const char *strsignal(int);
+#else
+  /* this is declared differently (const) in string.h on BeOS */
+  extern char *strsignal (int sig);
+#endif /* !G_OS_BEOS && !G_WITH_CYGWIN */
+  msg_locale = strsignal (signum);
+  if (g_get_charset (NULL))
+    return msg_locale;
+  else
+    {
+      gchar *msg_utf8 = g_locale_to_utf8 (msg_locale, -1, NULL, NULL, NULL);
+      if (msg_utf8)
+       {
+         /* Stick in the quark table so that we can return a static result
+          */
+         GQuark msg_quark = g_quark_from_string (msg_utf8);
+         g_free (msg_utf8);
+         
+         return g_quark_to_string (msg_quark);
+       }
+    }
+#elif NO_SYS_SIGLIST
+  switch (signum)
+    {
+#ifdef SIGHUP
+    case SIGHUP: return "Hangup";
+#endif
+#ifdef SIGINT
+    case SIGINT: return "Interrupt";
+#endif
+#ifdef SIGQUIT
+    case SIGQUIT: return "Quit";
+#endif
+#ifdef SIGILL
+    case SIGILL: return "Illegal instruction";
+#endif
+#ifdef SIGTRAP
+    case SIGTRAP: return "Trace/breakpoint trap";
+#endif
+#ifdef SIGABRT
+    case SIGABRT: return "IOT trap/Abort";
+#endif
+#ifdef SIGBUS
+    case SIGBUS: return "Bus error";
+#endif
+#ifdef SIGFPE
+    case SIGFPE: return "Floating point exception";
+#endif
+#ifdef SIGKILL
+    case SIGKILL: return "Killed";
+#endif
+#ifdef SIGUSR1
+    case SIGUSR1: return "User defined signal 1";
+#endif
+#ifdef SIGSEGV
+    case SIGSEGV: return "Segmentation fault";
+#endif
+#ifdef SIGUSR2
+    case SIGUSR2: return "User defined signal 2";
+#endif
+#ifdef SIGPIPE
+    case SIGPIPE: return "Broken pipe";
+#endif
+#ifdef SIGALRM
+    case SIGALRM: return "Alarm clock";
+#endif
+#ifdef SIGTERM
+    case SIGTERM: return "Terminated";
+#endif
+#ifdef SIGSTKFLT
+    case SIGSTKFLT: return "Stack fault";
+#endif
+#ifdef SIGCHLD
+    case SIGCHLD: return "Child exited";
+#endif
+#ifdef SIGCONT
+    case SIGCONT: return "Continued";
+#endif
+#ifdef SIGSTOP
+    case SIGSTOP: return "Stopped (signal)";
+#endif
+#ifdef SIGTSTP
+    case SIGTSTP: return "Stopped";
+#endif
+#ifdef SIGTTIN
+    case SIGTTIN: return "Stopped (tty input)";
+#endif
+#ifdef SIGTTOU
+    case SIGTTOU: return "Stopped (tty output)";
+#endif
+#ifdef SIGURG
+    case SIGURG: return "Urgent condition";
+#endif
+#ifdef SIGXCPU
+    case SIGXCPU: return "CPU time limit exceeded";
+#endif
+#ifdef SIGXFSZ
+    case SIGXFSZ: return "File size limit exceeded";
+#endif
+#ifdef SIGVTALRM
+    case SIGVTALRM: return "Virtual time alarm";
+#endif
+#ifdef SIGPROF
+    case SIGPROF: return "Profile signal";
+#endif
+#ifdef SIGWINCH
+    case SIGWINCH: return "Window size changed";
+#endif
+#ifdef SIGIO
+    case SIGIO: return "Possible I/O";
+#endif
+#ifdef SIGPWR
+    case SIGPWR: return "Power failure";
+#endif
+#ifdef SIGUNUSED
+    case SIGUNUSED: return "Unused signal";
+#endif
+    }
+#else /* NO_SYS_SIGLIST */
+
+#ifdef NO_SYS_SIGLIST_DECL
+  extern char *sys_siglist[];  /*(see Tue Jan 19 00:44:24 1999 in changelog)*/
+#endif
+
+  return (char*) /* this function should return const --josh */ sys_siglist [signum];
+#endif /* NO_SYS_SIGLIST */
+
+  msg = g_static_private_get (&msg_private);
+  if (!msg)
+    {
+      msg = g_new (gchar, 64);
+      g_static_private_set (&msg_private, msg, g_free);
+    }
+
+  _g_sprintf (msg, "unknown signal (%d)", signum);
+  
+  return msg;
+}
+
+/* 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)
+{
+  g_return_val_if_fail (dest != NULL, 0);
+  g_return_val_if_fail (src  != NULL, 0);
+  
+  return strlcpy (dest, src, dest_size);
+}
+
+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);
+}
+
+#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 */
+}
+
+/* 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)
+       {
+         *d++ = *s;
+         bytes_left--;
+       }
+      s++;
+    }
+  *d = 0;
+  
+  return dlength + (s - src);  /* count does not include NUL */
+}
+#endif /* ! HAVE_STRLCPY */
+
+/**
+ * g_ascii_strdown:
+ * @str: a string.
+ * @len: length of @str in bytes, or -1 if @str is nul-terminated.
+ * 
+ * Converts all upper case ASCII letters to lower case ASCII letters.
+ * 
+ * Return value: a newly-allocated string, with all the upper case
+ *               characters in @str converted to lower case, with
+ *               semantics that exactly match g_ascii_tolower(). (Note
+ *               that this is unlike the old g_strdown(), which modified
+ *               the string in place.)
+ **/
+gchar*
+g_ascii_strdown (const gchar *str,
+                gssize       len)
+{
+  gchar *result, *s;
+  
+  g_return_val_if_fail (str != NULL, NULL);
+
+  if (len < 0)
+    len = strlen (str);
+
+  result = g_strndup (str, len);
+  for (s = result; *s; s++)
+    *s = g_ascii_tolower (*s);
+  
+  return result;
+}
+
+/**
+ * g_ascii_strup:
+ * @str: a string.
+ * @len: length of @str in bytes, or -1 if @str is nul-terminated.
+ * 
+ * Converts all lower case ASCII letters to upper case ASCII letters.
+ * 
+ * Return value: a newly allocated string, with all the lower case
+ *               characters in @str converted to upper case, with
+ *               semantics that exactly match g_ascii_toupper(). (Note
+ *               that this is unlike the old g_strup(), which modified
+ *               the string in place.)
+ **/
+gchar*
+g_ascii_strup (const gchar *str,
+              gssize       len)
+{
+  gchar *result, *s;
+
+  g_return_val_if_fail (str != NULL, NULL);
+
+  if (len < 0)
+    len = strlen (str);
+
+  result = g_strndup (str, len);
+  for (s = result; *s; s++)
+    *s = g_ascii_toupper (*s);
+
+  return result;
+}
+
+/**
+ * g_strdown:
+ * @string: the string to convert.
+ * 
+ * Converts a string to lower case.  
+ * 
+ * Return value: the string 
+ *
+ * Deprecated:2.2: This function is totally broken for the reasons discussed 
+ * in the g_strncasecmp() docs - use g_ascii_strdown() or g_utf8_strdown() 
+ * instead.
+ **/
+gchar*
+g_strdown (gchar *string)
+{
+  register guchar *s;
+  
+  g_return_val_if_fail (string != NULL, NULL);
+  
+  s = (guchar *) string;
+  
+  while (*s)
+    {
+      if (isupper (*s))
+       *s = tolower (*s);
+      s++;
+    }
+  
+  return (gchar *) string;
+}
+
+/**
+ * g_strup:
+ * @string: the string to convert.
+ * 
+ * Converts a string to upper case. 
+ * 
+ * Return value: the string
+ *
+ * Deprecated:2.2: This function is totally broken for the reasons discussed 
+ * in the g_strncasecmp() docs - use g_ascii_strup() or g_utf8_strup() instead.
+ **/
+gchar*
+g_strup (gchar *string)
+{
+  register guchar *s;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  s = (guchar *) string;
+
+  while (*s)
+    {
+      if (islower (*s))
+       *s = toupper (*s);
+      s++;
+    }
+
+  return (gchar *) string;
+}
+
+gchar*
+g_strreverse (gchar *string)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (*string)
+    {
+      register gchar *h, *t;
+
+      h = string;
+      t = string + strlen (string) - 1;
+
+      while (h < t)
+       {
+         register gchar c;
+
+         c = *h;
+         *h = *t;
+         h++;
+         *t = c;
+         t--;
+       }
+    }
+
+  return string;
+}
+
+/**
+ * g_ascii_tolower:
+ * @c: any character.
+ * 
+ * Convert a character to ASCII lower case.
+ *
+ * Unlike the standard C library tolower() function, this only
+ * recognizes standard ASCII letters and ignores the locale, returning
+ * all non-ASCII characters unchanged, even if they are lower case
+ * letters in a particular character set. Also unlike the standard
+ * library function, this takes and returns a char, not an int, so
+ * don't call it on %EOF but no need to worry about casting to #guchar
+ * before passing a possibly non-ASCII character in.
+ * 
+ * Return value: the result of converting @c to lower case.
+ *               If @c is not an ASCII upper case letter,
+ *               @c is returned unchanged.
+ **/
+gchar
+g_ascii_tolower (gchar c)
+{
+  return g_ascii_isupper (c) ? c - 'A' + 'a' : c;
+}
+
+/**
+ * g_ascii_toupper:
+ * @c: any character.
+ * 
+ * Convert a character to ASCII upper case.
+ *
+ * Unlike the standard C library toupper() function, this only
+ * recognizes standard ASCII letters and ignores the locale, returning
+ * all non-ASCII characters unchanged, even if they are upper case
+ * letters in a particular character set. Also unlike the standard
+ * library function, this takes and returns a char, not an int, so
+ * don't call it on %EOF but no need to worry about casting to #guchar
+ * before passing a possibly non-ASCII character in.
+ * 
+ * Return value: the result of converting @c to upper case.
+ *               If @c is not an ASCII lower case letter,
+ *               @c is returned unchanged.
+ **/
+gchar
+g_ascii_toupper (gchar c)
+{
+  return g_ascii_islower (c) ? c - 'a' + 'A' : c;
+}
+
+/**
+ * g_ascii_digit_value:
+ * @c: an ASCII character.
+ *
+ * Determines the numeric value of a character as a decimal
+ * digit. Differs from g_unichar_digit_value() because it takes
+ * a char, so there's no worry about sign extension if characters
+ * are signed.
+ *
+ * Return value: If @c is a decimal digit (according to
+ * g_ascii_isdigit()), its numeric value. Otherwise, -1.
+ **/
+int
+g_ascii_digit_value (gchar c)
+{
+  if (g_ascii_isdigit (c))
+    return c - '0';
+  return -1;
+}
+
+/**
+ * g_ascii_xdigit_value:
+ * @c: an ASCII character.
+ *
+ * Determines the numeric value of a character as a hexidecimal
+ * digit. Differs from g_unichar_xdigit_value() because it takes
+ * a char, so there's no worry about sign extension if characters
+ * are signed.
+ *
+ * Return value: If @c is a hex digit (according to
+ * g_ascii_isxdigit()), its numeric value. Otherwise, -1.
+ **/
+int
+g_ascii_xdigit_value (gchar c)
+{
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  return g_ascii_digit_value (c);
+}
+
+/**
+ * g_ascii_strcasecmp:
+ * @s1: string to compare with @s2.
+ * @s2: string to compare with @s1.
+ * 
+ * Compare two strings, ignoring the case of ASCII characters.
+ *
+ * Unlike the BSD strcasecmp() function, this only recognizes standard
+ * ASCII letters and ignores the locale, treating all non-ASCII
+ * bytes as if they are not letters.
+ *
+ * This function should be used only on strings that are known to be
+ * in encodings where the bytes corresponding to ASCII letters always
+ * represent themselves. This includes UTF-8 and the ISO-8859-*
+ * charsets, but not for instance double-byte encodings like the
+ * Windows Codepage 932, where the trailing bytes of double-byte
+ * characters include all ASCII letters. If you compare two CP932
+ * strings using this function, you will get false matches.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2, 
+ *   or a positive value if @s1 &gt; @s2.
+ **/
+gint
+g_ascii_strcasecmp (const gchar *s1,
+                   const gchar *s2)
+{
+  gint c1, c2;
+
+  g_return_val_if_fail (s1 != NULL, 0);
+  g_return_val_if_fail (s2 != NULL, 0);
+
+  while (*s1 && *s2)
+    {
+      c1 = (gint)(guchar) TOLOWER (*s1);
+      c2 = (gint)(guchar) TOLOWER (*s2);
+      if (c1 != c2)
+       return (c1 - c2);
+      s1++; s2++;
+    }
+
+  return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
+}
+
+/**
+ * g_ascii_strncasecmp:
+ * @s1: string to compare with @s2.
+ * @s2: string to compare with @s1.
+ * @n:  number of characters to compare.
+ * 
+ * Compare @s1 and @s2, ignoring the case of ASCII characters and any
+ * characters after the first @n in each string.
+ *
+ * Unlike the BSD strcasecmp() function, this only recognizes standard
+ * ASCII letters and ignores the locale, treating all non-ASCII
+ * characters as if they are not letters.
+ * 
+ * The same warning as in g_ascii_strcasecmp() applies: Use this
+ * function only on strings known to be in encodings where bytes
+ * corresponding to ASCII letters always represent themselves.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2, 
+ *   or a positive value if @s1 &gt; @s2.
+ **/
+gint
+g_ascii_strncasecmp (const gchar *s1,
+                    const gchar *s2,
+                    gsize n)
+{
+  gint c1, c2;
+
+  g_return_val_if_fail (s1 != NULL, 0);
+  g_return_val_if_fail (s2 != NULL, 0);
+
+  while (n && *s1 && *s2)
+    {
+      n -= 1;
+      c1 = (gint)(guchar) TOLOWER (*s1);
+      c2 = (gint)(guchar) TOLOWER (*s2);
+      if (c1 != c2)
+       return (c1 - c2);
+      s1++; s2++;
+    }
+
+  if (n)
+    return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
+  else
+    return 0;
+}
+
+/**
+ * g_strcasecmp:
+ * @s1: a string.
+ * @s2: a string to compare with @s1.
+ * 
+ * A case-insensitive string comparison, corresponding to the standard
+ * strcasecmp() function on platforms which support it.
+ *
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2, 
+ *   or a positive value if @s1 &gt; @s2.
+ *
+ * Deprecated:2.2: See g_strncasecmp() for a discussion of why this function 
+ *   is deprecated and how to replace it.
+ **/
+gint
+g_strcasecmp (const gchar *s1,
+             const gchar *s2)
+{
+#ifdef HAVE_STRCASECMP
+  g_return_val_if_fail (s1 != NULL, 0);
+  g_return_val_if_fail (s2 != NULL, 0);
+
+  return strcasecmp (s1, s2);
+#else
+  gint c1, c2;
+
+  g_return_val_if_fail (s1 != NULL, 0);
+  g_return_val_if_fail (s2 != NULL, 0);
+
+  while (*s1 && *s2)
+    {
+      /* According to A. Cox, some platforms have islower's that
+       * don't work right on non-uppercase
+       */
+      c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
+      c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
+      if (c1 != c2)
+       return (c1 - c2);
+      s1++; s2++;
+    }
+
+  return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
+#endif
+}
+
+/**
+ * g_strncasecmp:
+ * @s1: a string.
+ * @s2: a string to compare with @s1.
+ * @n: the maximum number of characters to compare.
+ * 
+ * A case-insensitive string comparison, corresponding to the standard
+ * strncasecmp() function on platforms which support it.
+ * It is similar to g_strcasecmp() except it only compares the first @n 
+ * characters of the strings.
+ * 
+ * Return value: 0 if the strings match, a negative value if @s1 &lt; @s2, 
+ *   or a positive value if @s1 &gt; @s2.
+ *
+ * Deprecated:2.2: The problem with g_strncasecmp() is that it does the 
+ * comparison by calling toupper()/tolower(). These functions are
+ * locale-specific and operate on single bytes. However, it is impossible
+ * to handle things correctly from an I18N standpoint by operating on
+ * bytes, since characters may be multibyte. Thus g_strncasecmp() is
+ * broken if your string is guaranteed to be ASCII, since it's
+ * locale-sensitive, and it's broken if your string is localized, since
+ * it doesn't work on many encodings at all, including UTF-8, EUC-JP,
+ * etc.
+ *
+ * There are therefore two replacement functions: g_ascii_strncasecmp(),
+ * which only works on ASCII and is not locale-sensitive, and
+ * g_utf8_casefold(), which is good for case-insensitive sorting of UTF-8.
+ **/
+gint
+g_strncasecmp (const gchar *s1,
+              const gchar *s2,
+              guint n)     
+{
+#ifdef HAVE_STRNCASECMP
+  return strncasecmp (s1, s2, n);
+#else
+  gint c1, c2;
+
+  g_return_val_if_fail (s1 != NULL, 0);
+  g_return_val_if_fail (s2 != NULL, 0);
+
+  while (n && *s1 && *s2)
+    {
+      n -= 1;
+      /* According to A. Cox, some platforms have islower's that
+       * don't work right on non-uppercase
+       */
+      c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
+      c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
+      if (c1 != c2)
+       return (c1 - c2);
+      s1++; s2++;
+    }
+
+  if (n)
+    return (((gint) (guchar) *s1) - ((gint) (guchar) *s2));
+  else
+    return 0;
+#endif
+}
+
+gchar*
+g_strdelimit (gchar      *string,
+             const gchar *delimiters,
+             gchar        new_delim)
+{
+  register gchar *c;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (!delimiters)
+    delimiters = G_STR_DELIMITERS;
+
+  for (c = string; *c; c++)
+    {
+      if (strchr (delimiters, *c))
+       *c = new_delim;
+    }
+
+  return string;
+}
+
+gchar*
+g_strcanon (gchar       *string,
+           const gchar *valid_chars,
+           gchar        substitutor)
+{
+  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 = substitutor;
+    }
+
+  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 == '\\')
+       {
+         p++;
+         switch (*p)
+           {
+           case '\0':
+             g_warning ("g_strcompress: trailing \\");
+             goto out;
+           case '0':  case '1':  case '2':  case '3':  case '4':
+           case '5':  case '6':  case '7':
+             *q = 0;
+             octal = p;
+             while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
+               {
+                 *q = (*q * 8) + (*p - '0');
+                 p++;
+               }
+             q++;
+             p--;
+             break;
+           case 'b':
+             *q++ = '\b';
+             break;
+           case 'f':
+             *q++ = '\f';
+             break;
+           case 'n':
+             *q++ = '\n';
+             break;
+           case 'r':
+             *q++ = '\r';
+             break;
+           case 't':
+             *q++ = '\t';
+             break;
+           default:            /* Also handles \" and \\ */
+             *q++ = *p;
+             break;
+           }
+       }
+      else
+       *q++ = *p;
+      p++;
+    }
+out:
+  *q = 0;
+  
+  return dest;
+}
+
+gchar *
+g_strescape (const gchar *source,
+            const gchar *exceptions)
+{
+  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)
+    {
+      guchar *e = (guchar *) exceptions;
+
+      while (*e)
+       {
+         excmap[*e] = 1;
+         e++;
+       }
+    }
+
+  while (*p)
+    {
+      if (excmap[*p])
+       *q++ = *p;
+      else
+       {
+         switch (*p)
+           {
+           case '\b':
+             *q++ = '\\';
+             *q++ = 'b';
+             break;
+           case '\f':
+             *q++ = '\\';
+             *q++ = 'f';
+             break;
+           case '\n':
+             *q++ = '\\';
+             *q++ = 'n';
+             break;
+           case '\r':
+             *q++ = '\\';
+             *q++ = 'r';
+             break;
+           case '\t':
+             *q++ = '\\';
+             *q++ = 't';
+             break;
+           case '\\':
+             *q++ = '\\';
+             *q++ = '\\';
+             break;
+           case '"':
+             *q++ = '\\';
+             *q++ = '"';
+             break;
+           default:
+             if ((*p < ' ') || (*p >= 0177))
+               {
+                 *q++ = '\\';
+                 *q++ = '0' + (((*p) >> 6) & 07);
+                 *q++ = '0' + (((*p) >> 3) & 07);
+                 *q++ = '0' + ((*p) & 07);
+               }
+             else
+               *q++ = *p;
+             break;
+           }
+       }
+      p++;
+    }
+  *q = 0;
+  return dest;
+}
+
+gchar*
+g_strchug (gchar *string)
+{
+  guchar *start;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  for (start = (guchar*) string; *start && g_ascii_isspace (*start); start++)
+    ;
+
+  g_memmove (string, start, strlen ((gchar *) start) + 1);
+
+  return string;
+}
+
+gchar*
+g_strchomp (gchar *string)
+{
+  gsize len;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  len = strlen (string);
+  while (len--)
+    {
+      if (g_ascii_isspace ((guchar) string[len]))
+       string[len] = '\0';
+      else
+       break;
+    }
+
+  return string;
+}
+
+/**
+ * g_strsplit:
+ * @string: a string to split.
+ * @delimiter: a string which specifies the places at which to split the string.
+ *     The delimiter is not included in any of the resulting strings, unless
+ *     @max_tokens is reached.
+ * @max_tokens: the maximum number of pieces to split @string into. If this is
+ *              less than 1, the string is split completely.
+ * 
+ * Splits a string into a maximum of @max_tokens pieces, using the given
+ * @delimiter. If @max_tokens is reached, the remainder of @string is appended
+ * to the last token. 
+ *
+ * As a special case, the result of splitting the empty string "" is an empty
+ * vector, not a vector containing a single string. The reason for this
+ * special case is that being able to represent a empty vector is typically
+ * more useful than consistent handling of empty elements. If you do need
+ * to represent empty elements, you'll need to check for the empty string
+ * before calling g_strsplit().
+ * 
+ * Return value: a newly-allocated %NULL-terminated array of strings. Use 
+ *    g_strfreev() to free it.
+ **/
+gchar**
+g_strsplit (const gchar *string,
+           const gchar *delimiter,
+           gint         max_tokens)
+{
+  GSList *string_list = NULL, *slist;
+  gchar **str_array, *s;
+  guint n = 0;
+  const gchar *remainder;
+
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (delimiter != NULL, NULL);
+  g_return_val_if_fail (delimiter[0] != '\0', NULL);
+
+  if (max_tokens < 1)
+    max_tokens = G_MAXINT;
+
+  remainder = string;
+  s = strstr (remainder, delimiter);
+  if (s)
+    {
+      gsize delimiter_len = strlen (delimiter);   
+
+      while (--max_tokens && s)
+       {
+         gsize len;     
+
+         len = s - remainder;
+         string_list = g_slist_prepend (string_list,
+                                        g_strndup (remainder, len));
+         n++;
+         remainder = s + delimiter_len;
+         s = strstr (remainder, delimiter);
+       }
+    }
+  if (*string)
+    {
+      n++;
+      string_list = g_slist_prepend (string_list, g_strdup (remainder));
+    }
+
+  str_array = g_new (gchar*, n + 1);
+
+  str_array[n--] = NULL;
+  for (slist = string_list; slist; slist = slist->next)
+    str_array[n--] = slist->data;
+
+  g_slist_free (string_list);
+
+  return str_array;
+}
+
+/**
+ * g_strsplit_set:
+ * @string: The string to be tokenized
+ * @delimiters: A nul-terminated string containing bytes that are used
+ *              to split the string.
+ * @max_tokens: The maximum number of tokens to split @string into. 
+ *              If this is less than 1, the string is split completely
+ * 
+ * Splits @string into a number of tokens not containing any of the characters
+ * in @delimiter. A token is the (possibly empty) longest string that does not
+ * contain any of the characters in @delimiters. If @max_tokens is reached, the
+ * remainder is appended to the last token.
+ *
+ * For example the result of g_strsplit_set ("abc:def/ghi", ":/", -1) is a
+ * %NULL-terminated vector containing the three strings "abc", "def", 
+ * and "ghi".
+ *
+ * The result if g_strsplit_set (":def/ghi:", ":/", -1) is a %NULL-terminated
+ * vector containing the four strings "", "def", "ghi", and "".
+ * 
+ * As a special case, the result of splitting the empty string "" is an empty
+ * vector, not a vector containing a single string. The reason for this
+ * special case is that being able to represent a empty vector is typically
+ * more useful than consistent handling of empty elements. If you do need
+ * to represent empty elements, you'll need to check for the empty string
+ * before calling g_strsplit_set().
+ *
+ * Note that this function works on bytes not characters, so it can't be used 
+ * to delimit UTF-8 strings for anything but ASCII characters.
+ * 
+ * Return value: a newly-allocated %NULL-terminated array of strings. Use 
+ *    g_strfreev() to free it.
+ * 
+ * Since: 2.4
+ **/
+gchar **
+g_strsplit_set (const gchar *string,
+               const gchar *delimiters,
+               gint         max_tokens)
+{
+  gboolean delim_table[256];
+  GSList *tokens, *list;
+  gint n_tokens;
+  const gchar *s;
+  const gchar *current;
+  gchar *token;
+  gchar **result;
+  
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (delimiters != NULL, NULL);
+
+  if (max_tokens < 1)
+    max_tokens = G_MAXINT;
+
+  if (*string == '\0')
+    {
+      result = g_new (char *, 1);
+      result[0] = NULL;
+      return result;
+    }
+  
+  memset (delim_table, FALSE, sizeof (delim_table));
+  for (s = delimiters; *s != '\0'; ++s)
+    delim_table[*(guchar *)s] = TRUE;
+
+  tokens = NULL;
+  n_tokens = 0;
+
+  s = current = string;
+  while (*s != '\0')
+    {
+      if (delim_table[*(guchar *)s] && n_tokens + 1 < max_tokens)
+       {
+         gchar *token;
+
+         token = g_strndup (current, s - current);
+         tokens = g_slist_prepend (tokens, token);
+         ++n_tokens;
+
+         current = s + 1;
+       }
+      
+      ++s;
+    }
+
+  token = g_strndup (current, s - current);
+  tokens = g_slist_prepend (tokens, token);
+  ++n_tokens;
+
+  result = g_new (gchar *, n_tokens + 1);
+
+  result[n_tokens] = NULL;
+  for (list = tokens; list != NULL; list = list->next)
+    result[--n_tokens] = list->data;
+
+  g_slist_free (tokens);
+  
+  return result;
+}
+
+/**
+ * g_strfreev:
+ * @str_array: a %NULL-terminated array of strings to free.
+
+ * Frees a %NULL-terminated array of strings, and the array itself.
+ * If called on a %NULL value, g_strfreev() simply returns. 
+ **/
+void
+g_strfreev (gchar **str_array)
+{
+  if (str_array)
+    {
+      int i;
+
+      for (i = 0; str_array[i] != NULL; i++)
+       g_free (str_array[i]);
+
+      g_free (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)
+{
+  gchar *string;
+  gchar *ptr;
+
+  g_return_val_if_fail (str_array != NULL, NULL);
+
+  if (separator == NULL)
+    separator = "";
+
+  if (*str_array)
+    {
+      gint i;
+      gsize len;
+      gsize separator_len;     
+
+      separator_len = strlen (separator);
+      /* First part, getting length */
+      len = 1 + strlen (str_array[0]);
+      for (i = 1; str_array[i] != NULL; i++)
+        len += strlen (str_array[i]);
+      len += separator_len * (i - 1);
+
+      /* Second part, building string */
+      string = g_new (gchar, len);
+      ptr = g_stpcpy (string, *str_array);
+      for (i = 1; str_array[i] != NULL; i++)
+       {
+          ptr = g_stpcpy (ptr, separator);
+          ptr = g_stpcpy (ptr, str_array[i]);
+       }
+      }
+  else
+    string = g_strdup ("");
+
+  return string;
+}
+
+gchar*
+g_strjoin (const gchar  *separator,
+          ...)
+{
+  gchar *string, *s;
+  va_list args;
+  gsize len;               
+  gsize separator_len;     
+  gchar *ptr;
+
+  if (separator == NULL)
+    separator = "";
+
+  separator_len = strlen (separator);
+
+  va_start (args, separator);
+
+  s = va_arg (args, gchar*);
+
+  if (s)
+    {
+      /* First part, getting length */
+      len = 1 + strlen (s);
+
+      s = va_arg (args, gchar*);
+      while (s)
+       {
+         len += separator_len + strlen (s);
+         s = va_arg (args, gchar*);
+       }
+      va_end (args);
+
+      /* Second part, building string */
+      string = g_new (gchar, len);
+
+      va_start (args, separator);
+
+      s = va_arg (args, gchar*);
+      ptr = g_stpcpy (string, s);
+
+      s = va_arg (args, gchar*);
+      while (s)
+       {
+         ptr = g_stpcpy (ptr, separator);
+          ptr = g_stpcpy (ptr, s);
+         s = va_arg (args, gchar*);
+       }
+    }
+  else
+    string = g_strdup ("");
+
+  va_end (args);
+
+  return string;
+}
+
+
+/**
+ * g_strstr_len:
+ * @haystack: a string.
+ * @haystack_len: the maximum length of @haystack. Note that -1 is
+ * a valid length, if @haystack is nul-terminated, meaning it will
+ * search through the whole string.
+ * @needle: the string to search for.
+ *
+ * Searches the string @haystack for the first occurrence
+ * of the string @needle, limiting the length of the search
+ * to @haystack_len. 
+ *
+ * Return value: a pointer to the found occurrence, or
+ *    %NULL if not found.
+ **/
+gchar *
+g_strstr_len (const gchar *haystack,
+             gssize       haystack_len,
+             const gchar *needle)
+{
+  g_return_val_if_fail (haystack != NULL, NULL);
+  g_return_val_if_fail (needle != NULL, NULL);
+
+  if (haystack_len < 0)
+    return strstr (haystack, needle);
+  else
+    {
+      const gchar *p = haystack;
+      gsize needle_len = strlen (needle);
+      const gchar *end;
+      gsize i;
+
+      if (needle_len == 0)
+       return (gchar *)haystack;
+
+      if (haystack_len < needle_len)
+       return NULL;
+      
+      end = haystack + haystack_len - needle_len;
+      
+      while (p <= end && *p)
+       {
+         for (i = 0; i < needle_len; i++)
+           if (p[i] != needle[i])
+             goto next;
+         
+         return (gchar *)p;
+         
+       next:
+         p++;
+       }
+      
+      return NULL;
+    }
+}
+
+/**
+ * g_strrstr:
+ * @haystack: a nul-terminated string.
+ * @needle: the nul-terminated string to search for.
+ *
+ * Searches the string @haystack for the last occurrence
+ * of the string @needle.
+ *
+ * Return value: a pointer to the found occurrence, or
+ *    %NULL if not found.
+ **/
+gchar *
+g_strrstr (const gchar *haystack,
+          const gchar *needle)
+{
+  gsize i;
+  gsize needle_len;
+  gsize haystack_len;
+  const gchar *p;
+      
+  g_return_val_if_fail (haystack != NULL, NULL);
+  g_return_val_if_fail (needle != NULL, NULL);
+
+  needle_len = strlen (needle);
+  haystack_len = strlen (haystack);
+
+  if (needle_len == 0)
+    return (gchar *)haystack;
+
+  if (haystack_len < needle_len)
+    return NULL;
+  
+  p = haystack + haystack_len - needle_len;
+
+  while (p >= haystack)
+    {
+      for (i = 0; i < needle_len; i++)
+       if (p[i] != needle[i])
+         goto next;
+      
+      return (gchar *)p;
+      
+    next:
+      p--;
+    }
+  
+  return NULL;
+}
+
+/**
+ * g_strrstr_len:
+ * @haystack: a nul-terminated string.
+ * @haystack_len: the maximum length of @haystack.
+ * @needle: the nul-terminated string to search for.
+ *
+ * Searches the string @haystack for the last occurrence
+ * of the string @needle, limiting the length of the search
+ * to @haystack_len. 
+ *
+ * Return value: a pointer to the found occurrence, or
+ *    %NULL if not found.
+ **/
+gchar *
+g_strrstr_len (const gchar *haystack,
+              gssize        haystack_len,
+              const gchar *needle)
+{
+  g_return_val_if_fail (haystack != NULL, NULL);
+  g_return_val_if_fail (needle != NULL, NULL);
+  
+  if (haystack_len < 0)
+    return g_strrstr (haystack, needle);
+  else
+    {
+      gsize needle_len = strlen (needle);
+      const gchar *haystack_max = haystack + haystack_len;
+      const gchar *p = haystack;
+      gsize i;
+
+      while (p < haystack_max && *p)
+       p++;
+
+      if (p < haystack + needle_len)
+       return NULL;
+       
+      p -= needle_len;
+
+      while (p >= haystack)
+       {
+         for (i = 0; i < needle_len; i++)
+           if (p[i] != needle[i])
+             goto next;
+         
+         return (gchar *)p;
+         
+       next:
+         p--;
+       }
+
+      return NULL;
+    }
+}
+
+
+/**
+ * g_str_has_suffix:
+ * @str: a nul-terminated string.
+ * @suffix: the nul-terminated suffix to look for.
+ *
+ * Looks whether the string @str ends with @suffix.
+ *
+ * Return value: %TRUE if @str end with @suffix, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+g_str_has_suffix (const gchar  *str,
+                 const gchar  *suffix)
+{
+  int str_len;
+  int suffix_len;
+  
+  g_return_val_if_fail (str != NULL, FALSE);
+  g_return_val_if_fail (suffix != NULL, FALSE);
+
+  str_len = strlen (str);
+  suffix_len = strlen (suffix);
+
+  if (str_len < suffix_len)
+    return FALSE;
+
+  return strcmp (str + str_len - suffix_len, suffix) == 0;
+}
+
+/**
+ * g_str_has_prefix:
+ * @str: a nul-terminated string.
+ * @prefix: the nul-terminated prefix to look for.
+ *
+ * Looks whether the string @str begins with @prefix.
+ *
+ * Return value: %TRUE if @str begins with @prefix, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+g_str_has_prefix (const gchar  *str,
+                 const gchar  *prefix)
+{
+  int str_len;
+  int prefix_len;
+  
+  g_return_val_if_fail (str != NULL, FALSE);
+  g_return_val_if_fail (prefix != NULL, FALSE);
+
+  str_len = strlen (str);
+  prefix_len = strlen (prefix);
+
+  if (str_len < prefix_len)
+    return FALSE;
+  
+  return strncmp (str, prefix, prefix_len) == 0;
+}
+
+
+/**
+ * g_strip_context:
+ * @msgid: a string
+ * @msgval: another string
+ * 
+ * An auxiliary function for gettext() support (see Q_()).
+ * 
+ * Return value: @msgval, unless @msgval is identical to @msgid and contains
+ *   a '|' character, in which case a pointer to the substring of msgid after
+ *   the first '|' character is returned. 
+ *
+ * Since: 2.4
+ **/
+G_CONST_RETURN gchar *
+g_strip_context  (const gchar *msgid, 
+                 const gchar *msgval)
+{
+  if (msgval == msgid)
+    {
+      const char *c = strchr (msgid, '|');
+      if (c != NULL)
+       return c + 1;
+    }
+  
+  return msgval;
+}
+
+
+/**
+ * g_strv_length:
+ * @str_array: a %NULL-terminated array of strings.
+ * 
+ * Returns the length of the given %NULL-terminated 
+ * string array @str_array.
+ * 
+ * Return value: length of @str_array.
+ *
+ * Since: 2.6
+ **/
+guint
+g_strv_length (gchar **str_array)
+{
+  guint i = 0;
+
+  g_return_val_if_fail (str_array != NULL, 0);
+
+  while (str_array[i])
+    ++i;
+
+  return i;
+}
+
+
+/**
+ * g_dpgettext:
+ * @domain: the translation domain to use, or %NULL to use
+ *   the domain set with textdomain()
+ * @msgctxtid: a combined message context and message id, separated
+ *   by a \004 character
+ * @msgidoffset: the offset of the message id in @msgctxid
+ *
+ * This function is a variant of g_dgettext() which supports
+ * a disambiguating message context. GNU gettext uses the
+ * '\004' character to separate the message context and
+ * message id in @msgctxtid.
+ * If 0 is passed as @msgidoffset, this function will fall back to
+ * trying to use the deprecated convention of using "|" as a separation
+ * character.
+ *
+ * This uses g_dgettext() internally.  See that functions for differences
+ * with dgettext() proper.
+ *
+ * Applications should normally not use this function directly,
+ * but use the C_() macro for translations with context.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.16
+ */
+G_CONST_RETURN gchar *
+g_dpgettext (const gchar *domain, 
+             const gchar *msgctxtid, 
+             gsize        msgidoffset)
+{
+  const gchar *translation;
+  gchar *sep;
+
+  translation = g_dgettext (domain, msgctxtid);
+
+  if (translation == msgctxtid)
+    {
+      if (msgidoffset > 0)
+        return msgctxtid + msgidoffset;
+
+      sep = strchr (msgctxtid, '|');
+      if (sep)
+        {
+          /* try with '\004' instead of '|', in case
+           * xgettext -kQ_:1g was used
+           */
+          gchar *tmp = g_alloca (strlen (msgctxtid) + 1);
+          strcpy (tmp, msgctxtid);
+          tmp[sep - msgctxtid] = '\004';
+
+          translation = g_dgettext (domain, tmp);
+   
+          if (translation == tmp)
+            return sep + 1; 
+        }
+    }
+
+  return translation;
+}
+
+/* This function is taken from gettext.h 
+ * GNU gettext uses '\004' to separate context and msgid in .mo files.
+ */
+/**
+ * g_dpgettext2:
+ * @domain: the translation domain to use, or %NULL to use
+ *   the domain set with textdomain()
+ * @context: the message context
+ * @msgid: the message
+ *
+ * This function is a variant of g_dgettext() which supports
+ * a disambiguating message context. GNU gettext uses the
+ * '\004' character to separate the message context and
+ * message id in @msgctxtid.
+ *
+ * This uses g_dgettext() internally.  See that functions for differences
+ * with dgettext() proper.
+ *
+ * This function differs from C_() in that it is not a macro and 
+ * thus you may use non-string-literals as context and msgid arguments.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.18
+ */
+G_CONST_RETURN char *
+g_dpgettext2 (const char *domain,
+              const char *msgctxt,
+              const char *msgid)
+{
+  size_t msgctxt_len = strlen (msgctxt) + 1;
+  size_t msgid_len = strlen (msgid) + 1;
+  const char *translation;
+  char* msg_ctxt_id;
+
+  msg_ctxt_id = g_alloca (msgctxt_len + msgid_len);
+
+  memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
+  msg_ctxt_id[msgctxt_len - 1] = '\004';
+  memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
+
+  translation = g_dgettext (domain, msg_ctxt_id);
+
+  if (translation == msg_ctxt_id) 
+    {
+      /* try the old way of doing message contexts, too */
+      msg_ctxt_id[msgctxt_len - 1] = '|';
+      translation = g_dgettext (domain, msg_ctxt_id);
+
+      if (translation == msg_ctxt_id)
+        return msgid;
+    }
+
+  return translation;
+}
+
+static gboolean
+_g_dgettext_should_translate (void)
+{
+  static gsize translate = 0;
+  enum {
+    SHOULD_TRANSLATE = 1,
+    SHOULD_NOT_TRANSLATE = 2
+  };
+
+  if (G_UNLIKELY (g_once_init_enter (&translate)))
+    {
+      gboolean should_translate = TRUE;
+
+      const char *default_domain     = textdomain (NULL);
+      const char *translator_comment = gettext ("");
+#ifndef G_OS_WIN32
+      const char *translate_locale   = setlocale (LC_MESSAGES, NULL);
+#else
+      const char *translate_locale   = g_win32_getlocale ();
+#endif
+      /* We should NOT translate only if all the following hold:
+       *   - user has called textdomain() and set textdomain to non-default
+       *   - default domain has no translations
+       *   - locale does not start with "en_" and is not "C"
+       *
+       * Rationale:
+       *   - If text domain is still the default domain, maybe user calls
+       *     it later. Continue with old behavior of translating.
+       *   - If locale starts with "en_", we can continue using the
+       *     translations even if the app doesn't have translations for
+       *     this locale.  That is, en_UK and en_CA for example.
+       *   - If locale is "C", maybe user calls setlocale(LC_ALL,"") later.
+       *     Continue with old behavior of translating.
+       */
+      if (0 != strcmp (default_domain, "messages") &&
+         '\0' == *translator_comment &&
+         0 != strncmp (translate_locale, "en_", 3) &&
+         0 != strcmp (translate_locale, "C"))
+        should_translate = FALSE;
+      
+      g_once_init_leave (&translate,
+                        should_translate ?
+                        SHOULD_TRANSLATE :
+                        SHOULD_NOT_TRANSLATE);
+    }
+
+  return translate == SHOULD_TRANSLATE;
+}
+
+/**
+ * g_dgettext:
+ * @domain: the translation domain to use, or %NULL to use
+ *   the domain set with textdomain()
+ * @msgid: message to translate
+ *
+ * This function is a wrapper of dgettext() which does not translate
+ * the message if the default domain as set with textdomain() has no
+ * translations for the current locale.
+ *
+ * The advantage of using this function over dgettext() proper is that
+ * libraries using this function (like GTK+) will not use translations
+ * if the application using the library does not have translations for
+ * the current locale.  This results in a consistent English-only
+ * interface instead of one having partial translations.  For this
+ * feature to work, the call to textdomain() and setlocale() should
+ * precede any g_dgettext() invocations.  For GTK+, it means calling
+ * textdomain() before gtk_init or its variants.
+ *
+ * This function disables translations if and only if upon its first
+ * call all the following conditions hold:
+ * <itemizedlist>
+ * <listitem>@domain is not %NULL</listitem>
+ * <listitem>textdomain() has been called to set a default text domain</listitem>
+ * <listitem>there is no translations available for the default text domain
+ *           and the current locale</listitem>
+ * <listitem>current locale is not "C" or any English locales (those
+ *           starting with "en_")</listitem>
+ * </itemizedlist>
+ *
+ * Note that this behavior may not be desired for example if an application
+ * has its untranslated messages in a language other than English.  In those
+ * cases the application should call textdomain() after initializing GTK+.
+ *
+ * Applications should normally not use this function directly,
+ * but use the _() macro for translations.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.18
+ */
+G_CONST_RETURN gchar *
+g_dgettext (const gchar *domain,
+            const gchar *msgid)
+{
+  if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
+    return msgid;
+
+  return dgettext (domain, msgid);
+}
+
+/**
+ * g_dngettext:
+ * @domain: the translation domain to use, or %NULL to use
+ *   the domain set with textdomain()
+ * @msgid: message to translate
+ * @msgid_plural: plural form of the message
+ * @n: the quantity for which translation is needed
+ *
+ * This function is a wrapper of dngettext() which does not translate
+ * the message if the default domain as set with textdomain() has no
+ * translations for the current locale.
+ *
+ * See g_dgettext() for details of how this differs from dngettext()
+ * proper.
+ *
+ * Returns: The translated string
+ *
+ * Since: 2.18
+ */
+G_CONST_RETURN gchar *
+g_dngettext (const gchar *domain,
+             const gchar *msgid,
+             const gchar *msgid_plural,
+            gulong       n)
+{
+  if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
+    return n == 1 ? msgid : msgid_plural;
+
+  return dngettext (domain, msgid, msgid_plural, n);
+}
+
+
+#define __G_STRFUNCS_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gstrfuncs.h b/navit/navit/support/glib/gstrfuncs.h
new file mode 100644 (file)
index 0000000..ee291f8
--- /dev/null
@@ -0,0 +1,266 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_STRFUNCS_H__
+#define __G_STRFUNCS_H__
+
+#include <stdarg.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/* Functions like the ones in <ctype.h> that are not affected by locale. */
+typedef enum {
+  G_ASCII_ALNUM  = 1 << 0,
+  G_ASCII_ALPHA  = 1 << 1,
+  G_ASCII_CNTRL  = 1 << 2,
+  G_ASCII_DIGIT  = 1 << 3,
+  G_ASCII_GRAPH  = 1 << 4,
+  G_ASCII_LOWER  = 1 << 5,
+  G_ASCII_PRINT  = 1 << 6,
+  G_ASCII_PUNCT  = 1 << 7,
+  G_ASCII_SPACE  = 1 << 8,
+  G_ASCII_UPPER  = 1 << 9,
+  G_ASCII_XDIGIT = 1 << 10
+} GAsciiType;
+
+GLIB_VAR const guint16 * const g_ascii_table;
+
+#define g_ascii_isalnum(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0)
+
+#define g_ascii_isalpha(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_ALPHA) != 0)
+
+#define g_ascii_iscntrl(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_CNTRL) != 0)
+
+#define g_ascii_isdigit(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_DIGIT) != 0)
+
+#define g_ascii_isgraph(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_GRAPH) != 0)
+
+#define g_ascii_islower(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_LOWER) != 0)
+
+#define g_ascii_isprint(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_PRINT) != 0)
+
+#define g_ascii_ispunct(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_PUNCT) != 0)
+
+#define g_ascii_isspace(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0)
+
+#define g_ascii_isupper(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_UPPER) != 0)
+
+#define g_ascii_isxdigit(c) \
+  ((g_ascii_table[(guchar) (c)] & G_ASCII_XDIGIT) != 0)
+
+gchar                 g_ascii_tolower  (gchar        c) G_GNUC_CONST;
+gchar                 g_ascii_toupper  (gchar        c) G_GNUC_CONST;
+
+gint                  g_ascii_digit_value  (gchar    c) G_GNUC_CONST;
+gint                  g_ascii_xdigit_value (gchar    c) G_GNUC_CONST;
+
+/* String utility functions that modify a string argument or
+ * return a constant string that must not be freed.
+ */
+#define         G_STR_DELIMITERS       "_-|> <."
+gchar*               g_strdelimit     (gchar        *string,
+                                       const gchar  *delimiters,
+                                       gchar         new_delimiter);
+gchar*               g_strcanon       (gchar        *string,
+                                       const gchar  *valid_chars,
+                                       gchar         substitutor);
+G_CONST_RETURN gchar* g_strerror       (gint         errnum) G_GNUC_CONST;
+G_CONST_RETURN gchar* g_strsignal      (gint         signum) G_GNUC_CONST;
+gchar*               g_strreverse     (gchar        *string);
+gsize                g_strlcpy        (gchar        *dest,
+                                       const gchar  *src,
+                                       gsize         dest_size);
+gsize                g_strlcat        (gchar        *dest,
+                                       const gchar  *src,
+                                       gsize         dest_size);
+gchar *               g_strstr_len     (const gchar  *haystack,
+                                       gssize        haystack_len,
+                                       const gchar  *needle);
+gchar *               g_strrstr        (const gchar  *haystack,
+                                       const gchar  *needle);
+gchar *               g_strrstr_len    (const gchar  *haystack,
+                                       gssize        haystack_len,
+                                       const gchar  *needle);
+
+gboolean              g_str_has_suffix (const gchar  *str,
+                                       const gchar  *suffix);
+gboolean              g_str_has_prefix (const gchar  *str,
+                                       const gchar  *prefix);
+
+/* String to/from double conversion functions */
+
+gdouble                      g_strtod         (const gchar  *nptr,
+                                       gchar       **endptr);
+gdouble                      g_ascii_strtod   (const gchar  *nptr,
+                                       gchar       **endptr);
+guint64                      g_ascii_strtoull (const gchar *nptr,
+                                       gchar      **endptr,
+                                       guint        base);
+gint64               g_ascii_strtoll  (const gchar *nptr,
+                                       gchar      **endptr,
+                                       guint        base);
+/* 29 bytes should enough for all possible values that
+ * g_ascii_dtostr can produce.
+ * Then add 10 for good measure */
+#define G_ASCII_DTOSTR_BUF_SIZE (29 + 10)
+gchar *               g_ascii_dtostr   (gchar        *buffer,
+                                       gint          buf_len,
+                                       gdouble       d);
+gchar *               g_ascii_formatd  (gchar        *buffer,
+                                       gint          buf_len,
+                                       const gchar  *format,
+                                       gdouble       d);
+
+/* removes leading spaces */
+gchar*                g_strchug        (gchar        *string);
+/* removes trailing spaces */
+gchar*                g_strchomp       (gchar        *string);
+/* removes leading & trailing spaces */
+#define g_strstrip( string )   g_strchomp (g_strchug (string))
+
+gint                  g_ascii_strcasecmp  (const gchar *s1,
+                                          const gchar *s2);
+gint                  g_ascii_strncasecmp (const gchar *s1,
+                                          const gchar *s2,
+                                          gsize        n);
+gchar*                g_ascii_strdown     (const gchar *str,
+                                          gssize       len) G_GNUC_MALLOC;
+gchar*                g_ascii_strup       (const gchar *str,
+                                          gssize       len) G_GNUC_MALLOC;
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following four functions are deprecated and will be removed in
+ * the next major release. They use the locale-specific tolower and
+ * toupper, which is almost never the right thing.
+ */
+
+gint                 g_strcasecmp     (const gchar *s1,
+                                       const gchar *s2);
+gint                 g_strncasecmp    (const gchar *s1,
+                                       const gchar *s2,
+                                       guint        n);
+gchar*               g_strdown        (gchar        *string);
+gchar*               g_strup          (gchar        *string);
+
+#endif /* G_DISABLE_DEPRECATED */
+
+/* String utility functions that return a newly allocated string which
+ * ought to be freed with g_free from the caller at some point.
+ */
+gchar*               g_strdup         (const gchar *str) G_GNUC_MALLOC;
+gchar*               g_strdup_printf  (const gchar *format,
+                                       ...) G_GNUC_PRINTF (1, 2) G_GNUC_MALLOC;
+gchar*               g_strdup_vprintf (const gchar *format,
+                                       va_list      args) G_GNUC_MALLOC;
+gchar*               g_strndup        (const gchar *str,
+                                       gsize        n) G_GNUC_MALLOC;  
+gchar*               g_strnfill       (gsize        length,  
+                                       gchar        fill_char) G_GNUC_MALLOC;
+gchar*               g_strconcat      (const gchar *string1,
+                                       ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+gchar*                g_strjoin               (const gchar  *separator,
+                                       ...) G_GNUC_MALLOC G_GNUC_NULL_TERMINATED;
+
+/* Make a copy of a string interpreting C string -style escape
+ * sequences. Inverse of g_strescape. The recognized sequences are \b
+ * \f \n \r \t \\ \" and the octal format.
+ */
+gchar*                g_strcompress    (const gchar *source) G_GNUC_MALLOC;
+
+/* Copy a string escaping nonprintable characters like in C strings.
+ * Inverse of g_strcompress. The exceptions parameter, if non-NULL, points
+ * to a string containing characters that are not to be escaped.
+ *
+ * Deprecated API: gchar* g_strescape (const gchar *source);
+ * Luckily this function wasn't used much, using NULL as second parameter
+ * provides mostly identical semantics.
+ */
+gchar*                g_strescape      (const gchar *source,
+                                       const gchar *exceptions) G_GNUC_MALLOC;
+
+gpointer              g_memdup        (gconstpointer mem,
+                                       guint          byte_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(2);
+
+/* NULL terminated string arrays.
+ * g_strsplit(), g_strsplit_set() split up string into max_tokens tokens
+ * at delim and return a newly allocated string array.
+ * g_strjoinv() concatenates all of str_array's strings, sliding in an
+ * optional separator, the returned string is newly allocated.
+ * g_strfreev() frees the array itself and all of its strings.
+ * g_strdupv() copies a NULL-terminated array of strings
+ * g_strv_length() returns the length of a NULL-terminated array of strings
+ */
+gchar**                      g_strsplit       (const gchar  *string,
+                                       const gchar  *delimiter,
+                                       gint          max_tokens) G_GNUC_MALLOC;
+gchar **             g_strsplit_set   (const gchar *string,
+                                       const gchar *delimiters,
+                                       gint         max_tokens) G_GNUC_MALLOC;
+gchar*                g_strjoinv       (const gchar  *separator,
+                                       gchar       **str_array) G_GNUC_MALLOC;
+void                  g_strfreev       (gchar       **str_array);
+gchar**               g_strdupv        (gchar       **str_array) G_GNUC_MALLOC;
+guint                 g_strv_length    (gchar       **str_array);
+
+gchar*                g_stpcpy         (gchar        *dest,
+                                        const char   *src);
+
+G_CONST_RETURN gchar *g_strip_context  (const gchar *msgid, 
+                                       const gchar *msgval) G_GNUC_FORMAT(1);
+
+G_CONST_RETURN gchar *g_dgettext       (const gchar *domain,
+                                       const gchar *msgid) G_GNUC_FORMAT(2);
+
+G_CONST_RETURN gchar *g_dngettext      (const gchar *domain,
+                                       const gchar *msgid,
+                                       const gchar *msgid_plural,
+                                       gulong       n) G_GNUC_FORMAT(3);
+G_CONST_RETURN gchar *g_dpgettext      (const gchar *domain,
+                                        const gchar *msgctxtid,
+                                        gsize        msgidoffset) G_GNUC_FORMAT(2);
+G_CONST_RETURN gchar *g_dpgettext2     (const gchar *domain,
+                                        const gchar *context,
+                                        const gchar *msgid) G_GNUC_FORMAT(3);
+
+G_END_DECLS
+
+#endif /* __G_STRFUNCS_H__ */
diff --git a/navit/navit/support/glib/gstring.c b/navit/navit/support/glib/gstring.c
new file mode 100644 (file)
index 0000000..9f0198b
--- /dev/null
@@ -0,0 +1,1484 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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
+ */
+
+#include "config.h"
+
+#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"
+#include "gprintf.h"
+
+#include "galias.h"
+
+struct _GStringChunk
+{
+  GHashTable *const_table;
+  GSList     *storage_list;
+  gsize       storage_next;    
+  gsize       this_size;       
+  gsize       default_size;    
+};
+
+/* Hash Functions.
+ */
+
+/**
+ * g_str_equal:
+ * @v1: a key
+ * @v2: a key to compare with @v1
+ * 
+ * Compares two strings for byte-by-byte equality and returns %TRUE 
+ * if they are equal. It can be passed to g_hash_table_new() as the 
+ * @key_equal_func parameter, when using strings as keys in a #GHashTable.
+ *
+ * Returns: %TRUE if the two keys match
+ */
+gboolean
+g_str_equal (gconstpointer v1,
+            gconstpointer v2)
+{
+  const gchar *string1 = v1;
+  const gchar *string2 = v2;
+  
+  return strcmp (string1, string2) == 0;
+}
+
+/**
+ * g_str_hash:
+ * @v: a string key
+ *
+ * Converts a string to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func 
+ * parameter, when using strings as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key
+ */
+guint
+g_str_hash (gconstpointer v)
+{
+  /* 31 bit hash function */
+  const signed char *p = v;
+  guint32 h = *p;
+
+  if (h)
+    for (p += 1; *p != '\0'; p++)
+      h = (h << 5) - h + *p;
+
+  return h;
+}
+
+#define MY_MAXSIZE ((gsize)-1)
+
+static inline gsize
+nearest_power (gsize base, gsize num)    
+{
+  if (num > MY_MAXSIZE / 2)
+    {
+      return MY_MAXSIZE;
+    }
+  else
+    {
+      gsize n = base;
+
+      while (n < num)
+       n <<= 1;
+      
+      return n;
+    }
+}
+
+/* String Chunks.
+ */
+
+/**
+ * g_string_chunk_new:
+ * @size: the default size of the blocks of memory which are 
+ *        allocated to store the strings. If a particular string 
+ *        is larger than this default size, a larger block of 
+ *        memory will be allocated for it.
+ * 
+ * Creates a new #GStringChunk. 
+ * 
+ * Returns: a new #GStringChunk
+ */
+GStringChunk*
+g_string_chunk_new (gsize size)    
+{
+  GStringChunk *new_chunk = g_new (GStringChunk, 1);
+  gsize actual_size = 1;    
+
+  actual_size = nearest_power (1, size);
+
+  new_chunk->const_table       = NULL;
+  new_chunk->storage_list      = NULL;
+  new_chunk->storage_next      = actual_size;
+  new_chunk->default_size      = actual_size;
+  new_chunk->this_size         = actual_size;
+
+  return new_chunk;
+}
+
+/**
+ * g_string_chunk_free:
+ * @chunk: a #GStringChunk 
+ * 
+ * Frees all memory allocated by the #GStringChunk.
+ * After calling g_string_chunk_free() it is not safe to
+ * access any of the strings which were contained within it.
+ */
+void
+g_string_chunk_free (GStringChunk *chunk)
+{
+  GSList *tmp_list;
+
+  g_return_if_fail (chunk != NULL);
+
+  if (chunk->storage_list)
+    {
+      for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
+       g_free (tmp_list->data);
+
+      g_slist_free (chunk->storage_list);
+    }
+
+  if (chunk->const_table)
+    g_hash_table_destroy (chunk->const_table);
+
+  g_free (chunk);
+}
+
+/**
+ * g_string_chunk_clear:
+ * @chunk: a #GStringChunk
+ *
+ * Frees all strings contained within the #GStringChunk.
+ * After calling g_string_chunk_clear() it is not safe to
+ * access any of the strings which were contained within it.
+ *
+ * Since: 2.14
+ */
+void
+g_string_chunk_clear (GStringChunk *chunk)
+{
+  GSList *tmp_list;
+
+  g_return_if_fail (chunk != NULL);
+
+  if (chunk->storage_list)
+    {
+      for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next)
+        g_free (tmp_list->data);
+
+      g_slist_free (chunk->storage_list);
+
+      chunk->storage_list       = NULL;
+      chunk->storage_next       = chunk->default_size;
+      chunk->this_size          = chunk->default_size;
+    }
+
+  if (chunk->const_table)
+      g_hash_table_remove_all (chunk->const_table);
+}
+
+/**
+ * g_string_chunk_insert:
+ * @chunk: a #GStringChunk
+ * @string: the string to add
+ * 
+ * Adds a copy of @string to the #GStringChunk.
+ * It returns a pointer to the new copy of the string 
+ * in the #GStringChunk. The characters in the string 
+ * can be changed, if necessary, though you should not 
+ * change anything after the end of the string.
+ *
+ * Unlike g_string_chunk_insert_const(), this function 
+ * does not check for duplicates. Also strings added 
+ * with g_string_chunk_insert() will not be searched 
+ * by g_string_chunk_insert_const() when looking for 
+ * duplicates.
+ * 
+ * Returns: a pointer to the copy of @string within 
+ *          the #GStringChunk
+ */
+gchar*
+g_string_chunk_insert (GStringChunk *chunk,
+                      const gchar  *string)
+{
+  g_return_val_if_fail (chunk != NULL, NULL);
+
+  return g_string_chunk_insert_len (chunk, string, -1);
+}
+
+/**
+ * g_string_chunk_insert_const:
+ * @chunk: a #GStringChunk
+ * @string: the string to add
+ * 
+ * Adds a copy of @string to the #GStringChunk, unless the same 
+ * string has already been added to the #GStringChunk with 
+ * g_string_chunk_insert_const().
+ * 
+ * This function is useful if you need to copy a large number 
+ * of strings but do not want to waste space storing duplicates. 
+ * But you must remember that there may be several pointers to 
+ * the same string, and so any changes made to the strings 
+ * should be done very carefully.
+ * 
+ * Note that g_string_chunk_insert_const() will not return a 
+ * pointer to a string added with g_string_chunk_insert(), even 
+ * if they do match.
+ * 
+ * Returns: a pointer to the new or existing copy of @string 
+ *          within the #GStringChunk
+ */
+gchar*
+g_string_chunk_insert_const (GStringChunk *chunk,
+                            const gchar  *string)
+{
+  char* lookup;
+
+  g_return_val_if_fail (chunk != NULL, NULL);
+
+  if (!chunk->const_table)
+    chunk->const_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+  lookup = (char*) g_hash_table_lookup (chunk->const_table, (gchar *)string);
+
+  if (!lookup)
+    {
+      lookup = g_string_chunk_insert (chunk, string);
+      g_hash_table_insert (chunk->const_table, lookup, lookup);
+    }
+
+  return lookup;
+}
+
+/**
+ * g_string_chunk_insert_len:
+ * @chunk: a #GStringChunk
+ * @string: bytes to insert
+ * @len: number of bytes of @string to insert, or -1 to insert a 
+ *     nul-terminated string 
+ * 
+ * Adds a copy of the first @len bytes of @string to the #GStringChunk. 
+ * The copy is nul-terminated.
+ * 
+ * Since this function does not stop at nul bytes, it is the caller's
+ * responsibility to ensure that @string has at least @len addressable 
+ * bytes.
+ *
+ * The characters in the returned string can be changed, if necessary, 
+ * though you should not change anything after the end of the string.
+ * 
+ * Return value: a pointer to the copy of @string within the #GStringChunk
+ * 
+ * Since: 2.4
+ **/
+gchar*
+g_string_chunk_insert_len (GStringChunk *chunk,
+                          const gchar  *string, 
+                          gssize        len)
+{
+  gssize size;
+  gchar* pos;
+
+  g_return_val_if_fail (chunk != NULL, NULL);
+
+  if (len < 0)
+    size = strlen (string);
+  else
+    size = len;
+  
+  if ((chunk->storage_next + size + 1) > chunk->this_size)
+    {
+      gsize new_size = nearest_power (chunk->default_size, size + 1);
+
+      chunk->storage_list = g_slist_prepend (chunk->storage_list,
+                                            g_new (gchar, new_size));
+
+      chunk->this_size = new_size;
+      chunk->storage_next = 0;
+    }
+
+  pos = ((gchar *) chunk->storage_list->data) + chunk->storage_next;
+
+  *(pos + size) = '\0';
+
+  strncpy (pos, string, size);
+  if (len > 0)
+    size = strlen (pos);
+
+  chunk->storage_next += size + 1;
+
+  return pos;
+}
+
+/* Strings.
+ */
+static void
+g_string_maybe_expand (GString* string,
+                      gsize    len) 
+{
+  if (string->len + len >= string->allocated_len)
+    {
+      string->allocated_len = nearest_power (1, string->len + len + 1);
+      string->str = g_realloc (string->str, string->allocated_len);
+    }
+}
+
+/**
+ * g_string_sized_new:
+ * @dfl_size: the default size of the space allocated to 
+ *            hold the string
+ *
+ * Creates a new #GString, with enough space for @dfl_size 
+ * bytes. This is useful if you are going to add a lot of 
+ * text to the string and don't want it to be reallocated 
+ * too often.
+ *
+ * Returns: the new #GString
+ */
+GString*
+g_string_sized_new (gsize dfl_size)    
+{
+  GString *string = g_slice_new (GString);
+
+  string->allocated_len = 0;
+  string->len   = 0;
+  string->str   = NULL;
+
+  g_string_maybe_expand (string, MAX (dfl_size, 2));
+  string->str[0] = 0;
+
+  return string;
+}
+
+/**
+ * g_string_new:
+ * @init: the initial text to copy into the string
+ * 
+ * Creates a new #GString, initialized with the given string.
+ *
+ * Returns: the new #GString
+ */
+GString*
+g_string_new (const gchar *init)
+{
+  GString *string;
+
+  if (init == NULL || *init == '\0')
+    string = g_string_sized_new (2);
+  else 
+    {
+      gint len;
+
+      len = strlen (init);
+      string = g_string_sized_new (len + 2);
+
+      g_string_append_len (string, init, len);
+    }
+
+  return string;
+}
+
+/**
+ * g_string_new_len:
+ * @init: initial contents of the string
+ * @len: length of @init to use
+ *
+ * Creates a new #GString with @len bytes of the @init buffer.  
+ * Because a length is provided, @init need not be nul-terminated,
+ * and can contain embedded nul bytes.
+ *
+ * Since this function does not stop at nul bytes, it is the caller's
+ * responsibility to ensure that @init has at least @len addressable 
+ * bytes.
+ *
+ * Returns: a new #GString
+ */
+GString*
+g_string_new_len (const gchar *init,
+                  gssize       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;
+    }
+}
+
+/**
+ * g_string_free:
+ * @string: a #GString
+ * @free_segment: if %TRUE the actual character data is freed as well
+ *
+ * Frees the memory allocated for the #GString.
+ * If @free_segment is %TRUE it also frees the character data.
+ *
+ * Returns: the character data of @string 
+ *          (i.e. %NULL if @free_segment is %TRUE)
+ */
+gchar*
+g_string_free (GString *string,
+              gboolean free_segment)
+{
+  gchar *segment;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (free_segment)
+    {
+      g_free (string->str);
+      segment = NULL;
+    }
+  else
+    segment = string->str;
+
+  g_slice_free (GString, string);
+
+  return segment;
+}
+
+/**
+ * g_string_equal:
+ * @v: a #GString
+ * @v2: another #GString
+ *
+ * Compares two strings for equality, returning %TRUE if they are equal. 
+ * For use with #GHashTable.
+ *
+ * Returns: %TRUE if they strings are the same length and contain the 
+ *   same bytes
+ */
+gboolean
+g_string_equal (const GString *v,
+                const GString *v2)
+{
+  gchar *p, *q;
+  GString *string1 = (GString *) v;
+  GString *string2 = (GString *) v2;
+  gsize i = string1->len;    
+
+  if (i != string2->len)
+    return FALSE;
+
+  p = string1->str;
+  q = string2->str;
+  while (i)
+    {
+      if (*p != *q)
+       return FALSE;
+      p++;
+      q++;
+      i--;
+    }
+  return TRUE;
+}
+
+/**
+ * g_string_hash:
+ * @str: a string to hash
+ *
+ * Creates a hash code for @str; for use with #GHashTable.
+ *
+ * Returns: hash code for @str
+ */
+/* 31 bit hash function */
+guint
+g_string_hash (const GString *str)
+{
+  const gchar *p = str->str;
+  gsize n = str->len;    
+  guint h = 0;
+
+  while (n--)
+    {
+      h = (h << 5) - h + *p;
+      p++;
+    }
+
+  return h;
+}
+
+/**
+ * g_string_assign:
+ * @string: the destination #GString. Its current contents 
+ *          are destroyed.
+ * @rval: the string to copy into @string
+ *
+ * Copies the bytes from a string into a #GString, 
+ * destroying any previous contents. It is rather like 
+ * the standard strcpy() function, except that you do not 
+ * have to worry about having enough space to copy the string.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_assign (GString     *string,
+                const gchar *rval)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (rval != NULL, string);
+
+  /* Make sure assigning to itself doesn't corrupt the string.  */
+  if (string->str != rval)
+    {
+      /* Assigning from substring should be ok since g_string_truncate
+        does not realloc.  */
+      g_string_truncate (string, 0);
+      g_string_append (string, rval);
+    }
+
+  return string;
+}
+
+/**
+ * g_string_truncate:
+ * @string: a #GString
+ * @len: the new size of @string
+ *
+ * Cuts off the end of the GString, leaving the first @len bytes. 
+ *
+ * Returns: @string
+ */
+GString*
+g_string_truncate (GString *string,
+                  gsize    len)    
+{
+  g_return_val_if_fail (string != NULL, NULL);
+
+  string->len = MIN (len, string->len);
+  string->str[string->len] = 0;
+
+  return string;
+}
+
+/**
+ * g_string_set_size:
+ * @string: a #GString
+ * @len: the new length
+ * 
+ * Sets the length of a #GString. If the length is less than
+ * the current length, the string will be truncated. If the
+ * length is greater than the current length, the contents
+ * of the newly added area are undefined. (However, as
+ * always, string->str[string->len] will be a nul byte.) 
+ * 
+ * Return value: @string
+ **/
+GString*
+g_string_set_size (GString *string,
+                  gsize    len)    
+{
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (len >= string->allocated_len)
+    g_string_maybe_expand (string, len - string->len);
+  
+  string->len = len;
+  string->str[len] = 0;
+
+  return string;
+}
+
+/**
+ * g_string_insert_len:
+ * @string: a #GString
+ * @pos: position in @string where insertion should 
+ *       happen, or -1 for at the end
+ * @val: bytes to insert
+ * @len: number of bytes of @val to insert
+ * 
+ * Inserts @len bytes of @val into @string at @pos.  
+ * Because @len is provided, @val may contain embedded 
+ * nuls and need not be nul-terminated. If @pos is -1, 
+ * bytes are inserted at the end of the string.
+ *
+ * Since this function does not stop at nul bytes, it is 
+ * the caller's responsibility to ensure that @val has at 
+ * least @len addressable bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_insert_len (GString     *string,
+                    gssize       pos,    
+                    const gchar *val,
+                    gssize       len)    
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (val != NULL, string);
+
+  if (len < 0)
+    len = strlen (val);
+
+  if (pos < 0)
+    pos = string->len;
+  else
+    g_return_val_if_fail (pos <= string->len, string);
+
+  /* Check whether val represents a substring of string.  This test
+     probably violates chapter and verse of the C standards, since
+     ">=" and "<=" are only valid when val really is a substring.
+     In practice, it will work on modern archs.  */
+  if (val >= string->str && val <= string->str + string->len)
+    {
+      gsize offset = val - string->str;
+      gsize precount = 0;
+
+      g_string_maybe_expand (string, len);
+      val = string->str + offset;
+      /* At this point, val is valid again.  */
+
+      /* Open up space where we are going to insert.  */
+      if (pos < string->len)
+       g_memmove (string->str + pos + len, string->str + pos, string->len - pos);
+
+      /* Move the source part before the gap, if any.  */
+      if (offset < pos)
+       {
+         precount = MIN (len, pos - offset);
+         memcpy (string->str + pos, val, precount);
+       }
+
+      /* Move the source part after the gap, if any.  */
+      if (len > precount)
+       memcpy (string->str + pos + precount,
+               val + /* Already moved: */ precount + /* Space opened up: */ len,
+               len - precount);
+    }
+  else
+    {
+      g_string_maybe_expand (string, 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 */
+      if (len == 1)
+        string->str[pos] = *val;
+      else
+        memcpy (string->str + pos, val, len);
+    }
+
+  string->len += len;
+
+  string->str[string->len] = 0;
+
+  return string;
+}
+
+#define SUB_DELIM_CHARS  "!$&'()*+,;="
+
+static gboolean
+is_valid (char c, const char *reserved_chars_allowed)
+{
+  if (g_ascii_isalnum (c) ||
+      c == '-' ||
+      c == '.' ||
+      c == '_' ||
+      c == '~')
+    return TRUE;
+
+  if (reserved_chars_allowed &&
+      strchr (reserved_chars_allowed, c) != NULL)
+    return TRUE;
+  
+  return FALSE;
+}
+
+static gboolean 
+gunichar_ok (gunichar c)
+{
+  return
+    (c != (gunichar) -2) &&
+    (c != (gunichar) -1);
+}
+
+/**
+ * g_string_append_uri_escaped:
+ * @string: a #GString
+ * @unescaped: a string
+ * @reserved_chars_allowed: a string of reserved characters allowed to be used
+ * @allow_utf8: set %TRUE if the escaped string may include UTF8 characters
+ * 
+ * Appends @unescaped to @string, escaped any characters that
+ * are reserved in URIs using URI-style escape sequences.
+ * 
+ * Returns: @string
+ *
+ * Since: 2.16
+ **/
+GString *
+g_string_append_uri_escaped (GString *string,
+                            const char *unescaped,
+                            const char *reserved_chars_allowed,
+                            gboolean allow_utf8)
+{
+  unsigned char c;
+  const char *end;
+  static const gchar hex[16] = "0123456789ABCDEF";
+
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (unescaped != NULL, NULL);
+
+  end = unescaped + strlen (unescaped);
+  
+  while ((c = *unescaped) != 0)
+    {
+      if (c >= 0x80 && allow_utf8 &&
+         gunichar_ok (g_utf8_get_char_validated (unescaped, end - unescaped)))
+       {
+         int len = g_utf8_skip [c];
+         g_string_append_len (string, unescaped, len);
+         unescaped += len;
+       }
+      else if (is_valid (c, reserved_chars_allowed))
+       {
+         g_string_append_c (string, c);
+         unescaped++;
+       }
+      else
+       {
+         g_string_append_c (string, '%');
+         g_string_append_c (string, hex[((guchar)c) >> 4]);
+         g_string_append_c (string, hex[((guchar)c) & 0xf]);
+         unescaped++;
+       }
+    }
+
+  return string;
+}
+
+/**
+ * g_string_append:
+ * @string: a #GString
+ * @val: the string to append onto the end of @string
+ * 
+ * Adds a string onto the end of a #GString, expanding 
+ * it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_append (GString     *string,
+                const gchar *val)
+{  
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (val != NULL, string);
+
+  return g_string_insert_len (string, -1, val, -1);
+}
+
+/**
+ * g_string_append_len:
+ * @string: a #GString
+ * @val: bytes to append
+ * @len: number of bytes of @val to use
+ * 
+ * Appends @len bytes of @val to @string. Because @len is 
+ * provided, @val may contain embedded nuls and need not 
+ * be nul-terminated.
+ * 
+ * Since this function does not stop at nul bytes, it is 
+ * the caller's responsibility to ensure that @val has at 
+ * least @len addressable bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_append_len (GString    *string,
+                     const gchar *val,
+                     gssize       len)    
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (val != NULL, string);
+
+  return g_string_insert_len (string, -1, val, len);
+}
+
+/**
+ * g_string_append_c:
+ * @string: a #GString
+ * @c: the byte to append onto the end of @string
+ *
+ * Adds a byte onto the end of a #GString, expanding 
+ * it if necessary.
+ * 
+ * Returns: @string
+ */
+#undef g_string_append_c
+GString*
+g_string_append_c (GString *string,
+                  gchar    c)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+
+  return g_string_insert_c (string, -1, c);
+}
+
+/**
+ * g_string_append_unichar:
+ * @string: a #GString
+ * @wc: a Unicode character
+ * 
+ * Converts a Unicode character into UTF-8, and appends it
+ * to the string.
+ * 
+ * Return value: @string
+ **/
+GString*
+g_string_append_unichar (GString  *string,
+                        gunichar  wc)
+{  
+  g_return_val_if_fail (string != NULL, NULL);
+  
+  return g_string_insert_unichar (string, -1, wc);
+}
+
+/**
+ * g_string_prepend:
+ * @string: a #GString
+ * @val: the string to prepend on the start of @string
+ *
+ * Adds a string on to the start of a #GString, 
+ * expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_prepend (GString     *string,
+                 const gchar *val)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (val != NULL, string);
+  
+  return g_string_insert_len (string, 0, val, -1);
+}
+
+/**
+ * g_string_prepend_len:
+ * @string: a #GString
+ * @val: bytes to prepend
+ * @len: number of bytes in @val to prepend
+ *
+ * Prepends @len bytes of @val to @string. 
+ * Because @len is provided, @val may contain 
+ * embedded nuls and need not be nul-terminated.
+ *
+ * Since this function does not stop at nul bytes, 
+ * it is the caller's responsibility to ensure that 
+ * @val has at least @len addressable bytes.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_prepend_len (GString    *string,
+                      const gchar *val,
+                      gssize       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);
+}
+
+/**
+ * g_string_prepend_c:
+ * @string: a #GString
+ * @c: the byte to prepend on the start of the #GString
+ *
+ * Adds a byte onto the start of a #GString, 
+ * expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_prepend_c (GString *string,
+                   gchar    c)
+{  
+  g_return_val_if_fail (string != NULL, NULL);
+  
+  return g_string_insert_c (string, 0, c);
+}
+
+/**
+ * g_string_prepend_unichar:
+ * @string: a #GString
+ * @wc: a Unicode character
+ * 
+ * Converts a Unicode character into UTF-8, and prepends it
+ * to the string.
+ * 
+ * Return value: @string
+ **/
+GString*
+g_string_prepend_unichar (GString  *string,
+                         gunichar  wc)
+{  
+  g_return_val_if_fail (string != NULL, NULL);
+  
+  return g_string_insert_unichar (string, 0, wc);
+}
+
+/**
+ * g_string_insert:
+ * @string: a #GString
+ * @pos: the position to insert the copy of the string
+ * @val: the string to insert
+ *
+ * Inserts a copy of a string into a #GString, 
+ * expanding it if necessary.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_insert (GString     *string,
+                gssize       pos,    
+                const gchar *val)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (val != NULL, string);
+  if (pos >= 0)
+    g_return_val_if_fail (pos <= string->len, string);
+  
+  return g_string_insert_len (string, pos, val, -1);
+}
+
+/**
+ * g_string_insert_c:
+ * @string: a #GString
+ * @pos: the position to insert the byte
+ * @c: the byte to insert
+ *
+ * Inserts a byte into a #GString, expanding it if necessary.
+ * 
+ * Returns: @string
+ */
+GString*
+g_string_insert_c (GString *string,
+                  gssize   pos,    
+                  gchar    c)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+
+  g_string_maybe_expand (string, 1);
+
+  if (pos < 0)
+    pos = string->len;
+  else
+    g_return_val_if_fail (pos <= string->len, string);
+  
+  /* 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;
+
+  string->len += 1;
+
+  string->str[string->len] = 0;
+
+  return string;
+}
+
+/**
+ * g_string_insert_unichar:
+ * @string: a #GString
+ * @pos: the position at which to insert character, or -1 to
+ *       append at the end of the string
+ * @wc: a Unicode character
+ * 
+ * Converts a Unicode character into UTF-8, and insert it
+ * into the string at the given position.
+ * 
+ * Return value: @string
+ **/
+GString*
+g_string_insert_unichar (GString *string,
+                        gssize   pos,    
+                        gunichar wc)
+{
+  gint charlen, first, i;
+  gchar *dest;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  /* Code copied from g_unichar_to_utf() */
+  if (wc < 0x80)
+    {
+      first = 0;
+      charlen = 1;
+    }
+  else if (wc < 0x800)
+    {
+      first = 0xc0;
+      charlen = 2;
+    }
+  else if (wc < 0x10000)
+    {
+      first = 0xe0;
+      charlen = 3;
+    }
+   else if (wc < 0x200000)
+    {
+      first = 0xf0;
+      charlen = 4;
+    }
+  else if (wc < 0x4000000)
+    {
+      first = 0xf8;
+      charlen = 5;
+    }
+  else
+    {
+      first = 0xfc;
+      charlen = 6;
+    }
+  /* End of copied code */
+
+  g_string_maybe_expand (string, charlen);
+
+  if (pos < 0)
+    pos = string->len;
+  else
+    g_return_val_if_fail (pos <= string->len, string);
+
+  /* If not just an append, move the old stuff */
+  if (pos < string->len)
+    g_memmove (string->str + pos + charlen, string->str + pos, string->len - pos);
+
+  dest = string->str + pos;
+  /* Code copied from g_unichar_to_utf() */
+  for (i = charlen - 1; i > 0; --i)
+    {
+      dest[i] = (wc & 0x3f) | 0x80;
+      wc >>= 6;
+    }
+  dest[0] = wc | first;
+  /* End of copied code */
+  
+  string->len += charlen;
+
+  string->str[string->len] = 0;
+
+  return string;
+}
+
+/**
+ * g_string_overwrite:
+ * @string: a #GString
+ * @pos: the position at which to start overwriting
+ * @val: the string that will overwrite the @string starting at @pos
+ * 
+ * Overwrites part of a string, lengthening it if necessary.
+ * 
+ * Return value: @string
+ *
+ * Since: 2.14
+ **/
+GString *
+g_string_overwrite (GString     *string,
+                   gsize        pos,
+                   const gchar *val)
+{
+  g_return_val_if_fail (val != NULL, string);
+  return g_string_overwrite_len (string, pos, val, strlen (val));
+}
+
+/**
+ * g_string_overwrite_len:
+ * @string: a #GString
+ * @pos: the position at which to start overwriting
+ * @val: the string that will overwrite the @string starting at @pos
+ * @len: the number of bytes to write from @val
+ * 
+ * Overwrites part of a string, lengthening it if necessary. 
+ * This function will work with embedded nuls.
+ * 
+ * Return value: @string
+ *
+ * Since: 2.14
+ **/
+GString *
+g_string_overwrite_len (GString     *string,
+                       gsize        pos,
+                       const gchar *val,
+                       gssize       len)
+{
+  gsize end;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (!len)
+    return string;
+
+  g_return_val_if_fail (val != NULL, string);
+  g_return_val_if_fail (pos <= string->len, string);
+
+  if (len < 0)
+    len = strlen (val);
+
+  end = pos + len;
+
+  if (end > string->len)
+    g_string_maybe_expand (string, end - string->len);
+
+  memcpy (string->str + pos, val, len);
+
+  if (end > string->len)
+    {
+      string->str[end] = '\0';
+      string->len = end;
+    }
+
+  return string;
+}
+
+/**
+ * g_string_erase:
+ * @string: a #GString
+ * @pos: the position of the content to remove
+ * @len: the number of bytes to remove, or -1 to remove all
+ *       following bytes
+ *
+ * Removes @len bytes from a #GString, starting at position @pos.
+ * The rest of the #GString is shifted down to fill the gap.
+ *
+ * Returns: @string
+ */
+GString*
+g_string_erase (GString *string,
+               gssize   pos,
+               gssize   len)
+{
+  g_return_val_if_fail (string != NULL, NULL);
+  g_return_val_if_fail (pos >= 0, string);
+  g_return_val_if_fail (pos <= string->len, string);
+
+  if (len < 0)
+    len = string->len - pos;
+  else
+    {
+      g_return_val_if_fail (pos + len <= string->len, string);
+
+      if (pos + len < string->len)
+       g_memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
+    }
+
+  string->len -= len;
+  
+  string->str[string->len] = 0;
+
+  return string;
+}
+
+/**
+ * g_string_ascii_down:
+ * @string: a GString
+ * 
+ * Converts all upper case ASCII letters to lower case ASCII letters.
+ * 
+ * Return value: passed-in @string pointer, with all the upper case
+ *               characters converted to lower case in place, with
+ *               semantics that exactly match g_ascii_tolower().
+ **/
+GString*
+g_string_ascii_down (GString *string)
+{
+  gchar *s;
+  gint n;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  n = string->len;
+  s = string->str;
+
+  while (n)
+    {
+      *s = g_ascii_tolower (*s);
+      s++;
+      n--;
+    }
+
+  return string;
+}
+
+/**
+ * g_string_ascii_up:
+ * @string: a GString
+ * 
+ * Converts all lower case ASCII letters to upper case ASCII letters.
+ * 
+ * Return value: passed-in @string pointer, with all the lower case
+ *               characters converted to upper case in place, with
+ *               semantics that exactly match g_ascii_toupper().
+ **/
+GString*
+g_string_ascii_up (GString *string)
+{
+  gchar *s;
+  gint n;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  n = string->len;
+  s = string->str;
+
+  while (n)
+    {
+      *s = g_ascii_toupper (*s);
+      s++;
+      n--;
+    }
+
+  return string;
+}
+
+/**
+ * g_string_down:
+ * @string: a #GString
+ *  
+ * Converts a #GString to lowercase.
+ *
+ * Returns: the #GString.
+ *
+ * Deprecated:2.2: This function uses the locale-specific 
+ *   tolower() function, which is almost never the right thing. 
+ *   Use g_string_ascii_down() or g_utf8_strdown() instead.
+ */
+GString*
+g_string_down (GString *string)
+{
+  guchar *s;
+  glong n;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  n = string->len;    
+  s = (guchar *) string->str;
+
+  while (n)
+    {
+      if (isupper (*s))
+       *s = tolower (*s);
+      s++;
+      n--;
+    }
+
+  return string;
+}
+
+/**
+ * g_string_up:
+ * @string: a #GString 
+ * 
+ * Converts a #GString to uppercase.
+ * 
+ * Return value: @string
+ *
+ * Deprecated:2.2: This function uses the locale-specific 
+ *   toupper() function, which is almost never the right thing. 
+ *   Use g_string_ascii_up() or g_utf8_strup() instead.
+ **/
+GString*
+g_string_up (GString *string)
+{
+  guchar *s;
+  glong n;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  n = string->len;
+  s = (guchar *) string->str;
+
+  while (n)
+    {
+      if (islower (*s))
+       *s = toupper (*s);
+      s++;
+      n--;
+    }
+
+  return string;
+}
+
+/**
+ * g_string_append_vprintf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @args: the list of arguments to insert in the output
+ *
+ * Appends a formatted string onto the end of a #GString.
+ * This function is similar to g_string_append_printf()
+ * except that the arguments to the format string are passed
+ * as a va_list.
+ *
+ * Since: 2.14
+ */
+void
+g_string_append_vprintf (GString     *string,
+                        const gchar *format,
+                        va_list      args)
+{
+  gchar *buf;
+  gint len;
+  
+  g_return_if_fail (string != NULL);
+  g_return_if_fail (format != NULL);
+
+  len = g_vasprintf (&buf, format, args);
+
+  if (len >= 0)
+    {
+      g_string_maybe_expand (string, len);
+      memcpy (string->str + string->len, buf, len + 1);
+      string->len += len;
+      g_free (buf);
+    }
+}
+
+/**
+ * g_string_vprintf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @args: the parameters to insert into the format string
+ *
+ * Writes a formatted string into a #GString. 
+ * This function is similar to g_string_printf() except that 
+ * the arguments to the format string are passed as a va_list.
+ *
+ * Since: 2.14
+ */
+void
+g_string_vprintf (GString     *string,
+                 const gchar *format,
+                 va_list      args)
+{
+  g_string_truncate (string, 0);
+  g_string_append_vprintf (string, format, args);
+}
+
+/**
+ * g_string_sprintf:
+ * @string: a #GString
+ * @format: the string format. See the sprintf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Writes a formatted string into a #GString.
+ * This is similar to the standard sprintf() function,
+ * except that the #GString buffer automatically expands 
+ * to contain the results. The previous contents of the 
+ * #GString are destroyed. 
+ *
+ * Deprecated: This function has been renamed to g_string_printf().
+ */
+
+/**
+ * g_string_printf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Writes a formatted string into a #GString.
+ * This is similar to the standard sprintf() function,
+ * except that the #GString buffer automatically expands 
+ * to contain the results. The previous contents of the 
+ * #GString are destroyed.
+ */
+void
+g_string_printf (GString     *string,
+                const gchar *format,
+                ...)
+{
+  va_list args;
+
+  g_string_truncate (string, 0);
+
+  va_start (args, format);
+  g_string_append_vprintf (string, format, args);
+  va_end (args);
+}
+
+/**
+ * g_string_sprintfa:
+ * @string: a #GString
+ * @format: the string format. See the sprintf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Appends a formatted string onto the end of a #GString.
+ * This function is similar to g_string_sprintf() except that
+ * the text is appended to the #GString. 
+ *
+ * Deprecated: This function has been renamed to g_string_append_printf()
+ */
+
+/**
+ * g_string_append_printf:
+ * @string: a #GString
+ * @format: the string format. See the printf() documentation
+ * @Varargs: the parameters to insert into the format string
+ *
+ * Appends a formatted string onto the end of a #GString.
+ * This function is similar to g_string_printf() except 
+ * that the text is appended to the #GString.
+ */
+void
+g_string_append_printf (GString     *string,
+                       const gchar *format,
+                       ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  g_string_append_vprintf (string, format, args);
+  va_end (args);
+}
+
+#define __G_STRING_C__
+#include "galiasdef.c"
diff --git a/navit/navit/support/glib/gthreadprivate.h b/navit/navit/support/glib/gthreadprivate.h
new file mode 100644 (file)
index 0000000..c9b5fa5
--- /dev/null
@@ -0,0 +1,68 @@
+/* GLIB - Library of useful routines for C programming
+ *
+ * gthreadprivate.h - GLib internal thread system related declarations.
+ *
+ *  Copyright (C) 2003 Sebastian Wilhelmi
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * 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.
+ *
+ * The Gnome 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *   Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_THREADPRIVATE_H__
+#define __G_THREADPRIVATE_H__
+
+G_BEGIN_DECLS
+
+/* System thread identifier comparision and assignment */
+#if GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P
+# define g_system_thread_equal_simple(thread1, thread2)                        \
+   ((thread1).dummy_pointer == (thread2).dummy_pointer)
+# define g_system_thread_assign(dest, src)                             \
+   ((dest).dummy_pointer = (src).dummy_pointer)
+#else /* GLIB_SIZEOF_SYSTEM_THREAD != SIZEOF_VOID_P */
+# define g_system_thread_equal_simple(thread1, thread2)                        \
+   (memcmp (&(thread1), &(thread2), GLIB_SIZEOF_SYSTEM_THREAD) == 0)
+# define g_system_thread_assign(dest, src)                             \
+   (memcpy (&(dest), &(src), GLIB_SIZEOF_SYSTEM_THREAD))
+#endif /* GLIB_SIZEOF_SYSTEM_THREAD == SIZEOF_VOID_P */
+
+#define g_system_thread_equal(thread1, thread2)                                \
+  (g_thread_functions_for_glib_use.thread_equal ?                      \
+   g_thread_functions_for_glib_use.thread_equal (&(thread1), &(thread2)) :\
+   g_system_thread_equal_simple((thread1), (thread2)))
+
+/* Is called from gthread/gthread-impl.c */
+void g_thread_init_glib (void);
+
+/* base initializers, may only use g_mutex_new(), g_cond_new() */
+G_GNUC_INTERNAL void _g_mem_thread_init_noprivate_nomessage (void);
+/* initializers that may also use g_private_new() */
+G_GNUC_INTERNAL void _g_slice_thread_init_nomessage        (void);
+G_GNUC_INTERNAL void _g_messages_thread_init_nomessage      (void);
+
+/* full fledged initializers */
+G_GNUC_INTERNAL void _g_convert_thread_init (void);
+G_GNUC_INTERNAL void _g_rand_thread_init (void);
+G_GNUC_INTERNAL void _g_main_thread_init (void);
+G_GNUC_INTERNAL void _g_atomic_thread_init (void);
+G_GNUC_INTERNAL void _g_utils_thread_init (void);
+
+#ifdef G_OS_WIN32
+G_GNUC_INTERNAL void _g_win32_thread_init (void);
+#endif /* G_OS_WIN32 */
+
+G_END_DECLS
+
+#endif /* __G_THREADPRIVATE_H__ */
diff --git a/navit/navit/support/glib/gtypes.h b/navit/navit/support/glib/gtypes.h
new file mode 100644 (file)
index 0000000..3ac98fd
--- /dev/null
@@ -0,0 +1,432 @@
+/* GLIB - Library of useful routines for C programming
+ * 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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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/.
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TYPES_H__
+#define __G_TYPES_H__
+
+#include <glibconfig.h>
+
+G_BEGIN_DECLS
+
+/* Provide type definitions for commonly used types.
+ *  These are useful because a "gint8" can be adjusted
+ *  to be 1 byte (8 bits) on all platforms. Similarly and
+ *  more importantly, "gint32" can be adjusted to be
+ *  4 bytes (32 bits) on all platforms.
+ */
+
+typedef char   gchar;
+typedef short  gshort;
+typedef long   glong;
+typedef int    gint;
+typedef gint   gboolean;
+
+typedef unsigned char   guchar;
+typedef unsigned short  gushort;
+typedef unsigned long   gulong;
+typedef unsigned int    guint;
+
+typedef float   gfloat;
+typedef double  gdouble;
+
+/* Define min and max constants for the fixed size numerical types */
+#define G_MININT8      ((gint8)  0x80)
+#define G_MAXINT8      ((gint8)  0x7f)
+#define G_MAXUINT8     ((guint8) 0xff)
+
+#define G_MININT16     ((gint16)  0x8000)
+#define G_MAXINT16     ((gint16)  0x7fff)
+#define G_MAXUINT16    ((guint16) 0xffff)
+
+#define G_MININT32     ((gint32)  0x80000000)
+#define G_MAXINT32     ((gint32)  0x7fffffff)
+#define G_MAXUINT32    ((guint32) 0xffffffff)
+
+#define G_MININT64     ((gint64) G_GINT64_CONSTANT(0x8000000000000000))
+#define G_MAXINT64     G_GINT64_CONSTANT(0x7fffffffffffffff)
+#define G_MAXUINT64    G_GINT64_CONSTANT(0xffffffffffffffffU)
+
+typedef void* gpointer;
+typedef const void *gconstpointer;
+
+typedef gint            (*GCompareFunc)         (gconstpointer  a,
+                                                 gconstpointer  b);
+typedef gint            (*GCompareDataFunc)     (gconstpointer  a,
+                                                 gconstpointer  b,
+                                                gpointer       user_data);
+typedef gboolean        (*GEqualFunc)           (gconstpointer  a,
+                                                 gconstpointer  b);
+typedef void            (*GDestroyNotify)       (gpointer       data);
+typedef void            (*GFunc)                (gpointer       data,
+                                                 gpointer       user_data);
+typedef guint           (*GHashFunc)            (gconstpointer  key);
+typedef void            (*GHFunc)               (gpointer       key,
+                                                 gpointer       value,
+                                                 gpointer       user_data);
+typedef void            (*GFreeFunc)            (gpointer       data);
+typedef const gchar *   (*GTranslateFunc)       (const gchar   *str,
+                                                gpointer       data);
+
+
+/* Define some mathematical constants that aren't available
+ * symbolically in some strict ISO C implementations.
+ *
+ * Note that the large number of digits used in these definitions
+ * doesn't imply that GLib or current computers in general would be
+ * able to handle floating point numbers with an accuracy like this.
+ * It's mostly an exercise in futility and future proofing. For
+ * extended precision floating point support, look somewhere else
+ * than GLib.
+ */
+#define G_E     2.7182818284590452353602874713526624977572470937000
+#define G_LN2   0.69314718055994530941723212145817656807550013436026
+#define G_LN10  2.3025850929940456840179914546843642076011014886288
+#define G_PI    3.1415926535897932384626433832795028841971693993751
+#define G_PI_2  1.5707963267948966192313216916397514420985846996876
+#define G_PI_4  0.78539816339744830961566084581987572104929234984378
+#define G_SQRT2 1.4142135623730950488016887242096980785696718753769
+
+/* Portable endian checks and conversions
+ *
+ * glibconfig.h defines G_BYTE_ORDER which expands to one of
+ * the below macros.
+ */
+#define G_LITTLE_ENDIAN 1234
+#define G_BIG_ENDIAN    4321
+#define G_PDP_ENDIAN    3412           /* unused, need specific PDP check */   
+
+
+/* Basic bit swapping functions
+ */
+#define GUINT16_SWAP_LE_BE_CONSTANT(val)       ((guint16) ( \
+    (guint16) ((guint16) (val) >> 8) | \
+    (guint16) ((guint16) (val) << 8)))
+
+#define GUINT32_SWAP_LE_BE_CONSTANT(val)       ((guint32) ( \
+    (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
+    (((guint32) (val) & (guint32) 0x0000ff00U) <<  8) | \
+    (((guint32) (val) & (guint32) 0x00ff0000U) >>  8) | \
+    (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
+
+#define GUINT64_SWAP_LE_BE_CONSTANT(val)       ((guint64) ( \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x00000000000000ffU)) << 56) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x000000000000ff00U)) << 40) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x0000000000ff0000U)) << 24) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x00000000ff000000U)) <<  8) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x000000ff00000000U)) >>  8) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x0000ff0000000000U)) >> 24) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0x00ff000000000000U)) >> 40) |     \
+      (((guint64) (val) &                                              \
+       (guint64) G_GINT64_CONSTANT (0xff00000000000000U)) >> 56)))
+
+/* Arch specific stuff for speed
+ */
+#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
+#  if defined (__i386__)
+#    define GUINT16_SWAP_LE_BE_IA32(val) \
+       (__extension__                                          \
+       ({ register guint16 __v, __x = ((guint16) (val));       \
+          if (__builtin_constant_p (__x))                      \
+            __v = GUINT16_SWAP_LE_BE_CONSTANT (__x);           \
+          else                                                 \
+            __asm__ ("rorw $8, %w0"                            \
+                     : "=r" (__v)                              \
+                     : "0" (__x)                               \
+                     : "cc");                                  \
+           __v; }))
+#    if !defined (__i486__) && !defined (__i586__) \
+       && !defined (__pentium__) && !defined (__i686__) \
+       && !defined (__pentiumpro__) && !defined (__pentium4__)
+#       define GUINT32_SWAP_LE_BE_IA32(val) \
+         (__extension__                                        \
+          ({ register guint32 __v, __x = ((guint32) (val));    \
+             if (__builtin_constant_p (__x))                   \
+               __v = GUINT32_SWAP_LE_BE_CONSTANT (__x);        \
+             else                                              \
+               __asm__ ("rorw $8, %w0\n\t"                     \
+                        "rorl $16, %0\n\t"                     \
+                        "rorw $8, %w0"                         \
+                        : "=r" (__v)                           \
+                        : "0" (__x)                            \
+                        : "cc");                               \
+             __v; }))
+#    else /* 486 and higher has bswap */
+#       define GUINT32_SWAP_LE_BE_IA32(val) \
+         (__extension__                                        \
+          ({ register guint32 __v, __x = ((guint32) (val));    \
+             if (__builtin_constant_p (__x))                   \
+               __v = GUINT32_SWAP_LE_BE_CONSTANT (__x);        \
+             else                                              \
+               __asm__ ("bswap %0"                             \
+                        : "=r" (__v)                           \
+                        : "0" (__x));                          \
+             __v; }))
+#    endif /* processor specific 32-bit stuff */
+#    define GUINT64_SWAP_LE_BE_IA32(val) \
+       (__extension__                                                  \
+       ({ union { guint64 __ll;                                        \
+                  guint32 __l[2]; } __w, __r;                          \
+          __w.__ll = ((guint64) (val));                                \
+          if (__builtin_constant_p (__w.__ll))                         \
+            __r.__ll = GUINT64_SWAP_LE_BE_CONSTANT (__w.__ll);         \
+          else                                                         \
+            {                                                          \
+              __r.__l[0] = GUINT32_SWAP_LE_BE (__w.__l[1]);            \
+              __r.__l[1] = GUINT32_SWAP_LE_BE (__w.__l[0]);            \
+            }                                                          \
+          __r.__ll; }))
+     /* Possibly just use the constant version and let gcc figure it out? */
+#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA32 (val))
+#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA32 (val))
+#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA32 (val))
+#  elif defined (__ia64__)
+#    define GUINT16_SWAP_LE_BE_IA64(val) \
+       (__extension__                                          \
+       ({ register guint16 __v, __x = ((guint16) (val));       \
+          if (__builtin_constant_p (__x))                      \
+            __v = GUINT16_SWAP_LE_BE_CONSTANT (__x);           \
+          else                                                 \
+            __asm__ __volatile__ ("shl %0 = %1, 48 ;;"         \
+                                  "mux1 %0 = %0, @rev ;;"      \
+                                   : "=r" (__v)                \
+                                   : "r" (__x));               \
+           __v; }))
+#    define GUINT32_SWAP_LE_BE_IA64(val) \
+       (__extension__                                          \
+        ({ register guint32 __v, __x = ((guint32) (val));      \
+           if (__builtin_constant_p (__x))                     \
+             __v = GUINT32_SWAP_LE_BE_CONSTANT (__x);          \
+           else                                                \
+            __asm__ __volatile__ ("shl %0 = %1, 32 ;;"         \
+                                  "mux1 %0 = %0, @rev ;;"      \
+                                   : "=r" (__v)                \
+                                   : "r" (__x));               \
+           __v; }))
+#    define GUINT64_SWAP_LE_BE_IA64(val) \
+       (__extension__                                          \
+       ({ register guint64 __v, __x = ((guint64) (val));       \
+          if (__builtin_constant_p (__x))                      \
+            __v = GUINT64_SWAP_LE_BE_CONSTANT (__x);           \
+          else                                                 \
+            __asm__ __volatile__ ("mux1 %0 = %1, @rev ;;"      \
+                                  : "=r" (__v)                 \
+                                  : "r" (__x));                \
+          __v; }))
+#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_IA64 (val))
+#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_IA64 (val))
+#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_IA64 (val))
+#  elif defined (__x86_64__)
+#    define GUINT32_SWAP_LE_BE_X86_64(val) \
+       (__extension__                                          \
+        ({ register guint32 __v, __x = ((guint32) (val));      \
+           if (__builtin_constant_p (__x))                     \
+             __v = GUINT32_SWAP_LE_BE_CONSTANT (__x);          \
+           else                                                \
+            __asm__ ("bswapl %0"                               \
+                     : "=r" (__v)                              \
+                     : "0" (__x));                             \
+           __v; }))
+#    define GUINT64_SWAP_LE_BE_X86_64(val) \
+       (__extension__                                          \
+       ({ register guint64 __v, __x = ((guint64) (val));       \
+          if (__builtin_constant_p (__x))                      \
+            __v = GUINT64_SWAP_LE_BE_CONSTANT (__x);           \
+          else                                                 \
+            __asm__ ("bswapq %0"                               \
+                     : "=r" (__v)                              \
+                     : "0" (__x));                             \
+          __v; }))
+     /* gcc seems to figure out optimal code for this on its own */
+#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_X86_64 (val))
+#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_X86_64 (val))
+#  else /* generic gcc */
+#    define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+#    define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
+#    define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val))
+#  endif
+#else /* generic */
+#  define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
+#  define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
+#  define GUINT64_SWAP_LE_BE(val) (GUINT64_SWAP_LE_BE_CONSTANT (val))
+#endif /* generic */
+
+#define GUINT16_SWAP_LE_PDP(val)       ((guint16) (val))
+#define GUINT16_SWAP_BE_PDP(val)       (GUINT16_SWAP_LE_BE (val))
+#define GUINT32_SWAP_LE_PDP(val)       ((guint32) ( \
+    (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
+    (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
+#define GUINT32_SWAP_BE_PDP(val)       ((guint32) ( \
+    (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
+    (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
+
+/* The G*_TO_?E() macros are defined in glibconfig.h.
+ * The transformation is symmetric, so the FROM just maps to the TO.
+ */
+#define GINT16_FROM_LE(val)    (GINT16_TO_LE (val))
+#define GUINT16_FROM_LE(val)   (GUINT16_TO_LE (val))
+#define GINT16_FROM_BE(val)    (GINT16_TO_BE (val))
+#define GUINT16_FROM_BE(val)   (GUINT16_TO_BE (val))
+#define GINT32_FROM_LE(val)    (GINT32_TO_LE (val))
+#define GUINT32_FROM_LE(val)   (GUINT32_TO_LE (val))
+#define GINT32_FROM_BE(val)    (GINT32_TO_BE (val))
+#define GUINT32_FROM_BE(val)   (GUINT32_TO_BE (val))
+
+#define GINT64_FROM_LE(val)    (GINT64_TO_LE (val))
+#define GUINT64_FROM_LE(val)   (GUINT64_TO_LE (val))
+#define GINT64_FROM_BE(val)    (GINT64_TO_BE (val))
+#define GUINT64_FROM_BE(val)   (GUINT64_TO_BE (val))
+
+#define GLONG_FROM_LE(val)     (GLONG_TO_LE (val))
+#define GULONG_FROM_LE(val)    (GULONG_TO_LE (val))
+#define GLONG_FROM_BE(val)     (GLONG_TO_BE (val))
+#define GULONG_FROM_BE(val)    (GULONG_TO_BE (val))
+
+#define GINT_FROM_LE(val)      (GINT_TO_LE (val))
+#define GUINT_FROM_LE(val)     (GUINT_TO_LE (val))
+#define GINT_FROM_BE(val)      (GINT_TO_BE (val))
+#define GUINT_FROM_BE(val)     (GUINT_TO_BE (val))
+
+
+/* Portable versions of host-network order stuff
+ */
+#define g_ntohl(val) (GUINT32_FROM_BE (val))
+#define g_ntohs(val) (GUINT16_FROM_BE (val))
+#define g_htonl(val) (GUINT32_TO_BE (val))
+#define g_htons(val) (GUINT16_TO_BE (val))
+
+/* IEEE Standard 754 Single Precision Storage Format (gfloat):
+ *
+ *        31 30           23 22            0
+ * +--------+---------------+---------------+
+ * | s 1bit | e[30:23] 8bit | f[22:0] 23bit |
+ * +--------+---------------+---------------+
+ * B0------------------->B1------->B2-->B3-->
+ *
+ * IEEE Standard 754 Double Precision Storage Format (gdouble):
+ *
+ *        63 62            52 51            32   31            0
+ * +--------+----------------+----------------+ +---------------+
+ * | s 1bit | e[62:52] 11bit | f[51:32] 20bit | | f[31:0] 32bit |
+ * +--------+----------------+----------------+ +---------------+
+ * B0--------------->B1---------->B2--->B3---->  B4->B5->B6->B7->
+ */
+/* subtract from biased_exponent to form base2 exponent (normal numbers) */
+typedef union  _GDoubleIEEE754 GDoubleIEEE754;
+typedef union  _GFloatIEEE754  GFloatIEEE754;
+#define G_IEEE754_FLOAT_BIAS   (127)
+#define G_IEEE754_DOUBLE_BIAS  (1023)
+/* multiply with base2 exponent to get base10 exponent (normal numbers) */
+#define G_LOG_2_BASE_10                (0.30102999566398119521)
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+union _GFloatIEEE754
+{
+  gfloat v_float;
+  struct {
+    guint mantissa : 23;
+    guint biased_exponent : 8;
+    guint sign : 1;
+  } mpn;
+};
+union _GDoubleIEEE754
+{
+  gdouble v_double;
+  struct {
+    guint mantissa_low : 32;
+    guint mantissa_high : 20;
+    guint biased_exponent : 11;
+    guint sign : 1;
+  } mpn;
+};
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+union _GFloatIEEE754
+{
+  gfloat v_float;
+  struct {
+    guint sign : 1;
+    guint biased_exponent : 8;
+    guint mantissa : 23;
+  } mpn;
+};
+union _GDoubleIEEE754
+{
+  gdouble v_double;
+  struct {
+    guint sign : 1;
+    guint biased_exponent : 11;
+    guint mantissa_high : 20;
+    guint mantissa_low : 32;
+  } mpn;
+};
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+typedef struct _GTimeVal                GTimeVal;
+
+struct _GTimeVal
+{
+  glong tv_sec;
+  glong tv_usec;
+};
+
+G_END_DECLS
+
+/* We prefix variable declarations so they can
+ * properly get exported in Windows DLLs.
+ */
+#ifndef GLIB_VAR
+#  ifdef G_PLATFORM_WIN32
+#    ifdef GLIB_STATIC_COMPILATION
+#      define GLIB_VAR extern
+#    else /* !GLIB_STATIC_COMPILATION */
+#      ifdef GLIB_COMPILATION
+#        ifdef DLL_EXPORT
+#          define GLIB_VAR __declspec(dllexport)
+#        else /* !DLL_EXPORT */
+#          define GLIB_VAR extern
+#        endif /* !DLL_EXPORT */
+#      else /* !GLIB_COMPILATION */
+#        define GLIB_VAR extern __declspec(dllimport)
+#      endif /* !GLIB_COMPILATION */
+#    endif /* !GLIB_STATIC_COMPILATION */
+#  else /* !G_PLATFORM_WIN32 */
+#    define GLIB_VAR extern
+#  endif /* !G_PLATFORM_WIN32 */
+#endif /* GLIB_VAR */
+
+#endif /* __G_TYPES_H__ */
diff --git a/navit/navit/support/glib/gutils.c b/navit/navit/support/glib/gutils.c
new file mode 100644 (file)
index 0000000..df9c658
--- /dev/null
@@ -0,0 +1,3410 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1998  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 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
+ * Lesser General Public License for more details.
+ *
+ * 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-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 for the unix part, FIXME: make the win32 part MT safe as well.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+#include <ctype.h>             /* For tolower() */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_CRT_EXTERNS_H 
+#include <crt_externs.h> /* for _NSGetEnviron */
+#endif
+
+/* implement gutils's inline functions
+ */
+#define        G_IMPLEMENT_INLINES 1
+#define        __G_UTILS_C__
+#include "glib.h"
+#include "gprintfint.h"
+#include "gthreadprivate.h"
+#include "glibintl.h"
+#include "galias.h"
+
+#ifdef MAXPATHLEN
+#define        G_PATH_LENGTH   MAXPATHLEN
+#elif  defined (PATH_MAX)
+#define        G_PATH_LENGTH   PATH_MAX
+#elif   defined (_PC_PATH_MAX)
+#define        G_PATH_LENGTH   sysconf(_PC_PATH_MAX)
+#else  
+#define G_PATH_LENGTH   2048
+#endif
+
+#ifdef G_PLATFORM_WIN32
+#  define STRICT               /* Strict typing, please */
+#  include <windows.h>
+#  undef STRICT
+#  ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
+#    define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
+#    define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
+#  endif
+#  include <lmcons.h>          /* For UNLEN */
+#endif /* G_PLATFORM_WIN32 */
+
+#ifdef G_OS_WIN32
+#  include <direct.h>
+#  include <shlobj.h>
+   /* older SDK (e.g. msvc 5.0) does not have these*/
+#  ifndef CSIDL_MYMUSIC
+#    define CSIDL_MYMUSIC 13
+#  endif
+#  ifndef CSIDL_MYVIDEO
+#    define CSIDL_MYVIDEO 14
+#  endif
+#  ifndef CSIDL_INTERNET_CACHE
+#    define CSIDL_INTERNET_CACHE 32
+#  endif
+#  ifndef CSIDL_COMMON_APPDATA
+#    define CSIDL_COMMON_APPDATA 35
+#  endif
+#  ifndef CSIDL_MYPICTURES
+#    define CSIDL_MYPICTURES 0x27
+#  endif
+#  ifndef CSIDL_COMMON_DOCUMENTS
+#    define CSIDL_COMMON_DOCUMENTS 46
+#  endif
+#  ifndef CSIDL_PROFILE
+#    define CSIDL_PROFILE 40
+#  endif
+#  include <process.h>
+#endif
+
+#ifdef HAVE_CARBON
+#include <CoreServices/CoreServices.h>
+#endif
+
+#ifdef HAVE_CODESET
+#include <langinfo.h>
+#endif
+
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+#include <libintl.h>
+#endif
+
+const guint glib_major_version = GLIB_MAJOR_VERSION;
+const guint glib_minor_version = GLIB_MINOR_VERSION;
+const guint glib_micro_version = GLIB_MICRO_VERSION;
+const guint glib_interface_age = GLIB_INTERFACE_AGE;
+const guint glib_binary_age = GLIB_BINARY_AGE;
+
+#ifdef G_PLATFORM_WIN32
+
+static HMODULE glib_dll = NULL;
+
+#ifdef DLL_EXPORT
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+        DWORD     fdwReason,
+        LPVOID    lpvReserved)
+{
+  if (fdwReason == DLL_PROCESS_ATTACH)
+      glib_dll = hinstDLL;
+
+  return TRUE;
+}
+
+#endif
+
+gchar *
+_glib_get_installation_directory (void)
+{
+#ifdef DLL_EXPORT
+  if (glib_dll == NULL)
+    return NULL;
+#endif
+  /* In a static build of GLib just use the application's .exe file's
+   * installation directory...
+   */
+  return g_win32_get_package_installation_directory_of_module (glib_dll);
+}
+
+#endif
+
+/**
+ * glib_check_version:
+ * @required_major: the required major version.
+ * @required_minor: the required minor version.
+ * @required_micro: the required micro version.
+ *
+ * Checks that the GLib library in use is compatible with the
+ * given version. Generally you would pass in the constants
+ * #GLIB_MAJOR_VERSION, #GLIB_MINOR_VERSION, #GLIB_MICRO_VERSION
+ * as the three arguments to this function; that produces
+ * a check that the library in use is compatible with
+ * the version of GLib the application or module was compiled
+ * against.
+ *
+ * Compatibility is defined by two things: first the version
+ * of the running library is newer than the version
+ * @required_major.required_minor.@required_micro. Second
+ * the running library must be binary compatible with the
+ * version @required_major.required_minor.@required_micro
+ * (same major version.)
+ *
+ * Return value: %NULL if the GLib library is compatible with the
+ *   given version, or a string describing the version mismatch.
+ *   The returned string is owned by GLib and must not be modified
+ *   or freed.
+ *
+ * Since: 2.6
+ **/
+const gchar *
+glib_check_version (guint required_major,
+                    guint required_minor,
+                    guint required_micro)
+{
+  gint glib_effective_micro = 100 * GLIB_MINOR_VERSION + GLIB_MICRO_VERSION;
+  gint required_effective_micro = 100 * required_minor + required_micro;
+
+  if (required_major > GLIB_MAJOR_VERSION)
+    return "GLib version too old (major mismatch)";
+  if (required_major < GLIB_MAJOR_VERSION)
+    return "GLib version too new (major mismatch)";
+  if (required_effective_micro < glib_effective_micro - GLIB_BINARY_AGE)
+    return "GLib version too new (micro mismatch)";
+  if (required_effective_micro > glib_effective_micro)
+    return "GLib version too old (micro mismatch)";
+  return NULL;
+}
+
+#if !defined (HAVE_MEMMOVE) && !defined (HAVE_WORKING_BCOPY)
+/**
+ * g_memmove: 
+ * @dest: the destination address to copy the bytes to.
+ * @src: the source address to copy the bytes from.
+ * @len: the number of bytes to copy.
+ *
+ * Copies a block of memory @len bytes long, from @src to @dest.
+ * The source and destination areas may overlap.
+ *
+ * In order to use this function, you must include 
+ * <filename>string.h</filename> yourself, because this macro will 
+ * typically simply resolve to memmove() and GLib does not include 
+ * <filename>string.h</filename> for you.
+ */
+void 
+g_memmove (gpointer      dest, 
+          gconstpointer src, 
+          gulong        len)
+{
+  gchar* destptr = dest;
+  const gchar* srcptr = src;
+  if (src + len < dest || dest + len < src)
+    {
+      bcopy (src, dest, len);
+      return;
+    }
+  else if (dest <= src)
+    {
+      while (len--)
+       *(destptr++) = *(srcptr++);
+    }
+  else
+    {
+      destptr += len;
+      srcptr += len;
+      while (len--)
+       *(--destptr) = *(--srcptr);
+    }
+}
+#endif /* !HAVE_MEMMOVE && !HAVE_WORKING_BCOPY */
+
+#ifdef G_OS_WIN32
+#undef g_atexit
+#endif
+
+/**
+ * g_atexit:
+ * @func: the function to call on normal program termination.
+ * 
+ * Specifies a function to be called at normal program termination.
+ *
+ * Since GLib 2.8.2, on Windows g_atexit() actually is a preprocessor
+ * macro that maps to a call to the atexit() function in the C
+ * library. This means that in case the code that calls g_atexit(),
+ * i.e. atexit(), is in a DLL, the function will be called when the
+ * DLL is detached from the program. This typically makes more sense
+ * than that the function is called when the GLib DLL is detached,
+ * which happened earlier when g_atexit() was a function in the GLib
+ * DLL.
+ *
+ * The behaviour of atexit() in the context of dynamically loaded
+ * modules is not formally specified and varies wildly.
+ *
+ * On POSIX systems, calling g_atexit() (or atexit()) in a dynamically
+ * loaded module which is unloaded before the program terminates might
+ * well cause a crash at program exit.
+ *
+ * Some POSIX systems implement atexit() like Windows, and have each
+ * dynamically loaded module maintain an own atexit chain that is
+ * called when the module is unloaded.
+ *
+ * On other POSIX systems, before a dynamically loaded module is
+ * unloaded, the registered atexit functions (if any) residing in that
+ * module are called, regardless where the code that registered them
+ * resided. This is presumably the most robust approach.
+ *
+ * As can be seen from the above, for portability it's best to avoid
+ * calling g_atexit() (or atexit()) except in the main executable of a
+ * program.
+ */
+void
+g_atexit (GVoidFunc func)
+{
+  gint result;
+  const gchar *error = NULL;
+
+  /* keep this in sync with glib.h */
+
+#ifdef G_NATIVE_ATEXIT
+  result = ATEXIT (func);
+  if (result)
+    error = g_strerror (errno);
+#elif defined (HAVE_ATEXIT)
+#  ifdef NeXT /* @#%@! NeXTStep */
+  result = !atexit ((void (*)(void)) func);
+  if (result)
+    error = g_strerror (errno);
+#  else
+  result = atexit ((void (*)(void)) func);
+  if (result)
+    error = g_strerror (errno);
+#  endif /* NeXT */
+#elif defined (HAVE_ON_EXIT)
+  result = on_exit ((void (*)(int, void *)) func, NULL);
+  if (result)
+    error = g_strerror (errno);
+#else
+  result = 0;
+  error = "no implementation";
+#endif /* G_NATIVE_ATEXIT */
+
+  if (error)
+    g_error ("Could not register atexit() function: %s", error);
+}
+
+/* Based on execvp() from GNU Libc.
+ * Some of this code is cut-and-pasted into gspawn.c
+ */
+
+static gchar*
+my_strchrnul (const gchar *str, 
+             gchar        c)
+{
+  gchar *p = (gchar*)str;
+  while (*p && (*p != c))
+    ++p;
+
+  return p;
+}
+
+#ifdef G_OS_WIN32
+
+static gchar *inner_find_program_in_path (const gchar *program);
+
+gchar*
+g_find_program_in_path (const gchar *program)
+{
+  const gchar *last_dot = strrchr (program, '.');
+
+  if (last_dot == NULL ||
+      strchr (last_dot, '\\') != NULL ||
+      strchr (last_dot, '/') != NULL)
+    {
+      const gint program_length = strlen (program);
+      gchar *pathext = g_build_path (";",
+                                    ".exe;.cmd;.bat;.com",
+                                    g_getenv ("PATHEXT"),
+                                    NULL);
+      gchar *p;
+      gchar *decorated_program;
+      gchar *retval;
+
+      p = pathext;
+      do
+       {
+         gchar *q = my_strchrnul (p, ';');
+
+         decorated_program = g_malloc (program_length + (q-p) + 1);
+         memcpy (decorated_program, program, program_length);
+         memcpy (decorated_program+program_length, p, q-p);
+         decorated_program [program_length + (q-p)] = '\0';
+         
+         retval = inner_find_program_in_path (decorated_program);
+         g_free (decorated_program);
+
+         if (retval != NULL)
+           {
+             g_free (pathext);
+             return retval;
+           }
+         p = q;
+       } while (*p++ != '\0');
+      g_free (pathext);
+      return NULL;
+    }
+  else
+    return inner_find_program_in_path (program);
+}
+
+#endif
+
+/**
+ * g_find_program_in_path:
+ * @program: a program name in the GLib file name encoding
+ * 
+ * Locates the first executable named @program in the user's path, in the
+ * same way that execvp() would locate it. Returns an allocated string
+ * with the absolute path name, or %NULL if the program is not found in
+ * the path. If @program is already an absolute path, returns a copy of
+ * @program if @program exists and is executable, and %NULL otherwise.
+ *  
+ * On Windows, if @program does not have a file type suffix, tries
+ * with the suffixes .exe, .cmd, .bat and .com, and the suffixes in
+ * the <envar>PATHEXT</envar> environment variable. 
+ * 
+ * On Windows, it looks for the file in the same way as CreateProcess() 
+ * would. This means first in the directory where the executing
+ * program was loaded from, then in the current directory, then in the
+ * Windows 32-bit system directory, then in the Windows directory, and
+ * finally in the directories in the <envar>PATH</envar> environment 
+ * variable. If the program is found, the return value contains the 
+ * full name including the type suffix.
+ *
+ * Return value: absolute path, or %NULL
+ **/
+#ifdef G_OS_WIN32
+static gchar *
+inner_find_program_in_path (const gchar *program)
+#else
+gchar*
+g_find_program_in_path (const gchar *program)
+#endif
+{
+  const gchar *path, *p;
+  gchar *name, *freeme;
+#ifdef G_OS_WIN32
+  const gchar *path_copy;
+  gchar *filename = NULL, *appdir = NULL;
+  gchar *sysdir = NULL, *windir = NULL;
+  int n;
+  wchar_t wfilename[MAXPATHLEN], wsysdir[MAXPATHLEN],
+    wwindir[MAXPATHLEN];
+#endif
+  gsize len;
+  gsize pathlen;
+
+  g_return_val_if_fail (program != NULL, NULL);
+
+  /* If it is an absolute path, or a relative path including subdirectories,
+   * don't look in PATH.
+   */
+  if (g_path_is_absolute (program)
+      || strchr (program, G_DIR_SEPARATOR) != NULL
+#ifdef G_OS_WIN32
+      || strchr (program, '/') != NULL
+#endif
+      )
+    {
+      if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE) &&
+         !g_file_test (program, G_FILE_TEST_IS_DIR))
+        return g_strdup (program);
+      else
+        return NULL;
+    }
+  
+  path = g_getenv ("PATH");
+#if defined(G_OS_UNIX) || defined(G_OS_BEOS)
+  if (path == NULL)
+    {
+      /* There is no `PATH' in the environment.  The default
+       * search path in GNU libc is the current directory followed by
+       * the path `confstr' returns for `_CS_PATH'.
+       */
+      
+      /* In GLib we put . last, for security, and don't use the
+       * unportable confstr(); UNIX98 does not actually specify
+       * what to search if PATH is unset. POSIX may, dunno.
+       */
+      
+      path = "/bin:/usr/bin:.";
+    }
+#else
+  n = GetModuleFileNameW (NULL, wfilename, MAXPATHLEN);
+  if (n > 0 && n < MAXPATHLEN)
+    filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL);
+  
+  n = GetSystemDirectoryW (wsysdir, MAXPATHLEN);
+  if (n > 0 && n < MAXPATHLEN)
+    sysdir = g_utf16_to_utf8 (wsysdir, -1, NULL, NULL, NULL);
+  
+  n = GetWindowsDirectoryW (wwindir, MAXPATHLEN);
+  if (n > 0 && n < MAXPATHLEN)
+    windir = g_utf16_to_utf8 (wwindir, -1, NULL, NULL, NULL);
+  
+  if (filename)
+    {
+      appdir = g_path_get_dirname (filename);
+      g_free (filename);
+    }
+  
+  path = g_strdup (path);
+
+  if (windir)
+    {
+      const gchar *tem = path;
+      path = g_strconcat (windir, ";", path, NULL);
+      g_free ((gchar *) tem);
+      g_free (windir);
+    }
+  
+  if (sysdir)
+    {
+      const gchar *tem = path;
+      path = g_strconcat (sysdir, ";", path, NULL);
+      g_free ((gchar *) tem);
+      g_free (sysdir);
+    }
+  
+  {
+    const gchar *tem = path;
+    path = g_strconcat (".;", path, NULL);
+    g_free ((gchar *) tem);
+  }
+  
+  if (appdir)
+    {
+      const gchar *tem = path;
+      path = g_strconcat (appdir, ";", path, NULL);
+      g_free ((gchar *) tem);
+      g_free (appdir);
+    }
+
+  path_copy = path;
+#endif
+  
+  len = strlen (program) + 1;
+  pathlen = strlen (path);
+  freeme = name = g_malloc (pathlen + len + 1);
+  
+  /* Copy the file name at the top, including '\0'  */
+  memcpy (name + pathlen + 1, program, len);
+  name = name + pathlen;
+  /* And add the slash before the filename  */
+  *name = G_DIR_SEPARATOR;
+  
+  p = path;
+  do
+    {
+      char *startp;
+
+      path = p;
+      p = my_strchrnul (path, G_SEARCHPATH_SEPARATOR);
+
+      if (p == path)
+        /* Two adjacent colons, or a colon at the beginning or the end
+         * of `PATH' means to search the current directory.
+         */
+        startp = name + 1;
+      else
+        startp = memcpy (name - (p - path), path, p - path);
+
+      if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE) &&
+         !g_file_test (startp, G_FILE_TEST_IS_DIR))
+        {
+          gchar *ret;
+          ret = g_strdup (startp);
+          g_free (freeme);
+#ifdef G_OS_WIN32
+         g_free ((gchar *) path_copy);
+#endif
+          return ret;
+        }
+    }
+  while (*p++ != '\0');
+  
+  g_free (freeme);
+#ifdef G_OS_WIN32
+  g_free ((gchar *) path_copy);
+#endif
+
+  return NULL;
+}
+
+static gboolean
+debug_key_matches (const gchar *key,
+                  const gchar *token,
+                  guint        length)
+{
+  for (; length; length--, key++, token++)
+    {
+      char k = (*key   == '_') ? '-' : tolower (*key  );
+      char t = (*token == '_') ? '-' : tolower (*token);
+
+      if (k != t)
+        return FALSE;
+    }
+
+  return *key == '\0';
+}
+
+/**
+ * g_parse_debug_string:
+ * @string: a list of debug options separated by colons, spaces, or
+ * commas; or the string "all" to set all flags, or %NULL.
+ * @keys: pointer to an array of #GDebugKey which associate 
+ *     strings with bit flags.
+ * @nkeys: the number of #GDebugKey<!-- -->s in the array.
+ *
+ * Parses a string containing debugging options
+ * into a %guint containing bit flags. This is used 
+ * within GDK and GTK+ to parse the debug options passed on the
+ * command line or through environment variables.
+ *
+ * Returns: the combined set of bit flags.
+ */
+guint       
+g_parse_debug_string  (const gchar     *string, 
+                      const GDebugKey *keys, 
+                      guint            nkeys)
+{
+  guint i;
+  guint result = 0;
+  
+  if (string == NULL)
+    return 0;
+
+  /* this function is used by gmem.c/gslice.c initialization code,
+   * so introducing malloc dependencies here would require adaptions
+   * of those code portions.
+   */
+  
+  if (!g_ascii_strcasecmp (string, "all"))
+    {
+      for (i=0; i<nkeys; i++)
+       result |= keys[i].value;
+    }
+  else
+    {
+      const gchar *p = string;
+      const gchar *q;
+      
+      while (*p)
+       {
+         q = strpbrk (p, ":;, \t");
+         if (!q)
+           q = p + strlen(p);
+         
+         for (i = 0; i < nkeys; i++)
+           if (debug_key_matches (keys[i].key, p, q - p))
+             result |= keys[i].value;
+         
+         p = q;
+         if (*p)
+           p++;
+       }
+    }
+  
+  return result;
+}
+
+/**
+ * g_basename:
+ * @file_name: the name of the file.
+ * 
+ * Gets the name of the file without any leading directory components.  
+ * It returns a pointer into the given file name string.
+ * 
+ * Return value: the name of the file without any leading directory components.
+ *
+ * Deprecated:2.2: Use g_path_get_basename() instead, but notice that
+ * g_path_get_basename() allocates new memory for the returned string, unlike
+ * this function which returns a pointer into the argument.
+ **/
+G_CONST_RETURN gchar*
+g_basename (const gchar           *file_name)
+{
+  register gchar *base;
+  
+  g_return_val_if_fail (file_name != NULL, NULL);
+  
+  base = strrchr (file_name, G_DIR_SEPARATOR);
+
+#ifdef G_OS_WIN32
+  {
+    gchar *q = strrchr (file_name, '/');
+    if (base == NULL || (q != NULL && q > base))
+       base = q;
+  }
+#endif
+
+  if (base)
+    return base + 1;
+
+#ifdef G_OS_WIN32
+  if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+    return (gchar*) file_name + 2;
+#endif /* G_OS_WIN32 */
+  
+  return (gchar*) file_name;
+}
+
+/**
+ * g_path_get_basename:
+ * @file_name: the name of the file.
+ *
+ * Gets the last component of the filename. If @file_name ends with a 
+ * directory separator it gets the component before the last slash. If 
+ * @file_name consists only of directory separators (and on Windows, 
+ * possibly a drive letter), a single separator is returned. If
+ * @file_name is empty, it gets ".".
+ *
+ * Return value: a newly allocated string containing the last component of 
+ *   the filename.
+ */
+gchar*
+g_path_get_basename (const gchar   *file_name)
+{
+  register gssize base;             
+  register gssize last_nonslash;    
+  gsize len;    
+  gchar *retval;
+  g_return_val_if_fail (file_name != NULL, NULL);
+
+  if (file_name[0] == '\0')
+    /* empty string */
+    return g_strdup (".");
+  
+  last_nonslash = strlen (file_name) - 1;
+
+  while (last_nonslash >= 0 && G_IS_DIR_SEPARATOR (file_name [last_nonslash]))
+    last_nonslash--;
+
+  if (last_nonslash == -1)
+    /* string only containing slashes */
+    return g_strdup (G_DIR_SEPARATOR_S);
+
+#ifdef G_OS_WIN32
+  if (last_nonslash == 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+    /* string only containing slashes and a drive */
+    return g_strdup (G_DIR_SEPARATOR_S);
+#endif /* G_OS_WIN32 */
+
+  base = last_nonslash;
+
+  while (base >=0 && !G_IS_DIR_SEPARATOR (file_name [base]))
+    base--;
+
+#ifdef G_OS_WIN32
+  if (base == -1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+    base = 1;
+#endif /* G_OS_WIN32 */
+
+  len = last_nonslash - base;
+  retval = g_malloc (len + 1);
+  memcpy (retval, file_name + base + 1, len);
+  retval [len] = '\0';
+  return retval;
+}
+
+/**
+ * g_path_is_absolute:
+ * @file_name: a file name.
+ *
+ * Returns %TRUE if the given @file_name is an absolute file name,
+ * i.e. it contains a full path from the root directory such as "/usr/local"
+ * on UNIX or "C:\windows" on Windows systems.
+ *
+ * Returns: %TRUE if @file_name is an absolute path. 
+ */
+gboolean
+g_path_is_absolute (const gchar *file_name)
+{
+  g_return_val_if_fail (file_name != NULL, FALSE);
+  
+  if (G_IS_DIR_SEPARATOR (file_name[0]))
+    return TRUE;
+
+#ifdef G_OS_WIN32
+  /* Recognize drive letter on native Windows */
+  if (g_ascii_isalpha (file_name[0]) && 
+      file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
+    return TRUE;
+#endif /* G_OS_WIN32 */
+
+  return FALSE;
+}
+
+/**
+ * g_path_skip_root:
+ * @file_name: a file name.
+ *
+ * Returns a pointer into @file_name after the root component, i.e. after
+ * the "/" in UNIX or "C:\" under Windows. If @file_name is not an absolute
+ * path it returns %NULL.
+ *
+ * Returns: a pointer into @file_name after the root component.
+ */
+G_CONST_RETURN gchar*
+g_path_skip_root (const gchar *file_name)
+{
+  g_return_val_if_fail (file_name != NULL, NULL);
+  
+#ifdef G_PLATFORM_WIN32
+  /* Skip \\server\share or //server/share */
+  if (G_IS_DIR_SEPARATOR (file_name[0]) &&
+      G_IS_DIR_SEPARATOR (file_name[1]) &&
+      file_name[2] &&
+      !G_IS_DIR_SEPARATOR (file_name[2]))
+    {
+      gchar *p;
+
+      p = strchr (file_name + 2, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+      {
+       gchar *q = strchr (file_name + 2, '/');
+       if (p == NULL || (q != NULL && q < p))
+         p = q;
+      }
+#endif
+      if (p &&
+         p > file_name + 2 &&
+         p[1])
+       {
+         file_name = p + 1;
+
+         while (file_name[0] && !G_IS_DIR_SEPARATOR (file_name[0]))
+           file_name++;
+
+         /* Possibly skip a backslash after the share name */
+         if (G_IS_DIR_SEPARATOR (file_name[0]))
+           file_name++;
+
+         return (gchar *)file_name;
+       }
+    }
+#endif
+  
+  /* Skip initial slashes */
+  if (G_IS_DIR_SEPARATOR (file_name[0]))
+    {
+      while (G_IS_DIR_SEPARATOR (file_name[0]))
+       file_name++;
+      return (gchar *)file_name;
+    }
+
+#ifdef G_OS_WIN32
+  /* Skip X:\ */
+  if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
+    return (gchar *)file_name + 3;
+#endif
+
+  return NULL;
+}
+
+/**
+ * g_path_get_dirname:
+ * @file_name: the name of the file.
+ *
+ * Gets the directory components of a file name.  If the file name has no
+ * directory components "." is returned.  The returned string should be
+ * freed when no longer needed.
+ * 
+ * Returns: the directory components of the file.
+ */
+gchar*
+g_path_get_dirname (const gchar           *file_name)
+{
+  register gchar *base;
+  register gsize len;    
+  
+  g_return_val_if_fail (file_name != NULL, NULL);
+  
+  base = strrchr (file_name, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+  {
+    gchar *q = strrchr (file_name, '/');
+    if (base == NULL || (q != NULL && q > base))
+       base = q;
+  }
+#endif
+  if (!base)
+    {
+#ifdef G_OS_WIN32
+      if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+       {
+         gchar drive_colon_dot[4];
+
+         drive_colon_dot[0] = file_name[0];
+         drive_colon_dot[1] = ':';
+         drive_colon_dot[2] = '.';
+         drive_colon_dot[3] = '\0';
+
+         return g_strdup (drive_colon_dot);
+       }
+#endif
+    return g_strdup (".");
+    }
+
+  while (base > file_name && G_IS_DIR_SEPARATOR (*base))
+    base--;
+
+#ifdef G_OS_WIN32
+  /* base points to the char before the last slash.
+   *
+   * In case file_name is the root of a drive (X:\) or a child of the
+   * root of a drive (X:\foo), include the slash.
+   *
+   * In case file_name is the root share of an UNC path
+   * (\\server\share), add a slash, returning \\server\share\ .
+   *
+   * In case file_name is a direct child of a share in an UNC path
+   * (\\server\share\foo), include the slash after the share name,
+   * returning \\server\share\ .
+   */
+  if (base == file_name + 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
+    base++;
+  else if (G_IS_DIR_SEPARATOR (file_name[0]) &&
+          G_IS_DIR_SEPARATOR (file_name[1]) &&
+          file_name[2] &&
+          !G_IS_DIR_SEPARATOR (file_name[2]) &&
+          base >= file_name + 2)
+    {
+      const gchar *p = file_name + 2;
+      while (*p && !G_IS_DIR_SEPARATOR (*p))
+       p++;
+      if (p == base + 1)
+       {
+         len = (guint) strlen (file_name) + 1;
+         base = g_new (gchar, len + 1);
+         strcpy (base, file_name);
+         base[len-1] = G_DIR_SEPARATOR;
+         base[len] = 0;
+         return base;
+       }
+      if (G_IS_DIR_SEPARATOR (*p))
+       {
+         p++;
+         while (*p && !G_IS_DIR_SEPARATOR (*p))
+           p++;
+         if (p == base + 1)
+           base++;
+       }
+    }
+#endif
+
+  len = (guint) 1 + base - file_name;
+  
+  base = g_new (gchar, len + 1);
+  g_memmove (base, file_name, len);
+  base[len] = 0;
+  
+  return base;
+}
+
+/**
+ * g_get_current_dir:
+ *
+ * Gets the current directory.
+ * The returned string should be freed when no longer needed. The encoding 
+ * of the returned string is system defined. On Windows, it is always UTF-8.
+ * 
+ * Returns: the current directory.
+ */
+gchar*
+g_get_current_dir (void)
+{
+#ifdef G_OS_WIN32
+
+  gchar *dir = NULL;
+  wchar_t dummy[2], *wdir;
+  int len;
+
+  len = GetCurrentDirectoryW (2, dummy);
+  wdir = g_new (wchar_t, len);
+
+  if (GetCurrentDirectoryW (len, wdir) == len - 1)
+    dir = g_utf16_to_utf8 (wdir, -1, NULL, NULL, NULL);
+  
+  g_free (wdir);
+
+  if (dir == NULL)
+    dir = g_strdup ("\\");
+
+  return dir;
+
+#else
+
+  gchar *buffer = NULL;
+  gchar *dir = NULL;
+  static gulong max_len = 0;
+
+  if (max_len == 0) 
+    max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
+  
+  /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
+   * and, if that wasn't bad enough, hangs in doing so.
+   */
+#if    (defined (sun) && !defined (__SVR4)) || !defined(HAVE_GETCWD)
+  buffer = g_new (gchar, max_len + 1);
+  *buffer = 0;
+  dir = getwd (buffer);
+#else  /* !sun || !HAVE_GETCWD */
+  while (max_len < G_MAXULONG / 2)
+    {
+      g_free (buffer);
+      buffer = g_new (gchar, max_len + 1);
+      *buffer = 0;
+      dir = getcwd (buffer, max_len);
+
+      if (dir || errno != ERANGE)
+       break;
+
+      max_len *= 2;
+    }
+#endif /* !sun || !HAVE_GETCWD */
+  
+  if (!dir || !*buffer)
+    {
+      /* hm, should we g_error() out here?
+       * this can happen if e.g. "./" has mode \0000
+       */
+      buffer[0] = G_DIR_SEPARATOR;
+      buffer[1] = 0;
+    }
+
+  dir = g_strdup (buffer);
+  g_free (buffer);
+  
+  return dir;
+#endif /* !Win32 */
+}
+
+/**
+ * g_getenv:
+ * @variable: the environment variable to get, in the GLib file name encoding.
+ * 
+ * Returns the value of an environment variable. The name and value
+ * are in the GLib file name encoding. On UNIX, this means the actual
+ * bytes which might or might not be in some consistent character set
+ * and encoding. On Windows, it is in UTF-8. On Windows, in case the
+ * environment variable's value contains references to other
+ * environment variables, they are expanded.
+ * 
+ * Return value: the value of the environment variable, or %NULL if
+ * the environment variable is not found. The returned string may be
+ * overwritten by the next call to g_getenv(), g_setenv() or
+ * g_unsetenv().
+ **/
+G_CONST_RETURN gchar*
+g_getenv (const gchar *variable)
+{
+#ifndef G_OS_WIN32
+
+  g_return_val_if_fail (variable != NULL, NULL);
+
+  return getenv (variable);
+
+#else /* G_OS_WIN32 */
+
+  GQuark quark;
+  gchar *value;
+  wchar_t dummy[2], *wname, *wvalue;
+  int len;
+
+  g_return_val_if_fail (variable != NULL, NULL);
+  g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), NULL);
+
+  /* On Windows NT, it is relatively typical that environment
+   * variables contain references to other environment variables. If
+   * so, use ExpandEnvironmentStrings(). (In an ideal world, such
+   * environment variables would be stored in the Registry as
+   * REG_EXPAND_SZ type values, and would then get automatically
+   * expanded before a program sees them. But there is broken software
+   * that stores environment variables as REG_SZ values even if they
+   * contain references to other environment variables.)
+   */
+
+  wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
+
+  len = GetEnvironmentVariableW (wname, dummy, 2);
+
+  if (len == 0)
+    {
+      g_free (wname);
+      return NULL;
+    }
+  else if (len == 1)
+    len = 2;
+
+  wvalue = g_new (wchar_t, len);
+
+  if (GetEnvironmentVariableW (wname, wvalue, len) != len - 1)
+    {
+      g_free (wname);
+      g_free (wvalue);
+      return NULL;
+    }
+
+  if (wcschr (wvalue, L'%') != NULL)
+    {
+      wchar_t *tem = wvalue;
+
+      len = ExpandEnvironmentStringsW (wvalue, dummy, 2);
+
+      if (len > 0)
+       {
+         wvalue = g_new (wchar_t, len);
+
+         if (ExpandEnvironmentStringsW (tem, wvalue, len) != len)
+           {
+             g_free (wvalue);
+             wvalue = tem;
+           }
+         else
+           g_free (tem);
+       }
+    }
+
+  value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
+
+  g_free (wname);
+  g_free (wvalue);
+
+  quark = g_quark_from_string (value);
+  g_free (value);
+  
+  return g_quark_to_string (quark);
+
+#endif /* G_OS_WIN32 */
+}
+
+/* _g_getenv_nomalloc
+ * this function does a getenv() without doing any kind of allocation
+ * through glib. it's suitable for chars <= 127 only (both, for the
+ * variable name and the contents) and for contents < 1024 chars in
+ * length. also, it aliases "" to a NULL return value.
+ **/
+const gchar*
+_g_getenv_nomalloc (const gchar *variable,
+                    gchar        buffer[1024])
+{
+  const gchar *retval = getenv (variable);
+  if (retval && retval[0])
+    {
+      gint l = strlen (retval);
+      if (l < 1024)
+        {
+          strncpy (buffer, retval, l);
+          buffer[l] = 0;
+          return buffer;
+        }
+    }
+  return NULL;
+}
+
+/**
+ * g_setenv:
+ * @variable: the environment variable to set, must not contain '='.
+ * @value: the value for to set the variable to.
+ * @overwrite: whether to change the variable if it already exists.
+ *
+ * Sets an environment variable. Both the variable's name and value
+ * should be in the GLib file name encoding. On UNIX, this means that
+ * they can be any sequence of bytes. On Windows, they should be in
+ * UTF-8.
+ *
+ * Note that on some systems, when variables are overwritten, the memory 
+ * used for the previous variables and its value isn't reclaimed.
+ *
+ * Returns: %FALSE if the environment variable couldn't be set.
+ *
+ * Since: 2.4
+ */
+gboolean
+g_setenv (const gchar *variable, 
+         const gchar *value, 
+         gboolean     overwrite)
+{
+#ifndef G_OS_WIN32
+
+  gint result;
+#ifndef HAVE_SETENV
+  gchar *string;
+#endif
+
+  g_return_val_if_fail (variable != NULL, FALSE);
+  g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
+
+#ifdef HAVE_SETENV
+  result = setenv (variable, value, overwrite);
+#else
+  if (!overwrite && getenv (variable) != NULL)
+    return TRUE;
+  
+  /* This results in a leak when you overwrite existing
+   * settings. It would be fairly easy to fix this by keeping
+   * our own parallel array or hash table.
+   */
+  string = g_strconcat (variable, "=", value, NULL);
+  result = putenv (string);
+#endif
+  return result == 0;
+
+#else /* G_OS_WIN32 */
+
+  gboolean retval;
+  wchar_t *wname, *wvalue, *wassignment;
+  gchar *tem;
+
+  g_return_val_if_fail (variable != NULL, FALSE);
+  g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
+  g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), FALSE);
+  g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+
+  if (!overwrite && g_getenv (variable) != NULL)
+    return TRUE;
+
+  /* We want to (if possible) set both the environment variable copy
+   * kept by the C runtime and the one kept by the system.
+   *
+   * We can't use only the C runtime's putenv or _wputenv() as that
+   * won't work for arbitrary Unicode strings in a "non-Unicode" app
+   * (with main() and not wmain()). In a "main()" app the C runtime
+   * initializes the C runtime's environment table by converting the
+   * real (wide char) environment variables to system codepage, thus
+   * breaking those that aren't representable in the system codepage.
+   *
+   * As the C runtime's putenv() will also set the system copy, we do
+   * the putenv() first, then call SetEnvironmentValueW ourselves.
+   */
+
+  wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
+  wvalue = g_utf8_to_utf16 (value, -1, NULL, NULL, NULL);
+  tem = g_strconcat (variable, "=", value, NULL);
+  wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
+    
+  g_free (tem);
+  _wputenv (wassignment);
+  g_free (wassignment);
+
+  retval = (SetEnvironmentVariableW (wname, wvalue) != 0);
+
+  g_free (wname);
+  g_free (wvalue);
+
+  return retval;
+
+#endif /* G_OS_WIN32 */
+}
+
+#ifdef HAVE__NSGETENVIRON
+#define environ (*_NSGetEnviron())
+#elif !defined(G_OS_WIN32)
+
+/* According to the Single Unix Specification, environ is not in 
+ * any system header, although unistd.h often declares it.
+ */
+extern char **environ;
+#endif
+
+/**
+ * g_unsetenv:
+ * @variable: the environment variable to remove, must not contain '='.
+ * 
+ * Removes an environment variable from the environment.
+ *
+ * Note that on some systems, when variables are overwritten, the memory 
+ * used for the previous variables and its value isn't reclaimed.
+ * Furthermore, this function can't be guaranteed to operate in a 
+ * threadsafe way.
+ *
+ * Since: 2.4 
+ **/
+void
+g_unsetenv (const gchar *variable)
+{
+#ifndef G_OS_WIN32
+
+#ifdef HAVE_UNSETENV
+  g_return_if_fail (variable != NULL);
+  g_return_if_fail (strchr (variable, '=') == NULL);
+
+  unsetenv (variable);
+#else /* !HAVE_UNSETENV */
+  int len;
+  gchar **e, **f;
+
+  g_return_if_fail (variable != NULL);
+  g_return_if_fail (strchr (variable, '=') == NULL);
+
+  len = strlen (variable);
+  
+  /* Mess directly with the environ array.
+   * This seems to be the only portable way to do this.
+   *
+   * Note that we remove *all* environment entries for
+   * the variable name, not just the first.
+   */
+  e = f = environ;
+  while (*e != NULL) 
+    {
+      if (strncmp (*e, variable, len) != 0 || (*e)[len] != '=') 
+       {
+         *f = *e;
+         f++;
+       }
+      e++;
+    }
+  *f = NULL;
+#endif /* !HAVE_UNSETENV */
+
+#else  /* G_OS_WIN32 */
+
+  wchar_t *wname, *wassignment;
+  gchar *tem;
+
+  g_return_if_fail (variable != NULL);
+  g_return_if_fail (strchr (variable, '=') == NULL);
+  g_return_if_fail (g_utf8_validate (variable, -1, NULL));
+
+  wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
+  tem = g_strconcat (variable, "=", NULL);
+  wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
+    
+  g_free (tem);
+  _wputenv (wassignment);
+  g_free (wassignment);
+
+  SetEnvironmentVariableW (wname, NULL);
+
+  g_free (wname);
+
+#endif /* G_OS_WIN32 */
+}
+
+/**
+ * g_listenv:
+ *
+ * Gets the names of all variables set in the environment.
+ * 
+ * Returns: a %NULL-terminated list of strings which must be freed
+ * with g_strfreev().
+ *
+ * Programs that want to be portable to Windows should typically use
+ * this function and g_getenv() instead of using the environ array
+ * from the C library directly. On Windows, the strings in the environ
+ * array are in system codepage encoding, while in most of the typical
+ * use cases for environment variables in GLib-using programs you want
+ * the UTF-8 encoding that this function and g_getenv() provide.
+ *
+ * Since: 2.8
+ */
+gchar **
+g_listenv (void)
+{
+#ifndef G_OS_WIN32
+  gchar **result, *eq;
+  gint len, i, j;
+
+  len = g_strv_length (environ);
+  result = g_new0 (gchar *, len + 1);
+  
+  j = 0;
+  for (i = 0; i < len; i++)
+    {
+      eq = strchr (environ[i], '=');
+      if (eq)
+       result[j++] = g_strndup (environ[i], eq - environ[i]);
+    }
+
+  result[j] = NULL;
+
+  return result;
+#else
+  gchar **result, *eq;
+  gint len = 0, j;
+  wchar_t *p, *q;
+
+  p = (wchar_t *) GetEnvironmentStringsW ();
+  if (p != NULL)
+    {
+      q = p;
+      while (*q)
+       {
+         q += wcslen (q) + 1;
+         len++;
+       }
+    }
+  result = g_new0 (gchar *, len + 1);
+
+  j = 0;
+  q = p;
+  while (*q)
+    {
+      result[j] = g_utf16_to_utf8 (q, -1, NULL, NULL, NULL);
+      if (result[j] != NULL)
+       {
+         eq = strchr (result[j], '=');
+         if (eq && eq > result[j])
+           {
+             *eq = '\0';
+             j++;
+           }
+         else
+           g_free (result[j]);
+       }
+      q += wcslen (q) + 1;
+    }
+  result[j] = NULL;
+  FreeEnvironmentStringsW (p);
+
+  return result;
+#endif
+}
+
+G_LOCK_DEFINE_STATIC (g_utils_global);
+
+static gchar   *g_tmp_dir = NULL;
+static gchar   *g_user_name = NULL;
+static gchar   *g_real_name = NULL;
+static gchar   *g_home_dir = NULL;
+static gchar   *g_host_name = NULL;
+
+#ifdef G_OS_WIN32
+/* System codepage versions of the above, kept at file level so that they,
+ * too, are produced only once.
+ */
+static gchar   *g_tmp_dir_cp = NULL;
+static gchar   *g_user_name_cp = NULL;
+static gchar   *g_real_name_cp = NULL;
+static gchar   *g_home_dir_cp = NULL;
+#endif
+
+static  gchar   *g_user_data_dir = NULL;
+static  gchar  **g_system_data_dirs = NULL;
+static  gchar   *g_user_cache_dir = NULL;
+static  gchar   *g_user_config_dir = NULL;
+static  gchar  **g_system_config_dirs = NULL;
+
+static  gchar  **g_user_special_dirs = NULL;
+
+/* fifteen minutes of fame for everybody */
+#define G_USER_DIRS_EXPIRE      15 * 60
+
+#ifdef G_OS_WIN32
+
+static gchar *
+get_special_folder (int csidl)
+{
+  wchar_t path[MAX_PATH+1];
+  HRESULT hr;
+  LPITEMIDLIST pidl = NULL;
+  BOOL b;
+  gchar *retval = NULL;
+
+  hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl);
+  if (hr == S_OK)
+    {
+      b = SHGetPathFromIDListW (pidl, path);
+      if (b)
+       retval = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL);
+      CoTaskMemFree (pidl);
+    }
+  return retval;
+}
+
+static char *
+get_windows_directory_root (void)
+{
+  wchar_t wwindowsdir[MAX_PATH];
+
+  if (GetWindowsDirectoryW (wwindowsdir, G_N_ELEMENTS (wwindowsdir)))
+    {
+      /* Usually X:\Windows, but in terminal server environments
+       * might be an UNC path, AFAIK.
+       */
+      char *windowsdir = g_utf16_to_utf8 (wwindowsdir, -1, NULL, NULL, NULL);
+      char *p;
+
+      if (windowsdir == NULL)
+       return g_strdup ("C:\\");
+
+      p = (char *) g_path_skip_root (windowsdir);
+      if (G_IS_DIR_SEPARATOR (p[-1]) && p[-2] != ':')
+       p--;
+      *p = '\0';
+      return windowsdir;
+    }
+  else
+    return g_strdup ("C:\\");
+}
+
+#endif
+
+/* HOLDS: g_utils_global_lock */
+static void
+g_get_any_init_do (void)
+{
+  gchar hostname[100];
+
+  g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
+  if (!g_tmp_dir)
+    g_tmp_dir = g_strdup (g_getenv ("TMP"));
+  if (!g_tmp_dir)
+    g_tmp_dir = g_strdup (g_getenv ("TEMP"));
+
+#ifdef G_OS_WIN32
+  if (!g_tmp_dir)
+    g_tmp_dir = get_windows_directory_root ();
+#else  
+#ifdef P_tmpdir
+  if (!g_tmp_dir)
+    {
+      gsize k;    
+      g_tmp_dir = g_strdup (P_tmpdir);
+      k = strlen (g_tmp_dir);
+      if (k > 1 && G_IS_DIR_SEPARATOR (g_tmp_dir[k - 1]))
+       g_tmp_dir[k - 1] = '\0';
+    }
+#endif
+  
+  if (!g_tmp_dir)
+    {
+      g_tmp_dir = g_strdup ("/tmp");
+    }
+#endif /* !G_OS_WIN32 */
+  
+#ifdef G_OS_WIN32
+  /* We check $HOME first for Win32, though it is a last resort for Unix
+   * where we prefer the results of getpwuid().
+   */
+  g_home_dir = g_strdup (g_getenv ("HOME"));
+
+  /* Only believe HOME if it is an absolute path and exists */
+  if (g_home_dir)
+    {
+      if (!(g_path_is_absolute (g_home_dir) &&
+           g_file_test (g_home_dir, G_FILE_TEST_IS_DIR)))
+       {
+         g_free (g_home_dir);
+         g_home_dir = NULL;
+       }
+    }
+  
+  /* In case HOME is Unix-style (it happens), convert it to
+   * Windows style.
+   */
+  if (g_home_dir)
+    {
+      gchar *p;
+      while ((p = strchr (g_home_dir, '/')) != NULL)
+       *p = '\\';
+    }
+
+  if (!g_home_dir)
+    {
+      /* USERPROFILE is probably the closest equivalent to $HOME? */
+      if (g_getenv ("USERPROFILE") != NULL)
+       g_home_dir = g_strdup (g_getenv ("USERPROFILE"));
+    }
+
+  if (!g_home_dir)
+    g_home_dir = get_special_folder (CSIDL_PROFILE);
+  
+  if (!g_home_dir)
+    g_home_dir = get_windows_directory_root ();
+#endif /* G_OS_WIN32 */
+  
+#ifdef HAVE_PWD_H
+  {
+    struct passwd *pw = NULL;
+    gpointer buffer = NULL;
+    gint error;
+    gchar *logname;
+
+#  if defined (HAVE_POSIX_GETPWUID_R) || defined (HAVE_NONPOSIX_GETPWUID_R)
+    struct passwd pwd;
+#    ifdef _SC_GETPW_R_SIZE_MAX  
+    /* This reurns the maximum length */
+    glong bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
+    
+    if (bufsize < 0)
+      bufsize = 64;
+#    else /* _SC_GETPW_R_SIZE_MAX */
+    glong bufsize = 64;
+#    endif /* _SC_GETPW_R_SIZE_MAX */
+
+    logname = (gchar *) g_getenv ("LOGNAME");
+        
+    do
+      {
+       g_free (buffer);
+       /* we allocate 6 extra bytes to work around a bug in 
+        * Mac OS < 10.3. See #156446
+        */
+       buffer = g_malloc (bufsize + 6);
+       errno = 0;
+       
+#    ifdef HAVE_POSIX_GETPWUID_R
+       if (logname) {
+         error = getpwnam_r (logname, &pwd, buffer, bufsize, &pw);
+         if (!pw || (pw->pw_uid != getuid ())) {
+           /* LOGNAME is lying, fall back to looking up the uid */
+           error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
+         }
+       } else {
+         error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
+       }
+       error = error < 0 ? errno : error;
+#    else /* HAVE_NONPOSIX_GETPWUID_R */
+   /* HPUX 11 falls into the HAVE_POSIX_GETPWUID_R case */
+#      if defined(_AIX) || defined(__hpux)
+       error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
+       pw = error == 0 ? &pwd : NULL;
+#      else /* !_AIX */
+       if (logname) {
+         pw = getpwnam_r (logname, &pwd, buffer, bufsize);
+         if (!pw || (pw->pw_uid != getuid ())) {
+           /* LOGNAME is lying, fall back to looking up the uid */
+           pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
+         }
+       } else {
+         pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
+       }
+       error = pw ? 0 : errno;
+#      endif /* !_AIX */            
+#    endif /* HAVE_NONPOSIX_GETPWUID_R */
+       
+       if (!pw)
+         {
+           /* we bail out prematurely if the user id can't be found
+            * (should be pretty rare case actually), or if the buffer
+            * should be sufficiently big and lookups are still not
+            * successfull.
+            */
+           if (error == 0 || error == ENOENT)
+             {
+               g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
+                          (gulong) getuid ());
+               break;
+             }
+           if (bufsize > 32 * 1024)
+             {
+               g_warning ("getpwuid_r(): failed due to: %s.",
+                          g_strerror (error));
+               break;
+             }
+           
+           bufsize *= 2;
+         }
+      }
+    while (!pw);
+#  endif /* HAVE_POSIX_GETPWUID_R || HAVE_NONPOSIX_GETPWUID_R */
+    
+    if (!pw)
+      {
+       setpwent ();
+       pw = getpwuid (getuid ());
+       endpwent ();
+      }
+    if (pw)
+      {
+       g_user_name = g_strdup (pw->pw_name);
+
+       if (pw->pw_gecos && *pw->pw_gecos != '\0') 
+         {
+           gchar **gecos_fields;
+           gchar **name_parts;
+
+           /* split the gecos field and substitute '&' */
+           gecos_fields = g_strsplit (pw->pw_gecos, ",", 0);
+           name_parts = g_strsplit (gecos_fields[0], "&", 0);
+           pw->pw_name[0] = g_ascii_toupper (pw->pw_name[0]);
+           g_real_name = g_strjoinv (pw->pw_name, name_parts);
+           g_strfreev (gecos_fields);
+           g_strfreev (name_parts);
+         }
+
+       if (!g_home_dir)
+         g_home_dir = g_strdup (pw->pw_dir);
+      }
+    g_free (buffer);
+  }
+  
+#else /* !HAVE_PWD_H */
+  
+#ifdef G_OS_WIN32
+  {
+    guint len = UNLEN+1;
+    wchar_t buffer[UNLEN+1];
+    
+    if (GetUserNameW (buffer, (LPDWORD) &len))
+      {
+       g_user_name = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
+       g_real_name = g_strdup (g_user_name);
+      }
+  }
+#endif /* G_OS_WIN32 */
+
+#endif /* !HAVE_PWD_H */
+
+#ifndef G_OS_WIN32
+  if (!g_home_dir)
+    g_home_dir = g_strdup (g_getenv ("HOME"));
+#endif
+
+#ifdef __EMX__
+  /* change '\\' in %HOME% to '/' */
+  g_strdelimit (g_home_dir, "\\",'/');
+#endif
+  if (!g_user_name)
+    g_user_name = g_strdup ("somebody");
+  if (!g_real_name)
+    g_real_name = g_strdup ("Unknown");
+
+  {
+#ifndef G_OS_WIN32
+    gboolean hostname_fail = (gethostname (hostname, sizeof (hostname)) == -1);
+#else
+    DWORD size = sizeof (hostname);
+    gboolean hostname_fail = (!GetComputerName (hostname, &size));
+#endif
+    g_host_name = g_strdup (hostname_fail ? "localhost" : hostname);
+  }
+
+#ifdef G_OS_WIN32
+  g_tmp_dir_cp = g_locale_from_utf8 (g_tmp_dir, -1, NULL, NULL, NULL);
+  g_user_name_cp = g_locale_from_utf8 (g_user_name, -1, NULL, NULL, NULL);
+  g_real_name_cp = g_locale_from_utf8 (g_real_name, -1, NULL, NULL, NULL);
+
+  if (!g_tmp_dir_cp)
+    g_tmp_dir_cp = g_strdup ("\\");
+  if (!g_user_name_cp)
+    g_user_name_cp = g_strdup ("somebody");
+  if (!g_real_name_cp)
+    g_real_name_cp = g_strdup ("Unknown");
+
+  /* home_dir might be NULL, unlike tmp_dir, user_name and
+   * real_name.
+   */
+  if (g_home_dir)
+    g_home_dir_cp = g_locale_from_utf8 (g_home_dir, -1, NULL, NULL, NULL);
+  else
+    g_home_dir_cp = NULL;
+#endif /* G_OS_WIN32 */
+}
+
+static inline void
+g_get_any_init (void)
+{
+  if (!g_tmp_dir)
+    g_get_any_init_do ();
+}
+
+static inline void
+g_get_any_init_locked (void)
+{
+  G_LOCK (g_utils_global);
+  g_get_any_init ();
+  G_UNLOCK (g_utils_global);
+}
+
+
+/**
+ * g_get_user_name:
+ *
+ * Gets the user name of the current user. The encoding of the returned
+ * string is system-defined. On UNIX, it might be the preferred file name
+ * encoding, or something else, and there is no guarantee that it is even
+ * consistent on a machine. On Windows, it is always UTF-8.
+ *
+ * Returns: the user name of the current user.
+ */
+G_CONST_RETURN gchar*
+g_get_user_name (void)
+{
+  g_get_any_init_locked ();
+  return g_user_name;
+}
+
+/**
+ * g_get_real_name:
+ *
+ * Gets the real name of the user. This usually comes from the user's entry 
+ * in the <filename>passwd</filename> file. The encoding of the returned 
+ * string is system-defined. (On Windows, it is, however, always UTF-8.) 
+ * If the real user name cannot be determined, the string "Unknown" is 
+ * returned.
+ *
+ * Returns: the user's real name.
+ */
+G_CONST_RETURN gchar*
+g_get_real_name (void)
+{
+  g_get_any_init_locked ();
+  return g_real_name;
+}
+
+/**
+ * g_get_home_dir:
+ *
+ * Gets the current user's home directory as defined in the 
+ * password database.
+ *
+ * Note that in contrast to traditional UNIX tools, this function 
+ * prefers <filename>passwd</filename> entries over the <envar>HOME</envar> 
+ * environment variable. 
+ *
+ * One of the reasons for this decision is that applications in many 
+ * cases need special handling to deal with the case where 
+ * <envar>HOME</envar> is
+ * <simplelist>
+ *   <member>Not owned by the user</member>
+ *   <member>Not writeable</member>
+ *   <member>Not even readable</member>
+ * </simplelist>
+ * Since applications are in general <emphasis>not</emphasis> written 
+ * to deal with these situations it was considered better to make 
+ * g_get_home_dir() not pay attention to <envar>HOME</envar> and to 
+ * return the real home directory for the user. If applications
+ * want to pay attention to <envar>HOME</envar>, they can do:
+ * |[
+ *  const char *homedir = g_getenv ("HOME");
+ *   if (!homedir)
+ *      homedir = g_get_home_dir (<!-- -->);
+ * ]|
+ *
+ * Returns: the current user's home directory
+ */
+G_CONST_RETURN gchar*
+g_get_home_dir (void)
+{
+  g_get_any_init_locked ();
+  return g_home_dir;
+}
+
+/**
+ * g_get_tmp_dir:
+ *
+ * Gets the directory to use for temporary files. This is found from 
+ * inspecting the environment variables <envar>TMPDIR</envar>, 
+ * <envar>TMP</envar>, and <envar>TEMP</envar> in that order. If none 
+ * of those are defined "/tmp" is returned on UNIX and "C:\" on Windows. 
+ * The encoding of the returned string is system-defined. On Windows, 
+ * it is always UTF-8. The return value is never %NULL.
+ *
+ * Returns: the directory to use for temporary files.
+ */
+G_CONST_RETURN gchar*
+g_get_tmp_dir (void)
+{
+  g_get_any_init_locked ();
+  return g_tmp_dir;
+}
+
+/**
+ * g_get_host_name:
+ *
+ * Return a name for the machine. 
+ *
+ * The returned name is not necessarily a fully-qualified domain name,
+ * or even present in DNS or some other name service at all. It need
+ * not even be unique on your local network or site, but usually it
+ * is. Callers should not rely on the return value having any specific
+ * properties like uniqueness for security purposes. Even if the name
+ * of the machine is changed while an application is running, the
+ * return value from this function does not change. The returned
+ * string is owned by GLib and should not be modified or freed. If no
+ * name can be determined, a default fixed string "localhost" is
+ * returned.
+ *
+ * Returns: the host name of the machine.
+ *
+ * Since: 2.8
+ */
+const gchar *
+g_get_host_name (void)
+{
+  g_get_any_init_locked ();
+  return g_host_name;
+}
+
+G_LOCK_DEFINE_STATIC (g_prgname);
+static gchar *g_prgname = NULL;
+
+/**
+ * g_get_prgname:
+ *
+ * Gets the name of the program. This name should <emphasis>not</emphasis> 
+ * be localized, contrast with g_get_application_name().
+ * (If you are using GDK or GTK+ the program name is set in gdk_init(), 
+ * which is called by gtk_init(). The program name is found by taking 
+ * the last component of <literal>argv[0]</literal>.)
+ *
+ * Returns: the name of the program. The returned string belongs 
+ * to GLib and must not be modified or freed.
+ */
+gchar*
+g_get_prgname (void)
+{
+  gchar* retval;
+
+  G_LOCK (g_prgname);
+#ifdef G_OS_WIN32
+  if (g_prgname == NULL)
+    {
+      static gboolean beenhere = FALSE;
+
+      if (!beenhere)
+       {
+         gchar *utf8_buf = NULL;
+         wchar_t buf[MAX_PATH+1];
+
+         beenhere = TRUE;
+         if (GetModuleFileNameW (GetModuleHandle (NULL),
+                                 buf, G_N_ELEMENTS (buf)) > 0)
+           utf8_buf = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
+
+         if (utf8_buf)
+           {
+             g_prgname = g_path_get_basename (utf8_buf);
+             g_free (utf8_buf);
+           }
+       }
+    }
+#endif
+  retval = g_prgname;
+  G_UNLOCK (g_prgname);
+
+  return retval;
+}
+
+/**
+ * g_set_prgname:
+ * @prgname: the name of the program.
+ *
+ * Sets the name of the program. This name should <emphasis>not</emphasis> 
+ * be localized, contrast with g_set_application_name(). Note that for 
+ * thread-safety reasons this function can only be called once.
+ */
+void
+g_set_prgname (const gchar *prgname)
+{
+  G_LOCK (g_prgname);
+  g_free (g_prgname);
+  g_prgname = g_strdup (prgname);
+  G_UNLOCK (g_prgname);
+}
+
+G_LOCK_DEFINE_STATIC (g_application_name);
+static gchar *g_application_name = NULL;
+
+/**
+ * g_get_application_name:
+ * 
+ * Gets a human-readable name for the application, as set by
+ * g_set_application_name(). This name should be localized if
+ * possible, and is intended for display to the user.  Contrast with
+ * g_get_prgname(), which gets a non-localized name. If
+ * g_set_application_name() has not been called, returns the result of
+ * g_get_prgname() (which may be %NULL if g_set_prgname() has also not
+ * been called).
+ * 
+ * Return value: human-readable application name. may return %NULL
+ *
+ * Since: 2.2
+ **/
+G_CONST_RETURN gchar*
+g_get_application_name (void)
+{
+  gchar* retval;
+
+  G_LOCK (g_application_name);
+  retval = g_application_name;
+  G_UNLOCK (g_application_name);
+
+  if (retval == NULL)
+    return g_get_prgname ();
+  
+  return retval;
+}
+
+/**
+ * g_set_application_name:
+ * @application_name: localized name of the application
+ *
+ * Sets a human-readable name for the application. This name should be
+ * localized if possible, and is intended for display to the user.
+ * Contrast with g_set_prgname(), which sets a non-localized name.
+ * g_set_prgname() will be called automatically by gtk_init(),
+ * but g_set_application_name() will not.
+ *
+ * Note that for thread safety reasons, this function can only
+ * be called once.
+ *
+ * The application name will be used in contexts such as error messages,
+ * or when displaying an application's name in the task list.
+ * 
+ * Since: 2.2
+ **/
+void
+g_set_application_name (const gchar *application_name)
+{
+  gboolean already_set = FALSE;
+       
+  G_LOCK (g_application_name);
+  if (g_application_name)
+    already_set = TRUE;
+  else
+    g_application_name = g_strdup (application_name);
+  G_UNLOCK (g_application_name);
+
+  if (already_set)
+    g_warning ("g_set_application() name called multiple times");
+}
+
+/**
+ * g_get_user_data_dir:
+ * 
+ * Returns a base directory in which to access application data such
+ * as icons that is customized for a particular user.  
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ * 
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_data_dir (void)
+{
+  gchar *data_dir;  
+
+  G_LOCK (g_utils_global);
+
+  if (!g_user_data_dir)
+    {
+#ifdef G_OS_WIN32
+      data_dir = get_special_folder (CSIDL_PERSONAL);
+#else
+      data_dir = (gchar *) g_getenv ("XDG_DATA_HOME");
+
+      if (data_dir && data_dir[0])
+        data_dir = g_strdup (data_dir);
+#endif
+      if (!data_dir || !data_dir[0])
+       {
+         g_get_any_init ();
+
+         if (g_home_dir)
+           data_dir = g_build_filename (g_home_dir, ".local", 
+                                        "share", NULL);
+         else
+           data_dir = g_build_filename (g_tmp_dir, g_user_name, ".local", 
+                                        "share", NULL);
+       }
+
+      g_user_data_dir = data_dir;
+    }
+  else
+    data_dir = g_user_data_dir;
+
+  G_UNLOCK (g_utils_global);
+
+  return data_dir;
+}
+
+static void
+g_init_user_config_dir (void)
+{
+  gchar *config_dir;
+
+  if (!g_user_config_dir)
+    {
+#ifdef G_OS_WIN32
+      config_dir = get_special_folder (CSIDL_APPDATA);
+#else
+      config_dir = (gchar *) g_getenv ("XDG_CONFIG_HOME");
+
+      if (config_dir && config_dir[0])
+       config_dir = g_strdup (config_dir);
+#endif
+      if (!config_dir || !config_dir[0])
+       {
+         g_get_any_init ();
+
+         if (g_home_dir)
+           config_dir = g_build_filename (g_home_dir, ".config", NULL);
+         else
+           config_dir = g_build_filename (g_tmp_dir, g_user_name, ".config", NULL);
+       }
+
+      g_user_config_dir = config_dir;
+    }
+}
+
+/**
+ * g_get_user_config_dir:
+ * 
+ * Returns a base directory in which to store user-specific application 
+ * configuration information such as user preferences and settings. 
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ * 
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_config_dir (void)
+{
+  G_LOCK (g_utils_global);
+
+  g_init_user_config_dir ();
+
+  G_UNLOCK (g_utils_global);
+
+  return g_user_config_dir;
+}
+
+/**
+ * g_get_user_cache_dir:
+ * 
+ * Returns a base directory in which to store non-essential, cached
+ * data specific to particular user.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ * 
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_cache_dir (void)
+{
+  gchar *cache_dir;  
+
+  G_LOCK (g_utils_global);
+
+  if (!g_user_cache_dir)
+    {
+#ifdef G_OS_WIN32
+      cache_dir = get_special_folder (CSIDL_INTERNET_CACHE); /* XXX correct? */
+#else
+      cache_dir = (gchar *) g_getenv ("XDG_CACHE_HOME");
+
+      if (cache_dir && cache_dir[0])
+          cache_dir = g_strdup (cache_dir);
+#endif
+      if (!cache_dir || !cache_dir[0])
+       {
+         g_get_any_init ();
+       
+         if (g_home_dir)
+           cache_dir = g_build_filename (g_home_dir, ".cache", NULL);
+         else
+           cache_dir = g_build_filename (g_tmp_dir, g_user_name, ".cache", NULL);
+       }
+      g_user_cache_dir = cache_dir;
+    }
+  else
+    cache_dir = g_user_cache_dir;
+
+  G_UNLOCK (g_utils_global);
+
+  return cache_dir;
+}
+
+#ifdef HAVE_CARBON
+
+static gchar *
+find_folder (OSType type)
+{
+  gchar *filename = NULL;
+  FSRef  found;
+
+  if (FSFindFolder (kUserDomain, type, kDontCreateFolder, &found) == noErr)
+    {
+      CFURLRef url = CFURLCreateFromFSRef (kCFAllocatorSystemDefault, &found);
+
+      if (url)
+       {
+         CFStringRef path = CFURLCopyFileSystemPath (url, kCFURLPOSIXPathStyle);
+
+         if (path)
+           {
+             filename = g_strdup (CFStringGetCStringPtr (path, kCFStringEncodingUTF8));
+
+             if (! filename)
+               {
+                 filename = g_new0 (gchar, CFStringGetLength (path) * 3 + 1);
+
+                 CFStringGetCString (path, filename,
+                                     CFStringGetLength (path) * 3 + 1,
+                                     kCFStringEncodingUTF8);
+               }
+
+             CFRelease (path);
+           }
+
+         CFRelease (url);
+       }
+    }
+
+  return filename;
+}
+
+static void
+load_user_special_dirs (void)
+{
+  g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = find_folder (kDesktopFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = find_folder (kDocumentsFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = find_folder (kDesktopFolderType); /* XXX correct ? */
+  g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = find_folder (kMusicDocumentsFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = find_folder (kPictureDocumentsFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = NULL;
+  g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = NULL;
+  g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = find_folder (kMovieDocumentsFolderType);
+}
+
+#endif /* HAVE_CARBON */
+
+#if defined(G_OS_WIN32)
+static void
+load_user_special_dirs (void)
+{
+  typedef HRESULT (WINAPI *t_SHGetKnownFolderPath) (const GUID *rfid,
+                                                   DWORD dwFlags,
+                                                   HANDLE hToken,
+                                                   PWSTR *ppszPath);
+  t_SHGetKnownFolderPath p_SHGetKnownFolderPath;
+  static const GUID FOLDERID_Downloads =
+    { 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
+  static const GUID FOLDERID_Public =
+    { 0xDFDF76A2, 0xC82A, 0x4D63, { 0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85 } };
+  wchar_t *wcp;
+
+  p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (LoadLibrary ("shell32.dll"),
+                                                                   "SHGetKnownFolderPath");
+
+  g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+  g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = get_special_folder (CSIDL_PERSONAL);
+
+  if (p_SHGetKnownFolderPath == NULL)
+    {
+      g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+    }
+  else
+    {
+      wcp = NULL;
+      (*p_SHGetKnownFolderPath) (&FOLDERID_Downloads, 0, NULL, &wcp);
+      g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
+      if (g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] == NULL)
+       g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+      CoTaskMemFree (wcp);
+    }
+
+  g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = get_special_folder (CSIDL_MYMUSIC);
+  g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = get_special_folder (CSIDL_MYPICTURES);
+
+  if (p_SHGetKnownFolderPath == NULL)
+    {
+      /* XXX */
+      g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+    }
+  else
+    {
+      wcp = NULL;
+      (*p_SHGetKnownFolderPath) (&FOLDERID_Public, 0, NULL, &wcp);
+      g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
+      if (g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] == NULL)
+       g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+      CoTaskMemFree (wcp);
+    }
+  
+  g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = get_special_folder (CSIDL_TEMPLATES);
+  g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = get_special_folder (CSIDL_MYVIDEO);
+}
+#endif /* G_OS_WIN32 */
+
+static void g_init_user_config_dir (void);
+
+#if defined(G_OS_UNIX) && !defined(HAVE_CARBON)
+
+/* adapted from xdg-user-dir-lookup.c
+ *
+ * Copyright (C) 2007 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions: 
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software. 
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+static void
+load_user_special_dirs (void)
+{
+  gchar *config_file;
+  gchar *data;
+  gchar **lines;
+  gint n_lines, i;
+  
+  g_init_user_config_dir ();
+  config_file = g_build_filename (g_user_config_dir,
+                                  "user-dirs.dirs",
+                                  NULL);
+  
+  if (!g_file_get_contents (config_file, &data, NULL, NULL))
+    {
+      g_free (config_file);
+      return;
+    }
+
+  lines = g_strsplit (data, "\n", -1);
+  n_lines = g_strv_length (lines);
+  g_free (data);
+  
+  for (i = 0; i < n_lines; i++)
+    {
+      gchar *buffer = lines[i];
+      gchar *d, *p;
+      gint len;
+      gboolean is_relative = FALSE;
+      GUserDirectory directory;
+
+      /* Remove newline at end */
+      len = strlen (buffer);
+      if (len > 0 && buffer[len - 1] == '\n')
+       buffer[len - 1] = 0;
+      
+      p = buffer;
+      while (*p == ' ' || *p == '\t')
+       p++;
+      
+      if (strncmp (p, "XDG_DESKTOP_DIR", strlen ("XDG_DESKTOP_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_DESKTOP;
+          p += strlen ("XDG_DESKTOP_DIR");
+        }
+      else if (strncmp (p, "XDG_DOCUMENTS_DIR", strlen ("XDG_DOCUMENTS_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_DOCUMENTS;
+          p += strlen ("XDG_DOCUMENTS_DIR");
+        }
+      else if (strncmp (p, "XDG_DOWNLOAD_DIR", strlen ("XDG_DOWNLOAD_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_DOWNLOAD;
+          p += strlen ("XDG_DOWNLOAD_DIR");
+        }
+      else if (strncmp (p, "XDG_MUSIC_DIR", strlen ("XDG_MUSIC_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_MUSIC;
+          p += strlen ("XDG_MUSIC_DIR");
+        }
+      else if (strncmp (p, "XDG_PICTURES_DIR", strlen ("XDG_PICTURES_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_PICTURES;
+          p += strlen ("XDG_PICTURES_DIR");
+        }
+      else if (strncmp (p, "XDG_PUBLICSHARE_DIR", strlen ("XDG_PUBLICSHARE_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_PUBLIC_SHARE;
+          p += strlen ("XDG_PUBLICSHARE_DIR");
+        }
+      else if (strncmp (p, "XDG_TEMPLATES_DIR", strlen ("XDG_TEMPLATES_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_TEMPLATES;
+          p += strlen ("XDG_TEMPLATES_DIR");
+        }
+      else if (strncmp (p, "XDG_VIDEOS_DIR", strlen ("XDG_VIDEOS_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_VIDEOS;
+          p += strlen ("XDG_VIDEOS_DIR");
+        }
+      else
+       continue;
+
+      while (*p == ' ' || *p == '\t')
+       p++;
+
+      if (*p != '=')
+       continue;
+      p++;
+
+      while (*p == ' ' || *p == '\t')
+       p++;
+
+      if (*p != '"')
+       continue;
+      p++;
+
+      if (strncmp (p, "$HOME", 5) == 0)
+       {
+         p += 5;
+         is_relative = TRUE;
+       }
+      else if (*p != '/')
+       continue;
+
+      d = strrchr (p, '"');
+      if (!d)
+        continue;
+      *d = 0;
+
+      d = p;
+      
+      /* remove trailing slashes */
+      len = strlen (d);
+      if (d[len - 1] == '/')
+        d[len - 1] = 0;
+      
+      if (is_relative)
+        {
+          g_get_any_init ();
+          g_user_special_dirs[directory] = g_build_filename (g_home_dir, d, NULL);
+        }
+      else
+       g_user_special_dirs[directory] = g_strdup (d);
+    }
+
+  g_strfreev (lines);
+  g_free (config_file);
+}
+
+#endif /* G_OS_UNIX && !HAVE_CARBON */
+
+/**
+ * g_get_user_special_dir:
+ * @directory: the logical id of special directory
+ *
+ * Returns the full path of a special directory using its logical id.
+ *
+ * On Unix this is done using the XDG special user directories.
+ * For compatibility with existing practise, %G_USER_DIRECTORY_DESKTOP
+ * falls back to <filename>$HOME/Desktop</filename> when XDG special
+ * user directories have not been set up. 
+ *
+ * Depending on the platform, the user might be able to change the path
+ * of the special directory without requiring the session to restart; GLib
+ * will not reflect any change once the special directories are loaded.
+ *
+ * Return value: the path to the specified special directory, or %NULL
+ *   if the logical id was not found. The returned string is owned by
+ *   GLib and should not be modified or freed.
+ *
+ * Since: 2.14
+ */
+G_CONST_RETURN gchar *
+g_get_user_special_dir (GUserDirectory directory)
+{
+  g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
+                        directory < G_USER_N_DIRECTORIES, NULL);
+
+  G_LOCK (g_utils_global);
+
+  if (G_UNLIKELY (g_user_special_dirs == NULL))
+    {
+      g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
+
+      load_user_special_dirs ();
+
+      /* Special-case desktop for historical compatibility */
+      if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
+        {
+          g_get_any_init ();
+
+          g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] =
+            g_build_filename (g_home_dir, "Desktop", NULL);
+        }
+    }
+
+  G_UNLOCK (g_utils_global);
+
+  return g_user_special_dirs[directory];
+}
+
+#ifdef G_OS_WIN32
+
+#undef g_get_system_data_dirs
+
+static HMODULE
+get_module_for_address (gconstpointer address)
+{
+  /* Holds the g_utils_global lock */
+
+  static gboolean beenhere = FALSE;
+  typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
+  static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
+  HMODULE hmodule = NULL;
+
+  if (!address)
+    return NULL;
+
+  if (!beenhere)
+    {
+      p_GetModuleHandleExA =
+       (t_GetModuleHandleExA) GetProcAddress (LoadLibrary ("kernel32.dll"),
+                                              "GetModuleHandleExA");
+      beenhere = TRUE;
+    }
+
+  if (p_GetModuleHandleExA == NULL ||
+      !(*p_GetModuleHandleExA) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+                               GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                               address, &hmodule))
+    {
+      MEMORY_BASIC_INFORMATION mbi;
+      VirtualQuery (address, &mbi, sizeof (mbi));
+      hmodule = (HMODULE) mbi.AllocationBase;
+    }
+
+  return hmodule;
+}
+
+static gchar *
+get_module_share_dir (gconstpointer address)
+{
+  HMODULE hmodule;
+  gchar *filename;
+  gchar *retval;
+
+  hmodule = get_module_for_address (address);
+  if (hmodule == NULL)
+    return NULL;
+
+  filename = g_win32_get_package_installation_directory_of_module (hmodule);
+  retval = g_build_filename (filename, "share", NULL);
+  g_free (filename);
+
+  return retval;
+}
+
+G_CONST_RETURN gchar * G_CONST_RETURN *
+g_win32_get_system_data_dirs_for_module (gconstpointer address)
+{
+  GArray *data_dirs;
+  HMODULE hmodule;
+  static GHashTable *per_module_data_dirs = NULL;
+  gchar **retval;
+  gchar *p;
+  gchar *exe_root;
+      
+  if (address)
+    {
+      G_LOCK (g_utils_global);
+      hmodule = get_module_for_address (address);
+      if (hmodule != NULL)
+       {
+         if (per_module_data_dirs == NULL)
+           per_module_data_dirs = g_hash_table_new (NULL, NULL);
+         else
+           {
+             retval = g_hash_table_lookup (per_module_data_dirs, hmodule);
+             
+             if (retval != NULL)
+               {
+                 G_UNLOCK (g_utils_global);
+                 return (G_CONST_RETURN gchar * G_CONST_RETURN *) retval;
+               }
+           }
+       }
+    }
+
+  data_dirs = g_array_new (TRUE, TRUE, sizeof (char *));
+
+  /* Documents and Settings\All Users\Application Data */
+  p = get_special_folder (CSIDL_COMMON_APPDATA);
+  if (p)
+    g_array_append_val (data_dirs, p);
+  
+  /* Documents and Settings\All Users\Documents */
+  p = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+  if (p)
+    g_array_append_val (data_dirs, p);
+       
+  /* Using the above subfolders of Documents and Settings perhaps
+   * makes sense from a Windows perspective.
+   *
+   * But looking at the actual use cases of this function in GTK+
+   * and GNOME software, what we really want is the "share"
+   * subdirectory of the installation directory for the package
+   * our caller is a part of.
+   *
+   * The address parameter, if non-NULL, points to a function in the
+   * calling module. Use that to determine that module's installation
+   * folder, and use its "share" subfolder.
+   *
+   * Additionally, also use the "share" subfolder of the installation
+   * locations of GLib and the .exe file being run.
+   *
+   * To guard against none of the above being what is really wanted,
+   * callers of this function should have Win32-specific code to look
+   * up their installation folder themselves, and handle a subfolder
+   * "share" of it in the same way as the folders returned from this
+   * function.
+   */
+
+  p = get_module_share_dir (address);
+  if (p)
+    g_array_append_val (data_dirs, p);
+    
+  if (glib_dll != NULL)
+    {
+      gchar *glib_root = g_win32_get_package_installation_directory_of_module (glib_dll);
+      p = g_build_filename (glib_root, "share", NULL);
+      if (p)
+       g_array_append_val (data_dirs, p);
+      g_free (glib_root);
+    }
+  
+  exe_root = g_win32_get_package_installation_directory_of_module (NULL);
+  p = g_build_filename (exe_root, "share", NULL);
+  if (p)
+    g_array_append_val (data_dirs, p);
+  g_free (exe_root);
+
+  retval = (gchar **) g_array_free (data_dirs, FALSE);
+
+  if (address)
+    {
+      if (hmodule != NULL)
+       g_hash_table_insert (per_module_data_dirs, hmodule, retval);
+      G_UNLOCK (g_utils_global);
+    }
+
+  return (G_CONST_RETURN gchar * G_CONST_RETURN *) retval;
+}
+
+#endif
+
+/**
+ * g_get_system_data_dirs:
+ * 
+ * Returns an ordered list of base directories in which to access 
+ * system-wide application data.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ * 
+ * On Windows the first elements in the list are the Application Data
+ * and Documents folders for All Users. (These can be determined only
+ * on Windows 2000 or later and are not present in the list on other
+ * Windows versions.) See documentation for CSIDL_COMMON_APPDATA and
+ * CSIDL_COMMON_DOCUMENTS.
+ *
+ * Then follows the "share" subfolder in the installation folder for
+ * the package containing the DLL that calls this function, if it can
+ * be determined.
+ * 
+ * Finally the list contains the "share" subfolder in the installation
+ * folder for GLib, and in the installation folder for the package the
+ * application's .exe file belongs to.
+ *
+ * The installation folders above are determined by looking up the
+ * folder where the module (DLL or EXE) in question is located. If the
+ * folder's name is "bin", its parent is used, otherwise the folder
+ * itself.
+ *
+ * Note that on Windows the returned list can vary depending on where
+ * this function is called.
+ *
+ * Return value: a %NULL-terminated array of strings owned by GLib that must 
+ *               not be modified or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar * G_CONST_RETURN * 
+g_get_system_data_dirs (void)
+{
+  gchar **data_dir_vector;
+
+  G_LOCK (g_utils_global);
+
+  if (!g_system_data_dirs)
+    {
+#ifdef G_OS_WIN32
+      data_dir_vector = (gchar **) g_win32_get_system_data_dirs_for_module (NULL);
+#else
+      gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
+
+      if (!data_dirs || !data_dirs[0])
+          data_dirs = "/usr/local/share/:/usr/share/";
+
+      data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+#endif
+
+      g_system_data_dirs = data_dir_vector;
+    }
+  else
+    data_dir_vector = g_system_data_dirs;
+
+  G_UNLOCK (g_utils_global);
+
+  return (G_CONST_RETURN gchar * G_CONST_RETURN *) data_dir_vector;
+}
+
+/**
+ * g_get_system_config_dirs:
+ * 
+ * Returns an ordered list of base directories in which to access 
+ * system-wide configuration information.
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ * 
+ * Return value: a %NULL-terminated array of strings owned by GLib that must 
+ *               not be modified or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar * G_CONST_RETURN *
+g_get_system_config_dirs (void)
+{
+  gchar *conf_dirs, **conf_dir_vector;
+
+  G_LOCK (g_utils_global);
+
+  if (!g_system_config_dirs)
+    {
+#ifdef G_OS_WIN32
+      conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
+      if (conf_dirs)
+       {
+         conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+         g_free (conf_dirs);
+       }
+      else
+       {
+         /* Return empty list */
+         conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
+       }
+#else
+      conf_dirs = (gchar *) g_getenv ("XDG_CONFIG_DIRS");
+
+      if (!conf_dirs || !conf_dirs[0])
+          conf_dirs = "/etc/xdg";
+
+      conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+#endif
+
+      g_system_config_dirs = conf_dir_vector;
+    }
+  else
+    conf_dir_vector = g_system_config_dirs;
+  G_UNLOCK (g_utils_global);
+
+  return (G_CONST_RETURN gchar * G_CONST_RETURN *) conf_dir_vector;
+}
+
+#ifndef G_OS_WIN32
+
+static GHashTable *alias_table = NULL;
+
+/* read an alias file for the locales */
+static void
+read_aliases (gchar *file)
+{
+  FILE *fp;
+  char buf[256];
+  
+  if (!alias_table)
+    alias_table = g_hash_table_new (g_str_hash, g_str_equal);
+  fp = fopen (file,"r");
+  if (!fp)
+    return;
+  while (fgets (buf, 256, fp))
+    {
+      char *p, *q;
+
+      g_strstrip (buf);
+
+      /* Line is a comment */
+      if ((buf[0] == '#') || (buf[0] == '\0'))
+       continue;
+
+      /* Reads first column */
+      for (p = buf, q = NULL; *p; p++) {
+       if ((*p == '\t') || (*p == ' ') || (*p == ':')) {
+         *p = '\0';
+         q = p+1;
+         while ((*q == '\t') || (*q == ' ')) {
+           q++;
+         }
+         break;
+       }
+      }
+      /* The line only had one column */
+      if (!q || *q == '\0')
+       continue;
+      
+      /* Read second column */
+      for (p = q; *p; p++) {
+       if ((*p == '\t') || (*p == ' ')) {
+         *p = '\0';
+         break;
+       }
+      }
+
+      /* Add to alias table if necessary */
+      if (!g_hash_table_lookup (alias_table, buf)) {
+       g_hash_table_insert (alias_table, g_strdup (buf), g_strdup (q));
+      }
+    }
+  fclose (fp);
+}
+
+#endif
+
+static char *
+unalias_lang (char *lang)
+{
+#ifndef G_OS_WIN32
+  char *p;
+  int i;
+
+  if (!alias_table)
+    read_aliases ("/usr/share/locale/locale.alias");
+
+  i = 0;
+  while ((p = g_hash_table_lookup (alias_table, lang)) && (strcmp (p, lang) != 0))
+    {
+      lang = p;
+      if (i++ == 30)
+        {
+          static gboolean said_before = FALSE;
+         if (!said_before)
+            g_warning ("Too many alias levels for a locale, "
+                      "may indicate a loop");
+         said_before = TRUE;
+         return lang;
+       }
+    }
+#endif
+  return lang;
+}
+
+/* Mask for components of locale spec. The ordering here is from
+ * least significant to most significant
+ */
+enum
+{
+  COMPONENT_CODESET =   1 << 0,
+  COMPONENT_TERRITORY = 1 << 1,
+  COMPONENT_MODIFIER =  1 << 2
+};
+
+/* Break an X/Open style locale specification into components
+ */
+static guint
+explode_locale (const gchar *locale,
+               gchar      **language, 
+               gchar      **territory, 
+               gchar      **codeset, 
+               gchar      **modifier)
+{
+  const gchar *uscore_pos;
+  const gchar *at_pos;
+  const gchar *dot_pos;
+
+  guint mask = 0;
+
+  uscore_pos = strchr (locale, '_');
+  dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
+  at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
+
+  if (at_pos)
+    {
+      mask |= COMPONENT_MODIFIER;
+      *modifier = g_strdup (at_pos);
+    }
+  else
+    at_pos = locale + strlen (locale);
+
+  if (dot_pos)
+    {
+      mask |= COMPONENT_CODESET;
+      *codeset = g_strndup (dot_pos, at_pos - dot_pos);
+    }
+  else
+    dot_pos = at_pos;
+
+  if (uscore_pos)
+    {
+      mask |= COMPONENT_TERRITORY;
+      *territory = g_strndup (uscore_pos, dot_pos - uscore_pos);
+    }
+  else
+    uscore_pos = dot_pos;
+
+  *language = g_strndup (locale, uscore_pos - locale);
+
+  return mask;
+}
+
+/*
+ * Compute all interesting variants for a given locale name -
+ * by stripping off different components of the value.
+ *
+ * For simplicity, we assume that the locale is in
+ * X/Open format: language[_territory][.codeset][@modifier]
+ *
+ * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
+ *       as well. We could just copy the code from glibc wholesale
+ *       but it is big, ugly, and complicated, so I'm reluctant
+ *       to do so when this should handle 99% of the time...
+ */
+GSList *
+_g_compute_locale_variants (const gchar *locale)
+{
+  GSList *retval = NULL;
+
+  gchar *language = NULL;
+  gchar *territory = NULL;
+  gchar *codeset = NULL;
+  gchar *modifier = NULL;
+
+  guint mask;
+  guint i;
+
+  g_return_val_if_fail (locale != NULL, NULL);
+
+  mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
+
+  /* Iterate through all possible combinations, from least attractive
+   * to most attractive.
+   */
+  for (i = 0; i <= mask; i++)
+    if ((i & ~mask) == 0)
+      {
+       gchar *val = g_strconcat (language,
+                                 (i & COMPONENT_TERRITORY) ? territory : "",
+                                 (i & COMPONENT_CODESET) ? codeset : "",
+                                 (i & COMPONENT_MODIFIER) ? modifier : "",
+                                 NULL);
+       retval = g_slist_prepend (retval, val);
+      }
+
+  g_free (language);
+  if (mask & COMPONENT_CODESET)
+    g_free (codeset);
+  if (mask & COMPONENT_TERRITORY)
+    g_free (territory);
+  if (mask & COMPONENT_MODIFIER)
+    g_free (modifier);
+
+  return retval;
+}
+
+/* The following is (partly) taken from the gettext package.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.  */
+
+static const gchar *
+guess_category_value (const gchar *category_name)
+{
+  const gchar *retval;
+
+  /* The highest priority value is the `LANGUAGE' environment
+     variable.  This is a GNU extension.  */
+  retval = g_getenv ("LANGUAGE");
+  if ((retval != NULL) && (retval[0] != '\0'))
+    return retval;
+
+  /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
+     methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
+     systems this can be done by the `setlocale' function itself.  */
+
+  /* Setting of LC_ALL overwrites all other.  */
+  retval = g_getenv ("LC_ALL");  
+  if ((retval != NULL) && (retval[0] != '\0'))
+    return retval;
+
+  /* Next comes the name of the desired category.  */
+  retval = g_getenv (category_name);
+  if ((retval != NULL) && (retval[0] != '\0'))
+    return retval;
+
+  /* Last possibility is the LANG environment variable.  */
+  retval = g_getenv ("LANG");
+  if ((retval != NULL) && (retval[0] != '\0'))
+    return retval;
+
+#ifdef G_PLATFORM_WIN32
+  /* g_win32_getlocale() first checks for LC_ALL, LC_MESSAGES and
+   * LANG, which we already did above. Oh well. The main point of
+   * calling g_win32_getlocale() is to get the thread's locale as used
+   * by Windows and the Microsoft C runtime (in the "English_United
+   * States" format) translated into the Unixish format.
+   */
+  retval = g_win32_getlocale ();
+  if ((retval != NULL) && (retval[0] != '\0'))
+    return retval;
+#endif  
+
+  return NULL;
+}
+
+typedef struct _GLanguageNamesCache GLanguageNamesCache;
+
+struct _GLanguageNamesCache {
+  gchar *languages;
+  gchar **language_names;
+};
+
+static void
+language_names_cache_free (gpointer data)
+{
+  GLanguageNamesCache *cache = data;
+  g_free (cache->languages);
+  g_strfreev (cache->language_names);
+  g_free (cache);
+}
+
+/**
+ * g_get_language_names:
+ * 
+ * Computes a list of applicable locale names, which can be used to 
+ * e.g. construct locale-dependent filenames or search paths. The returned 
+ * list is sorted from most desirable to least desirable and always contains 
+ * the default locale "C".
+ *
+ * For example, if LANGUAGE=de:en_US, then the returned list is
+ * "de", "en_US", "en", "C".
+ *
+ * This function consults the environment variables <envar>LANGUAGE</envar>, 
+ * <envar>LC_ALL</envar>, <envar>LC_MESSAGES</envar> and <envar>LANG</envar> 
+ * to find the list of locales specified by the user.
+ * 
+ * Return value: a %NULL-terminated array of strings owned by GLib 
+ *    that must not be modified or freed.
+ *
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar * G_CONST_RETURN * 
+g_get_language_names (void)
+{
+  static GStaticPrivate cache_private = G_STATIC_PRIVATE_INIT;
+  GLanguageNamesCache *cache = g_static_private_get (&cache_private);
+  const gchar *value;
+
+  if (!cache)
+    {
+      cache = g_new0 (GLanguageNamesCache, 1);
+      g_static_private_set (&cache_private, cache, language_names_cache_free);
+    }
+
+  value = guess_category_value ("LC_MESSAGES");
+  if (!value)
+    value = "C";
+
+  if (!(cache->languages && strcmp (cache->languages, value) == 0))
+    {
+      gchar **languages;
+      gchar **alist, **a;
+      GSList *list, *l;
+      gint i;
+
+      g_free (cache->languages);
+      g_strfreev (cache->language_names);
+      cache->languages = g_strdup (value);
+
+      alist = g_strsplit (value, ":", 0);
+      list = NULL;
+      for (a = alist; *a; a++)
+       {
+         gchar *b = unalias_lang (*a);
+         list = g_slist_concat (list, _g_compute_locale_variants (b));
+       }
+      g_strfreev (alist);
+      list = g_slist_append (list, g_strdup ("C"));
+
+      cache->language_names = languages = g_new (gchar *, g_slist_length (list) + 1);
+      for (l = list, i = 0; l; l = l->next, i++)
+       languages[i] = l->data;
+      languages[i] = NULL;
+
+      g_slist_free (list);
+    }
+
+  return (G_CONST_RETURN gchar * G_CONST_RETURN *) cache->language_names;
+}
+
+/**
+ * g_direct_hash:
+ * @v: a #gpointer key
+ *
+ * Converts a gpointer to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func parameter, 
+ * when using pointers as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ */
+guint
+g_direct_hash (gconstpointer v)
+{
+  return GPOINTER_TO_UINT (v);
+}
+
+/**
+ * g_direct_equal:
+ * @v1: a key.
+ * @v2: a key to compare with @v1.
+ *
+ * Compares two #gpointer arguments and returns %TRUE if they are equal.
+ * It can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using pointers as keys in a #GHashTable.
+ * 
+ * Returns: %TRUE if the two keys match.
+ */
+gboolean
+g_direct_equal (gconstpointer v1,
+               gconstpointer v2)
+{
+  return v1 == v2;
+}
+
+/**
+ * g_int_equal:
+ * @v1: a pointer to a #gint key.
+ * @v2: a pointer to a #gint key to compare with @v1.
+ *
+ * Compares the two #gint values being pointed to and returns 
+ * %TRUE if they are equal.
+ * It can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using pointers to integers as keys in a #GHashTable.
+ * 
+ * Returns: %TRUE if the two keys match.
+ */
+gboolean
+g_int_equal (gconstpointer v1,
+            gconstpointer v2)
+{
+  return *((const gint*) v1) == *((const gint*) v2);
+}
+
+/**
+ * g_int_hash:
+ * @v: a pointer to a #gint key
+ *
+ * Converts a pointer to a #gint to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func parameter, 
+ * when using pointers to integers values as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ */
+guint
+g_int_hash (gconstpointer v)
+{
+  return *(const gint*) v;
+}
+
+/**
+ * g_nullify_pointer:
+ * @nullify_location: the memory address of the pointer.
+ * 
+ * Set the pointer at the specified location to %NULL.
+ **/
+void
+g_nullify_pointer (gpointer *nullify_location)
+{
+  g_return_if_fail (nullify_location != NULL);
+
+  *nullify_location = NULL;
+}
+
+/**
+ * g_get_codeset:
+ * 
+ * Get the codeset for the current locale.
+ * 
+ * Return value: a newly allocated string containing the name
+ * of the codeset. This string must be freed with g_free().
+ **/
+gchar *
+g_get_codeset (void)
+{
+  const gchar *charset;
+
+  g_get_charset (&charset);
+
+  return g_strdup (charset);
+}
+
+/* This is called from g_thread_init(). It's used to
+ * initialize some static data in a threadsafe way.
+ */
+void
+_g_utils_thread_init (void)
+{
+  g_get_language_names ();
+}
+
+#ifdef G_OS_WIN32
+
+/**
+ * _glib_get_locale_dir:
+ *
+ * Return the path to the share\locale or lib\locale subfolder of the
+ * GLib installation folder. The path is in the system codepage. We
+ * have to use system codepage as bindtextdomain() doesn't have a
+ * UTF-8 interface.
+ */
+static gchar *
+_glib_get_locale_dir (void)
+{
+  gchar *install_dir = NULL, *locale_dir;
+  gchar *retval = NULL;
+
+  if (glib_dll != NULL)
+    install_dir = g_win32_get_package_installation_directory_of_module (glib_dll);
+
+  if (install_dir)
+    {
+      /*
+       * Append "/share/locale" or "/lib/locale" depending on whether
+       * autoconfigury detected GNU gettext or not.
+       */
+      const char *p = GLIB_LOCALE_DIR + strlen (GLIB_LOCALE_DIR);
+      while (*--p != '/')
+       ;
+      while (*--p != '/')
+       ;
+
+      locale_dir = g_build_filename (install_dir, p, NULL);
+
+      retval = g_win32_locale_filename_from_utf8 (locale_dir);
+
+      g_free (install_dir);
+      g_free (locale_dir);
+    }
+
+  if (retval)
+    return retval;
+  else
+    return g_strdup ("");
+}
+
+#undef GLIB_LOCALE_DIR
+
+#endif /* G_OS_WIN32 */
+
+/**
+ * glib_gettext:
+ * @str: The string to be translated
+ *
+ * Returns the translated string from the glib translations.
+ * This is an internal function and should only be used by
+ * the internals of glib (such as libgio).
+ *
+ * Returns: the transation of @str to the current locale
+ */
+G_CONST_RETURN gchar *
+glib_gettext (const gchar *str)
+{
+  static gboolean _glib_gettext_initialized = FALSE;
+
+  if (!_glib_gettext_initialized)
+    {
+#ifdef G_OS_WIN32
+      gchar *tmp = _glib_get_locale_dir ();
+      bindtextdomain (GETTEXT_PACKAGE, tmp);
+      g_free (tmp);
+#else
+      bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
+#endif
+#    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#    endif
+      _glib_gettext_initialized = TRUE;
+    }
+  
+  return g_dgettext (GETTEXT_PACKAGE, str);
+}
+
+#if defined (G_OS_WIN32) && !defined (_WIN64)
+
+/* Binary compatibility versions. Not for newly compiled code. */
+
+#undef g_find_program_in_path
+
+gchar*
+g_find_program_in_path (const gchar *program)
+{
+  gchar *utf8_program = g_locale_to_utf8 (program, -1, NULL, NULL, NULL);
+  gchar *utf8_retval = g_find_program_in_path_utf8 (utf8_program);
+  gchar *retval;
+
+  g_free (utf8_program);
+  if (utf8_retval == NULL)
+    return NULL;
+  retval = g_locale_from_utf8 (utf8_retval, -1, NULL, NULL, NULL);
+  g_free (utf8_retval);
+
+  return retval;
+}
+
+#undef g_get_current_dir
+
+gchar*
+g_get_current_dir (void)
+{
+  gchar *utf8_dir = g_get_current_dir_utf8 ();
+  gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL);
+  g_free (utf8_dir);
+  return dir;
+}
+
+#undef g_getenv
+
+G_CONST_RETURN gchar*
+g_getenv (const gchar *variable)
+{
+  gchar *utf8_variable = g_locale_to_utf8 (variable, -1, NULL, NULL, NULL);
+  const gchar *utf8_value = g_getenv_utf8 (utf8_variable);
+  gchar *value;
+  GQuark quark;
+
+  g_free (utf8_variable);
+  if (!utf8_value)
+    return NULL;
+  value = g_locale_from_utf8 (utf8_value, -1, NULL, NULL, NULL);
+  quark = g_quark_from_string (value);
+  g_free (value);
+
+  return g_quark_to_string (quark);
+}
+
+#undef g_setenv
+
+gboolean
+g_setenv (const gchar *variable, 
+         const gchar *value, 
+         gboolean     overwrite)
+{
+  gchar *utf8_variable = g_locale_to_utf8 (variable, -1, NULL, NULL, NULL);
+  gchar *utf8_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
+  gboolean retval = g_setenv_utf8 (utf8_variable, utf8_value, overwrite);
+
+  g_free (utf8_variable);
+  g_free (utf8_value);
+
+  return retval;
+}
+
+#undef g_unsetenv
+
+void
+g_unsetenv (const gchar *variable)
+{
+  gchar *utf8_variable = g_locale_to_utf8 (variable, -1, NULL, NULL, NULL);
+
+  g_unsetenv_utf8 (utf8_variable);
+
+  g_free (utf8_variable);
+}
+
+#undef g_get_user_name
+
+G_CONST_RETURN gchar*
+g_get_user_name (void)
+{
+  g_get_any_init_locked ();
+  return g_user_name_cp;
+}
+
+#undef g_get_real_name
+
+G_CONST_RETURN gchar*
+g_get_real_name (void)
+{
+  g_get_any_init_locked ();
+  return g_real_name_cp;
+}
+
+#undef g_get_home_dir
+
+G_CONST_RETURN gchar*
+g_get_home_dir (void)
+{
+  g_get_any_init_locked ();
+  return g_home_dir_cp;
+}
+
+#undef g_get_tmp_dir
+
+G_CONST_RETURN gchar*
+g_get_tmp_dir (void)
+{
+  g_get_any_init_locked ();
+  return g_tmp_dir_cp;
+}
+
+#endif
+
+#define __G_UTILS_C__
+#include "galiasdef.c"