[cogl/wip/standalone: 6/6] [WIP] build: Allow cogl to build without any dependency



commit 46a569bc404ddb8f53c106f31fdc7ca8671da63b
Author: Damien Lespiau <damien lespiau intel com>
Date:   Wed Feb 22 16:21:56 2012 +0000

    [WIP] build: Allow cogl to build without any dependency

 .gitignore                            |    2 +
 build/autotools/acglib.m4             |  131 ++
 build/autotools/as-glibconfig.m4      | 1981 +++++++++++++++++
 cogl/cogl-bitmap-pixbuf.c             |   19 +-
 cogl/cogl-bitmap-private.h            |    2 +-
 cogl/cogl-bitmap.c                    |    4 +-
 cogl/cogl-bitmap.h                    |    6 +-
 cogl/cogl-blend-string.c              |   24 +-
 cogl/cogl-blend-string.h              |    2 +-
 cogl/cogl-context-private.h           |    2 +-
 cogl/cogl-context.c                   |    8 +-
 cogl/cogl-context.h                   |    4 +-
 cogl/cogl-debug.c                     |   26 +-
 cogl/cogl-display.c                   |    6 +-
 cogl/cogl-display.h                   |    4 +-
 cogl/cogl-error.c                     |  712 ++++++
 cogl/cogl-error.h                     |  120 +
 cogl/cogl-framebuffer.c               |    6 +-
 cogl/cogl-framebuffer.h               |    4 +-
 cogl/cogl-index-buffer.c              |    2 +-
 cogl/cogl-material-compat.c           |    8 +-
 cogl/cogl-material-compat.h           |   16 +-
 cogl/cogl-pipeline-layer-state.c      |   21 +-
 cogl/cogl-pipeline-layer-state.h      |    8 +-
 cogl/cogl-pipeline-state.c            |   19 +-
 cogl/cogl-pipeline-state.h            |    8 +-
 cogl/cogl-private.h                   |    4 +-
 cogl/cogl-renderer.c                  |   16 +-
 cogl/cogl-renderer.h                  |    8 +-
 cogl/cogl-texture-2d-private.h        |    4 +-
 cogl/cogl-texture-2d-sliced.c         |   14 +-
 cogl/cogl-texture-2d-sliced.h         |    4 +-
 cogl/cogl-texture-2d.c                |   20 +-
 cogl/cogl-texture-2d.h                |   16 +-
 cogl/cogl-texture-3d-private.h        |    4 +-
 cogl/cogl-texture-3d.c                |   38 +-
 cogl/cogl-texture-3d.h                |   12 +-
 cogl/cogl-texture-rectangle.c         |    8 +-
 cogl/cogl-texture-rectangle.h         |    4 +-
 cogl/cogl-texture.c                   |    2 +-
 cogl/cogl-texture.h                   |    6 +-
 cogl/cogl-types.h                     |   17 +-
 cogl/cogl-xlib-renderer-private.h     |    2 +-
 cogl/cogl-xlib-renderer.c             |    6 +-
 cogl/cogl.c                           |    6 -
 cogl/cogl1-context.h                  |    3 +
 cogl/driver/gl/cogl-gl.c              |   11 +-
 cogl/driver/gles/cogl-gles.c          |    2 +-
 cogl/winsys/cogl-texture-pixmap-x11.c |    2 +-
 cogl/winsys/cogl-texture-pixmap-x11.h |    6 +-
 cogl/winsys/cogl-winsys-egl-android.c |   12 +-
 cogl/winsys/cogl-winsys-egl-gdl.c     |   26 +-
 cogl/winsys/cogl-winsys-egl-kms.c     |   30 +-
 cogl/winsys/cogl-winsys-egl-null.c    |   12 +-
 cogl/winsys/cogl-winsys-egl-private.h |   12 +-
 cogl/winsys/cogl-winsys-egl-wayland.c |   18 +-
 cogl/winsys/cogl-winsys-egl-x11.c     |   18 +-
 cogl/winsys/cogl-winsys-egl.c         |   23 +-
 cogl/winsys/cogl-winsys-glx.c         |   60 +-
 cogl/winsys/cogl-winsys-private.h     |    8 +-
 cogl/winsys/cogl-winsys-sdl.c         |   18 +-
 cogl/winsys/cogl-winsys-stub.c        |    8 +-
 cogl/winsys/cogl-winsys-wgl.c         |   26 +-
 configure.ac                          |   92 +-
 deps/glib/README                      |    1 +
 deps/glib/garray.c                    | 1624 ++++++++++++++
 deps/glib/garray.h                    |  181 ++
 deps/glib/gdataset.c                  | 1355 ++++++++++++
 deps/glib/gdataset.h                  |  122 +
 deps/glib/gdatasetprivate.h           |   44 +
 deps/glib/gerror.c                    |  711 ++++++
 deps/glib/gerror.h                    |  107 +
 deps/glib/ghash.c                     | 1575 +++++++++++++
 deps/glib/ghash.h                     |  168 ++
 deps/glib/ghook.c                     |  636 ++++++
 deps/glib/ghook.h                     |  181 ++
 deps/glib/glib.h                      |   21 +
 deps/glib/glibconfig.h                |  227 ++
 deps/glib/glist.c                     | 1170 ++++++++++
 deps/glib/glist.h                     |  122 +
 deps/glib/gmacros.h                   |  290 +++
 deps/glib/gmem.c                      | 1397 ++++++++++++
 deps/glib/gmem.h                      |  309 +++
 deps/glib/gmessages.c                 | 1218 +++++++++++
 deps/glib/gmessages.h                 |  405 ++++
 deps/glib/gprintf.c                   |  340 +++
 deps/glib/gprintf.h                   |   52 +
 deps/glib/gprintfint.h                |   59 +
 deps/glib/gquark.h                    |   52 +
 deps/glib/gslice.c                    | 1495 +++++++++++++
 deps/glib/gslice.h                    |   86 +
 deps/glib/gslist.c                    | 1082 +++++++++
 deps/glib/gslist.h                    |  116 +
 deps/glib/gstrfuncs.c                 | 3283 ++++++++++++++++++++++++++++
 deps/glib/gstrfuncs.h                 |  269 +++
 deps/glib/gstring.c                   | 1528 +++++++++++++
 deps/glib/gstring.h                   |  190 ++
 deps/glib/gtypes.h                    |  461 ++++
 deps/glib/gunicode.h                  |  729 ++++++
 deps/glib/gutils.c                    | 3890 +++++++++++++++++++++++++++++++++
 deps/glib/gutils.h                    |  528 +++++
 deps/gmodule/gmodule-dl.c             |  168 ++
 deps/gmodule/gmodule-dld.c            |  163 ++
 deps/gmodule/gmodule-dyld.c           |  154 ++
 deps/gmodule/gmodule-win32.c          |  202 ++
 deps/gmodule/gmodule.c                |  685 ++++++
 deps/gmodule/gmodule.h                |  101 +
 deps/gmodule/gmoduleconf.h.in         |   54 +
 deps/gmodule/gmoduleconf.h.win32      |   44 +
 109 files changed, 30941 insertions(+), 377 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 584938d..49ef5d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,7 +21,9 @@ stamp-marshal
 /build/config.rpath
 /build/config.sub
 /build/autotools/*.m4
+!/build/autotools/acglib.m4
 !/build/autotools/introspection.m4
+!/build/autotools/as-glibconfig.m4
 !/build/autotools/as-linguas.m4
 !/build/autotools/as-compiler-flag.m4
 /build/config.guess
diff --git a/build/autotools/acglib.m4 b/build/autotools/acglib.m4
new file mode 100644
index 0000000..4778bfa
--- /dev/null
+++ b/build/autotools/acglib.m4
@@ -0,0 +1,131 @@
+## Portability defines that help interoperate with classic and modern autoconfs
+ifdef([AC_TR_SH],[
+define([GLIB_TR_SH],[AC_TR_SH([$1])])
+define([GLIB_TR_CPP],[AC_TR_CPP([$1])])
+], [
+define([GLIB_TR_SH],
+       [patsubst(translit([[$1]], [*+], [pp]), [[^a-zA-Z0-9_]], [_])])
+define([GLIB_TR_CPP],
+       [patsubst(translit([[$1]],
+  	                  [*abcdefghijklmnopqrstuvwxyz],
+ 			  [PABCDEFGHIJKLMNOPQRSTUVWXYZ]),
+		 [[^A-Z0-9_]], [_])])
+])
+
+# GLIB_AC_DIVERT_BEFORE_HELP(STUFF)
+# ---------------------------------
+# Put STUFF early enough so that they are available for $ac_help expansion.
+# Handle both classic (<= v2.13) and modern autoconf
+AC_DEFUN([GLIB_AC_DIVERT_BEFORE_HELP],
+[ifdef([m4_divert_text], [m4_divert_text([NOTICE],[$1])],
+       [ifdef([AC_DIVERT], [AC_DIVERT([NOTICE],[$1])],
+              [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl
+$1
+AC_DIVERT_POP()])])])
+
+dnl GLIB_IF_VAR_EQ (ENV_VAR, VALUE [, EQUALS_ACTION] [, ELSE_ACTION])
+AC_DEFUN([GLIB_IF_VAR_EQ],[
+        case "$[$1]" in
+        "[$2]"[)]
+                [$3]
+                ;;
+        *[)]
+                [$4]
+                ;;
+        esac
+])
+dnl GLIB_STR_CONTAINS (SRC_STRING, SUB_STRING [, CONTAINS_ACTION] [, ELSE_ACTION])
+AC_DEFUN([GLIB_STR_CONTAINS],[
+        case "[$1]" in
+        *"[$2]"*[)]
+                [$3]
+                ;;
+        *[)]
+                [$4]
+                ;;
+        esac
+])
+dnl GLIB_ADD_TO_VAR (ENV_VARIABLE, CHECK_STRING, ADD_STRING)
+AC_DEFUN([GLIB_ADD_TO_VAR],[
+        GLIB_STR_CONTAINS($[$1], [$2], [$1]="$[$1]", [$1]="$[$1] [$3]")
+])
+
+# GLIB_SIZEOF (INCLUDES, TYPE, ALIAS)
+# ---------------------------------------------------------------
+# The definition here is based of that of AC_CHECK_SIZEOF
+AC_DEFUN([GLIB_SIZEOF],
+[AS_LITERAL_IF([$3], [],
+               [AC_FATAL([$0: requires literal arguments])])dnl
+AC_CACHE_CHECK([size of $2], AS_TR_SH([glib_cv_sizeof_$3]),
+[ # The cast to unsigned long works around a bug in the HP C Compiler
+  # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+  # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+  # This bug is HP SR number 8606223364.
+  _AC_COMPUTE_INT([(long) (sizeof ($2))],
+                  [AS_TR_SH([glib_cv_sizeof_$3])],
+                  [AC_INCLUDES_DEFAULT([$1])],
+                  [AC_MSG_ERROR([cannot compute sizeof ($2), 77])])
+])dnl
+AC_DEFINE_UNQUOTED(GLIB_TR_CPP(glib_sizeof_$3), $AS_TR_SH([glib_cv_sizeof_$3]),
+                   [The size of $3, as computed by sizeof.])
+])# GLIB_SIZEOF
+
+dnl GLIB_BYTE_CONTENTS (INCLUDES, TYPE, ALIAS, N_BYTES, INITIALIZER)
+AC_DEFUN([GLIB_BYTE_CONTENTS],
+[pushdef([glib_ByteContents], GLIB_TR_SH([glib_cv_byte_contents_$3]))dnl
+AC_CACHE_CHECK([byte contents of $5], glib_ByteContents,
+[AC_TRY_RUN([#include <stdio.h>
+$1
+main()
+{
+  static $2 tv = $5;
+  char *p = (char*) &tv;
+  int i;
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  for (i = 0; i < $4; i++)
+    fprintf(f, "%s%d", i?",":"", *(p++));
+  fprintf(f, "\n");
+  exit(0);
+}], 
+   [glib_ByteContents=`cat conftestval`  dnl''
+], 
+   [glib_ByteContents=no],
+   [glib_ByteContents=no])])
+AC_DEFINE_UNQUOTED(GLIB_TR_CPP(glib_byte_contents_$3), [$[]glib_ByteContents],
+	[Byte contents of $3])
+popdef([glib_ByteContents])dnl
+])
+
+# GLIB_CHECK_VALUE(SYMBOL, INCLUDES, ACTION-IF-FAIL)
+# ---------------------------------------------------------------
+AC_DEFUN([GLIB_CHECK_VALUE],
+[AC_CACHE_CHECK([value of $1], AS_TR_SH([glib_cv_value_$1]),
+  [_AC_COMPUTE_INT([$1], AS_TR_SH([glib_cv_value_$1]), [$2], [$3])])
+])dnl
+
+# GLIB_CHECK_COMPILE_WARNINGS(PROGRAM, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# ---------------------------------------------------------------------
+# Try to compile PROGRAM, check for warnings
+m4_define([GLIB_CHECK_COMPILE_WARNINGS],
+[m4_ifvaln([$1], [AC_LANG_CONFTEST([$1])])dnl
+rm -f conftest.$ac_objext
+glib_ac_compile_save="$ac_compile"
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext'
+AS_IF([_AC_EVAL_STDERR($ac_compile) &&
+         AC_TRY_COMMAND([(if test -s conftest.err; then false ; else true; fi)])],
+      [$2],
+      [echo "$as_me: failed program was:" >&AS_MESSAGE_LOG_FD
+cat conftest.$ac_ext >&AS_MESSAGE_LOG_FD
+m4_ifvaln([$3],[$3])dnl])
+ac_compile="$glib_ac_compile_save"
+rm -f conftest.$ac_objext conftest.err m4_ifval([$1], [conftest.$ac_ext])[]dnl
+])# GLIB_CHECK_COMPILE_WARNINGS
+
+# GLIB_ASSERT_SET(VARIABLE)
+# -------------------------
+AC_DEFUN([GLIB_ASSERT_SET],
+[if test "x${$1+set}" != "xset" ; then
+  AC_MSG_ERROR($1 [must be set in cache file when cross-compiling.])
+fi
+])dnl
diff --git a/build/autotools/as-glibconfig.m4 b/build/autotools/as-glibconfig.m4
new file mode 100644
index 0000000..d298d13
--- /dev/null
+++ b/build/autotools/as-glibconfig.m4
@@ -0,0 +1,1981 @@
+dnl
+dnl Test program for basic POSIX threads functionality
+dnl
+m4_define([glib_thread_test],[
+#include <pthread.h> 
+int check_me = 0;
+void* func(void* data) {check_me = 42; return &check_me;}
+int main()
+ { pthread_t t; 
+   void *ret;
+   pthread_create (&t, $1, func, 0);
+   pthread_join (t, &ret);
+   return (check_me != 42 || ret != &check_me);
+}])
+
+AC_DEFUN([AS_GLIBCONFIG],
+[
+
+GLIB_MAJOR_VERSION=2
+GLIB_MINOR_VERSION=30
+GLIB_MICRO_VERSION=2
+
+dnl Let's use the system printf unconditionally
+enable_included_printf=no
+
+dnl No support for static window libraries 
+glib_win32_static_compilation=no
+
+dnl that's the defaults in glib's configure (which provides a --with-threads
+dnl option we don't expose here)
+want_threads=yes
+
+AC_CANONICAL_HOST
+
+AC_MSG_CHECKING([for Win32])
+LIB_EXE_MACHINE_FLAG=X86
+case "$host" in
+  *-*-mingw*)
+    glib_native_win32=yes
+    glib_pid_type='void *'
+    glib_cv_stack_grows=no
+    # Unfortunately the mingw implementations of C99-style snprintf and vsnprintf
+    # don't seem to be quite good enough, at least not in mingw-runtime-3.14.
+    # (Sorry, I don't know exactly what is the problem, but it is related to
+    # floating point formatting and decimal point vs. comma.)
+    # The simple tests in AC_FUNC_VSNPRINTF_C99 and AC_FUNC_SNPRINTF_C99 aren't
+    # rigorous enough to notice, though.
+    # So preset the autoconf cache variables.
+    ac_cv_func_vsnprintf_c99=no
+    ac_cv_func_snprintf_c99=no
+    case "$host" in
+    x86_64-*-*)
+      LIB_EXE_MACHINE_FLAG=X64
+      ;;
+    esac
+    ;;
+  *)
+    glib_native_win32=no
+    glib_pid_type=int
+    ;;
+esac
+case $host in
+  *-*-linux*)
+    glib_os_linux=yes
+    ;;
+esac
+
+AC_MSG_RESULT([$glib_native_win32])
+
+AC_SUBST(LIB_EXE_MACHINE_FLAG)
+
+glib_have_carbon=no
+AC_MSG_CHECKING([for Mac OS X Carbon support])
+AC_TRY_CPP([
+#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
+], glib_have_carbon=yes)
+
+AC_MSG_RESULT([$glib_have_carbon])
+
+AM_CONDITIONAL(OS_WIN32, [test "$glib_native_win32" = "yes"])
+AM_CONDITIONAL(OS_WIN32_X64, [test "$LIB_EXE_MACHINE_FLAG" = "X64"])
+AM_CONDITIONAL(OS_UNIX, [test "$glib_native_win32" != "yes"])
+AM_CONDITIONAL(OS_LINUX, [test "$glib_os_linux" = "yes"])
+AM_CONDITIONAL(OS_CARBON, [test "$glib_have_carbon" = "yes"])
+
+AC_CHECK_HEADERS([limits.h float.h values.h alloca.h sys/poll.h])
+AC_CHECK_FUNCS(atexit on_exit memmove)
+
+AC_CHECK_SIZEOF(char)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(__int64)
+
+if test x$ac_cv_sizeof_long = x8 || test x$ac_cv_sizeof_long_long = x8 || test x$ac_cv_sizeof___int64 = x8 ; then
+  :
+else
+  AC_MSG_ERROR([
+*** GLib requires a 64 bit type. You might want to consider
+*** using the GNU C compiler.
+])
+fi
+
+if test x$glib_native_win32 != xyes && test x$ac_cv_sizeof_long_long = x8; then
+	# long long is a 64 bit integer.
+	AC_MSG_CHECKING(for format to printf and scanf a guint64)
+	AC_CACHE_VAL(glib_cv_long_long_format,[
+		for format in ll q I64; do
+		  AC_TRY_RUN([#include <stdio.h>  
+			int main()
+			{
+			  long long b, a = -0x3AFAFAFAFAFAFAFALL;
+			  char buffer[1000];
+			  sprintf (buffer, "%${format}u", a);
+  			  sscanf (buffer, "%${format}u", &b);
+			  exit (b!=a);
+			}
+			],
+			[glib_cv_long_long_format=${format}
+			break],
+			[],[:])
+		done])
+	if test -n "$glib_cv_long_long_format"; then
+	  AC_MSG_RESULT(%${glib_cv_long_long_format}u)
+	  AC_DEFINE(HAVE_LONG_LONG_FORMAT,1,[define if system printf can print long long])
+	  if test x"$glib_cv_long_long_format" = xI64; then
+	    AC_DEFINE(HAVE_INT64_AND_I64,1,[define to support printing 64-bit integers with format I64])
+	  fi
+        else
+	  AC_MSG_RESULT(none)
+        fi
+elif test x$ac_cv_sizeof___int64 = x8; then
+	# __int64 is a 64 bit integer.
+	AC_MSG_CHECKING(for format to printf and scanf a guint64)
+	# We know this is MSVCRT.DLL, and what the formats are
+	glib_cv_long_long_format=I64
+	AC_MSG_RESULT(%${glib_cv_long_long_format}u)
+        AC_DEFINE(HAVE_LONG_LONG_FORMAT,1,[define if system printf can print long long])
+	AC_DEFINE(HAVE_INT64_AND_I64,1,[define to support printing 64-bit integers with format I64])
+fi
+
+# check additional type sizes
+AC_CHECK_SIZEOF(size_t)
+
+dnl Try to figure out whether gsize, gssize should be long or int
+AC_MSG_CHECKING([for the appropriate definition for size_t])
+
+case $ac_cv_sizeof_size_t in
+  $ac_cv_sizeof_short) 
+      glib_size_type=short
+      ;;
+  $ac_cv_sizeof_int) 
+      glib_size_type=int
+      ;;
+  $ac_cv_sizeof_long) 
+      glib_size_type=long
+      ;;
+  $ac_cv_sizeof_long_long)
+      glib_size_type='long long'
+      ;;
+  $ac_cv_sizeof__int64)
+      glib_size_type='__int64'
+      ;;
+  *)  AC_MSG_ERROR([No type matching size_t in size])
+      ;;
+esac
+
+dnl If int/long are the same size, we see which one produces
+dnl warnings when used in the location as size_t. (This matters
+dnl on AIX with xlc)
+dnl
+if test $ac_cv_sizeof_size_t = $ac_cv_sizeof_int &&
+   test $ac_cv_sizeof_size_t = $ac_cv_sizeof_long ; then
+  GLIB_CHECK_COMPILE_WARNINGS([AC_LANG_SOURCE([[
+#if defined(_AIX) && !defined(__GNUC__)
+#pragma options langlvl=stdc89
+#endif
+#include <stddef.h> 
+int main ()
+{
+  size_t s = 1;
+  unsigned int *size_int = &s;
+  return (int)*size_int;
+}
+    ]])],glib_size_type=int,
+      [GLIB_CHECK_COMPILE_WARNINGS([AC_LANG_SOURCE([[
+#if defined(_AIX) && !defined(__GNUC__)
+#pragma options langlvl=stdc89
+#endif
+#include <stddef.h> 
+int main ()
+{
+   size_t s = 1;
+   unsigned long *size_long = &s;
+   return (int)*size_long;
+}
+        ]])],glib_size_type=long)])
+fi
+
+AC_MSG_RESULT(unsigned $glib_size_type)
+
+# Check if bcopy can be used for overlapping copies, if memmove isn't found.
+# The check is borrowed from the PERL Configure script.
+if test "$ac_cv_func_memmove" != "yes"; then
+  AC_CACHE_CHECK(whether bcopy can handle overlapping copies,
+    glib_cv_working_bcopy,[AC_TRY_RUN([
+      int main() {
+        char buf[128], abc[128], *b;
+        int len, off, align;
+        bcopy("abcdefghijklmnopqrstuvwxyz0123456789", abc, 36);
+        for (align = 7; align >= 0; align--) {
+          for (len = 36; len; len--) {
+            b = buf+align; bcopy(abc, b, len);
+            for (off = 1; off <= len; off++) {
+              bcopy(b, b+off, len); bcopy(b+off, b, len);
+                if (bcmp(b, abc, len)) return(1);
+            }
+          }
+        }
+        return(0);
+      }],glib_cv_working_bcopy=yes,glib_cv_working_bcopy=no)])
+
+  GLIB_ASSERT_SET(glib_cv_working_bcopy)
+  if test "$glib_cv_working_bcopy" = "yes"; then
+    AC_DEFINE(HAVE_WORKING_BCOPY,1,[Have a working bcopy])
+  fi
+fi
+
+dnl va_copy checks
+dnl we currently check for all three va_copy possibilities, so we get
+dnl all results in config.log for bug reports.
+AC_CACHE_CHECK([for an implementation of va_copy()],glib_cv_va_copy,[
+	AC_LINK_IFELSE([AC_LANG_SOURCE([[#include <stdarg.h>
+#include <stdlib.h>
+	void f (int i, ...) {
+	va_list args1, args2;
+	va_start (args1, i);
+	va_copy (args2, args1);
+	if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42)
+	  exit (1);
+	va_end (args1); va_end (args2);
+	}
+	int main() {
+	  f (0, 42);
+	  return 0;
+	}]])],
+	[glib_cv_va_copy=yes],
+	[glib_cv_va_copy=no])
+])
+AC_CACHE_CHECK([for an implementation of __va_copy()],glib_cv___va_copy,[
+	AC_LINK_IFELSE([AC_LANG_SOURCE([[#include <stdarg.h>
+#include <stdlib.h>
+	void f (int i, ...) {
+	va_list args1, args2;
+	va_start (args1, i);
+	__va_copy (args2, args1);
+	if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42)
+	  exit (1);
+	va_end (args1); va_end (args2);
+	}
+	int main() {
+	  f (0, 42);
+	  return 0;
+	}]])],
+	[glib_cv___va_copy=yes],
+	[glib_cv___va_copy=no])
+])
+
+if test "x$glib_cv_va_copy" = "xyes"; then
+  g_va_copy_func=va_copy
+else if test "x$glib_cv___va_copy" = "xyes"; then
+  g_va_copy_func=__va_copy
+fi
+fi
+
+if test -n "$g_va_copy_func"; then
+  AC_DEFINE_UNQUOTED(G_VA_COPY,$g_va_copy_func,[A 'va_copy' style function])
+fi
+
+AC_CACHE_CHECK([whether va_lists can be copied by value],glib_cv_va_val_copy,[
+	AC_TRY_RUN([#include <stdarg.h>
+#include <stdlib.h> 
+	void f (int i, ...) {
+	va_list args1, args2;
+	va_start (args1, i);
+	args2 = args1;
+	if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42)
+	  exit (1);
+	va_end (args1); va_end (args2);
+	}
+	int main() {
+	  f (0, 42);
+	  return 0;
+	}],
+	[glib_cv_va_val_copy=yes],
+	[glib_cv_va_val_copy=no],
+	[glib_cv_va_val_copy=yes])
+])
+
+if test "x$glib_cv_va_val_copy" = "xno"; then
+  AC_DEFINE(G_VA_COPY_AS_ARRAY,1, ['va_lists' cannot be copies as values])
+fi
+
+dnl ***********************
+dnl *** g_module checks ***
+dnl ***********************
+G_MODULE_LIBS=
+G_MODULE_LIBS_EXTRA=
+G_MODULE_PLUGIN_LIBS=
+if test x"$glib_native_win32" = xyes; then
+  dnl No use for this on Win32
+  G_MODULE_LDFLAGS=
+else
+  export SED
+  G_MODULE_LDFLAGS=`(./libtool --config; echo eval echo \\$export_dynamic_flag_spec) | sh`
+fi
+dnl G_MODULE_IMPL= don't reset, so cmd-line can override
+G_MODULE_NEED_USCORE=0
+G_MODULE_BROKEN_RTLD_GLOBAL=0
+G_MODULE_HAVE_DLERROR=0
+dnl *** force native WIN32 shared lib loader 
+if test -z "$G_MODULE_IMPL"; then
+  case "$host" in
+  *-*-mingw*|*-*-cygwin*) G_MODULE_IMPL=G_MODULE_IMPL_WIN32 ;;
+  esac
+fi
+dnl *** force native AIX library loader
+dnl *** dlopen() filepath must be of the form /path/libname.a(libname.so)
+if test -z "$G_MODULE_IMPL"; then
+  case "$host" in
+  *-*-aix*) G_MODULE_IMPL=G_MODULE_IMPL_AR ;;
+  esac
+fi
+dnl *** dlopen() and dlsym() in system libraries
+if test -z "$G_MODULE_IMPL"; then
+	AC_CHECK_FUNC(dlopen,
+		      [AC_CHECK_FUNC(dlsym,
+			             [G_MODULE_IMPL=G_MODULE_IMPL_DL],[])],
+		      [])
+fi
+dnl *** load_image (BeOS)
+if test -z "$G_MODULE_IMPL" && test "x$glib_native_beos" = "xyes"; then
+  AC_CHECK_LIB(root, load_image,
+      [G_MODULE_LIBS="-lbe -lroot -lglib-2.0 "
+      G_MODULE_LIBS_EXTRA="-L\$(top_builddir_full)/.libs"
+      G_MODULE_PLUGIN_LIBS="-L\$(top_builddir_full)/gmodule/.libs -lgmodule"
+      G_MODULE_IMPL=G_MODULE_IMPL_BEOS],
+      [])
+fi   
+dnl *** NSLinkModule (dyld) in system libraries (Darwin)
+if test -z "$G_MODULE_IMPL"; then
+ 	AC_CHECK_FUNC(NSLinkModule,
+		      [G_MODULE_IMPL=G_MODULE_IMPL_DYLD
+		       G_MODULE_NEED_USCORE=1],
+		      [])
+fi
+dnl *** dlopen() and dlsym() in libdl
+if test -z "$G_MODULE_IMPL"; then
+	AC_CHECK_LIB(dl, dlopen,
+		     [AC_CHECK_LIB(dl, dlsym,
+			           [G_MODULE_LIBS=-ldl
+		                   G_MODULE_IMPL=G_MODULE_IMPL_DL],[])],
+		     [])
+fi
+dnl *** shl_load() in libdld (HP-UX)
+if test -z "$G_MODULE_IMPL"; then
+	AC_CHECK_LIB(dld, shl_load,
+		[G_MODULE_LIBS=-ldld
+		G_MODULE_IMPL=G_MODULE_IMPL_DLD],
+		[])
+fi
+dnl *** additional checks for G_MODULE_IMPL_DL
+if test "$G_MODULE_IMPL" = "G_MODULE_IMPL_DL"; then
+	LIBS_orig="$LIBS"
+	LDFLAGS_orig="$LDFLAGS"
+	LIBS="$G_MODULE_LIBS $LIBS"
+	LDFLAGS="$LDFLAGS $G_MODULE_LDFLAGS"
+dnl *** check for OSF1/5.0 RTLD_GLOBAL brokenness
+	echo "void glib_plugin_test(void) { }" > plugin.c
+	${SHELL} ./libtool --mode=compile ${CC} -shared \
+		-export-dynamic -o plugin.o plugin.c 2>&1 >/dev/null
+	AC_CACHE_CHECK([for RTLD_GLOBAL brokenness],
+		glib_cv_rtldglobal_broken,[
+		AC_TRY_RUN([
+#include <dlfcn.h>
+#ifndef RTLD_GLOBAL
+#  define RTLD_GLOBAL 0
+#endif
+#ifndef RTLD_LAZY
+#  define RTLD_LAZY 0
+#endif
+int glib_plugin_test;
+int main () {
+    void *handle, *global, *local;
+    global = &glib_plugin_test;
+    handle = dlopen ("./.libs/plugin.o", RTLD_GLOBAL | RTLD_LAZY);
+    if (!handle) return 0;
+    local = dlsym (handle, "glib_plugin_test");
+    return global == local;
+}                       ],
+			[glib_cv_rtldglobal_broken=no],
+			[glib_cv_rtldglobal_broken=yes],
+			[glib_cv_rtldglobal_broken=no])
+		rm -f plugin.c plugin.o plugin.lo .libs/plugin.o
+		rmdir .libs 2>/dev/null
+	])
+	if test "x$glib_cv_rtldglobal_broken" = "xyes"; then
+  		G_MODULE_BROKEN_RTLD_GLOBAL=1
+	else
+  		G_MODULE_BROKEN_RTLD_GLOBAL=0
+	fi
+dnl *** check whether we need preceeding underscores
+	AC_CACHE_CHECK([for preceeding underscore in symbols],
+		glib_cv_uscore,[
+		AC_TRY_RUN([#include <dlfcn.h>
+                int glib_underscore_test (void) { return 42; }
+		int main() {
+		  void *f1 = (void*)0, *f2 = (void*)0, *handle;
+		  handle = dlopen ((void*)0, 0);
+		  if (handle) {
+		    f1 = dlsym (handle, "glib_underscore_test");
+		    f2 = dlsym (handle, "_glib_underscore_test");
+		  } return (!f2 || f1);
+		}],
+			[glib_cv_uscore=yes],
+			[glib_cv_uscore=no],
+			[])
+		rm -f plugin.c plugin.$ac_objext plugin.lo
+	])
+        GLIB_ASSERT_SET(glib_cv_uscore)
+	if test "x$glib_cv_uscore" = "xyes"; then
+  		G_MODULE_NEED_USCORE=1
+	else
+  		G_MODULE_NEED_USCORE=0
+	fi
+
+	LDFLAGS="$LDFLAGS_orig"
+dnl *** check for having dlerror()
+	AC_CHECK_FUNC(dlerror,
+		[G_MODULE_HAVE_DLERROR=1],
+		[G_MODULE_HAVE_DLERROR=0])
+	LIBS="$LIBS_orig"
+fi
+dnl *** done, have we got an implementation?
+if test -z "$G_MODULE_IMPL"; then
+	G_MODULE_IMPL=0
+        G_MODULE_SUPPORTED=false
+else
+        G_MODULE_SUPPORTED=true
+fi
+
+AC_MSG_CHECKING(for the suffix of module shared libraries)
+export SED
+shrext_cmds=`./libtool --config | grep '^shrext_cmds='`
+eval $shrext_cmds
+module=yes eval std_shrext=$shrext_cmds
+# chop the initial dot
+glib_gmodule_suffix=`echo $std_shrext | sed 's/^\.//'`
+AC_MSG_RESULT(.$glib_gmodule_suffix)
+# any reason it may fail?
+if test "x$glib_gmodule_suffix" = x; then
+	AC_MSG_ERROR(Cannot determine shared library suffix from libtool)
+fi
+ 
+AC_SUBST(G_MODULE_SUPPORTED)
+AC_SUBST(G_MODULE_IMPL)
+AC_SUBST(G_MODULE_LIBS)
+AC_SUBST(G_MODULE_LIBS_EXTRA)
+AC_SUBST(G_MODULE_PLUGIN_LIBS)
+AC_SUBST(G_MODULE_LDFLAGS)
+AC_SUBST(G_MODULE_HAVE_DLERROR)
+AC_SUBST(G_MODULE_BROKEN_RTLD_GLOBAL)
+AC_SUBST(G_MODULE_NEED_USCORE)
+AC_SUBST(GLIB_DEBUG_FLAGS)
+
+dnl AC_C_INLINE is useless to us since it bails out too early, we need to
+dnl truely know which ones of `inline', `__inline' and `__inline__' are
+dnl actually supported.
+AC_CACHE_CHECK([for __inline],glib_cv_has__inline,[
+        AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+	__inline int foo () { return 0; }
+	int main () { return foo (); }
+	]])],
+	glib_cv_has__inline=yes
+        ,
+	glib_cv_has__inline=no
+        ,)
+])
+case x$glib_cv_has__inline in
+xyes) AC_DEFINE(G_HAVE___INLINE,1,[Have __inline keyword])
+esac
+AC_CACHE_CHECK([for __inline__],glib_cv_has__inline__,[
+        AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+	__inline__ int foo () { return 0; }
+	int main () { return foo (); }
+	]])],
+	glib_cv_has__inline__=yes
+        ,
+	glib_cv_has__inline__=no
+        ,)
+])
+case x$glib_cv_has__inline__ in
+xyes) AC_DEFINE(G_HAVE___INLINE__,1,[Have __inline__ keyword])
+esac
+AC_CACHE_CHECK([for inline], glib_cv_hasinline,[
+        AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+	#undef inline
+	inline int foo () { return 0; }
+	int main () { return foo (); }
+	]])],
+	glib_cv_hasinline=yes
+        ,
+	glib_cv_hasinline=no
+        ,)
+])
+case x$glib_cv_hasinline in
+xyes) AC_DEFINE(G_HAVE_INLINE,1,[Have inline keyword])
+esac
+
+# if we can use inline functions in headers
+AC_MSG_CHECKING(if inline functions in headers work)
+AC_LINK_IFELSE([AC_LANG_SOURCE([[
+#if defined (G_HAVE_INLINE) && defined (__GNUC__) && defined (__STRICT_ANSI__)
+#  undef inline
+#  define inline __inline__
+#elif !defined (G_HAVE_INLINE)
+#  undef inline
+#  if defined (G_HAVE___INLINE__)
+#    define inline __inline__
+#  elif defined (G_HAVE___INLINE)
+#    define inline __inline
+#  endif
+#endif
+
+int glib_test_func2 (int);
+
+static inline int
+glib_test_func1 (void) {
+  return glib_test_func2 (1);
+}
+
+int
+main (void) {
+  int i = 1;
+}]])],[g_can_inline=yes],[g_can_inline=no])
+AC_MSG_RESULT($g_can_inline)
+
+# check for flavours of varargs macros
+AC_MSG_CHECKING(for ISO C99 varargs macros in C)
+AC_TRY_COMPILE([],[
+int a(int p1, int p2, int p3);
+#define call_a(...) a(1,__VA_ARGS__)
+call_a(2,3);
+],g_have_iso_c_varargs=yes,g_have_iso_c_varargs=no)
+AC_MSG_RESULT($g_have_iso_c_varargs)
+
+AC_MSG_CHECKING(for ISO C99 varargs macros in C++)
+if test "$CXX" = ""; then
+dnl No C++ compiler
+  g_have_iso_cxx_varargs=no
+else
+  AC_LANG_CPLUSPLUS
+  AC_TRY_COMPILE([],[
+int a(int p1, int p2, int p3);
+#define call_a(...) a(1,__VA_ARGS__)
+call_a(2,3);
+],g_have_iso_cxx_varargs=yes,g_have_iso_cxx_varargs=no)
+  AC_LANG_C
+fi
+AC_MSG_RESULT($g_have_iso_cxx_varargs)
+
+AC_MSG_CHECKING(for GNUC varargs macros)
+AC_TRY_COMPILE([],[
+int a(int p1, int p2, int p3);
+#define call_a(params...) a(1,params)
+call_a(2,3);
+],g_have_gnuc_varargs=yes,g_have_gnuc_varargs=no)
+AC_MSG_RESULT($g_have_gnuc_varargs)
+
+AC_MSG_CHECKING([for EILSEQ])
+AC_TRY_COMPILE([
+#include <errno.h>
+],
+[
+int error = EILSEQ;
+], have_eilseq=yes, have_eilseq=no);
+AC_MSG_RESULT($have_eilseq)
+
+# check for GNUC visibility support
+AC_MSG_CHECKING(for GNUC visibility attribute)
+GLIB_CHECK_COMPILE_WARNINGS([AC_LANG_SOURCE([[
+void
+__attribute__ ((visibility ("hidden")))
+     f_hidden (void)
+{
+}
+void
+__attribute__ ((visibility ("internal")))
+     f_internal (void)
+{
+}
+void
+__attribute__ ((visibility ("protected")))
+     f_protected (void)
+{
+}
+void
+__attribute__ ((visibility ("default")))
+     f_default (void)
+{
+}
+int main (int argc, char **argv)
+{
+	f_hidden();
+	f_internal();
+	f_protected();
+	f_default();
+	return 0;
+}
+]])],g_have_gnuc_visibility=yes,g_have_gnuc_visibility=no)
+AC_MSG_RESULT($g_have_gnuc_visibility)
+AM_CONDITIONAL(HAVE_GNUC_VISIBILITY, [test x$g_have_gnuc_visibility = xyes])
+
+# check for bytesex stuff
+AC_C_BIGENDIAN
+if test x$ac_cv_c_bigendian = xuniversal ; then
+AC_TRY_COMPILE([#include <endian.h>], [#if __BYTE_ORDER == __BIG_ENDIAN
+#else
+#error Not a big endian. 
+#endif],
+    ac_cv_c_bigendian=yes
+    ,AC_TRY_COMPILE([#include <endian.h>], [#if __BYTE_ORDER == __LITTLE_ENDIAN
+#else
+#error Not a little endian. 
+#endif],
+    ac_cv_c_bigendian=no
+    ,AC_MSG_WARN([Could not determine endianness.])))
+fi
+
+dnl error and warning message
+dnl *************************
+
+THREAD_NO_IMPLEMENTATION="You do not have any known thread system on your
+                computer. GLib will not have a default thread implementation."
+
+FLAG_DOES_NOT_WORK="I can't find the MACRO to enable thread safety on your
+                platform (normally it's "_REENTRANT"). I'll not use any flag on
+                compilation now, but then your programs might not work.
+                Please provide information on how it is done on your system."
+
+LIBS_NOT_FOUND_1="I can't find the libraries for the thread implementation
+		"
+
+LIBS_NOT_FOUND_2=". Please choose another thread implementation or
+		provide information on your thread implementation.
+		You can also run 'configure --disable-threads' 
+		to compile without thread support."
+
+FUNC_NO_GETPWUID_R="the 'g_get_(user_name|real_name|home_dir|tmp_dir)'
+		functions will not be MT-safe during their first call because
+		there is no working 'getpwuid_r' on your system."
+
+FUNC_NO_LOCALTIME_R="the 'g_date_set_time' function will not be MT-safe
+		because there is no 'localtime_r' on your system."
+
+POSIX_NO_YIELD="I can not find a yield functions for your platform. A rather
+		crude surrogate will be used. If you happen to know a 
+		yield function for your system, please inform the GLib 
+		developers."
+
+POSIX_NO_PRIORITIES="I can not find the minimal and maximal priorities for 
+		threads on your system. Thus threads can only have the default 
+		priority. If you happen to know these main/max
+		priorities, please inform the GLib developers."
+
+AIX_COMPILE_INFO="AIX's C compiler needs to be called by a different name, when
+		linking threaded applications. As GLib cannot do that 
+		automatically, you will get an linkg error everytime you are 
+		not using the right compiler. In that case you have to relink 
+		with the right compiler. Ususally just '_r' is appended 
+		to the compiler name."
+
+dnl determination of thread implementation
+dnl ***************************************
+
+# have_threads=no   means no thread support
+# have_threads=none means no default thread implementation
+
+have_threads=no
+if test "x$want_threads" = xyes || test "x$want_threads" = xposix \
+				|| test "x$want_threads" = xdce; then
+	# -D_POSIX4_DRAFT_SOURCE -D_POSIX4A_DRAFT10_SOURCE is for DG/UX
+	# -U_OSF_SOURCE is for Digital UNIX 4.0d
+	GTHREAD_COMPILE_IMPL_DEFINES="-D_POSIX4_DRAFT_SOURCE -D_POSIX4A_DRAFT10_SOURCE -U_OSF_SOURCE"
+	glib_save_CPPFLAGS="$CPPFLAGS"
+	CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
+        if test "x$have_threads" = xno; then
+                AC_TRY_COMPILE([#include <pthread.h>],
+			[pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;],
+			have_threads=posix)
+        fi
+        if test "x$have_threads" = xno; then
+                AC_TRY_COMPILE([#include <pthread.h>],
+			[pthread_mutex_t m; 
+                         pthread_mutex_init (&m, pthread_mutexattr_default);],
+			have_threads=dce)
+        fi
+	# Tru64Unix requires -pthread to find pthread.h. See #103020
+	CPPFLAGS="$CPPFLAGS -pthread"
+	if test "x$have_threads" = xno; then
+	AC_TRY_COMPILE([#include <pthread.h>],
+		       [pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;],
+		       have_threads=posix)
+        fi
+	CPPFLAGS="$glib_save_CPPFLAGS"
+fi
+if test "x$want_threads" = xyes || test "x$want_threads" = xwin32; then
+       	case $host in
+               	*-*-mingw*)
+		have_threads=win32
+		;;
+	esac
+fi
+if test "x$want_threads" = xnone; then
+	have_threads=none
+fi
+
+AC_MSG_CHECKING(for thread implementation)
+
+if test "x$have_threads" = xno && test "x$want_threads" != xno; then
+	AC_MSG_RESULT(none available)
+        AC_MSG_WARN($THREAD_NO_IMPLEMENTATION)
+else
+	AC_MSG_RESULT($have_threads)
+fi
+
+
+dnl determination of G_THREAD_CFLAGS
+dnl ********************************
+
+G_THREAD_LIBS=
+G_THREAD_LIBS_EXTRA=
+G_THREAD_CFLAGS=
+
+dnl
+dnl Test program for sched_get_priority_min()
+dnl
+m4_define([glib_sched_priority_test],[
+#include <sched.h>
+#include <errno.h>
+int main() {
+    errno = 0;
+    return sched_get_priority_min(SCHED_OTHER)==-1
+ 	   && errno != 0;
+}])
+
+if test x"$have_threads" != xno; then
+
+  if test x"$have_threads" = xposix; then
+    # First we test for posix, whether -pthread or -pthreads do the trick as 
+    # both CPPFLAG and LIBS. 
+    # One of them does for most gcc versions and some other platforms/compilers
+    # too and could be considered as the canonical way to go. 
+    case $host in
+      *-*-cygwin*|*-*-darwin*)
+         # skip cygwin and darwin -pthread or -pthreads test
+         ;;
+      *-solaris*)
+        # These compiler/linker flags work with both Sun Studio and gcc
+	# Sun Studio expands -mt to -D_REENTRANT and -lthread
+	# gcc expands -pthreads to -D_REENTRANT -D_PTHREADS -lpthread
+        G_THREAD_CFLAGS="-D_REENTRANT -D_PTHREADS"
+        G_THREAD_LIBS="-lpthread -lthread"
+        ;;
+      *)
+        for flag in pthread pthreads mt; do
+          glib_save_CFLAGS="$CFLAGS"
+          CFLAGS="$CFLAGS -$flag"
+          AC_TRY_RUN(glib_thread_test(0),
+                     glib_flag_works=yes,
+                     glib_flag_works=no,
+                     [AC_LINK_IFELSE([AC_LANG_SOURCE(glib_thread_test(0))],
+                                     glib_flag_works=yes,
+                                     glib_flag_works=no)])
+          CFLAGS="$glib_save_CFLAGS"
+          if test $glib_flag_works = yes ; then
+             G_THREAD_CFLAGS=-$flag
+	     G_THREAD_LIBS=-$flag
+	     break;
+          fi
+        done
+         ;;
+    esac 
+  fi
+
+  if test x"$G_THREAD_CFLAGS" = x; then
+
+    # The canonical -pthread[s] does not work. Try something different.
+
+    case $host in
+	*-aix*)
+		if test x"$GCC" = xyes; then
+			# GCC 3.0 and above needs -pthread. 
+			# Should be coverd by the case above.
+			# GCC 2.x and below needs -mthreads
+			G_THREAD_CFLAGS="-mthreads"		
+			G_THREAD_LIBS=$G_THREAD_CFLAGS
+		else 
+			# We are probably using the aix compiler. Normaly a 
+			# program would have to be compiled with the _r variant
+			# of the corresponding compiler, but we as GLib cannot 
+			# do that: but the good news is that for compiling the
+			# only difference is the added -D_THREAD_SAFE compile 
+			# option. This is according to the "C for AIX User's 
+			# Guide".
+			G_THREAD_CFLAGS="-D_THREAD_SAFE"
+		fi
+		;;
+	*-dg-dgux*)  # DG/UX
+		G_THREAD_CFLAGS="-D_REENTRANT -D_POSIX4A_DRAFT10_SOURCE"
+		;;
+	*-osf*)
+		# So we are using dce threads. posix threads are already 
+		# catched above.
+		G_THREAD_CFLAGS="-threads"
+		G_THREAD_LIBS=$G_THREAD_CFLAGS
+		;;
+	*-sysv5uw7*) # UnixWare 7 
+		# We are not using gcc with -pthread. Catched above.
+		G_THREAD_CFLAGS="-Kthread"
+		G_THREAD_LIBS=$G_THREAD_CFLAGS
+		;;
+	*-mingw*)
+		# No flag needed when using MSVCRT.DLL
+		G_THREAD_CFLAGS=""
+		;;
+	*)
+		G_THREAD_CFLAGS="-D_REENTRANT" # good default guess otherwise
+		;;
+    esac
+ 
+  fi
+
+    # if we are not finding the localtime_r function, then we probably are
+    # not using the proper multithread flag
+
+    glib_save_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $G_THREAD_CFLAGS"
+
+    # First we test, whether localtime_r is declared in time.h
+    # directly. Then we test whether a macro localtime_r exists, in
+    # which case localtime_r in the test program is replaced and thus
+    # if we still find localtime_r in the output, it is not defined as 
+    # a macro.
+
+    AC_EGREP_CPP([[^a-zA-Z1-9_]localtime_r[^a-zA-Z1-9_]], [#include <time.h>], ,
+      [AC_EGREP_CPP([[^a-zA-Z1-9_]localtime_r[^a-zA-Z1-9_]], [#include <time.h> 
+							   localtime_r(a,b)],
+      		   AC_MSG_WARN($FLAG_DOES_NOT_WORK))])
+
+    CPPFLAGS="$glib_save_CPPFLAGS"
+
+    AC_MSG_CHECKING(thread related cflags)
+    AC_MSG_RESULT($G_THREAD_CFLAGS)
+    CPPFLAGS="$CPPFLAGS $G_THREAD_CFLAGS"
+fi
+
+dnl determination of G_THREAD_LIBS
+dnl ******************************
+
+mutex_has_default=no
+case $have_threads in
+        posix|dce)
+	  glib_save_CPPFLAGS="$CPPFLAGS"
+	  CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
+          if test x"$G_THREAD_LIBS" = x; then
+            case $host in
+              *-aix*)
+                # We are not using gcc (would have set G_THREAD_LIBS) and thus 
+                # probably using the aix compiler.
+		AC_MSG_WARN($AIX_COMPILE_INFO)
+                ;;
+              *)
+                G_THREAD_LIBS=error
+	        glib_save_LIBS="$LIBS"
+	        for thread_lib in "" pthread pthread32 pthreads thread dce; do
+			if test x"$thread_lib" = x; then
+				add_thread_lib=""
+				IN=""
+			else
+				add_thread_lib="-l$thread_lib"
+				IN=" in -l$thread_lib"
+			fi
+			if test x"$have_threads" = xposix; then
+				defattr=0
+			else
+				defattr=pthread_attr_default
+			fi
+			
+			LIBS="$add_thread_lib $glib_save_LIBS"
+			
+			AC_MSG_CHECKING(for pthread_create/pthread_join$IN)
+			AC_TRY_RUN(glib_thread_test([$defattr]),
+                                   glib_result=yes,
+                                   glib_result=no,
+                                   [AC_LINK_IFELSE([AC_LANG_SOURCE(glib_thread_test([$defattr]))],
+                                                   glib_result=yes,
+                                                   glib_result=no)])
+                        AC_MSG_RESULT($glib_result)
+			
+                        if test "$glib_result" = "yes" ; then
+			  G_THREAD_LIBS="$add_thread_lib"
+                          break
+                        fi
+		done
+		if test "x$G_THREAD_LIBS" = xerror; then
+		  AC_MSG_ERROR($LIBS_NOT_FOUND_1$have_threads$LIBS_NOT_FOUND_2)
+		fi 
+		LIBS="$glib_save_LIBS"
+                ;;
+            esac
+          fi
+
+          glib_save_LIBS="$LIBS"
+	  for thread_lib in "" rt rte; do
+	    if test x"$thread_lib" = x; then
+	      add_thread_lib=""
+	      IN=""
+	    else
+	      add_thread_lib="-l$thread_lib"
+	      IN=" in -l$thread_lib"
+	    fi
+	    LIBS="$add_thread_lib $glib_save_LIBS"
+	    
+            AC_MSG_CHECKING(for sched_get_priority_min$IN)
+	    AC_TRY_RUN(glib_sched_priority_test,
+                       glib_result=yes,
+                       glib_result=no,
+                       [AC_LINK_IFELSE([AC_LANG_SOURCE(glib_sched_priority_test)],
+                                       glib_result=yes,
+                                       glib_result=no)])
+	    AC_MSG_RESULT($glib_result)
+
+	    if test "$glib_result" = "yes" ; then	    
+ 	       G_THREAD_LIBS="$G_THREAD_LIBS $add_thread_lib"
+	       posix_priority_min="sched_get_priority_min(SCHED_OTHER)"
+	       posix_priority_max="sched_get_priority_max(SCHED_OTHER)"
+	       break
+            fi
+	  done
+	  LIBS="$glib_save_LIBS"
+          mutex_has_default=yes
+          mutex_default_type='pthread_mutex_t'
+          mutex_default_init='PTHREAD_MUTEX_INITIALIZER'
+          mutex_header_file='pthread.h'
+	  if test "x$have_threads" = "xposix"; then
+	    g_threads_impl="POSIX"
+	  else
+	    g_threads_impl="DCE"
+	    have_threads="posix"
+	  fi
+	  AC_SUBST(GTHREAD_COMPILE_IMPL_DEFINES)
+          CPPFLAGS="$glib_save_CPPFLAGS"
+          ;;
+	win32)
+	   g_threads_impl="WIN32"
+	   ;;
+        none|no)
+	   g_threads_impl="NONE"
+           ;;
+        *)
+	   g_threads_impl="NONE"
+           G_THREAD_LIBS=error
+           ;;
+esac
+
+if test "x$G_THREAD_LIBS" = xerror; then
+        AC_MSG_ERROR($LIBS_NOT_FOUND_1$have_threads$LIBS_NOT_FOUND_2)
+fi
+
+AC_MSG_CHECKING(thread related libraries)
+AC_MSG_RESULT($G_THREAD_LIBS)
+
+dnl check for mt safe function variants and some posix functions
+dnl ************************************************************
+
+if test x"$have_threads" != xno; then
+	glib_save_LIBS="$LIBS"
+
+	LIBS="$G_THREAD_LIBS $LIBS"
+	if test x"$have_threads" = xposix; then
+		glib_save_CPPFLAGS="$CPPFLAGS"
+		CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
+		dnl we might grow sizeof(pthread_t) later on, so use a dummy name here
+		GLIB_SIZEOF([#include <pthread.h>], pthread_t, system_thread)
+		# This is not AC_CHECK_FUNC to also work with function
+		# name mangling in header files.
+		AC_MSG_CHECKING(for pthread_attr_setstacksize)
+		AC_TRY_LINK([#include <pthread.h>],
+			[pthread_attr_t t; pthread_attr_setstacksize(&t,0)],
+			[AC_MSG_RESULT(yes)
+			AC_DEFINE(HAVE_PTHREAD_ATTR_SETSTACKSIZE,1,
+				  [Have function pthread_attr_setstacksize])],
+			[AC_MSG_RESULT(no)])
+		AC_MSG_CHECKING(for minimal/maximal thread priority)
+		if test x"$posix_priority_min" = x; then
+			AC_EGREP_CPP(PX_PRIO_MIN,[#include <pthread.h>
+				PX_PRIO_MIN],,[
+				posix_priority_min=PX_PRIO_MIN
+				posix_priority_max=PX_PRIO_MAX])
+		fi
+		if test x"$posix_priority_min" = x; then
+			# AIX
+			AC_EGREP_CPP(PTHREAD_PRIO_MIN,[#include <pthread.h>
+				PTHREAD_PRIO_MIN],,[
+				posix_priority_min=PTHREAD_PRIO_MIN
+				posix_priority_max=PTHREAD_PRIO_MAX])
+		fi
+		if test x"$posix_priority_min" = x; then
+			AC_EGREP_CPP(PRI_OTHER_MIN,[#include <pthread.h>
+				PRI_OTHER_MIN],,[
+				posix_priority_min=PRI_OTHER_MIN	
+				posix_priority_max=PRI_OTHER_MAX])
+		fi
+		if test x"$posix_priority_min" = x; then
+			AC_MSG_RESULT(none found)
+			AC_MSG_WARN($POSIX_NO_PRIORITIES)
+	                posix_priority_min=-1
+			posix_priority_max=-1
+		else
+			AC_MSG_RESULT($posix_priority_min/$posix_priority_max)
+			AC_MSG_CHECKING(for pthread_setschedparam)
+			AC_TRY_LINK([#include <pthread.h>],
+		          [pthread_t t; pthread_setschedparam(t, 0, NULL)],
+			  [AC_MSG_RESULT(yes)
+			AC_DEFINE_UNQUOTED(POSIX_MIN_PRIORITY,$posix_priority_min,[Minimum POSIX RT priority])
+			   AC_DEFINE_UNQUOTED(POSIX_MAX_PRIORITY,$posix_priority_max,[Maximum POSIX RT priority])],
+                          [AC_MSG_RESULT(no)
+                           AC_MSG_WARN($POSIX_NO_PRIORITIES)])
+		fi
+		posix_yield_func=none
+		AC_MSG_CHECKING(for posix yield function)
+		for yield_func in sched_yield pthread_yield_np pthread_yield \
+							thr_yield; do
+			AC_TRY_LINK([#include <pthread.h>],
+				[$yield_func()],
+				[posix_yield_func="$yield_func"
+				break])
+		done		
+		if test x"$posix_yield_func" = xnone; then
+			AC_MSG_RESULT(none found)
+			AC_MSG_WARN($POSIX_NO_YIELD)
+	                posix_yield_func="g_usleep(1000)"
+		else
+			AC_MSG_RESULT($posix_yield_func)
+			posix_yield_func="$posix_yield_func()"
+		fi
+		AC_DEFINE_UNQUOTED(POSIX_YIELD_FUNC,$posix_yield_func,[The POSIX RT yield function])
+		CPPFLAGS="$glib_save_CPPFLAGS"
+           
+	elif test x"$have_threads" = xwin32; then
+		# It's a pointer to a private struct
+		GLIB_SIZEOF(,struct _GThreadData *, system_thread)
+	fi
+
+	LIBS="$glib_save_LIBS"
+fi
+
+if test x"$glib_cv_sizeof_system_thread" = x; then
+   # use a pointer as a fallback.
+   GLIB_SIZEOF(,void *, system_thread)
+fi
+
+#
+# Hack to deal with:
+# 
+#  a) GCC < 3.3 for Linux doesn't include -lpthread when
+#     building shared libraries with linux.
+#  b) FreeBSD doesn't do this either.
+#
+case $host in
+  *-*-freebsd*|*-*-linux*)
+    G_THREAD_LIBS_FOR_GTHREAD="`echo $G_THREAD_LIBS | sed s/-pthread/-lpthread/`"
+    ;;
+  *-*-openbsd*)
+    LDFLAGS="$LDFLAGS -pthread"
+    ;;
+  *)
+    G_THREAD_LIBS_FOR_GTHREAD="$G_THREAD_LIBS"
+    ;;
+esac
+
+AM_CONDITIONAL(HAVE_THREADS, [test "$have_threads" != "none"])
+AC_DEFINE_UNQUOTED(G_THREAD_SOURCE,"gthread-$have_threads.c",
+		   [Source file containing theread implementation])
+AC_SUBST(G_THREAD_CFLAGS)
+AC_SUBST(G_THREAD_LIBS)
+AC_SUBST(G_THREAD_LIBS_FOR_GTHREAD)
+AC_SUBST(G_THREAD_LIBS_EXTRA)
+
+dnl **********************************************
+dnl *** GDefaultMutex setup and initialization ***
+dnl **********************************************
+dnl
+dnl if mutex_has_default = yes, we also got
+dnl mutex_default_type, mutex_default_init and mutex_header_file
+if test $mutex_has_default = yes ; then
+	glib_save_CPPFLAGS="$CPPFLAGS"
+	glib_save_LIBS="$LIBS"
+	LIBS="$G_THREAD_LIBS $LIBS"
+	CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
+	GLIB_SIZEOF([#include <$mutex_header_file>],
+                    $mutex_default_type,
+                    gmutex)
+	GLIB_BYTE_CONTENTS([#include <$mutex_header_file>],
+			   $mutex_default_type,
+			   gmutex,
+			   $glib_cv_sizeof_gmutex,
+			   $mutex_default_init)
+	if test x"$glib_cv_byte_contents_gmutex" = xno; then
+		mutex_has_default=no
+	fi
+	CPPFLAGS="$glib_save_CPPFLAGS"
+	LIBS="$glib_save_LIBS"
+fi
+
+dnl ************************
+dnl *** g_atomic_* tests ***
+dnl ************************
+
+AC_MSG_CHECKING([whether to use assembler code for atomic operations])
+    case $host_cpu in
+      i386)
+        AC_MSG_RESULT([none])
+        glib_memory_barrier_needed=no
+        ;;
+      i?86)
+        AC_MSG_RESULT([i486])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_I486, 1,
+			   [i486 atomic implementation])
+        glib_memory_barrier_needed=no
+        ;;
+      sparc*)
+        SPARCV9_WARNING="Try to rerun configure with CFLAGS='-mcpu=v9',
+			 when you are using a sparc with v9 instruction set (most
+			 sparcs nowadays). This will make the code for atomic
+			 operations much faster. The resulting code will not run
+			 on very old sparcs though."
+
+        AC_LINK_IFELSE([AC_LANG_SOURCE([[
+          main ()
+          {
+            int tmp1, tmp2, tmp3;
+            __asm__ __volatile__("casx [%2], %0, %1"
+                                 : "=&r" (tmp1), "=&r" (tmp2) : "r" (&tmp3));
+          }]])],
+          AC_MSG_RESULT([sparcv9])
+          AC_DEFINE_UNQUOTED(G_ATOMIC_SPARCV9, 1,
+			     [sparcv9 atomic implementation]),
+          AC_MSG_RESULT([no])
+          AC_MSG_WARN([[$SPARCV9_WARNING]]))
+        glib_memory_barrier_needed=yes
+        ;;
+      alpha*)
+        AC_MSG_RESULT([alpha])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_ALPHA, 1,
+			   [alpha atomic implementation])
+        glib_memory_barrier_needed=yes
+        ;;
+      x86_64)
+        AC_MSG_RESULT([x86_64])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_X86_64, 1,
+			   [x86_64 atomic implementation])
+        glib_memory_barrier_needed=no
+       ;;
+      powerpc*)
+        AC_MSG_RESULT([powerpc])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_POWERPC, 1,
+			   [powerpc atomic implementation])
+        glib_memory_barrier_needed=yes
+        AC_MSG_CHECKING([whether asm supports numbered local labels])
+        AC_TRY_COMPILE(
+		       ,[
+		       __asm__ __volatile__ ("1:       nop\n"
+			       "         bne-    1b")
+		       ],[
+		       AC_DEFINE_UNQUOTED(ASM_NUMERIC_LABELS, 1, [define if asm blocks can use numeric local labels])
+		       AC_MSG_RESULT([yes])
+		       ],[
+		       AC_MSG_RESULT([no])
+		       ])
+        ;;
+      ia64)
+        AC_MSG_RESULT([ia64])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_IA64, 1,
+			   [ia64 atomic implementation])
+        glib_memory_barrier_needed=yes
+        ;;
+      s390|s390x)
+        AC_MSG_RESULT([s390])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_S390, 1,
+			   [s390 atomic implementation])
+        glib_memory_barrier_needed=no
+        ;;
+      arm*)
+        AC_MSG_RESULT([arm])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_ARM, 1,
+			   [arm atomic implementation])
+        glib_memory_barrier_needed=no
+        ;;
+      crisv32*|etraxfs*)
+        AC_MSG_RESULT([crisv32])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_CRISV32, 1,
+			   [crisv32 atomic implementation])
+        glib_memory_barrier_needed=no
+        ;;
+      cris*|etrax*)
+        AC_MSG_RESULT([cris])
+        AC_DEFINE_UNQUOTED(G_ATOMIC_CRIS, 1,
+			   [cris atomic implementation])
+        glib_memory_barrier_needed=no
+        ;;
+      *)
+        AC_MSG_RESULT([none])
+        glib_memory_barrier_needed=yes
+        ;;
+    esac
+
+glib_cv_gcc_has_builtin_atomic_operations=no
+if test x"$GCC" = xyes; then
+  AC_MSG_CHECKING([whether GCC supports built-in atomic intrinsics])
+  AC_TRY_LINK([],
+	      [int i;
+	       __sync_synchronize ();
+	       __sync_bool_compare_and_swap (&i, 0, 1);
+	       __sync_fetch_and_add (&i, 1);
+	      ],
+	      [glib_cv_gcc_has_builtin_atomic_operations=yes],
+	      [glib_cv_gcc_has_builtin_atomic_operations=no])
+
+  AC_MSG_RESULT($glib_cv_gcc_has_builtin_atomic_operations)
+fi
+AM_CONDITIONAL(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS,
+	       [test $glib_cv_gcc_has_builtin_atomic_operations = yes])
+
+AC_MSG_CHECKING([for Win32 atomic intrinsics])
+glib_cv_has_win32_atomic_operations=no
+AC_TRY_LINK([],
+	[int i; _InterlockedExchangeAdd (&i, 0);],
+	[glib_cv_has_win32_atomic_operations=yes],
+	[glib_cv_has_win32_atomic_operations=no])
+AC_MSG_RESULT($glib_cv_has_win32_atomic_operations)
+if test "x$glib_cv_has_win32_atomic_operations" = xyes; then
+	AC_DEFINE(HAVE_WIN32_BUILTINS_FOR_ATOMIC_OPERATIONS,1,[Have Win32 atomic intrinsics])
+fi
+
+dnl ************************
+dnl ** Check for futex(2) **
+dnl ************************
+AC_CACHE_CHECK(for futex(2) system call,
+    glib_cv_futex,AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+],[
+int
+main (void)
+{
+  /* it is not like this actually runs or anything... */
+  syscall (__NR_futex, NULL, FUTEX_WAKE, FUTEX_WAIT);
+  return 0;
+}
+])],glib_cv_futex=yes,glib_cv_futex=no))
+if test x"$glib_cv_futex" = xyes; then
+  AC_DEFINE(HAVE_FUTEX, 1, [we have the futex(2) system call])
+fi
+
+dnl this section will only be run if config.status is invoked with no
+dnl arguments, or with "$1/glibconfig.h" as an argument.
+AC_CONFIG_COMMANDS([$1/glibconfig.h],
+[
+	outfile=$1/glibconfig.h-tmp
+	cat > $outfile <<\_______EOF
+/* glibconfig.h
+ *
+ * This is a generated file.  Please modify 'configure.ac'
+ */
+
+#ifndef __G_LIBCONFIG_H__
+#define __G_LIBCONFIG_H__
+
+#include <glib/gmacros.h>
+
+_______EOF
+
+	if test x$glib_limits_h = xyes; then
+	  echo '#include <limits.h>' >> $outfile
+	fi
+	if test x$glib_float_h = xyes; then
+	  echo '#include <float.h>' >> $outfile
+	fi
+	if test x$glib_values_h = xyes; then
+	  echo '#include <values.h>' >> $outfile
+	fi
+	if test "$glib_header_alloca_h" = "yes"; then
+	  echo '#define GLIB_HAVE_ALLOCA_H' >> $outfile
+	fi
+	if test x$glib_sys_poll_h = xyes; then
+	  echo '#define GLIB_HAVE_SYS_POLL_H' >> $outfile
+	fi
+	if test x$glib_included_printf != xyes; then
+          echo "
+/* Specifies that GLib's g_print*() functions wrap the
+ * system printf functions.  This is useful to know, for example,
+ * when using glibc's register_printf_function().
+ */" >> $outfile
+	  echo '#define GLIB_USING_SYSTEM_PRINTF' >> $outfile
+	fi
+
+	cat >> $outfile <<_______EOF
+
+G_BEGIN_DECLS
+
+#define G_MINFLOAT	$glib_mf
+#define G_MAXFLOAT	$glib_Mf
+#define G_MINDOUBLE	$glib_md
+#define G_MAXDOUBLE	$glib_Md
+#define G_MINSHORT	$glib_ms
+#define G_MAXSHORT	$glib_Ms
+#define G_MAXUSHORT	$glib_Mus
+#define G_MININT	$glib_mi
+#define G_MAXINT	$glib_Mi
+#define G_MAXUINT	$glib_Mui
+#define G_MINLONG	$glib_ml
+#define G_MAXLONG	$glib_Ml
+#define G_MAXULONG	$glib_Mul
+
+_______EOF
+
+
+	### this should always be true in a modern C/C++ compiler
+	cat >>$outfile <<_______EOF
+typedef signed char gint8;
+typedef unsigned char guint8;
+_______EOF
+
+
+	if test -n "$gint16"; then
+	  cat >>$outfile <<_______EOF
+typedef signed $gint16 gint16;
+typedef unsigned $gint16 guint16;
+#define G_GINT16_MODIFIER $gint16_modifier
+#define G_GINT16_FORMAT $gint16_format
+#define G_GUINT16_FORMAT $guint16_format
+_______EOF
+	fi
+
+
+	if test -n "$gint32"; then
+	  cat >>$outfile <<_______EOF
+typedef signed $gint32 gint32;
+typedef unsigned $gint32 guint32;
+#define G_GINT32_MODIFIER $gint32_modifier
+#define G_GINT32_FORMAT $gint32_format
+#define G_GUINT32_FORMAT $guint32_format
+_______EOF
+	fi
+
+	cat >>$outfile <<_______EOF
+#define G_HAVE_GINT64 1          /* deprecated, always true */
+
+${glib_extension}typedef signed $gint64 gint64;
+${glib_extension}typedef unsigned $gint64 guint64;
+
+#define G_GINT64_CONSTANT(val)	$gint64_constant
+#define G_GUINT64_CONSTANT(val)	$guint64_constant
+_______EOF
+
+	if test x$gint64_format != x ; then
+	  cat >>$outfile <<_______EOF
+#define G_GINT64_MODIFIER $gint64_modifier
+#define G_GINT64_FORMAT $gint64_format
+#define G_GUINT64_FORMAT $guint64_format
+_______EOF
+        else
+	  cat >>$outfile <<_______EOF
+#undef G_GINT64_MODIFIER
+#undef G_GINT64_FORMAT
+#undef G_GUINT64_FORMAT
+_______EOF
+        fi           
+
+        cat >>$outfile <<_______EOF
+
+#define GLIB_SIZEOF_VOID_P $glib_void_p
+#define GLIB_SIZEOF_LONG   $glib_long
+#define GLIB_SIZEOF_SIZE_T $glib_size_t
+
+_______EOF
+
+        cat >>$outfile <<_______EOF
+typedef signed $glib_size_type_define gssize;
+typedef unsigned $glib_size_type_define gsize;
+#define G_GSIZE_MODIFIER $gsize_modifier
+#define G_GSSIZE_FORMAT $gssize_format
+#define G_GSIZE_FORMAT $gsize_format
+
+#define G_MAXSIZE	G_MAXU$glib_msize_type
+#define G_MINSSIZE	G_MIN$glib_msize_type
+#define G_MAXSSIZE	G_MAX$glib_msize_type
+
+typedef gint64 goffset;
+#define G_MINOFFSET	G_MININT64
+#define G_MAXOFFSET	G_MAXINT64
+
+#define G_GOFFSET_MODIFIER      G_GINT64_MODIFIER
+#define G_GOFFSET_FORMAT        G_GINT64_FORMAT
+#define G_GOFFSET_CONSTANT(val) G_GINT64_CONSTANT(val)
+
+_______EOF
+
+	if test -z "$glib_unknown_void_p"; then
+	  cat >>$outfile <<_______EOF
+
+#define GPOINTER_TO_INT(p)	((gint)  ${glib_gpi_cast} (p))
+#define GPOINTER_TO_UINT(p)	((guint) ${glib_gpui_cast} (p))
+
+#define GINT_TO_POINTER(i)	((gpointer) ${glib_gpi_cast} (i))
+#define GUINT_TO_POINTER(u)	((gpointer) ${glib_gpui_cast} (u))
+
+typedef signed $glib_intptr_type_define gintptr;
+typedef unsigned $glib_intptr_type_define guintptr;
+
+#define G_GINTPTR_MODIFIER      $gintptr_modifier
+#define G_GINTPTR_FORMAT        $gintptr_format
+#define G_GUINTPTR_FORMAT       $guintptr_format
+_______EOF
+	else
+	  echo '#error SIZEOF_VOID_P unknown - This should never happen' >>$outfile
+	fi
+
+
+
+	cat >>$outfile <<_______EOF
+$glib_atexit
+$glib_memmove
+$glib_defines
+$glib_os
+$glib_static_compilation
+
+$glib_vacopy
+
+#ifdef	__cplusplus
+#define	G_HAVE_INLINE	1
+#else	/* !__cplusplus */
+$glib_inline
+#endif	/* !__cplusplus */
+
+#ifdef	__cplusplus
+#define G_CAN_INLINE	1
+_______EOF
+
+	if test x$g_can_inline = xyes ; then
+		cat >>$outfile <<_______EOF
+#else	/* !__cplusplus */
+#define G_CAN_INLINE	1
+_______EOF
+	fi
+
+	cat >>$outfile <<_______EOF
+#endif
+
+_______EOF
+
+	if test x$g_have_iso_c_varargs = xyes ; then
+		cat >>$outfile <<_______EOF
+#ifndef __cplusplus
+# define G_HAVE_ISO_VARARGS 1
+#endif
+_______EOF
+	fi
+	if test x$g_have_iso_cxx_varargs = xyes ; then
+		cat >>$outfile <<_______EOF
+#ifdef __cplusplus
+# define G_HAVE_ISO_VARARGS 1
+#endif
+_______EOF
+	fi
+	if test x$g_have_gnuc_varargs = xyes ; then
+		cat >>$outfile <<_______EOF
+
+/* 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
+_______EOF
+	fi
+
+	echo >>$outfile
+	if test x$g_have_eilseq = xno; then
+		cat >>$outfile <<_______EOF
+#ifndef EILSEQ
+/* On some systems, like SunOS and NetBSD, EILSEQ is not defined.
+ * The correspondence between this and the corresponding definition
+ * in libiconv is essential.
+ */
+#  define EILSEQ ENOENT
+#endif
+_______EOF
+
+	fi
+
+	if test x$g_have_gnuc_visibility = xyes; then
+		cat >>$outfile <<_______EOF
+#define G_HAVE_GNUC_VISIBILITY 1
+_______EOF
+	fi
+		cat >>$outfile <<_______EOF
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define G_GNUC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define G_GNUC_INTERNAL __hidden
+#elif defined (__GNUC__) && defined (G_HAVE_GNUC_VISIBILITY)
+#define G_GNUC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define G_GNUC_INTERNAL
+#endif 
+_______EOF
+
+
+	echo >>$outfile
+	if test x$g_mutex_has_default = xyes; then
+		cat >>$outfile <<_______EOF
+$g_enable_threads_def G_THREADS_ENABLED
+#define G_THREADS_IMPL_$g_threads_impl_def
+typedef struct _GStaticMutex GStaticMutex;
+struct _GStaticMutex
+{
+  struct _GMutex *runtime_mutex;
+  union {
+    char   pad[[$g_mutex_sizeof]];
+    double dummy_double;
+    void  *dummy_pointer;
+    long   dummy_long;
+  } static_mutex;
+};
+#define	G_STATIC_MUTEX_INIT	{ NULL, { { $g_mutex_contents} } }
+#define	g_static_mutex_get_mutex(mutex) \\
+  (g_thread_use_default_impl ? ((GMutex*)(gpointer) ((mutex)->static_mutex.pad)) : \\
+   g_static_mutex_get_mutex_impl_shortcut (&((mutex)->runtime_mutex)))
+_______EOF
+	else
+		cat >>$outfile <<_______EOF
+$g_enable_threads_def G_THREADS_ENABLED
+#define G_THREADS_IMPL_$g_threads_impl_def
+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))
+_______EOF
+	fi
+
+	cat >>$outfile <<_______EOF
+/* 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
+{
+  char   data[[$g_system_thread_sizeof]];
+  double dummy_double;
+  void  *dummy_pointer;
+  long   dummy_long;
+};
+_______EOF
+	if test x"$g_memory_barrier_needed" != xno; then
+	  echo >>$outfile
+	  echo "#define G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 1" >>$outfile
+	fi
+	if test x"$g_gcc_atomic_ops" != xno; then
+          echo >>$outfile
+          echo "#define G_ATOMIC_OP_USE_GCC_BUILTINS 1" >>$outfile
+        fi
+	echo >>$outfile
+	g_bit_sizes="16 32 64"
+	for bits in $g_bit_sizes; do
+	  cat >>$outfile <<_______EOF
+#define GINT${bits}_TO_${g_bs_native}(val)	((gint${bits}) (val))
+#define GUINT${bits}_TO_${g_bs_native}(val)	((guint${bits}) (val))
+#define GINT${bits}_TO_${g_bs_alien}(val)	((gint${bits}) GUINT${bits}_SWAP_LE_BE (val))
+#define GUINT${bits}_TO_${g_bs_alien}(val)	(GUINT${bits}_SWAP_LE_BE (val))
+_______EOF
+	done
+
+	cat >>$outfile <<_______EOF
+#define GLONG_TO_LE(val)	((glong) GINT${glongbits}_TO_LE (val))
+#define GULONG_TO_LE(val)	((gulong) GUINT${glongbits}_TO_LE (val))
+#define GLONG_TO_BE(val)	((glong) GINT${glongbits}_TO_BE (val))
+#define GULONG_TO_BE(val)	((gulong) GUINT${glongbits}_TO_BE (val))
+#define GINT_TO_LE(val)		((gint) GINT${gintbits}_TO_LE (val))
+#define GUINT_TO_LE(val)	((guint) GUINT${gintbits}_TO_LE (val))
+#define GINT_TO_BE(val)		((gint) GINT${gintbits}_TO_BE (val))
+#define GUINT_TO_BE(val)	((guint) GUINT${gintbits}_TO_BE (val))
+#define GSIZE_TO_LE(val)	((gsize) GUINT${gsizebits}_TO_LE (val))
+#define GSSIZE_TO_LE(val)	((gssize) GINT${gsizebits}_TO_LE (val))
+#define GSIZE_TO_BE(val)	((gsize) GUINT${gsizebits}_TO_BE (val))
+#define GSSIZE_TO_BE(val)	((gssize) GINT${gsizebits}_TO_BE (val))
+#define G_BYTE_ORDER $g_byte_order
+
+#define G_MODULE_SUFFIX "$g_module_suffix"
+
+/* 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 $g_pid_type GPid;
+
+G_END_DECLS
+
+#endif /* GLIBCONFIG_H */
+_______EOF
+
+
+	if cmp -s $outfile $1/glibconfig.h; then
+	  AC_MSG_NOTICE([$1/glibconfig.h is unchanged])
+	  rm -f $outfile
+	else
+	  mv $outfile $1/glibconfig.h
+	fi
+],[
+
+# Note that if two cases are the same, case goes with the first one.
+# Note also that this is inside an AC_OUTPUT_COMMAND.  We do not depend
+# on variable expansion in case labels.  Look at the generated config.status
+# for a hint.
+
+if test "x${ac_cv_working_alloca_h+set}" = xset ; then
+  glib_header_alloca_h="$ac_cv_working_alloca_h"
+else
+  glib_header_alloca_h="$ac_cv_header_alloca_h"
+fi
+
+case xyes in
+x$ac_cv_header_float_h)
+  glib_float_h=yes
+  glib_mf=FLT_MIN glib_Mf=FLT_MAX
+  glib_md=DBL_MIN glib_Md=DBL_MAX
+  ;;
+x$ac_cv_header_values_h)
+  glib_values_h=yes
+  glib_mf=MINFLOAT  glib_Mf=MAXFLOAT
+  glib_md=MINDOUBLE glib_Md=MAXDOUBLE
+  ;;
+esac
+
+case xyes in
+x$ac_cv_header_limits_h)
+  glib_limits_h=yes
+  glib_ms=SHRT_MIN glib_Ms=SHRT_MAX glib_Mus=USHRT_MAX
+  glib_mi=INT_MIN  glib_Mi=INT_MAX  glib_Mui=UINT_MAX
+  glib_ml=LONG_MIN glib_Ml=LONG_MAX glib_Mul=ULONG_MAX
+  ;;
+x$ac_cv_header_values_h)
+  glib_values_h=yes
+  glib_ms=MINSHORT glib_Ms=MAXSHORT glib_Mus="(((gushort)G_MAXSHORT)*2+1)"
+  glib_mi=MININT   glib_Mi=MAXINT   glib_Mui="(((guint)G_MAXINT)*2+1)"
+  glib_ml=MINLONG  glib_Ml=MAXLONG  glib_Mul="(((gulong)G_MAXLONG)*2+1)"
+  ;;
+esac
+
+if test x$ac_cv_header_sys_poll_h = xyes ; then
+  glib_sys_poll_h=yes
+fi
+
+if test x$enable_included_printf = xyes ; then
+  glib_included_printf=yes
+fi
+
+case 2 in
+$ac_cv_sizeof_short)		
+  gint16=short
+  gint16_modifier='"h"'
+  gint16_format='"hi"'
+  guint16_format='"hu"'
+  ;;
+$ac_cv_sizeof_int)		
+  gint16=int
+  gint16_modifier='""'
+  gint16_format='"i"'
+  guint16_format='"u"'
+  ;;
+esac
+case 4 in
+$ac_cv_sizeof_short)		
+  gint32=short
+  gint32_modifier='"h"'
+  gint32_format='"hi"'
+  guint32_format='"hu"'
+  ;;
+$ac_cv_sizeof_int)		
+  gint32=int
+  gint32_modifier='""'
+  gint32_format='"i"'
+  guint32_format='"u"'
+  ;;
+$ac_cv_sizeof_long)		
+  gint32=long
+  gint32_modifier='"l"'
+  gint32_format='"li"'
+  guint32_format='"lu"'
+  ;;
+esac
+case 8 in
+$ac_cv_sizeof_int)
+  gint64=int
+  gint64_modifier='""'
+  gint64_format='"i"'
+  guint64_format='"u"'
+  glib_extension=
+  gint64_constant='(val)'
+  guint64_constant='(val)'
+  ;;
+$ac_cv_sizeof_long)
+  gint64=long
+  gint64_modifier='"l"'
+  gint64_format='"li"'
+  guint64_format='"lu"'
+  glib_extension=
+  gint64_constant='(val##L)'
+  guint64_constant='(val##UL)'
+  ;;
+$ac_cv_sizeof_long_long)
+  gint64='long long'
+  if test -n "$glib_cv_long_long_format"; then
+    gint64_modifier='"'$glib_cv_long_long_format'"'
+    gint64_format='"'$glib_cv_long_long_format'i"'
+    guint64_format='"'$glib_cv_long_long_format'u"'
+  fi
+  glib_extension='G_GNUC_EXTENSION '
+  gint64_constant='(G_GNUC_EXTENSION (val##LL))'
+  guint64_constant='(G_GNUC_EXTENSION (val##ULL))'
+  ;;
+$ac_cv_sizeof___int64)
+  gint64='__int64'
+  if test -n "$glib_cv_long_long_format"; then
+    gint64_modifier='"'$glib_cv_long_long_format'"'
+    gint64_format='"'$glib_cv_long_long_format'i"'
+    guint64_format='"'$glib_cv_long_long_format'u"'
+  fi
+  glib_extension=
+  gint64_constant='(val##i64)'
+  guint64_constant='(val##ui64)'
+  ;;
+esac
+glib_size_t=$ac_cv_sizeof_size_t
+glib_size_type_define="$glib_size_type"
+glib_void_p=$ac_cv_sizeof_void_p
+glib_long=$ac_cv_sizeof_long
+
+case "$glib_size_type" in
+short)
+  gsize_modifier='"h"'
+  gsize_format='"hu"'
+  gssize_format='"hi"'
+  glib_msize_type='SHRT'
+  ;;
+int)
+  gsize_modifier='""'
+  gsize_format='"u"'
+  gssize_format='"i"'
+  glib_msize_type='INT'
+  ;;
+long)
+  gsize_modifier='"l"'
+  gsize_format='"lu"'
+  gssize_format='"li"'
+  glib_msize_type='LONG'
+  ;;
+"long long"|__int64)
+  gsize_modifier='"I64"'
+  gsize_format='"I64u"'
+  gssize_format='"I64i"'
+  glib_msize_type='INT64'
+  ;;
+esac
+
+gintbits=`expr $ac_cv_sizeof_int \* 8`
+glongbits=`expr $ac_cv_sizeof_long \* 8`
+gsizebits=`expr $ac_cv_sizeof_size_t \* 8`
+
+case $ac_cv_sizeof_void_p in
+$ac_cv_sizeof_int)
+  glib_intptr_type_define=int
+  gintptr_modifier='""'
+  gintptr_format='"i"'
+  guintptr_format='"u"'
+  glib_gpi_cast=''
+  glib_gpui_cast=''
+  ;;
+$ac_cv_sizeof_long)
+  glib_intptr_type_define=long
+  gintptr_modifier='"l"'
+  gintptr_format='"li"'
+  guintptr_format='"lu"'
+  glib_gpi_cast='(glong)'
+  glib_gpui_cast='(gulong)'
+  ;;
+$ac_cv_sizeof_long_long)
+  glib_intptr_type_define='long long'
+  gintptr_modifier='"I64"'
+  gintptr_format='"I64i"'
+  guintptr_format='"I64u"'
+  glib_gpi_cast='(gint64)'
+  glib_gpui_cast='(guint64)'
+  ;;
+$ac_cv_sizeof___int64)
+  glib_intptr_type_define=__int64
+  gintptr_modifier='"I64"'
+  gintptr_format='"I64i"'
+  guintptr_format='"I64u"'
+  glib_gpi_cast='(gint64)'
+  glib_gpui_cast='(guint64)'
+  ;;
+*)
+  glib_unknown_void_p=yes
+  ;;
+esac
+
+
+case xyes in
+x$ac_cv_func_atexit)
+  glib_atexit="
+#ifdef NeXT /* @#% ! NeXTStep */
+# define g_ATEXIT(proc)	(!atexit (proc))
+#else
+# define g_ATEXIT(proc)	(atexit (proc))
+#endif"
+  ;;
+x$ac_cv_func_on_exit)
+  glib_atexit="
+#define g_ATEXIT(proc)	(on_exit ((void (*)(int, void*))(proc), NULL))"
+  ;;
+esac
+
+case xyes in
+x$ac_cv_func_memmove)
+  glib_memmove='
+#define g_memmove(dest,src,len) G_STMT_START { memmove ((dest), (src), (len)); } G_STMT_END'
+  ;;
+x$glib_cv_working_bcopy)
+  glib_memmove="
+/* memmove isn't available, but bcopy can copy overlapping memory regions */
+#define g_memmove(d,s,n) G_STMT_START { bcopy ((s), (d), (n)); } G_STMT_END"
+  ;;
+*)  
+  glib_memmove="
+/* memmove isn't found and bcopy can't copy overlapping memory regions, 
+ * so we have to roll our own copy routine. */
+void g_memmove (void* dest, const void * src, unsigned long len);"
+  ;;
+esac
+
+glib_defines="
+#define GLIB_MAJOR_VERSION $GLIB_MAJOR_VERSION
+#define GLIB_MINOR_VERSION $GLIB_MINOR_VERSION
+#define GLIB_MICRO_VERSION $GLIB_MICRO_VERSION
+"
+
+case xyes in
+x$glib_cv_va_copy)	glib_vacopy='#define G_VA_COPY	va_copy' ;;
+x$glib_cv___va_copy)	glib_vacopy='#define G_VA_COPY	__va_copy' ;;
+*)			glib_vacopy=''
+esac
+
+if test x$glib_cv_va_val_copy = xno; then
+  glib_vacopy="\$glib_vacopy
+#define G_VA_COPY_AS_ARRAY 1"
+fi
+
+if test x$glib_cv_hasinline = xyes; then
+    glib_inline='#define G_HAVE_INLINE 1'
+fi
+if test x$glib_cv_has__inline = xyes; then
+    glib_inline="\$glib_inline
+#define G_HAVE___INLINE 1"
+fi
+if test x$glib_cv_has__inline__ = xyes; then
+    glib_inline="\$glib_inline
+#define G_HAVE___INLINE__ 1"
+fi
+
+g_have_gnuc_varargs=$g_have_gnuc_varargs
+g_have_iso_c_varargs=$g_have_iso_c_varargs
+g_have_iso_cxx_varargs=$g_have_iso_cxx_varargs
+
+g_can_inline=$g_can_inline
+g_have_gnuc_visibility=$g_have_gnuc_visibility
+g_have_sunstudio_visibility=$g_have_sunstudio_visibility
+
+if test x$ac_cv_c_bigendian = xyes; then
+  g_byte_order=G_BIG_ENDIAN
+  g_bs_native=BE
+  g_bs_alien=LE
+else
+  g_byte_order=G_LITTLE_ENDIAN
+  g_bs_native=LE
+  g_bs_alien=BE
+fi
+
+g_pollin=$glib_cv_value_POLLIN
+g_pollout=$glib_cv_value_POLLOUT
+g_pollpri=$glib_cv_value_POLLPRI
+g_pollhup=$glib_cv_value_POLLHUP
+g_pollerr=$glib_cv_value_POLLERR
+g_pollnval=$glib_cv_value_POLLNVAL
+
+g_af_unix=$glib_cv_value_AF_UNIX
+g_af_inet=$glib_cv_value_AF_INET
+g_af_inet6=$glib_cv_value_AF_INET6
+
+g_msg_peek=$glib_cv_value_MSG_PEEK
+g_msg_oob=$glib_cv_value_MSG_OOB
+g_msg_dontroute=$glib_cv_value_MSG_DONTROUTE
+
+g_have_eilseq=$have_eilseq
+
+case x$have_threads in
+xno)	g_enable_threads_def="#undef";;
+*)	g_enable_threads_def="#define";;
+esac
+
+g_threads_impl_def=$g_threads_impl
+
+g_mutex_has_default="$mutex_has_default"
+g_mutex_sizeof="$glib_cv_sizeof_gmutex"
+g_system_thread_sizeof="$glib_cv_sizeof_system_thread"
+g_mutex_contents="$glib_cv_byte_contents_gmutex"
+
+g_memory_barrier_needed="$glib_memory_barrier_needed"
+g_gcc_atomic_ops="$glib_cv_gcc_has_builtin_atomic_operations"
+
+g_module_suffix="$glib_gmodule_suffix"
+
+g_pid_type="$glib_pid_type"
+case $host in
+  *-*-beos*)
+    glib_os="#define G_OS_BEOS"
+    ;;
+  *-*-cygwin*)
+    glib_os="#define G_OS_UNIX
+#define G_PLATFORM_WIN32
+#define G_WITH_CYGWIN"
+    ;;
+  *-*-mingw*)
+    glib_os="#define G_OS_WIN32
+#define G_PLATFORM_WIN32"
+    ;;
+  *)
+    glib_os="#define G_OS_UNIX"
+    ;;
+esac
+glib_static_compilation=""
+if test x$glib_win32_static_compilation = xyes; then
+  glib_static_compilation="#define GLIB_STATIC_COMPILATION 1
+#define GOBJECT_STATIC_COMPILATION 1"
+fi
+])dnl AC_CONFIG_COMMANDS
+
+])dnl AC_DEFUN
diff --git a/cogl/cogl-bitmap-pixbuf.c b/cogl/cogl-bitmap-pixbuf.c
index b64af5a..d958032 100644
--- a/cogl/cogl-bitmap-pixbuf.c
+++ b/cogl/cogl-bitmap-pixbuf.c
@@ -28,6 +28,7 @@
 #include "cogl-util.h"
 #include "cogl-internal.h"
 #include "cogl-bitmap-private.h"
+#include "cogl-error.h"
 
 #include <string.h>
 
@@ -93,7 +94,7 @@ _cogl_bitmap_get_size_from_file (const char *filename,
 /* the error does not contain the filename as the caller already has it */
 CoglBitmap *
 _cogl_bitmap_from_file (const char  *filename,
-			GError     **error)
+			CoglError     **error)
 {
   CFURLRef url;
   CGImageSourceRef image_source;
@@ -119,10 +120,10 @@ _cogl_bitmap_from_file (const char  *filename,
   if (image_source == NULL)
     {
       /* doesn't exist, not readable, etc. */
-      g_set_error_literal (error,
-                           COGL_BITMAP_ERROR,
-                           COGL_BITMAP_ERROR_FAILED,
-                           g_strerror (save_errno));
+      cogl_set_error_literal (error,
+                              COGL_BITMAP_ERROR,
+                              COGL_BITMAP_ERROR_FAILED,
+                              g_strerror (save_errno));
       return NULL;
     }
 
@@ -133,7 +134,7 @@ _cogl_bitmap_from_file (const char  *filename,
   if (type == NULL)
     {
       CFRelease (image_source);
-      g_set_error_literal (error,
+      cogl_set_error_literal (error,
                            COGL_BITMAP_ERROR,
                            COGL_BITMAP_ERROR_UNKNOWN_TYPE,
                            "Unknown image type");
@@ -151,7 +152,7 @@ _cogl_bitmap_from_file (const char  *filename,
     {
       /* incomplete or corrupt */
       CFRelease (image);
-      g_set_error_literal (error,
+      cogl_set_error_literal (error,
                            COGL_BITMAP_ERROR,
                            COGL_BITMAP_ERROR_CORRUPT_IMAGE,
                            "Image has zero width or height");
@@ -212,7 +213,7 @@ _cogl_bitmap_unref_pixbuf (guint8 *pixels,
 
 CoglBitmap *
 _cogl_bitmap_from_file (const char   *filename,
-			GError      **error)
+			CoglError      **error)
 {
   GdkPixbuf        *pixbuf;
   gboolean          has_alpha;
@@ -299,7 +300,7 @@ _cogl_bitmap_get_size_from_file (const char *filename,
 
 CoglBitmap *
 _cogl_bitmap_from_file (const char  *filename,
-			GError     **error)
+			CoglError     **error)
 {
   CoglBitmap *bmp;
   int      stb_pixel_format;
diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl-bitmap-private.h
index 7a398d5..69523e7 100644
--- a/cogl/cogl-bitmap-private.h
+++ b/cogl/cogl-bitmap-private.h
@@ -113,7 +113,7 @@ _cogl_bitmap_fallback_premult (CoglBitmap *dst_bmp);
 
 CoglBitmap *
 _cogl_bitmap_from_file (const char *filename,
-			GError     **error);
+			CoglError     **error);
 
 CoglBitmap *
 _cogl_bitmap_fallback_from_file (const char *filename);
diff --git a/cogl/cogl-bitmap.c b/cogl/cogl-bitmap.c
index 20fd808..a395d8e 100644
--- a/cogl/cogl-bitmap.c
+++ b/cogl/cogl-bitmap.c
@@ -288,7 +288,7 @@ _cogl_bitmap_new_shared (CoglBitmap              *shared_bmp,
 
 CoglBitmap *
 cogl_bitmap_new_from_file (const char  *filename,
-                           GError     **error)
+                           CoglError     **error)
 {
   CoglBitmap *bmp;
 
@@ -300,7 +300,7 @@ cogl_bitmap_new_from_file (const char  *filename,
       if ((bmp = _cogl_bitmap_fallback_from_file (filename))
           && error && *error)
         {
-          g_error_free (*error);
+          cogl_error_free (*error);
           *error = NULL;
         }
     }
diff --git a/cogl/cogl-bitmap.h b/cogl/cogl-bitmap.h
index fed0a02..844d883 100644
--- a/cogl/cogl-bitmap.h
+++ b/cogl/cogl-bitmap.h
@@ -49,7 +49,7 @@ typedef struct _CoglBitmap CoglBitmap;
 /**
  * cogl_bitmap_new_from_file:
  * @filename: the file to load.
- * @error: a #GError or %NULL.
+ * @error: a #CoglError or %NULL.
  *
  * Loads an image file from disk. This function can be safely called from
  * within a thread.
@@ -61,7 +61,7 @@ typedef struct _CoglBitmap CoglBitmap;
  */
 CoglBitmap *
 cogl_bitmap_new_from_file (const char *filename,
-                           GError **error);
+                           CoglError **error);
 
 #if defined (COGL_ENABLE_EXPERIMENTAL_API)
 
@@ -128,7 +128,7 @@ cogl_is_bitmap (CoglHandle handle);
 /**
  * COGL_BITMAP_ERROR:
  *
- * #GError domain for bitmap errors.
+ * #CoglError domain for bitmap errors.
  *
  * Since: 1.4
  */
diff --git a/cogl/cogl-blend-string.c b/cogl/cogl-blend-string.c
index bcdbd15..5fccbab 100644
--- a/cogl/cogl-blend-string.c
+++ b/cogl/cogl-blend-string.c
@@ -161,7 +161,7 @@ _cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement,
 static gboolean
 validate_tex_combine_statements (CoglBlendStringStatement *statements,
                                  int n_statements,
-                                 GError **error)
+                                 CoglError **error)
 {
   int i, j;
   const char *error_string;
@@ -190,7 +190,7 @@ validate_tex_combine_statements (CoglBlendStringStatement *statements,
   return TRUE;
 
 error:
-  g_set_error (error,
+  cogl_set_error (error,
                COGL_BLEND_STRING_ERROR,
                detail,
                "Invalid texture combine string: %s",
@@ -207,7 +207,7 @@ error:
 static gboolean
 validate_blend_statements (CoglBlendStringStatement *statements,
                            int n_statements,
-                           GError **error)
+                           CoglError **error)
 {
   int i, j;
   const char *error_string;
@@ -275,7 +275,7 @@ validate_blend_statements (CoglBlendStringStatement *statements,
   return TRUE;
 
 error:
-  g_set_error (error,
+  cogl_set_error (error,
                COGL_BLEND_STRING_ERROR,
                detail,
                "Invalid blend string: %s",
@@ -287,7 +287,7 @@ static gboolean
 validate_statements_for_context (CoglBlendStringStatement *statements,
                                  int n_statements,
                                  CoglBlendStringContext context,
-                                 GError **error)
+                                 CoglError **error)
 {
   const char *error_string;
 
@@ -313,7 +313,7 @@ validate_statements_for_context (CoglBlendStringStatement *statements,
     return validate_tex_combine_statements (statements, n_statements, error);
 
 error:
-  g_set_error (error,
+  cogl_set_error (error,
                COGL_BLEND_STRING_ERROR,
                COGL_BLEND_STRING_ERROR_INVALID_ERROR,
                "Invalid %s string: %s",
@@ -474,7 +474,7 @@ parse_argument (const char *string, /* original user string */
                 int current_arg,
                 CoglBlendStringArgument *arg, /* OUT */
                 CoglBlendStringContext context,
-                GError **error)
+                CoglError **error)
 {
   const char *p = *ret_p;
   const char *mark = NULL;
@@ -743,7 +743,7 @@ parse_argument (const char *string, /* original user string */
 error:
   {
     int offset = p - string;
-    g_set_error (error,
+    cogl_set_error (error,
                  COGL_BLEND_STRING_ERROR,
                  COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR,
                  "Syntax error for argument %d at offset %d: %s",
@@ -764,7 +764,7 @@ int
 _cogl_blend_string_compile (const char *string,
                             CoglBlendStringContext context,
                             CoglBlendStringStatement *statements,
-                            GError **error)
+                            CoglError **error)
 {
   const char *p = string;
   const char *mark = NULL;
@@ -924,7 +924,7 @@ finished:
 error:
     {
       int offset = p - string;
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_BLEND_STRING_ERROR,
                    COGL_BLEND_STRING_ERROR_PARSE_ERROR,
                    "Syntax error at offset %d: %s",
@@ -977,7 +977,7 @@ _cogl_blend_string_test (void)
   };
   int i;
 
-  GError *error = NULL;
+  CoglError *error = NULL;
   for (i = 0; strings[i].string; i++)
     {
       CoglBlendStringStatement statements[2];
@@ -990,7 +990,7 @@ _cogl_blend_string_test (void)
           g_print ("Failed to parse string:\n%s\n%s\n",
                    strings[i].string,
                    error->message);
-          g_error_free (error);
+          cogl_error_free (error);
           error = NULL;
           continue;
         }
diff --git a/cogl/cogl-blend-string.h b/cogl/cogl-blend-string.h
index 99fe407..63d95a0 100644
--- a/cogl/cogl-blend-string.h
+++ b/cogl/cogl-blend-string.h
@@ -126,7 +126,7 @@ gboolean
 _cogl_blend_string_compile (const char *string,
                             CoglBlendStringContext context,
                             CoglBlendStringStatement *statements,
-                            GError **error);
+                            CoglError **error);
 
 void
 _cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement,
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 522f5d4..82594ca 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -317,7 +317,7 @@ _cogl_context_get_winsys (CoglContext *context);
  * return FALSE and set @error */
 gboolean
 _cogl_context_update_features (CoglContext *context,
-                               GError **error);
+                               CoglError **error);
 
 /* Obtains the context and returns retval if NULL */
 #define _COGL_GET_CONTEXT(ctxvar, retval) \
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index fb27160..20b56ce 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -129,7 +129,7 @@ _cogl_context_get_winsys (CoglContext *context)
  */
 CoglContext *
 cogl_context_new (CoglDisplay *display,
-                  GError **error)
+                  CoglError **error)
 {
   CoglContext *context;
   GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
@@ -537,7 +537,7 @@ _cogl_context_free (CoglContext *context)
 CoglContext *
 _cogl_context_get_default (void)
 {
-  GError *error = NULL;
+  CoglError *error = NULL;
   /* Create if doesn't exist yet */
   if (_context == NULL)
     {
@@ -546,7 +546,7 @@ _cogl_context_get_default (void)
         {
           g_warning ("Failed to create default context: %s",
                      error->message);
-          g_error_free (error);
+          cogl_error_free (error);
         }
     }
 
@@ -574,7 +574,7 @@ cogl_egl_context_get_egl_display (CoglContext *context)
 
 gboolean
 _cogl_context_update_features (CoglContext *context,
-                               GError **error)
+                               CoglError **error)
 {
 #ifdef HAVE_COGL_GL
   if (context->driver == COGL_DRIVER_GL)
diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h
index 86c746b..d3c1362 100644
--- a/cogl/cogl-context.h
+++ b/cogl/cogl-context.h
@@ -77,7 +77,7 @@ G_BEGIN_DECLS
 /**
  * cogl_context_new:
  * @display: A #CoglDisplay pointer
- * @error: A GError return location.
+ * @error: A CoglError return location.
  *
  * Creates a new #CoglContext which acts as an application sandbox
  * for any state objects that are allocated.
@@ -88,7 +88,7 @@ G_BEGIN_DECLS
  */
 CoglContext *
 cogl_context_new (CoglDisplay *display,
-                  GError **error);
+                  CoglError **error);
 
 /**
  * cogl_context_get_display:
diff --git a/cogl/cogl-debug.c b/cogl/cogl-debug.c
index bdbb1ff..686a0ee 100644
--- a/cogl/cogl-debug.c
+++ b/cogl/cogl-debug.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <glib/gi18n-lib.h>
 
+#include "cogl-defines.h"
 #include "cogl-private.h"
 #include "cogl-debug.h"
 
@@ -219,16 +220,6 @@ cogl_arg_no_debug_cb (const char *key,
 }
 #endif /* COGL_ENABLE_DEBUG */
 
-static GOptionEntry cogl_args[] = {
-#ifdef COGL_ENABLE_DEBUG
-  { "cogl-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_debug_cb,
-    N_("Cogl debugging flags to set"), "FLAGS" },
-  { "cogl-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_no_debug_cb,
-    N_("Cogl debugging flags to unset"), "FLAGS" },
-#endif /* COGL_ENABLE_DEBUG */
-  { NULL, },
-};
-
 void
 _cogl_debug_check_environment (void)
 {
@@ -253,11 +244,23 @@ _cogl_debug_check_environment (void)
     }
 }
 
+#ifdef COGL_HAS_GLIB_SUPPORT
+
+static GOptionEntry cogl_args[] = {
+#ifdef COGL_ENABLE_DEBUG
+  { "cogl-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_debug_cb,
+    N_("Cogl debugging flags to set"), "FLAGS" },
+  { "cogl-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_no_debug_cb,
+    N_("Cogl debugging flags to unset"), "FLAGS" },
+#endif /* COGL_ENABLE_DEBUG */
+  { NULL, },
+};
+
 static gboolean
 pre_parse_hook (GOptionContext  *context,
                 GOptionGroup    *group,
                 gpointer         data,
-                GError         **error)
+                CoglError         **error)
 {
   _cogl_init ();
 
@@ -283,3 +286,4 @@ cogl_get_option_group (void)
 
   return group;
 }
+#endif
diff --git a/cogl/cogl-display.c b/cogl/cogl-display.c
index 651277f..6a7f752 100644
--- a/cogl/cogl-display.c
+++ b/cogl/cogl-display.c
@@ -86,7 +86,7 @@ cogl_display_new (CoglRenderer *renderer,
                   CoglOnscreenTemplate *onscreen_template)
 {
   CoglDisplay *display = g_slice_new0 (CoglDisplay);
-  GError *error = NULL;
+  CoglError *error = NULL;
 
   _cogl_init ();
 
@@ -99,7 +99,7 @@ cogl_display_new (CoglRenderer *renderer,
   if (!cogl_renderer_connect (display->renderer, &error))
     {
       g_warning ("Failed to connect renderer: %s\n", error->message);
-      g_error_free (error);
+      cogl_error_free (error);
       g_object_unref (display->renderer);
       g_slice_free (CoglDisplay, display);
       return NULL;
@@ -128,7 +128,7 @@ cogl_display_get_renderer (CoglDisplay *display)
 
 gboolean
 cogl_display_setup (CoglDisplay *display,
-                    GError **error)
+                    CoglError **error)
 {
   const CoglWinsysVtable *winsys;
 
diff --git a/cogl/cogl-display.h b/cogl/cogl-display.h
index d0b7e4b..fbb7c51 100644
--- a/cogl/cogl-display.h
+++ b/cogl/cogl-display.h
@@ -124,7 +124,7 @@ cogl_display_get_renderer (CoglDisplay *display);
 /**
  * cogl_display_setup:
  * @display: a #CoglDisplay
- * @error: return location for a #GError
+ * @error: return location for a #CoglError
  *
  * Explicitly sets up the given @display object. Use of this api is
  * optional since Cogl will internally setup the display if not done
@@ -154,7 +154,7 @@ cogl_display_get_renderer (CoglDisplay *display);
  */
 gboolean
 cogl_display_setup (CoglDisplay *display,
-                    GError **error);
+                    CoglError **error);
 
 #ifdef COGL_HAS_EGL_PLATFORM_GDL_SUPPORT
 /**
diff --git a/cogl/cogl-error.c b/cogl/cogl-error.c
new file mode 100644
index 0000000..421ce59
--- /dev/null
+++ b/cogl/cogl-error.c
@@ -0,0 +1,712 @@
+/* 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/.
+ */
+
+/**
+ * SECTION:error_reporting
+ * @Title: Error Reporting
+ * @Short_description: a system for reporting errors
+ *
+ * GLib provides a standard method of reporting errors from a called
+ * function to the calling code. (This is the same problem solved by
+ * exceptions in other languages.) It's important to understand that
+ * this method is both a <emphasis>data type</emphasis> (the #CoglError
+ * object) and a <emphasis>set of rules.</emphasis> If you use #CoglError
+ * incorrectly, then your code will not properly interoperate with other
+ * code that uses #CoglError, and users of your API will probably get confused.
+ *
+ * First and foremost: <emphasis>#CoglError should only be used to report
+ * recoverable runtime errors, never to report programming
+ * errors.</emphasis> If the programmer has screwed up, then you should
+ * use g_warning(), g_return_if_fail(), g_assert(), g_error(), or some
+ * similar facility. (Incidentally, remember that the g_error() function
+ * should <emphasis>only</emphasis> be used for programming errors, it
+ * should not be used to print any error reportable via #CoglError.)
+ *
+ * Examples of recoverable runtime errors are "file not found" or
+ * "failed to parse input." Examples of programming errors are "NULL
+ * passed to strcmp()" or "attempted to free the same pointer twice."
+ * These two kinds of errors are fundamentally different: runtime errors
+ * should be handled or reported to the user, programming errors should
+ * be eliminated by fixing the bug in the program. This is why most
+ * functions in GLib and GTK+ do not use the #CoglError facility.
+ *
+ * Functions that can fail take a return location for a #CoglError as their
+ * last argument. For example:
+ * |[
+ * gboolean g_file_get_contents (const gchar  *filename,
+ *                               gchar       **contents,
+ *                               gsize        *length,
+ *                               CoglError      **error);
+ * ]|
+ * If you pass a non-%NULL value for the <literal>error</literal>
+ * argument, it should point to a location where an error can be placed.
+ * For example:
+ * |[
+ * gchar *contents;
+ * CoglError *err = NULL;
+ * g_file_get_contents ("foo.txt", &amp;contents, NULL, &amp;err);
+ * g_assert ((contents == NULL &amp;&amp; err != NULL) || (contents != NULL &amp;&amp; err == NULL));
+ * if (err != NULL)
+ *   {
+ *     /&ast; Report error to user, and free error &ast;/
+ *     g_assert (contents == NULL);
+ *     fprintf (stderr, "Unable to read file: &percnt;s\n", err->message);
+ *     g_error_free (err);
+ *   }
+ * else
+ *   {
+ *     /&ast; Use file contents &ast;/
+ *     g_assert (contents != NULL);
+ *   }
+ * ]|
+ * Note that <literal>err != NULL</literal> in this example is a
+ * <emphasis>reliable</emphasis> indicator of whether
+ * g_file_get_contents() failed. Additionally, g_file_get_contents()
+ * returns a boolean which indicates whether it was successful.
+ *
+ * Because g_file_get_contents() returns %FALSE on failure, if you
+ * are only interested in whether it failed and don't need to display
+ * an error message, you can pass %NULL for the <literal>error</literal>
+ * argument:
+ * |[
+ * if (g_file_get_contents ("foo.txt", &amp;contents, NULL, NULL)) /&ast; ignore errors &ast;/
+ *   /&ast; no error occurred &ast;/ ;
+ * else
+ *   /&ast; error &ast;/ ;
+ * ]|
+ *
+ * The #CoglError object contains three fields: <literal>domain</literal>
+ * indicates the module the error-reporting function is located in,
+ * <literal>code</literal> indicates the specific error that occurred,
+ * and <literal>message</literal> is a user-readable error message with
+ * as many details as possible. Several functions are provided to deal
+ * with an error received from a called function: g_error_matches()
+ * returns %TRUE if the error matches a given domain and code,
+ * g_propagate_error() copies an error into an error location (so the
+ * calling function will receive it), and g_clear_error() clears an
+ * error location by freeing the error and resetting the location to
+ * %NULL. To display an error to the user, simply display
+ * <literal>error-&gt;message</literal>, perhaps along with additional
+ * context known only to the calling function (the file being opened,
+ * or whatever -- though in the g_file_get_contents() case,
+ * <literal>error-&gt;message</literal> already contains a filename).
+ *
+ * When implementing a function that can report errors, the basic
+ * tool is g_set_error(). Typically, if a fatal error occurs you
+ * want to g_set_error(), then return immediately. g_set_error()
+ * does nothing if the error location passed to it is %NULL.
+ * Here's an example:
+ * |[
+ * gint
+ * foo_open_file (CoglError **error)
+ * {
+ *   gint fd;
+ *
+ *   fd = open ("file.txt", O_RDONLY);
+ *
+ *   if (fd &lt; 0)
+ *     {
+ *       g_set_error (error,
+ *                    FOO_ERROR,                 /&ast; error domain &ast;/
+ *                    FOO_ERROR_BLAH,            /&ast; error code &ast;/
+ *                    "Failed to open file: &percnt;s", /&ast; error message format string &ast;/
+ *                    g_strerror (errno));
+ *       return -1;
+ *     }
+ *   else
+ *     return fd;
+ * }
+ * ]|
+ *
+ * Things are somewhat more complicated if you yourself call another
+ * function that can report a #CoglError. If the sub-function indicates
+ * fatal errors in some way other than reporting a #CoglError, such as
+ * by returning %TRUE on success, you can simply do the following:
+ * |[
+ * gboolean
+ * my_function_that_can_fail (CoglError **err)
+ * {
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   if (!sub_function_that_can_fail (err))
+ *     {
+ *       /&ast; assert that error was set by the sub-function &ast;/
+ *       g_assert (err == NULL || *err != NULL);
+ *       return FALSE;
+ *     }
+ *
+ *   /&ast; otherwise continue, no error occurred &ast;/
+ *   g_assert (err == NULL || *err == NULL);
+ * }
+ * ]|
+ *
+ * If the sub-function does not indicate errors other than by
+ * reporting a #CoglError, you need to create a temporary #CoglError
+ * since the passed-in one may be %NULL. g_propagate_error() is
+ * intended for use in this case.
+ * |[
+ * gboolean
+ * my_function_that_can_fail (CoglError **err)
+ * {
+ *   CoglError *tmp_error;
+ *
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   tmp_error = NULL;
+ *   sub_function_that_can_fail (&amp;tmp_error);
+ *
+ *   if (tmp_error != NULL)
+ *     {
+ *       /&ast; store tmp_error in err, if err != NULL,
+ *        &ast; otherwise call g_error_free() on tmp_error
+ *        &ast;/
+ *       g_propagate_error (err, tmp_error);
+ *       return FALSE;
+ *     }
+ *
+ *   /&ast; otherwise continue, no error occurred &ast;/
+ * }
+ * ]|
+ *
+ * Error pileups are always a bug. For example, this code is incorrect:
+ * |[
+ * gboolean
+ * my_function_that_can_fail (CoglError **err)
+ * {
+ *   CoglError *tmp_error;
+ *
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   tmp_error = NULL;
+ *   sub_function_that_can_fail (&amp;tmp_error);
+ *   other_function_that_can_fail (&amp;tmp_error);
+ *
+ *   if (tmp_error != NULL)
+ *     {
+ *       g_propagate_error (err, tmp_error);
+ *       return FALSE;
+ *     }
+ * }
+ * ]|
+ * <literal>tmp_error</literal> should be checked immediately after
+ * sub_function_that_can_fail(), and either cleared or propagated
+ * upward. The rule is: <emphasis>after each error, you must either
+ * handle the error, or return it to the calling function</emphasis>.
+ * Note that passing %NULL for the error location is the equivalent
+ * of handling an error by always doing nothing about it. So the
+ * following code is fine, assuming errors in sub_function_that_can_fail()
+ * are not fatal to my_function_that_can_fail():
+ * |[
+ * gboolean
+ * my_function_that_can_fail (CoglError **err)
+ * {
+ *   CoglError *tmp_error;
+ *
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   sub_function_that_can_fail (NULL); /&ast; ignore errors &ast;/
+ *
+ *   tmp_error = NULL;
+ *   other_function_that_can_fail (&amp;tmp_error);
+ *
+ *   if (tmp_error != NULL)
+ *     {
+ *       g_propagate_error (err, tmp_error);
+ *       return FALSE;
+ *     }
+ * }
+ * ]|
+ *
+ * Note that passing %NULL for the error location
+ * <emphasis>ignores</emphasis> errors; it's equivalent to
+ * <literal>try { sub_function_that_can_fail (); } catch (...) {}</literal>
+ * in C++. It does <emphasis>not</emphasis> mean to leave errors
+ * unhandled; it means to handle them by doing nothing.
+ *
+ * Error domains and codes are conventionally named as follows:
+ * <itemizedlist>
+ * <listitem><para>
+ *   The error domain is called
+ *   <literal>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR</literal>,
+ *   for example %G_SPAWN_ERROR or %G_THREAD_ERROR:
+ *   |[
+ * #define G_SPAWN_ERROR g_spawn_error_quark ()
+ *
+ * GQuark
+ * g_spawn_error_quark (void)
+ * {
+ *   return g_quark_from_static_string ("g-spawn-error-quark");
+ * }
+ *   ]|
+ * </para></listitem>
+ * <listitem><para>
+ *   The quark function for the error domain is called
+ *   <literal>&lt;namespace&gt;_&lt;module&gt;_error_quark</literal>,
+ *   for example g_spawn_error_quark() or %g_thread_error_quark().
+ * </para></listitem>
+ * <listitem><para>
+ *   The error codes are in an enumeration called
+ *   <literal>&lt;Namespace&gt;&lt;Module&gt;Error</literal>;
+ *   for example,#GThreadError or #GSpawnError.
+ * </para></listitem>
+ * <listitem><para>
+ *   Members of the error code enumeration are called
+ *   <literal>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR_&lt;CODE&gt;</literal>,
+ *   for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN.
+ * </para></listitem>
+ * <listitem><para>
+ *   If there's a "generic" or "unknown" error code for unrecoverable
+ *   errors it doesn't make sense to distinguish with specific codes,
+ *   it should be called <literal>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR_FAILED</literal>,
+ *   for example %G_SPAWN_ERROR_FAILED or %G_THREAD_ERROR_FAILED.
+ * </para></listitem>
+ * </itemizedlist>
+ *
+ * Summary of rules for use of #CoglError:
+ * <itemizedlist>
+ * <listitem><para>
+ *   Do not report programming errors via #CoglError.
+ * </para></listitem>
+ * <listitem><para>
+ *   The last argument of a function that returns an error should
+ *   be a location where a #CoglError can be placed (i.e. "#CoglError** error").
+ *   If #CoglError is used with varargs, the #CoglError** should be the last
+ *   argument before the "...".
+ * </para></listitem>
+ * <listitem><para>
+ *   The caller may pass %NULL for the #CoglError** if they are not interested
+ *   in details of the exact error that occurred.
+ * </para></listitem>
+ * <listitem><para>
+ *   If %NULL is passed for the #CoglError** argument, then errors should
+ *   not be returned to the caller, but your function should still
+ *   abort and return if an error occurs. That is, control flow should
+ *   not be affected by whether the caller wants to get a #CoglError.
+ * </para></listitem>
+ * <listitem><para>
+ *   If a #CoglError is reported, then your function by definition
+ *   <emphasis>had a fatal failure and did not complete whatever
+ *   it was supposed to do</emphasis>. If the failure was not fatal,
+ *   then you handled it and you should not report it. If it was fatal,
+ *   then you must report it and discontinue whatever you were doing
+ *   immediately.
+ * </para></listitem>
+ * <listitem><para>
+ *   A #CoglError* must be initialized to %NULL before passing its address
+ *   to a function that can report errors.
+ * </para></listitem>
+ * <listitem><para>
+ *   "Piling up" errors is always a bug. That is, if you assign a
+ *   new #CoglError to a #CoglError* that is non-%NULL, thus overwriting
+ *   the previous error, it indicates that you should have aborted
+ *   the operation instead of continuing. If you were able to continue,
+ *   you should have cleared the previous error with g_clear_error().
+ *   g_set_error() will complain if you pile up errors.
+ * </para></listitem>
+ * <listitem><para>
+ *   By convention, if you return a boolean value indicating success
+ *   then %TRUE means success and %FALSE means failure. If %FALSE is
+ *   returned, the error <emphasis>must</emphasis> be set to a non-%NULL
+ *   value.
+ * </para></listitem>
+ * <listitem><para>
+ *   A %NULL return value is also frequently used to mean that an error
+ *   occurred. You should make clear in your documentation whether %NULL
+ *   is a valid return value in non-error cases; if %NULL is a valid value,
+ *   then users must check whether an error was returned to see if the
+ *   function succeeded.
+ * </para></listitem>
+ * <listitem><para>
+ *   When implementing a function that can report errors, you may want
+ *   to add a check at the top of your function that the error return
+ *   location is either %NULL or contains a %NULL error (e.g.
+ *   <literal>g_return_if_fail (error == NULL || *error == NULL);</literal>).
+ * </para></listitem>
+ * </itemizedlist>
+ */
+
+#ifdef COGL_HAS_GLIB_SUPPORT
+#include <glib.h>
+#else
+#include "glib/gstrfuncs.h"
+#endif
+
+#include "cogl-error.h"
+
+/**
+ * cogl_error_new_valist:
+ * @domain: error domain
+ * @code: error code
+ * @format: printf()-style format for error message
+ * @args: #va_list of parameters for the message format
+ *
+ * Creates a new #CoglError with the given @domain and @code,
+ * and a message formatted with @format.
+ *
+ * Returns: a new #CoglError
+ *
+ * Since: 2.22
+ */
+CoglError*
+cogl_error_new_valist (GQuark       domain,
+                       gint         code,
+                       const gchar *format,
+                       va_list      args)
+{
+  CoglError *error;
+
+  error = g_slice_new (CoglError);
+
+  error->domain = domain;
+  error->code = code;
+  error->message = g_strdup_vprintf (format, args);
+
+  return error;
+}
+
+/**
+ * cogl_error_new:
+ * @domain: error domain
+ * @code: error code
+ * @format: printf()-style format for error message
+ * @...: parameters for message format
+ *
+ * Creates a new #CoglError with the given @domain and @code,
+ * and a message formatted with @format.
+ *
+ * Return value: a new #CoglError
+ */
+CoglError*
+cogl_error_new (GQuark       domain,
+                gint         code,
+                const gchar *format,
+                ...)
+{
+  CoglError* 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;
+}
+
+/**
+ * cogl_error_new_literal:
+ * @domain: error domain
+ * @code: error code
+ * @message: error message
+ *
+ * Creates a new #CoglError; unlike cogl_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 #CoglError
+ **/
+CoglError*
+cogl_error_new_literal (GQuark       domain,
+                        gint         code,
+                        const gchar *message)
+{
+  CoglError* err;
+
+  g_return_val_if_fail (message != NULL, NULL);
+  g_return_val_if_fail (domain != 0, NULL);
+
+  err = g_slice_new (CoglError);
+
+  err->domain = domain;
+  err->code = code;
+  err->message = g_strdup (message);
+
+  return err;
+}
+
+/**
+ * cogl_error_free:
+ * @error: a #CoglError
+ *
+ * Frees a #CoglError and associated resources.
+ */
+void
+cogl_error_free (CoglError *error)
+{
+  g_return_if_fail (error != NULL);
+
+  g_free (error->message);
+
+  g_slice_free (CoglError, error);
+}
+
+/**
+ * cogl_error_copy:
+ * @error: a #CoglError
+ *
+ * Makes a copy of @error.
+ *
+ * Return value: a new #CoglError
+ */
+CoglError*
+cogl_error_copy (const CoglError *error)
+{
+  CoglError *copy;
+ 
+  g_return_val_if_fail (error != NULL, NULL);
+
+  copy = g_slice_new (CoglError);
+
+  *copy = *error;
+
+  copy->message = g_strdup (error->message);
+
+  return copy;
+}
+
+/**
+ * cogl_error_matches:
+ * @error: a #CoglError or %NULL
+ * @domain: an error domain
+ * @code: an error code
+ *
+ * Returns %TRUE if @error matches @domain and @code, %FALSE
+ * otherwise. In particular, when @error is %NULL, %FALSE will
+ * be returned.
+ *
+ * Return value: whether @error has @domain and @code
+ */
+gboolean
+cogl_error_matches (const CoglError *error,
+                    GQuark        domain,
+                    gint          code)
+{
+  return error &&
+    error->domain == domain &&
+    error->code == code;
+}
+
+#define ERROR_OVERWRITTEN_WARNING "CoglError set over the top of a previous CoglError 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"
+
+/**
+ * cogl_set_error:
+ * @err: a return location for a #CoglError, or %NULL
+ * @domain: error domain
+ * @code: error code
+ * @format: printf()-style format
+ * @...: args for @format
+ *
+ * Does nothing if @err is %NULL; if @err is non-%NULL, then * err
+ * must be %NULL. A new #CoglError is created and assigned to * err 
+ */
+void
+cogl_set_error (CoglError      **err,
+                GQuark        domain,
+                gint          code,
+                const gchar  *format,
+                ...)
+{
+  CoglError *new;
+
+  va_list args;
+
+  if (err == NULL)
+    return;
+
+  va_start (args, format);
+  new = cogl_error_new_valist (domain, code, format, args);
+  va_end (args);
+
+  if (*err == NULL)
+    *err = new;
+  else
+    g_warning (ERROR_OVERWRITTEN_WARNING, new->message); 
+}
+
+/**
+ * cogl_set_error_literal:
+ * @err: a return location for a #CoglError, 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 #CoglError is created and assigned to * err 
+ * Unlike cogl_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
+cogl_set_error_literal (CoglError      **err,
+                        GQuark        domain,
+                        gint          code,
+                        const gchar  *message)
+{
+  CoglError *new;
+
+  if (err == NULL)
+    return;
+
+  new = cogl_error_new_literal (domain, code, message);
+  if (*err == NULL)
+    *err = new;
+  else
+    g_warning (ERROR_OVERWRITTEN_WARNING, new->message); 
+}
+
+/**
+ * cogl_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
+cogl_propagate_error (CoglError **dest,
+		   CoglError  *src)
+{
+  g_return_if_fail (src != NULL);
+ 
+  if (dest == NULL)
+    {
+      if (src)
+        cogl_error_free (src);
+      return;
+    }
+  else
+    {
+      if (*dest != NULL)
+        g_warning (ERROR_OVERWRITTEN_WARNING, src->message);
+      else
+        *dest = src;
+    }
+}
+
+/**
+ * cogl_clear_error:
+ * @err: a #CoglError return location
+ *
+ * If @err is %NULL, does nothing. If @err is non-%NULL,
+ * calls cogl_error_free() on * err and sets * err to %NULL.
+ */
+void
+cogl_clear_error (CoglError **err)
+{
+  if (err && *err)
+    {
+      cogl_error_free (*err);
+      *err = NULL;
+    }
+}
+
+static void
+cogl_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);
+}
+
+/**
+ * cogl_prefix_error:
+ * @err: a return location for a #CoglError, 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
+cogl_prefix_error (CoglError      **err,
+                const gchar  *format,
+                ...)
+{
+  if (err && *err)
+    {
+      va_list ap;
+
+      va_start (ap, format);
+      cogl_error_add_prefix (&(*err)->message, format, ap);
+      va_end (ap);
+    }
+}
+
+/**
+ * cogl_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
+ * cogl_prefix_error().
+ *
+ * Since: 2.16
+ **/
+void
+cogl_propagate_prefixed_error (CoglError      **dest,
+                               CoglError       *src,
+                               const gchar  *format,
+                               ...)
+{
+  cogl_propagate_error (dest, src);
+
+  if (dest && *dest)
+    {
+      va_list ap;
+
+      va_start (ap, format);
+      cogl_error_add_prefix (&(*dest)->message, format, ap);
+      va_end (ap);
+    }
+}
diff --git a/cogl/cogl-error.h b/cogl/cogl-error.h
new file mode 100644
index 0000000..b60efd9
--- /dev/null
+++ b/cogl/cogl-error.h
@@ -0,0 +1,120 @@
+/* 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.
+ */
+
+#ifndef __COGL_ERROR_H__
+#define __COGL_ERROR_H__
+
+#include <stdarg.h>
+
+#include <glib.h>
+
+#include <cogl/cogl-defines.h>
+
+#ifdef COGL_HAS_GLIB_SUPPORT
+
+#define CoglErrorDomain GQuark
+#define CoglError       GError
+
+#else
+
+G_BEGIN_DECLS
+
+typedef guint32 CoglErrorDomain;
+
+/**
+ * CoglError:
+ * @domain: error domain, e.g. #G_FILE_ERROR
+ * @code: error code, e.g. %G_FILE_ERROR_NOENT
+ * @message: human-readable informative error message
+ *
+ * The <structname>CoglError</structname> structure contains
+ * information about an error that has occurred.
+ */
+typedef struct
+{
+  CoglErrorDomain  domain;
+  gint             code;
+  gchar           *message;
+} CoglError;
+
+CoglError*  cogl_error_new           (CoglErrorDomain         domain,
+                                gint           code,
+                                const gchar   *format,
+                                ...) G_GNUC_PRINTF (3, 4);
+
+CoglError*  cogl_error_new_literal   (CoglErrorDomain         domain,
+                                gint           code,
+                                const gchar   *message);
+CoglError*  cogl_error_new_valist    (CoglErrorDomain         domain,
+                                gint           code,
+                                const gchar   *format,
+                                va_list        args);
+
+void     cogl_error_free          (CoglError        *error);
+CoglError*  cogl_error_copy          (const CoglError  *error);
+
+gboolean cogl_error_matches       (const CoglError  *error,
+                                CoglErrorDomain         domain,
+                                gint           code);
+
+/* if (err) *err = cogl_error_new(domain, code, format, ...), also has
+ * some sanity checks.
+ */
+void
+cogl_set_error (CoglError       **err,
+                CoglErrorDomain   domain,
+                gint              code,
+                const gchar      *format,
+                ...) G_GNUC_PRINTF (4, 5);
+
+void
+cogl_set_error_literal (CoglError       **err,
+                        CoglErrorDomain   domain,
+                        gint              code,
+                        const gchar      *message);
+
+/* if (dest) *dest = src; also has some sanity checks.
+ */
+void
+cogl_propagate_error (CoglError **dest,
+                      CoglError  *src);
+
+/* if (err && *err) { cogl_error_free(*err); *err = NULL; } */
+void
+cogl_clear_error (CoglError **err);
+
+/* if (err) prefix the formatted string to the ->message */
+void
+cogl_prefix_error (CoglError   **err,
+                   const gchar  *format,
+                   ...) G_GNUC_PRINTF (2, 3);
+
+/* cogl_propagate_error then cogl_error_prefix on dest */
+void
+cogl_propagate_prefixed_error (CoglError   **dest,
+                               CoglError    *src,
+                               const gchar  *format,
+                               ...) G_GNUC_PRINTF (3, 4);
+
+G_END_DECLS
+
+#endif /* COGL_HAS_GLIB_SUPPORT */
+
+#endif /* __COGL_ERROR_H__ */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 5a549ab..ed50a6c 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -987,7 +987,7 @@ try_creating_fbo (CoglOffscreen *offscreen,
 
 static gboolean
 _cogl_offscreen_allocate (CoglOffscreen *offscreen,
-                          GError **error)
+                          CoglError **error)
 {
   CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
   CoglContext *ctx = fb->context;
@@ -1035,7 +1035,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
 
   if (!fbo_created)
     {
-      g_set_error (error, COGL_FRAMEBUFFER_ERROR,
+      cogl_set_error (error, COGL_FRAMEBUFFER_ERROR,
                    COGL_FRAMEBUFFER_ERROR_ALLOCATE,
                    "Failed to create an OpenGL framebuffer object");
       return FALSE;
@@ -1046,7 +1046,7 @@ _cogl_offscreen_allocate (CoglOffscreen *offscreen,
 
 gboolean
 cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
-                           GError **error)
+                           CoglError **error)
 {
   CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
   const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index 1fbd23d..9ce10be 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -96,7 +96,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
 /**
  * cogl_framebuffer_allocate:
  * @framebuffer: A #CoglFramebuffer
- * @error: A pointer to a #GError for returning exceptions.
+ * @error: A pointer to a #CoglError for returning exceptions.
  *
  * Explicitly allocates a configured #CoglFramebuffer allowing developers to
  * check and handle any errors that might arise from an unsupported
@@ -115,7 +115,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
  */
 gboolean
 cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
-                           GError **error);
+                           CoglError **error);
 
 /**
  * cogl_framebuffer_get_width:
diff --git a/cogl/cogl-index-buffer.c b/cogl/cogl-index-buffer.c
index 7a6b196..5b67e09 100644
--- a/cogl/cogl-index-buffer.c
+++ b/cogl/cogl-index-buffer.c
@@ -75,7 +75,7 @@ _cogl_index_buffer_free (CoglIndexBuffer *indices)
 
 gboolean
 cogl_index_buffer_allocate (CoglIndexBuffer *indices,
-                            GError *error)
+                            CoglError *error)
 {
   /* TODO */
   return TRUE;
diff --git a/cogl/cogl-material-compat.c b/cogl/cogl-material-compat.c
index 2e71928..5765d70 100644
--- a/cogl/cogl-material-compat.c
+++ b/cogl/cogl-material-compat.c
@@ -192,7 +192,7 @@ cogl_material_set_alpha_test_function (CoglMaterial         *material,
 gboolean
 cogl_material_set_blend (CoglMaterial *material,
                          const char   *blend_string,
-                         GError      **error)
+                         CoglError      **error)
 {
   return cogl_pipeline_set_blend (COGL_PIPELINE (material),
                                   blend_string,
@@ -252,7 +252,7 @@ gboolean
 cogl_material_set_layer_combine (CoglMaterial *material,
 				 int           layer_index,
 				 const char   *blend_string,
-                                 GError      **error)
+                                 CoglError      **error)
 {
   return cogl_pipeline_set_layer_combine (COGL_PIPELINE (material),
                                           layer_index,
@@ -331,7 +331,7 @@ gboolean
 cogl_material_set_layer_point_sprite_coords_enabled (CoglMaterial *material,
                                                      int           layer_index,
                                                      gboolean      enable,
-                                                     GError      **error)
+                                                     CoglError      **error)
 {
   CoglPipeline *pipeline = COGL_PIPELINE (material);
   return cogl_pipeline_set_layer_point_sprite_coords_enabled (pipeline,
@@ -439,7 +439,7 @@ cogl_material_foreach_layer (CoglMaterial *material,
 gboolean
 cogl_material_set_depth_state (CoglMaterial *material,
                                const CoglDepthState *state,
-                               GError **error)
+                               CoglError **error)
 {
   return cogl_pipeline_set_depth_state (COGL_PIPELINE (material),
                                         state, error);
diff --git a/cogl/cogl-material-compat.h b/cogl/cogl-material-compat.h
index f07bb69..0cce043 100644
--- a/cogl/cogl-material-compat.h
+++ b/cogl/cogl-material-compat.h
@@ -508,7 +508,7 @@ cogl_material_set_alpha_test_function (CoglMaterial         *material,
  * @material: A #CoglMaterial object
  * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
  *   describing the desired blend function.
- * @error: return location for a #GError that may report lack of driver
+ * @error: return location for a #CoglError that may report lack of driver
  *   support if you give separate blend string statements for the alpha
  *   channel and RGB channels since some drivers, or backends such as
  *   GLES 1.1, don't support this feature. May be %NULL, in which case a
@@ -590,7 +590,7 @@ cogl_material_set_alpha_test_function (CoglMaterial         *material,
 gboolean
 cogl_material_set_blend (CoglMaterial *material,
                          const char   *blend_string,
-                         GError      **error);
+                         CoglError      **error);
 
 /**
  * cogl_material_set_blend_constant:
@@ -746,7 +746,7 @@ cogl_material_remove_layer (CoglMaterial *material,
  * @layer_index: Specifies the layer you want define a combine function for
  * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
  *    describing the desired texture combine function.
- * @error: A #GError that may report parse errors or lack of GPU/driver
+ * @error: A #CoglError that may report parse errors or lack of GPU/driver
  *   support. May be %NULL, in which case a warning will be printed out if an
  *   error is encountered.
  *
@@ -836,7 +836,7 @@ gboolean
 cogl_material_set_layer_combine (CoglMaterial *material,
 				 int           layer_index,
 				 const char   *blend_string,
-                                 GError      **error);
+                                 CoglError      **error);
 
 /**
  * cogl_material_set_layer_combine_constant:
@@ -997,7 +997,7 @@ cogl_material_set_layer_filters (CoglMaterial      *material,
  * @material: a #CoglHandle to a material.
  * @layer_index: the layer number to change.
  * @enable: whether to enable point sprite coord generation.
- * @error: A return location for a GError, or NULL to ignore errors.
+ * @error: A return location for a CoglError, or NULL to ignore errors.
  *
  * When rendering points, if @enable is %TRUE then the texture
  * coordinates for this layer will be replaced with coordinates that
@@ -1017,7 +1017,7 @@ gboolean
 cogl_material_set_layer_point_sprite_coords_enabled (CoglMaterial *material,
                                                      int           layer_index,
                                                      gboolean      enable,
-                                                     GError      **error);
+                                                     CoglError      **error);
 
 /**
  * cogl_material_get_layer_point_sprite_coords_enabled:
@@ -1199,7 +1199,7 @@ cogl_material_layer_get_wrap_mode_p (CoglMaterialLayer *layer);
  * cogl_material_set_depth_state:
  * @material: A #CoglMaterial object
  * @state: A #CoglDepthState struct
- * @error: A #GError to report failures to setup the given @state.
+ * @error: A #CoglError to report failures to setup the given @state.
  *
  * This commits all the depth state configured in @state struct to the
  * given @material. The configuration values are copied into the
@@ -1218,7 +1218,7 @@ cogl_material_layer_get_wrap_mode_p (CoglMaterialLayer *layer);
 gboolean
 cogl_material_set_depth_state (CoglMaterial *material,
                                const CoglDepthState *state,
-                               GError **error);
+                               CoglError **error);
 
 /**
  * cogl_material_get_depth_state:
diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c
index 910215a..b612467 100644
--- a/cogl/cogl-pipeline-layer-state.c
+++ b/cogl/cogl-pipeline-layer-state.c
@@ -36,6 +36,7 @@
 #include "cogl-matrix.h"
 #include "cogl-snippet-private.h"
 #include "cogl-texture-private.h"
+#include "cogl-error.h"
 
 #include "string.h"
 #if 0
@@ -693,7 +694,7 @@ gboolean
 cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
                                                      int layer_index,
                                                      gboolean enable,
-                                                     GError **error)
+                                                     CoglError **error)
 {
   CoglPipelineLayerState       change =
     COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
@@ -711,11 +712,11 @@ cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
     {
       if (error)
         {
-          g_set_error (error,
-                       COGL_RENDERER_ERROR,
-                       COGL_RENDERER_ERROR_UNSUPPORTED,
-                       "Point sprite texture coordinates are enabled "
-                       "for a layer but the GL driver does not support it.");
+          cogl_set_error (error,
+                          COGL_RENDERER_ERROR,
+                          COGL_RENDERER_ERROR_UNSUPPORTED,
+                          "Point sprite texture coordinates are enabled "
+                          "for a layer but the GL driver does not support it.");
         }
       else
         {
@@ -1160,7 +1161,7 @@ gboolean
 cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
 				 int layer_index,
 				 const char *combine_description,
-                                 GError **error)
+                                 CoglError **error)
 {
   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE;
   CoglPipelineLayer *authority;
@@ -1169,7 +1170,7 @@ cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
   CoglBlendStringStatement split[2];
   CoglBlendStringStatement *rgb;
   CoglBlendStringStatement *a;
-  GError *internal_error = NULL;
+  CoglError *internal_error = NULL;
   int count;
 
   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
@@ -1194,12 +1195,12 @@ cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
   if (!count)
     {
       if (error)
-	g_propagate_error (error, internal_error);
+	cogl_propagate_error (error, internal_error);
       else
 	{
 	  g_warning ("Cannot compile combine description: %s\n",
 		     internal_error->message);
-	  g_error_free (internal_error);
+	  cogl_error_free (internal_error);
 	}
       return FALSE;
     }
diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h
index bfe0483..cd494fd 100644
--- a/cogl/cogl-pipeline-layer-state.h
+++ b/cogl/cogl-pipeline-layer-state.h
@@ -208,7 +208,7 @@ cogl_pipeline_remove_layer (CoglPipeline *pipeline,
  * @layer_index: Specifies the layer you want define a combine function for
  * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
  *    describing the desired texture combine function.
- * @error: A #GError that may report parse errors or lack of GPU/driver
+ * @error: A #CoglError that may report parse errors or lack of GPU/driver
  *   support. May be %NULL, in which case a warning will be printed out if an
  *   error is encountered.
  *
@@ -299,7 +299,7 @@ gboolean
 cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
 				 int           layer_index,
 				 const char   *blend_string,
-                                 GError      **error);
+                                 CoglError      **error);
 
 /**
  * cogl_pipeline_set_layer_combine_constant:
@@ -416,7 +416,7 @@ cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
  * @pipeline: a #CoglHandle to a pipeline.
  * @layer_index: the layer number to change.
  * @enable: whether to enable point sprite coord generation.
- * @error: A return location for a GError, or NULL to ignore errors.
+ * @error: A return location for a CoglError, or NULL to ignore errors.
  *
  * When rendering points, if @enable is %TRUE then the texture
  * coordinates for this layer will be replaced with coordinates that
@@ -437,7 +437,7 @@ gboolean
 cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
                                                      int           layer_index,
                                                      gboolean      enable,
-                                                     GError      **error);
+                                                     CoglError      **error);
 
 /**
  * cogl_pipeline_get_layer_point_sprite_coords_enabled:
diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c
index 313e57f..2875f4d 100644
--- a/cogl/cogl-pipeline-state.c
+++ b/cogl/cogl-pipeline-state.c
@@ -36,6 +36,7 @@
 #include "cogl-depth-state-private.h"
 #include "cogl-pipeline-state-private.h"
 #include "cogl-snippet-private.h"
+#include "cogl-error.h"
 
 #include "string.h"
 
@@ -938,14 +939,14 @@ setup_blend_state (CoglBlendStringStatement *statement,
 gboolean
 cogl_pipeline_set_blend (CoglPipeline *pipeline,
                          const char *blend_description,
-                         GError **error)
+                         CoglError **error)
 {
   CoglPipelineState state = COGL_PIPELINE_STATE_BLEND;
   CoglPipeline *authority;
   CoglBlendStringStatement statements[2];
   CoglBlendStringStatement *rgb;
   CoglBlendStringStatement *a;
-  GError *internal_error = NULL;
+  CoglError *internal_error = NULL;
   int count;
   CoglPipelineBlendState *blend_state;
 
@@ -961,12 +962,12 @@ cogl_pipeline_set_blend (CoglPipeline *pipeline,
   if (!count)
     {
       if (error)
-	g_propagate_error (error, internal_error);
+	cogl_propagate_error (error, internal_error);
       else
 	{
 	  g_warning ("Cannot compile blend description: %s\n",
 		     internal_error->message);
-	  g_error_free (internal_error);
+	  cogl_error_free (internal_error);
 	}
       return FALSE;
     }
@@ -1161,7 +1162,7 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline,
 gboolean
 cogl_pipeline_set_depth_state (CoglPipeline *pipeline,
                                const CoglDepthState *depth_state,
-                               GError **error)
+                               CoglError **error)
 {
   CoglPipelineState state = COGL_PIPELINE_STATE_DEPTH;
   CoglPipeline *authority;
@@ -1186,10 +1187,10 @@ cogl_pipeline_set_depth_state (CoglPipeline *pipeline,
       (depth_state->range_near != 0 ||
        depth_state->range_far != 1))
     {
-      g_set_error (error,
-                   COGL_RENDERER_ERROR,
-                   COGL_RENDERER_ERROR_UNSUPPORTED,
-                   "glDepthRange not available on GLES 1");
+      cogl_set_error (error,
+                      COGL_RENDERER_ERROR,
+                      COGL_RENDERER_ERROR_UNSUPPORTED,
+                      "glDepthRange not available on GLES 1");
       return FALSE;
     }
 
diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl-pipeline-state.h
index 8686629..5662def 100644
--- a/cogl/cogl-pipeline-state.h
+++ b/cogl/cogl-pipeline-state.h
@@ -385,7 +385,7 @@ cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline);
  * @pipeline: A #CoglPipeline object
  * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link>
  *   describing the desired blend function.
- * @error: return location for a #GError that may report lack of driver
+ * @error: return location for a #CoglError that may report lack of driver
  *   support if you give separate blend string statements for the alpha
  *   channel and RGB channels since some drivers, or backends such as
  *   GLES 1.1, don't support this feature. May be %NULL, in which case a
@@ -465,7 +465,7 @@ cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline);
 gboolean
 cogl_pipeline_set_blend (CoglPipeline *pipeline,
                          const char   *blend_string,
-                         GError      **error);
+                         CoglError      **error);
 
 /**
  * cogl_pipeline_set_blend_constant:
@@ -619,7 +619,7 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline,
  * cogl_pipeline_set_depth_state:
  * @pipeline: A #CoglPipeline object
  * @state: A #CoglDepthState struct
- * @error: A #GError to report failures to setup the given @state.
+ * @error: A #CoglError to report failures to setup the given @state.
  *
  * This commits all the depth state configured in @state struct to the
  * given @pipeline. The configuration values are copied into the
@@ -638,7 +638,7 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline,
 gboolean
 cogl_pipeline_set_depth_state (CoglPipeline *pipeline,
                                const CoglDepthState *state,
-                               GError **error);
+                               CoglError **error);
 
 /**
  * cogl_pipeline_get_depth_state
diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h
index 8f2a72e..4ae12b8 100644
--- a/cogl/cogl-private.h
+++ b/cogl/cogl-private.h
@@ -32,11 +32,11 @@ G_BEGIN_DECLS
 
 gboolean
 _cogl_gl_update_features (CoglContext *context,
-                          GError **error);
+                          CoglError **error);
 
 gboolean
 _cogl_gles_update_features (CoglContext *context,
-                            GError **error);
+                            CoglError **error);
 
 gboolean
 _cogl_check_extension (const char *name, const char *ext);
diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c
index 2af1f74..7e4f545 100644
--- a/cogl/cogl-renderer.c
+++ b/cogl/cogl-renderer.c
@@ -215,7 +215,7 @@ cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer,
 gboolean
 cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
                                        CoglOnscreenTemplate *onscreen_template,
-                                       GError **error)
+                                       CoglError **error)
 {
   CoglDisplay *display;
 
@@ -236,7 +236,7 @@ cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
 
 static gboolean
 _cogl_renderer_choose_driver (CoglRenderer *renderer,
-                              GError **error)
+                              CoglError **error)
 {
   const char *driver_name = g_getenv ("COGL_DRIVER");
   const char *libgl_name;
@@ -271,7 +271,7 @@ _cogl_renderer_choose_driver (CoglRenderer *renderer,
     }
 #endif
 
-  g_set_error (error,
+  cogl_set_error (error,
                COGL_DRIVER_ERROR,
                COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND,
                "No suitable driver found");
@@ -286,7 +286,7 @@ _cogl_renderer_choose_driver (CoglRenderer *renderer,
 
   if (renderer->libgl_module == NULL)
     {
-      g_set_error (error, COGL_DRIVER_ERROR,
+      cogl_set_error (error, COGL_DRIVER_ERROR,
                    COGL_DRIVER_ERROR_FAILED_TO_LOAD_LIBRARY,
                    "Failed to dynamically open the GL library \"%s\"",
                    libgl_name);
@@ -301,7 +301,7 @@ _cogl_renderer_choose_driver (CoglRenderer *renderer,
 /* Final connection API */
 
 gboolean
-cogl_renderer_connect (CoglRenderer *renderer, GError **error)
+cogl_renderer_connect (CoglRenderer *renderer, CoglError **error)
 {
   int i;
   GString *error_message;
@@ -319,7 +319,7 @@ cogl_renderer_connect (CoglRenderer *renderer, GError **error)
   for (i = 0; i < G_N_ELEMENTS (_cogl_winsys_vtable_getters); i++)
     {
       const CoglWinsysVtable *winsys = _cogl_winsys_vtable_getters[i]();
-      GError *tmp_error = NULL;
+      CoglError *tmp_error = NULL;
       GList *l;
       gboolean constraints_failed = FALSE;
 
@@ -359,7 +359,7 @@ cogl_renderer_connect (CoglRenderer *renderer, GError **error)
         {
           g_string_append_c (error_message, '\n');
           g_string_append (error_message, tmp_error->message);
-          g_error_free (tmp_error);
+          cogl_error_free (tmp_error);
         }
       else
         {
@@ -372,7 +372,7 @@ cogl_renderer_connect (CoglRenderer *renderer, GError **error)
   if (!renderer->connected)
     {
       renderer->winsys_vtable = NULL;
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Failed to connected to any renderer: %s",
                    error_message->str);
diff --git a/cogl/cogl-renderer.h b/cogl/cogl-renderer.h
index 06b0f5c..f0041ff 100644
--- a/cogl/cogl-renderer.h
+++ b/cogl/cogl-renderer.h
@@ -220,7 +220,7 @@ cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer);
  * cogl_renderer_check_onscreen_template:
  * @renderer: A #CoglRenderer
  * @onscreen_template: A #CoglOnscreenTemplate
- * @error: A pointer to a #GError for reporting exceptions
+ * @error: A pointer to a #CoglError for reporting exceptions
  *
  * Tests if a given @onscreen_template can be supported with the given
  * @renderer.
@@ -233,14 +233,14 @@ cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer);
 gboolean
 cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
                                        CoglOnscreenTemplate *onscreen_template,
-                                       GError **error);
+                                       CoglError **error);
 
 /* Final connection API */
 
 /**
  * cogl_renderer_connect:
  * @renderer: An unconnected #CoglRenderer
- * @error a pointer to a #GError for reporting exceptions
+ * @error a pointer to a #CoglError for reporting exceptions
  *
  * Connects the configured @renderer. Renderer connection isn't a
  * very active process, it basically just means validating that
@@ -253,7 +253,7 @@ cogl_renderer_check_onscreen_template (CoglRenderer *renderer,
  * Stability: unstable
  */
 gboolean
-cogl_renderer_connect (CoglRenderer *renderer, GError **error);
+cogl_renderer_connect (CoglRenderer *renderer, CoglError **error);
 
 /**
  * CoglRendererConstraint:
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h
index b19c6ea..26d0e37 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl-texture-2d-private.h
@@ -57,7 +57,7 @@ CoglHandle
 _cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
                                   CoglTextureFlags flags,
                                   CoglPixelFormat  internal_format,
-                                  GError         **error);
+                                  CoglError         **error);
 
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
 /* NB: The reason we require the width, height and format to be passed
@@ -69,7 +69,7 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                                      int height,
                                      CoglPixelFormat format,
                                      EGLImageKHR image,
-                                     GError **error);
+                                     CoglError **error);
 #endif
 
 /*
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c
index 1ec9ed4..6dc41fb 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl-texture-2d-sliced.c
@@ -748,7 +748,7 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
 
       for (x = 0; x < n_x_slices; ++x)
         {
-          GError *error = NULL;
+          CoglError *error = NULL;
           x_span = &g_array_index (tex_2ds->slice_x_spans, CoglSpan, x);
 
           COGL_NOTE (SLICING, "CREATE SLICE (%d,%d)\tsize (%d,%d)",
@@ -762,7 +762,7 @@ _cogl_texture_2d_sliced_slices_create (CoglContext *ctx,
           if (!slice_textures[y * n_x_slices + x])
             {
               g_array_set_size (tex_2ds->slice_textures, y * n_x_slices + x);
-              g_error_free (error);
+              cogl_error_free (error);
               return FALSE;
             }
         }
@@ -839,7 +839,7 @@ cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
                                       unsigned int height,
                                       int max_waste,
                                       CoglPixelFormat internal_format,
-                                      GError **error)
+                                      CoglError **error)
 {
   CoglTexture2DSliced   *tex_2ds;
 
@@ -858,10 +858,10 @@ cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
                                           internal_format))
     {
       _cogl_texture_2d_sliced_free (tex_2ds);
-      g_set_error (error,
-                   COGL_RENDERER_ERROR,
-                   COGL_RENDERER_ERROR_NO_MEMORY,
-                   "Not enough memory to allocate texture slices");
+      cogl_set_error (error,
+                      COGL_RENDERER_ERROR,
+                      COGL_RENDERER_ERROR_NO_MEMORY,
+                      "Not enough memory to allocate texture slices");
       return NULL;
     }
 
diff --git a/cogl/cogl-texture-2d-sliced.h b/cogl/cogl-texture-2d-sliced.h
index b0e3136..5b0036a 100644
--- a/cogl/cogl-texture-2d-sliced.h
+++ b/cogl/cogl-texture-2d-sliced.h
@@ -75,7 +75,7 @@ typedef struct _CoglTexture2DSliced CoglTexture2DSliced;
  *             are allowed in the non-power-of-two textures before
  *             they must be sliced to reduce the amount of waste.
  * @internal_format: The format of the texture
- * @error: A #GError for exceptions.
+ * @error: A #CoglError for exceptions.
  *
  * Creates a #CoglTexture2DSliced that may internally be comprised of
  * 1 or more #CoglTexture2D textures with power-of-two sizes.
@@ -97,6 +97,6 @@ cogl_texture_2d_sliced_new_with_size (CoglContext *ctx,
                                       unsigned int height,
                                       int max_waste,
                                       CoglPixelFormat internal_format,
-                                      GError **error);
+                                      CoglError **error);
 
 #endif /* __COGL_TEXURE_2D_SLICED_H */
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index cabae1f..bee2aad 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -172,7 +172,7 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
                                int width,
                                int height,
                                CoglPixelFormat internal_format,
-                               GError **error)
+                               CoglError **error)
 {
   CoglTexture2D         *tex_2d;
   GLenum                 gl_intformat;
@@ -185,7 +185,7 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
 
   if (!_cogl_texture_2d_can_create (width, height, internal_format))
     {
-      g_set_error (error, COGL_TEXTURE_ERROR,
+      cogl_set_error (error, COGL_TEXTURE_ERROR,
                    COGL_TEXTURE_ERROR_SIZE,
                    "Failed to create texture 2d due to size/format"
                    " constraints");
@@ -214,7 +214,7 @@ CoglHandle
 _cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
                                   CoglTextureFlags flags,
                                   CoglPixelFormat  internal_format,
-                                  GError         **error)
+                                  CoglError         **error)
 {
   CoglTexture2D *tex_2d;
   CoglBitmap    *dst_bmp;
@@ -235,7 +235,7 @@ _cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
                                     _cogl_bitmap_get_height (bmp),
                                     internal_format))
     {
-      g_set_error (error, COGL_TEXTURE_ERROR,
+      cogl_set_error (error, COGL_TEXTURE_ERROR,
                    COGL_TEXTURE_ERROR_SIZE,
                    "Failed to create texture 2d due to size/format"
                    " constraints");
@@ -250,7 +250,7 @@ _cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
                                                    &gl_format,
                                                    &gl_type)) == NULL)
     {
-      g_set_error (error, COGL_TEXTURE_ERROR,
+      cogl_set_error (error, COGL_TEXTURE_ERROR,
                    COGL_TEXTURE_ERROR_FORMAT,
                    "Failed to prepare texture upload due to format");
       return NULL;
@@ -300,7 +300,7 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
                                CoglPixelFormat internal_format,
                                int rowstride,
                                const guint8 *data,
-                               GError **error)
+                               CoglError **error)
 {
   CoglBitmap *bmp;
   CoglHandle tex;
@@ -335,7 +335,7 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
                                   int width,
                                   int height,
                                   CoglPixelFormat format,
-                                  GError **error)
+                                  CoglError **error)
 {
   /* NOTE: width, height and internal format are not queriable
    * in GLES, hence such a function prototype.
@@ -455,7 +455,7 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                                      int height,
                                      CoglPixelFormat format,
                                      EGLImageKHR image,
-                                     GError **error)
+                                     CoglError **error)
 {
   CoglTexture2D *tex_2d;
   GLenum gl_error;
@@ -481,7 +481,7 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
   ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image);
   if (ctx->glGetError () != GL_NO_ERROR)
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_TEXTURE_ERROR,
                    COGL_TEXTURE_ERROR_BAD_PARAMETER,
                    "Could not create a CoglTexture2D from a given EGLImage");
@@ -496,7 +496,7 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
 CoglTexture2D *
 cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
                                          struct wl_buffer *buffer,
-                                         GError **error)
+                                         CoglError **error)
 {
   if (wl_buffer_is_shm (buffer))
     {
diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl-texture-2d.h
index 8e2e710..57d22d8 100644
--- a/cogl/cogl-texture-2d.h
+++ b/cogl/cogl-texture-2d.h
@@ -77,7 +77,7 @@ cogl_is_texture_2d (void *object);
  * @width: Width of the texture to allocate
  * @height: Height of the texture to allocate
  * @internal_format: The format of the texture
- * @error: A #GError for exceptions
+ * @error: A #CoglError for exceptions
  *
  * Allocates a low-level #CoglTexture2D texture that your GPU can
  * texture from directly. This is unlike sliced textures for example
@@ -102,7 +102,7 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
                                int width,
                                int height,
                                CoglPixelFormat internal_format,
-                               GError **error);
+                               CoglError **error);
 
 #define cogl_texture_2d_new_from_data cogl_texture_2d_new_from_data_EXP
 /**
@@ -123,7 +123,7 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
  *    scanlines in @data. A value of 0 will make Cogl automatically
  *    calculate @rowstride from @width and @format.
  * @data: pointer the memory region where the source buffer resides
- * @error: A #GError for exceptions
+ * @error: A #CoglError for exceptions
  *
  * Creates a new #CoglTexture2D texture based on data residing in memory.
  * These are unlike sliced textures for example which may be comprised
@@ -150,7 +150,7 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
                                CoglPixelFormat internal_format,
                                int rowstride,
                                const guint8 *data,
-                               GError **error);
+                               CoglError **error);
 
 #define cogl_texture_2d_new_from_foreign cogl_texture_2d_new_from_foreign_EXP
 /**
@@ -160,7 +160,7 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
  * @width: Width of the foreign GL texture
  * @height: Height of the foreign GL texture
  * @internal_format: The format of the texture
- * @error: A #GError for exceptions
+ * @error: A #CoglError for exceptions
  *
  * Wraps an existing GL_TEXTURE_2D texture object as a #CoglTexture2D.
  * This can be used for integrating Cogl with software using OpenGL
@@ -183,7 +183,7 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
                                   int width,
                                   int height,
                                   CoglPixelFormat format,
-                                  GError **error);
+                                  CoglError **error);
 
 #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
 #define cogl_wayland_texture_2d_new_from_buffer \
@@ -192,7 +192,7 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
  * cogl_wayland_texture_2d_new_from_buffer:
  * @ctx: A #CoglContext
  * @buffer: A Wayland buffer
- * @error: A #GError for exceptions
+ * @error: A #CoglError for exceptions
  *
  * Uploads the given Wayland @buffer to a #CoglTexture2D.
  *
@@ -213,7 +213,7 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
 CoglTexture2D *
 cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
                                          struct wl_buffer *buffer,
-                                         GError **error);
+                                         CoglError **error);
 #endif /* COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT */
 
 G_END_DECLS
diff --git a/cogl/cogl-texture-3d-private.h b/cogl/cogl-texture-3d-private.h
index b1cc7d8..914f5e1 100644
--- a/cogl/cogl-texture-3d-private.h
+++ b/cogl/cogl-texture-3d-private.h
@@ -68,7 +68,7 @@ struct _CoglTexture3D
  *    is if you have non-premultiplied source data and are going to adjust
  *    the blend mode (see cogl_pipeline_set_blend()) or use the data for
  *    something other than straight blending.
- * @error: A GError return location.
+ * @error: A CoglError return location.
  *
  * Creates a new 3D texture and initializes it with the images in
  * @bmp_handle. The images are assumed to be packed together after one
@@ -86,6 +86,6 @@ _cogl_texture_3d_new_from_bitmap (CoglContext *context,
                                   unsigned int height,
                                   unsigned int depth,
                                   CoglPixelFormat internal_format,
-                                  GError **error);
+                                  CoglError **error);
 
 #endif /* __COGL_TEXTURE_3D_PRIVATE_H */
diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c
index 46a1172..dc329ce 100644
--- a/cogl/cogl-texture-3d.c
+++ b/cogl/cogl-texture-3d.c
@@ -137,7 +137,7 @@ _cogl_texture_3d_can_create (CoglContext *ctx,
                              int height,
                              int depth,
                              CoglPixelFormat internal_format,
-                             GError **error)
+                             CoglError **error)
 {
   GLenum gl_intformat;
   GLenum gl_type;
@@ -145,10 +145,10 @@ _cogl_texture_3d_can_create (CoglContext *ctx,
   /* This should only happen on GLES */
   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
     {
-      g_set_error (error,
-                   COGL_RENDERER_ERROR,
-                   COGL_RENDERER_ERROR_UNSUPPORTED,
-                   "3D textures are not supported by the GPU");
+      cogl_set_error (error,
+                      COGL_RENDERER_ERROR,
+                      COGL_RENDERER_ERROR_UNSUPPORTED,
+                      "3D textures are not supported by the GPU");
       return FALSE;
     }
 
@@ -159,11 +159,11 @@ _cogl_texture_3d_can_create (CoglContext *ctx,
        !_cogl_util_is_pot (height) ||
        !_cogl_util_is_pot (depth)))
     {
-      g_set_error (error,
-                   COGL_RENDERER_ERROR,
-                   COGL_RENDERER_ERROR_UNSUPPORTED,
-                   "A non-power-of-two size was requested but this is not "
-                   "supported by the GPU");
+      cogl_set_error (error,
+                      COGL_RENDERER_ERROR,
+                      COGL_RENDERER_ERROR_UNSUPPORTED,
+                      "A non-power-of-two size was requested but this is not "
+                      "supported by the GPU");
       return FALSE;
     }
 
@@ -180,10 +180,10 @@ _cogl_texture_3d_can_create (CoglContext *ctx,
                                                height,
                                                depth))
     {
-      g_set_error (error,
-                   COGL_RENDERER_ERROR,
-                   COGL_RENDERER_ERROR_UNSUPPORTED,
-                   "The requested dimensions are not supported by the GPU");
+      cogl_set_error (error,
+                      COGL_RENDERER_ERROR,
+                      COGL_RENDERER_ERROR_UNSUPPORTED,
+                      "The requested dimensions are not supported by the GPU");
       return FALSE;
     }
 
@@ -196,7 +196,7 @@ cogl_texture_3d_new_with_size (CoglContext *ctx,
                                int height,
                                int depth,
                                CoglPixelFormat internal_format,
-                               GError **error)
+                               CoglError **error)
 {
   CoglTexture3D         *tex_3d;
   GLenum                 gl_intformat;
@@ -238,7 +238,7 @@ _cogl_texture_3d_new_from_bitmap (CoglContext *ctx,
                                   unsigned int height,
                                   unsigned int depth,
                                   CoglPixelFormat internal_format,
-                                  GError **error)
+                                  CoglError **error)
 {
   CoglTexture3D   *tex_3d;
   CoglBitmap      *dst_bmp;
@@ -270,7 +270,7 @@ _cogl_texture_3d_new_from_bitmap (CoglContext *ctx,
 
   if (dst_bmp == NULL)
     {
-      g_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_FAILED,
+      cogl_set_error (error, COGL_BITMAP_ERROR, COGL_BITMAP_ERROR_FAILED,
                    "Bitmap conversion failed");
       return NULL;
     }
@@ -323,13 +323,13 @@ cogl_texture_3d_new_from_data (CoglContext *context,
                                int rowstride,
                                int image_stride,
                                const guint8 *data,
-                               GError **error)
+                               CoglError **error)
 {
   CoglBitmap *bitmap;
   CoglTexture3D *ret;
 
   /* These are considered a programmer errors so we won't set a
-     GError. It would be nice if this was a _COGL_RETURN_IF_FAIL but the
+     CoglError. It would be nice if this was a _COGL_RETURN_IF_FAIL but the
      rest of Cogl isn't using that */
   if (format == COGL_PIXEL_FORMAT_ANY)
     return NULL;
diff --git a/cogl/cogl-texture-3d.h b/cogl/cogl-texture-3d.h
index 6c14912..8d03873 100644
--- a/cogl/cogl-texture-3d.h
+++ b/cogl/cogl-texture-3d.h
@@ -57,12 +57,12 @@ typedef struct _CoglTexture3D CoglTexture3D;
  * @depth: depth of the texture in pixels.
  * @internal_format: the #CoglPixelFormat to use for the GPU
  *    storage of the texture.
- * @error: A GError return location.
+ * @error: A CoglError return location.
  *
  * Creates a new Cogl 3D texture with the specified dimensions and
  * pixel format.
  *
- * Note that this function will throw a #GError if
+ * Note that this function will throw a #CoglError if
  * %COGL_FEATURE_TEXTURE_3D is not advertised. It can also fail if the
  * requested dimensions are not supported by the GPU.
  *
@@ -78,7 +78,7 @@ cogl_texture_3d_new_with_size (CoglContext *context,
                                int height,
                                int depth,
                                CoglPixelFormat  internal_format,
-                               GError **error);
+                               CoglError **error);
 
 /**
  * cogl_texture_3d_new_from_data:
@@ -103,13 +103,13 @@ cogl_texture_3d_new_with_size (CoglContext *context,
  *    rows. Alternatively 0 can be passed to infer the @image_stride
  *    from the @height.
  * @data: pointer the memory region where the source buffer resides
- * @error: A GError return location.
+ * @error: A CoglError return location.
  *
  * Creates a new 3D texture and initializes it with @data. The data is
  * assumed to be packed array of @depth images. There can be padding
  * between the images using @image_stride.
  *
- * Note that this function will throw a #GError if
+ * Note that this function will throw a #CoglError if
  * %COGL_FEATURE_TEXTURE_3D is not advertised. It can also fail if the
  * requested dimensions are not supported by the GPU.
  *
@@ -129,7 +129,7 @@ cogl_texture_3d_new_from_data (CoglContext *context,
                                int rowstride,
                                int image_stride,
                                const guint8 *data,
-                               GError **error);
+                               CoglError **error);
 
 /**
  * cogl_is_texture_3d:
diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c
index 7580fc9..b68fdf4 100644
--- a/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl-texture-rectangle.c
@@ -112,7 +112,7 @@ static gboolean
 _cogl_texture_rectangle_can_create (unsigned int width,
                                     unsigned int height,
                                     CoglPixelFormat internal_format,
-                                    GError **error)
+                                    CoglError **error)
 {
   GLenum gl_intformat;
   GLenum gl_type;
@@ -121,7 +121,7 @@ _cogl_texture_rectangle_can_create (unsigned int width,
 
   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_TEXTURE_ERROR,
                    COGL_TEXTURE_ERROR_TYPE,
                    "The CoglTextureRectangle feature isn't available");
@@ -140,7 +140,7 @@ _cogl_texture_rectangle_can_create (unsigned int width,
                                             width,
                                             height))
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_TEXTURE_ERROR,
                    COGL_TEXTURE_ERROR_SIZE,
                    "The requested texture size + format is unsupported");
@@ -181,7 +181,7 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
                                       int width,
                                       int height,
                                       CoglPixelFormat internal_format,
-                                      GError **error)
+                                      CoglError **error)
 {
   CoglTextureRectangle *tex_rect;
   GLenum                gl_intformat;
diff --git a/cogl/cogl-texture-rectangle.h b/cogl/cogl-texture-rectangle.h
index 927bb93..3b5fbc3 100644
--- a/cogl/cogl-texture-rectangle.h
+++ b/cogl/cogl-texture-rectangle.h
@@ -85,7 +85,7 @@ cogl_is_texture_rectangle (void *object);
  * @width: The texture width to allocate
  * @height: The texture height to allocate
  * @internal_format: The desired internal texture format
- * @error: An optional GError pointer for reporting exceptions
+ * @error: An optional CoglError pointer for reporting exceptions
  *
  * Allocates a new #CoglRectangle texture with a given @width, @height
  * and @internal_format. This texture is a low-level texture that
@@ -111,7 +111,7 @@ cogl_texture_rectangle_new_with_size (CoglContext *ctx,
                                       int width,
                                       int height,
                                       CoglPixelFormat internal_format,
-                                      GError **error);
+                                      CoglError **error);
 
 G_END_DECLS
 
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 9cb3a6a..6645580 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -391,7 +391,7 @@ CoglTexture *
 cogl_texture_new_from_file (const char        *filename,
                             CoglTextureFlags   flags,
                             CoglPixelFormat    internal_format,
-                            GError           **error)
+                            CoglError           **error)
 {
   CoglBitmap *bmp;
   CoglTexture *texture = NULL;
diff --git a/cogl/cogl-texture.h b/cogl/cogl-texture.h
index 5bbd06a..60e2e9e 100644
--- a/cogl/cogl-texture.h
+++ b/cogl/cogl-texture.h
@@ -58,7 +58,7 @@ G_BEGIN_DECLS
 /**
  * COGL_TEXTURE_ERROR:
  *
- * #GError domain for texture errors.
+ * #CoglError domain for texture errors.
  *
  * Since: 2.0
  * Stability: Unstable
@@ -134,7 +134,7 @@ cogl_texture_new_with_size (unsigned int width,
  *    have non-premultiplied source data and are going to adjust the blend
  *    mode (see cogl_material_set_blend()) or use the data for something
  *    other than straight blending.
- * @error: return location for a #GError or %NULL
+ * @error: return location for a #CoglError or %NULL
  *
  * Creates a #CoglTexture from an image file.
  *
@@ -146,7 +146,7 @@ CoglTexture *
 cogl_texture_new_from_file (const char       *filename,
                             CoglTextureFlags   flags,
                             CoglPixelFormat    internal_format,
-                            GError           **error);
+                            CoglError           **error);
 
 /**
  * cogl_texture_new_from_data:
diff --git a/cogl/cogl-types.h b/cogl/cogl-types.h
index 0bb18b5..7ab46dc 100644
--- a/cogl/cogl-types.h
+++ b/cogl/cogl-types.h
@@ -28,9 +28,14 @@
 #ifndef __COGL_TYPES_H__
 #define __COGL_TYPES_H__
 
-#include <glib-object.h>
-
 #include <cogl/cogl-defines.h>
+#include <cogl/cogl-error.h>
+
+#ifdef COGL_HAS_GLIB_SUPPORT
+#include <glib-object.h>
+#else
+#include <glib.h>
+#endif
 
 G_BEGIN_DECLS
 
@@ -71,8 +76,11 @@ typedef gpointer CoglHandle;
 #define COGL_INVALID_HANDLE NULL
 
 #define COGL_TYPE_HANDLE        (cogl_handle_get_type ())
+
+#ifdef COGL_HAS_GLIB_SUPPORT
 GType
 cogl_handle_get_type (void) G_GNUC_CONST;
+#endif
 
 /**
  * cogl_handle_ref:
@@ -145,8 +153,11 @@ typedef struct _CoglEuler CoglEuler;
 typedef gint32 CoglFixed;
 
 #define COGL_TYPE_FIXED         (cogl_fixed_get_type ())
+
+#ifdef COGL_HAS_GLIB_SUPPORT
 GType
 cogl_fixed_get_type (void) G_GNUC_CONST;
+#endif
 
 /**
  * CoglAngle:
@@ -515,7 +526,7 @@ typedef enum {
 /**
  * COGL_BLEND_STRING_ERROR:
  *
- * #GError domain for blend string parser errors
+ * #CoglError domain for blend string parser errors
  *
  * Since: 1.0
  */
diff --git a/cogl/cogl-xlib-renderer-private.h b/cogl/cogl-xlib-renderer-private.h
index d0715c1..216e510 100644
--- a/cogl/cogl-xlib-renderer-private.h
+++ b/cogl/cogl-xlib-renderer-private.h
@@ -44,7 +44,7 @@ typedef struct _CoglXlibRenderer
 } CoglXlibRenderer;
 
 gboolean
-_cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **error);
+_cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error);
 
 void
 _cogl_xlib_renderer_disconnect (CoglRenderer *renderer);
diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl-xlib-renderer.c
index 1bbbe14..617feba 100644
--- a/cogl/cogl-xlib-renderer.c
+++ b/cogl/cogl-xlib-renderer.c
@@ -164,7 +164,7 @@ _cogl_xlib_renderer_untrap_errors (CoglRenderer *renderer,
 }
 
 static Display *
-assert_xlib_display (CoglRenderer *renderer, GError **error)
+assert_xlib_display (CoglRenderer *renderer, CoglError **error)
 {
   Display *xdpy = cogl_xlib_renderer_get_foreign_display (renderer);
   CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
@@ -179,7 +179,7 @@ assert_xlib_display (CoglRenderer *renderer, GError **error)
   xdpy = XOpenDisplay (_cogl_x11_display_name);
   if (xdpy == NULL)
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_RENDERER_ERROR,
                    COGL_RENDERER_ERROR_XLIB_DISPLAY_OPEN,
                    "Failed to open X Display %s", _cogl_x11_display_name);
@@ -191,7 +191,7 @@ assert_xlib_display (CoglRenderer *renderer, GError **error)
 }
 
 gboolean
-_cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **error)
+_cogl_xlib_renderer_connect (CoglRenderer *renderer, CoglError **error)
 {
   CoglXlibRenderer *xlib_renderer =
     _cogl_xlib_renderer_get_data (renderer);
diff --git a/cogl/cogl.c b/cogl/cogl.c
index 3784836..f7fdd2a 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -982,12 +982,6 @@ _cogl_transform_point (const CoglMatrix *matrix_mv,
 #undef VIEWPORT_TRANSFORM_X
 #undef VIEWPORT_TRANSFORM_Y
 
-GQuark
-_cogl_error_quark (void)
-{
-  return g_quark_from_static_string ("cogl-error-quark");
-}
-
 void
 _cogl_init (void)
 {
diff --git a/cogl/cogl1-context.h b/cogl/cogl1-context.h
index c59bd69..6d9c418 100644
--- a/cogl/cogl1-context.h
+++ b/cogl/cogl1-context.h
@@ -33,12 +33,14 @@
 
 #include <glib.h>
 
+#include <cogl/cogl-defines.h>
 #include <cogl/cogl-types.h>
 #include <cogl/cogl-texture.h>
 #include <cogl/cogl-framebuffer.h>
 
 G_BEGIN_DECLS
 
+#if COGL_HAS_GLIB_SUPPORT
 /**
  * cogl_get_option_group:
  *
@@ -52,6 +54,7 @@ G_BEGIN_DECLS
  */
 GOptionGroup *
 cogl_get_option_group (void);
+#endif
 
 /* Misc */
 /**
diff --git a/cogl/driver/gl/cogl-gl.c b/cogl/driver/gl/cogl-gl.c
index b35ddbe..4f6fa9e 100644
--- a/cogl/driver/gl/cogl-gl.c
+++ b/cogl/driver/gl/cogl-gl.c
@@ -32,6 +32,7 @@
 #include "cogl-context-private.h"
 #include "cogl-feature-private.h"
 #include "cogl-renderer-private.h"
+#include "cogl-error.h"
 
 static gboolean
 _cogl_get_gl_version (int *major_out, int *minor_out)
@@ -72,14 +73,14 @@ _cogl_get_gl_version (int *major_out, int *minor_out)
 
 static gboolean
 check_gl_version (CoglContext *ctx,
-                  GError **error)
+                  CoglError **error)
 {
   int major, minor;
   const char *gl_extensions;
 
   if (!_cogl_get_gl_version (&major, &minor))
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_DRIVER_ERROR,
                    COGL_DRIVER_ERROR_UNKNOWN_VERSION,
                    "The OpenGL version could not be determined");
@@ -96,7 +97,7 @@ check_gl_version (CoglContext *ctx,
      extension */
   if (!_cogl_check_extension ("GL_ARB_multitexture", gl_extensions))
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_DRIVER_ERROR,
                    COGL_DRIVER_ERROR_INVALID_VERSION,
                    "The OpenGL driver is missing "
@@ -107,7 +108,7 @@ check_gl_version (CoglContext *ctx,
   /* OpenGL 1.2 is required */
   if (!COGL_CHECK_GL_VERSION (major, minor, 1, 2))
     {
-      g_set_error (error,
+      cogl_set_error (error,
                    COGL_DRIVER_ERROR,
                    COGL_DRIVER_ERROR_INVALID_VERSION,
                    "The OpenGL version of your driver (%i.%i) "
@@ -121,7 +122,7 @@ check_gl_version (CoglContext *ctx,
 
 gboolean
 _cogl_gl_update_features (CoglContext *context,
-                          GError **error)
+                          CoglError **error)
 {
   CoglPrivateFeatureFlags private_flags = 0;
   CoglFeatureFlags flags = 0;
diff --git a/cogl/driver/gles/cogl-gles.c b/cogl/driver/gles/cogl-gles.c
index 2afdbeb..51600d9 100644
--- a/cogl/driver/gles/cogl-gles.c
+++ b/cogl/driver/gles/cogl-gles.c
@@ -34,7 +34,7 @@
 
 gboolean
 _cogl_gles_update_features (CoglContext *context,
-                            GError **error)
+                            CoglError **error)
 {
   CoglPrivateFeatureFlags private_flags = 0;
   CoglFeatureFlags flags = 0;
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c
index 0723ab3..c08d442 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -273,7 +273,7 @@ CoglTexturePixmapX11 *
 cogl_texture_pixmap_x11_new (CoglContext *ctxt,
                              guint32 pixmap,
                              gboolean automatic_updates,
-                             GError **error)
+                             CoglError **error)
 {
   CoglTexturePixmapX11 *tex_pixmap = g_new (CoglTexturePixmapX11, 1);
   Display *display = cogl_xlib_get_display ();
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.h b/cogl/winsys/cogl-texture-pixmap-x11.h
index 604011c..b82a76c 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.h
+++ b/cogl/winsys/cogl-texture-pixmap-x11.h
@@ -59,7 +59,7 @@ typedef enum
 /**
  * COGL_TEXTURE_PIXMAP_X11_ERROR:
  *
- * #GError domain for texture-pixmap-x11 errors.
+ * #CoglError domain for texture-pixmap-x11 errors.
  *
  * Since: 1.10
  */
@@ -86,7 +86,7 @@ GQuark cogl_texture_pixmap_x11_error_quark (void);
  * @pixmap: A X11 pixmap ID
  * @automatic_updates: Whether to automatically copy the contents of
  * the pixmap to the texture.
- * @error: A #GError for exceptions
+ * @error: A #CoglError for exceptions
  *
  * Creates a texture that contains the contents of @pixmap. If
  * @automatic_updates is %TRUE then Cogl will attempt to listen for
@@ -102,7 +102,7 @@ CoglTexturePixmapX11 *
 cogl_texture_pixmap_x11_new (CoglContext *context,
                              guint32 pixmap,
                              gboolean automatic_updates,
-                             GError **error);
+                             CoglError **error);
 
 /**
  * cogl_texture_pixmap_x11_update_area:
diff --git a/cogl/winsys/cogl-winsys-egl-android.c b/cogl/winsys/cogl-winsys-egl-android.c
index 2efa6b2..619d9e7 100644
--- a/cogl/winsys/cogl-winsys-egl-android.c
+++ b/cogl/winsys/cogl-winsys-egl-android.c
@@ -69,7 +69,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglRendererEGL *egl_renderer;
 
@@ -92,7 +92,7 @@ error:
 
 static gboolean
 _cogl_winsys_egl_context_created (CoglDisplay *display,
-                                  GError **error)
+                                  CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
@@ -154,7 +154,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
   return TRUE;
 
  fail:
-  g_set_error (error, COGL_WINSYS_ERROR,
+  cogl_set_error (error, COGL_WINSYS_ERROR,
                COGL_WINSYS_ERROR_CREATE_CONTEXT,
                "%s", error_message);
   return FALSE;
@@ -162,7 +162,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
 
 static gboolean
 _cogl_winsys_egl_display_setup (CoglDisplay *display,
-                                GError **error)
+                                CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
   CoglDisplayAndroid *android_display;
@@ -184,7 +184,7 @@ _cogl_winsys_egl_display_destroy (CoglDisplay *display)
 static gboolean
 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
                                 EGLConfig egl_config,
-                                GError **error)
+                                CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -195,7 +195,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
 
   if (android_display->have_onscreen)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "EGL platform only supports a single onscreen window");
       return FALSE;
diff --git a/cogl/winsys/cogl-winsys-egl-gdl.c b/cogl/winsys/cogl-winsys-egl-gdl.c
index 1f7a2c3..6cc8bd8 100644
--- a/cogl/winsys/cogl-winsys-egl-gdl.c
+++ b/cogl/winsys/cogl-winsys-egl-gdl.c
@@ -67,7 +67,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglRendererEGL *egl_renderer;
   CoglRendererGDL *gdl_renderer;
@@ -91,7 +91,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   rc = gdl_init (NULL);
   if (rc != GDL_SUCCESS)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "GDL initialize failed. %s",
                    gdl_get_error_string (rc));
@@ -101,7 +101,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   rc = gdl_get_display_info (GDL_DISPLAY_ID_0, &gdl_display_info);
   if (rc != GDL_SUCCESS)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "GDL failed to get display information: %s",
                    gdl_get_error_string (rc));
@@ -120,7 +120,7 @@ error:
 
 static gboolean
 _cogl_winsys_egl_context_created (CoglDisplay *display,
-                                  GError **error)
+                                  CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
@@ -162,14 +162,14 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
   return TRUE;
 
  fail:
-  g_set_error (error, COGL_WINSYS_ERROR,
+  cogl_set_error (error, COGL_WINSYS_ERROR,
                COGL_WINSYS_ERROR_CREATE_CONTEXT,
                "%s", error_message);
   return FALSE;
 }
 
 static gboolean
-gdl_plane_init (CoglDisplay *display, GError **error)
+gdl_plane_init (CoglDisplay *display, CoglError **error)
 {
   gboolean ret = TRUE;
   gdl_color_space_t colorSpace = GDL_COLOR_SPACE_RGB;
@@ -180,7 +180,7 @@ gdl_plane_init (CoglDisplay *display, GError **error)
 
   if (!display->gdl_plane)
     {
-      g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
+      cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "No GDL plane specified with "
                    "cogl_gdl_display_set_plane");
       return FALSE;
@@ -189,7 +189,7 @@ gdl_plane_init (CoglDisplay *display, GError **error)
   rc = gdl_init (NULL);
   if (rc != GDL_SUCCESS)
     {
-      g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
+      cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "GDL initialize failed. %s", gdl_get_error_string (rc));
       return FALSE;
     }
@@ -197,7 +197,7 @@ gdl_plane_init (CoglDisplay *display, GError **error)
   rc = gdl_get_display_info (GDL_DISPLAY_ID_0, &display_info);
   if (rc != GDL_SUCCESS)
     {
-      g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
+      cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "GDL failed to get display infomation: %s",
                    gdl_get_error_string (rc));
       gdl_close ();
@@ -243,7 +243,7 @@ gdl_plane_init (CoglDisplay *display, GError **error)
 
   if (rc != GDL_SUCCESS)
     {
-      g_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
+      cogl_set_error (error, COGL_WINSYS_ERROR, COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "GDL configuration failed: %s.", gdl_get_error_string (rc));
       ret = FALSE;
     }
@@ -255,7 +255,7 @@ gdl_plane_init (CoglDisplay *display, GError **error)
 
 static gboolean
 _cogl_winsys_egl_display_setup (CoglDisplay *display,
-                                GError **error)
+                                CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
   CoglDisplayGDL *gdl_display;
@@ -294,7 +294,7 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
 static gboolean
 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
                                 EGLConfig egl_config,
-                                GError **error)
+                                CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -305,7 +305,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
 
   if (gdl_display->have_onscreen)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "EGL platform only supports a single onscreen window");
       return FALSE;
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index 7864bd2..620ce29 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -89,7 +89,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglRendererEGL *egl_renderer;
   CoglRendererKMS *kms_renderer;
@@ -105,7 +105,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   if (kms_renderer->fd < 0)
     {
       /* Probably permissions error */
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Couldn't open %s", device_name);
       return FALSE;
@@ -114,7 +114,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   kms_renderer->gbm = gbm_create_device (kms_renderer->fd);
   if (kms_renderer->gbm == NULL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Couldn't create gbm device");
       goto close_fd;
@@ -123,7 +123,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
   egl_renderer->edpy = eglGetDisplay ((EGLNativeDisplayType)kms_renderer->gbm);
   if (egl_renderer->edpy == EGL_NO_DISPLAY)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Couldn't get eglDisplay");
       goto destroy_gbm_device;
@@ -148,7 +148,7 @@ close_fd:
 
 static gboolean
 _cogl_winsys_egl_display_setup (CoglDisplay *display,
-                                GError **error)
+                                CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
   CoglDisplayKMS *kms_display;
@@ -182,7 +182,7 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
 
   if (!(egl_renderer->private_features & surfaceless_feature))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "EGL_KHR_surfaceless_%s extension not available",
                    surfaceless_feature_name);
@@ -192,7 +192,7 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
   resources = drmModeGetResources (kms_renderer->fd);
   if (!resources)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "drmModeGetResources failed");
       return FALSE;
@@ -214,7 +214,7 @@ _cogl_winsys_egl_display_setup (CoglDisplay *display,
 
   if (i == resources->count_connectors)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "No currently active connector found");
       return FALSE;
@@ -256,7 +256,7 @@ _cogl_winsys_egl_display_destroy (CoglDisplay *display)
 static gboolean
 _cogl_winsys_egl_try_create_context (CoglDisplay *display,
                                      EGLint *attribs,
-                                     GError **error)
+                                     CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
@@ -269,7 +269,7 @@ _cogl_winsys_egl_try_create_context (CoglDisplay *display,
 
   if (egl_display->egl_context == NULL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Couldn't create EGL context");
       return FALSE;
@@ -280,7 +280,7 @@ _cogl_winsys_egl_try_create_context (CoglDisplay *display,
                        EGL_NO_SURFACE,
                        egl_display->egl_context))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Failed to make context current");
       return FALSE;
@@ -357,7 +357,7 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
 
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
+                            CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -392,7 +392,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                        GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
       if (!kms_onscreen->bo[i])
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_CONTEXT,
                        "Failed to allocate buffer");
           return FALSE;
@@ -406,7 +406,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
 
       if (kms_onscreen->image[i] == EGL_NO_IMAGE_KHR)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_CONTEXT,
                        "Failed to create EGL image");
           return FALSE;
@@ -429,7 +429,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                         handle,
                         &kms_onscreen->fb_id[i]) != 0)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_CONTEXT,
                        "Failed to create framebuffer from buffer");
           return FALSE;
diff --git a/cogl/winsys/cogl-winsys-egl-null.c b/cogl/winsys/cogl-winsys-egl-null.c
index f0b9200..58bfe94 100644
--- a/cogl/winsys/cogl-winsys-egl-null.c
+++ b/cogl/winsys/cogl-winsys-egl-null.c
@@ -56,7 +56,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglRendererEGL *egl_renderer;
 
@@ -79,7 +79,7 @@ error:
 
 static gboolean
 _cogl_winsys_egl_context_created (CoglDisplay *display,
-                                  GError **error)
+                                  CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
@@ -120,7 +120,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
   return TRUE;
 
  fail:
-  g_set_error (error, COGL_WINSYS_ERROR,
+  cogl_set_error (error, COGL_WINSYS_ERROR,
                COGL_WINSYS_ERROR_CREATE_CONTEXT,
                "%s", error_message);
   return FALSE;
@@ -128,7 +128,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
 
 static gboolean
 _cogl_winsys_egl_display_setup (CoglDisplay *display,
-                                GError **error)
+                                CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
   CoglDisplayNull *null_display;
@@ -164,7 +164,7 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
 static gboolean
 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
                                 EGLConfig egl_config,
-                                GError **error)
+                                CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -175,7 +175,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
 
   if (null_display->have_onscreen)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "EGL platform only supports a single onscreen window");
       return FALSE;
diff --git a/cogl/winsys/cogl-winsys-egl-private.h b/cogl/winsys/cogl-winsys-egl-private.h
index 6658278..002fd9a 100644
--- a/cogl/winsys/cogl-winsys-egl-private.h
+++ b/cogl/winsys/cogl-winsys-egl-private.h
@@ -34,24 +34,24 @@ typedef struct _CoglWinsysEGLVtable
 {
   gboolean
   (* display_setup) (CoglDisplay *display,
-                     GError **error);
+                     CoglError **error);
   void
   (* display_destroy) (CoglDisplay *display);
 
   gboolean
   (* try_create_context) (CoglDisplay *display,
                           EGLint *attribs,
-                          GError **error);
+                          CoglError **error);
 
   gboolean
   (* context_created) (CoglDisplay *display,
-                       GError **error);
+                       CoglError **error);
 
   void
   (* cleanup_context) (CoglDisplay *display);
 
   gboolean
-  (* context_init) (CoglContext *context, GError **error);
+  (* context_init) (CoglContext *context, CoglError **error);
 
   void
   (* context_deinit) (CoglContext *context);
@@ -59,7 +59,7 @@ typedef struct _CoglWinsysEGLVtable
   gboolean
   (* onscreen_init) (CoglOnscreen *onscreen,
                      EGLConfig config,
-                     GError **error);
+                     CoglError **error);
   void
   (* onscreen_deinit) (CoglOnscreen *onscreen);
 
@@ -152,6 +152,6 @@ _cogl_egl_destroy_image (CoglContext *ctx,
 
 gboolean
 _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
-                                          GError **error);
+                                          CoglError **error);
 
 #endif /* __COGL_WINSYS_EGL_PRIVATE_H */
diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
index fe75e07..51a2d59 100644
--- a/cogl/winsys/cogl-winsys-egl-wayland.c
+++ b/cogl/winsys/cogl-winsys-egl-wayland.c
@@ -102,7 +102,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglRendererEGL *egl_renderer;
   CoglRendererWayland *wayland_renderer;
@@ -138,7 +138,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
       wayland_renderer->wayland_display = wl_display_connect (NULL);
       if (!wayland_renderer->wayland_display)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_INIT,
                        "Failed to connect wayland display");
           goto error;
@@ -174,7 +174,7 @@ error:
 
 static gboolean
 _cogl_winsys_egl_display_setup (CoglDisplay *display,
-                                GError **error)
+                                CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
   CoglDisplayWayland *wayland_display;
@@ -195,7 +195,7 @@ _cogl_winsys_egl_display_destroy (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_egl_context_created (CoglDisplay *display,
-                                  GError **error)
+                                  CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglRendererEGL *egl_renderer = renderer->winsys;
@@ -246,7 +246,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
   return TRUE;
 
  fail:
-  g_set_error (error, COGL_WINSYS_ERROR,
+  cogl_set_error (error, COGL_WINSYS_ERROR,
                COGL_WINSYS_ERROR_CREATE_CONTEXT,
                "%s", error_message);
   return FALSE;
@@ -281,7 +281,7 @@ _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_egl_context_init (CoglContext *context,
-                               GError **error)
+                               CoglError **error)
 {
   context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE;
   COGL_FLAGS_SET (context->features,
@@ -296,7 +296,7 @@ _cogl_winsys_egl_context_init (CoglContext *context,
 static gboolean
 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
                                 EGLConfig egl_config,
-                                GError **error)
+                                CoglError **error)
 {
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
   CoglOnscreenWayland *wayland_onscreen;
@@ -313,7 +313,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
     wl_compositor_create_surface (wayland_renderer->wayland_compositor);
   if (!wayland_onscreen->wayland_surface)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "Error while creating wayland surface for CoglOnscreen");
       return FALSE;
@@ -329,7 +329,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
                           cogl_framebuffer_get_height (framebuffer));
   if (!wayland_onscreen->wayland_egl_native_window)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "Error while creating wayland egl native window "
                    "for CoglOnscreen");
diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c
index 55cbbc2..0c0f70b 100644
--- a/cogl/winsys/cogl-winsys-egl-x11.c
+++ b/cogl/winsys/cogl-winsys-egl-x11.c
@@ -175,7 +175,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglRendererEGL *egl_renderer;
   CoglXlibRenderer *xlib_renderer;
@@ -204,7 +204,7 @@ error:
 
 static gboolean
 _cogl_winsys_egl_display_setup (CoglDisplay *display,
-                                GError **error)
+                                CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
   CoglDisplayXlib *xlib_display;
@@ -225,7 +225,7 @@ _cogl_winsys_egl_display_destroy (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_egl_context_init (CoglContext *context,
-                               GError **error)
+                               CoglError **error)
 {
   cogl_xlib_renderer_add_filter (context->display->renderer,
                                  event_filter_cb,
@@ -252,7 +252,7 @@ _cogl_winsys_egl_context_deinit (CoglContext *context)
 static gboolean
 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
                                 EGLConfig egl_config,
-                                GError **error)
+                                CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -293,7 +293,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
           char message[1000];
           XGetErrorText (xlib_renderer->xdpy, xerror,
                          message, sizeof (message));
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "Unable to query geometry of foreign "
                        "xid 0x%08lX: %s",
@@ -328,7 +328,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
       xvisinfo = get_visual_info (display, egl_config);
       if (xvisinfo == NULL)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "Unable to retrieve the X11 visual of context's "
                        "fbconfig");
@@ -370,7 +370,7 @@ _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
           char message[1000];
           XGetErrorText (xlib_renderer->xdpy, xerror,
                          message, sizeof (message));
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "X error while creating Window for CoglOnscreen: %s",
                        message);
@@ -452,7 +452,7 @@ _cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
 
 static gboolean
 _cogl_winsys_egl_context_created (CoglDisplay *display,
-                                  GError **error)
+                                  CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglDisplayEGL *egl_display = display->winsys;
@@ -517,7 +517,7 @@ _cogl_winsys_egl_context_created (CoglDisplay *display,
   return TRUE;
 
 fail:
-  g_set_error (error, COGL_WINSYS_ERROR,
+  cogl_set_error (error, COGL_WINSYS_ERROR,
                COGL_WINSYS_ERROR_CREATE_CONTEXT,
                "%s", error_message);
   return FALSE;
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c
index 5d96ac4..80082e1 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -38,6 +38,7 @@
 #include "cogl-swap-chain-private.h"
 #include "cogl-renderer-private.h"
 #include "cogl-onscreen-template-private.h"
+#include "cogl-error.h"
 
 #include "cogl-private.h"
 
@@ -132,7 +133,7 @@ check_egl_extensions (CoglRenderer *renderer)
 
 gboolean
 _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
-                                          GError **error)
+                                          CoglError **error)
 {
   CoglRendererEGL *egl_renderer = renderer->winsys;
 
@@ -140,7 +141,7 @@ _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
                       &egl_renderer->egl_version_major,
                       &egl_renderer->egl_version_minor))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Couldn't initialize EGL");
       return FALSE;
@@ -153,7 +154,7 @@ _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   /* This function must be overridden by a platform winsys */
   g_assert_not_reached ();
@@ -220,7 +221,7 @@ egl_attributes_from_framebuffer_config (CoglDisplay *display,
 static gboolean
 try_create_context (CoglDisplay *display,
                     gboolean with_stencil_buffer,
-                    GError **error)
+                    CoglError **error)
 {
   CoglRenderer *renderer = display->renderer;
   CoglDisplayEGL *egl_display = display->winsys;
@@ -288,7 +289,7 @@ try_create_context (CoglDisplay *display,
   return TRUE;
 
 fail:
-  g_set_error (error, COGL_WINSYS_ERROR,
+  cogl_set_error (error, COGL_WINSYS_ERROR,
                COGL_WINSYS_ERROR_CREATE_CONTEXT,
                "%s", error_message);
   return FALSE;
@@ -314,7 +315,7 @@ cleanup_context (CoglDisplay *display)
 }
 
 static gboolean
-create_context (CoglDisplay *display, GError **error)
+create_context (CoglDisplay *display, CoglError **error)
 {
   CoglDisplayEGL *egl_display = display->winsys;
 
@@ -331,7 +332,7 @@ create_context (CoglDisplay *display, GError **error)
     }
   else
     {
-      g_clear_error (error);
+      cogl_clear_error (error);
       cleanup_context (display);
       egl_display->stencil_disabled = TRUE;
       return try_create_context (display, FALSE, error);
@@ -357,7 +358,7 @@ _cogl_winsys_display_destroy (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_display_setup (CoglDisplay *display,
-                            GError **error)
+                            CoglError **error)
 {
   CoglDisplayEGL *egl_display;
   CoglRenderer *renderer = display->renderer;
@@ -396,7 +397,7 @@ error:
 }
 
 static gboolean
-_cogl_winsys_context_init (CoglContext *context, GError **error)
+_cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
   CoglRenderer *renderer = context->display->renderer;
   CoglDisplayEGL *egl_display = context->display->winsys;
@@ -442,7 +443,7 @@ _cogl_winsys_context_deinit (CoglContext *context)
 
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
+                            CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -470,7 +471,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                             &config_count);
   if (status != EGL_TRUE || config_count == 0)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "Failed to find a suitable EGL configuration");
       return FALSE;
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 765191b..2ec6574 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -236,7 +236,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 resolve_core_glx_functions (CoglRenderer *renderer,
-                            GError **error)
+                            CoglError **error)
 {
   CoglGLXRenderer *glx_renderer;
 
@@ -281,7 +281,7 @@ resolve_core_glx_functions (CoglRenderer *renderer,
        !g_module_symbol (glx_renderer->libgl_module, "glXGetProcAddressARB",
                          (void **) &glx_renderer->glXGetProcAddress)))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Failed to resolve required GLX symbol");
       return FALSE;
@@ -292,7 +292,7 @@ resolve_core_glx_functions (CoglRenderer *renderer,
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   CoglGLXRenderer *glx_renderer;
   CoglXlibRenderer *xlib_renderer;
@@ -307,7 +307,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
 
   if (renderer->driver != COGL_DRIVER_GL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "GLX Backend can only be used in conjunction with OpenGL");
       goto error;
@@ -318,7 +318,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
 
   if (glx_renderer->libgl_module == NULL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "Failed to dynamically open the OpenGL library");
       goto error;
@@ -331,7 +331,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
                                         &glx_renderer->glx_error_base,
                                         &glx_renderer->glx_event_base))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "XServer appears to lack required GLX support");
       goto error;
@@ -345,7 +345,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
                                       &glx_renderer->glx_minor)
       || !(glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 2))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "XServer appears to lack required GLX 1.2 support");
       goto error;
@@ -361,7 +361,7 @@ error:
 }
 
 static gboolean
-update_winsys_features (CoglContext *context, GError **error)
+update_winsys_features (CoglContext *context, CoglError **error)
 {
   CoglGLXDisplay *glx_display = context->display->winsys;
   CoglXlibRenderer *xlib_renderer =
@@ -490,7 +490,7 @@ static gboolean
 find_fbconfig (CoglDisplay *display,
                CoglFramebufferConfig *config,
                GLXFBConfig *config_ret,
-               GError **error)
+               CoglError **error)
 {
   CoglXlibRenderer *xlib_renderer =
     _cogl_xlib_renderer_get_data (display->renderer);
@@ -509,7 +509,7 @@ find_fbconfig (CoglDisplay *display,
                                              &n_configs);
   if (!configs || n_configs == 0)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Failed to find any compatible fbconfigs");
       ret = FALSE;
@@ -539,7 +539,7 @@ find_fbconfig (CoglDisplay *display,
             }
         }
 
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to find fbconfig with rgba visual");
       ret = FALSE;
@@ -557,7 +557,7 @@ done:
 }
 
 static gboolean
-create_context (CoglDisplay *display, GError **error)
+create_context (CoglDisplay *display, CoglError **error)
 {
   CoglGLXDisplay *glx_display = display->winsys;
   CoglXlibRenderer *xlib_renderer =
@@ -566,7 +566,7 @@ create_context (CoglDisplay *display, GError **error)
   gboolean support_transparent_windows =
     display->onscreen_template->config.swap_chain->has_alpha;
   GLXFBConfig config;
-  GError *fbconfig_error = NULL;
+  CoglError *fbconfig_error = NULL;
   XSetWindowAttributes attrs;
   XVisualInfo *xvisinfo;
   GLXDrawable dummy_drawable;
@@ -579,11 +579,11 @@ create_context (CoglDisplay *display, GError **error)
                    &fbconfig_error);
   if (!glx_display->found_fbconfig)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to find suitable fbconfig for the GLX context: %s",
                    fbconfig_error->message);
-      g_error_free (fbconfig_error);
+      cogl_error_free (fbconfig_error);
       return FALSE;
     }
 
@@ -601,7 +601,7 @@ create_context (CoglDisplay *display, GError **error)
                                        True);
   if (glx_display->glx_context == NULL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to create suitable GL context");
       return FALSE;
@@ -622,7 +622,7 @@ create_context (CoglDisplay *display, GError **error)
                                                      config);
   if (xvisinfo == NULL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to retrieve the X11 visual");
       return FALSE;
@@ -677,7 +677,7 @@ create_context (CoglDisplay *display, GError **error)
 
   if (_cogl_xlib_renderer_untrap_errors (display->renderer, &old_state))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to select the newly created GLX context");
       return FALSE;
@@ -724,7 +724,7 @@ _cogl_winsys_display_destroy (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_display_setup (CoglDisplay *display,
-                            GError **error)
+                            CoglError **error)
 {
   CoglGLXDisplay *glx_display;
   int i;
@@ -748,7 +748,7 @@ error:
 }
 
 static gboolean
-_cogl_winsys_context_init (CoglContext *context, GError **error)
+_cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
   context->winsys = g_new0 (CoglContextGLX, 1);
 
@@ -769,7 +769,7 @@ _cogl_winsys_context_deinit (CoglContext *context)
 
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
+                            CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -782,7 +782,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
   CoglOnscreenXlib *xlib_onscreen;
   CoglOnscreenGLX *glx_onscreen;
   GLXFBConfig fbconfig;
-  GError *fbconfig_error = NULL;
+  CoglError *fbconfig_error = NULL;
 
   _COGL_RETURN_VAL_IF_FAIL (glx_display->glx_context, FALSE);
 
@@ -790,11 +790,11 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                       &fbconfig,
                       &fbconfig_error))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to find suitable fbconfig for the GLX context: %s",
                    fbconfig_error->message);
-      g_error_free (fbconfig_error);
+      cogl_error_free (fbconfig_error);
       return FALSE;
     }
 
@@ -838,7 +838,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
         {
           char message[1000];
           XGetErrorText (xlib_renderer->xdpy, xerror, message, sizeof(message));
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "Unable to query geometry of foreign xid 0x%08lX: %s",
                        xwin, message);
@@ -872,7 +872,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
                                                          fbconfig);
       if (xvisinfo == NULL)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "Unable to retrieve the X11 visual of context's "
                        "fbconfig");
@@ -911,7 +911,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
           char message[1000];
           XGetErrorText (xlib_renderer->xdpy, xerror,
                          message, sizeof (message));
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "X error while creating Window for CoglOnscreen: %s",
                        message);
@@ -1063,7 +1063,7 @@ _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
 
   XSync (xlib_renderer->xdpy, False);
 
-  /* FIXME: We should be reporting a GError here
+  /* FIXME: We should be reporting a CoglError here
    */
   if (_cogl_xlib_renderer_untrap_errors (context->display->renderer,
                                          &old_state))
@@ -1820,7 +1820,7 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
   if (glx_tex_pixmap->glx_tex == COGL_INVALID_HANDLE)
     {
       CoglPixelFormat texture_format;
-      GError *error = NULL;
+      CoglError *error = NULL;
 
       texture_format = (tex_pixmap->depth >= 32 ?
                         COGL_PIXEL_FORMAT_RGBA_8888_PRE :
@@ -1843,7 +1843,7 @@ _cogl_winsys_texture_pixmap_x11_update (CoglTexturePixmapX11 *tex_pixmap,
               COGL_NOTE (TEXTURE_PIXMAP, "Falling back for %p because a "
                          "texture rectangle could not be created: %s",
                          tex_pixmap, error->message);
-              g_error_free (error);
+              cogl_error_free (error);
               free_glx_pixmap (ctx, glx_tex_pixmap);
               return FALSE;
             }
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index 0e6c78b..d73c930 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/winsys/cogl-winsys-private.h
@@ -70,25 +70,25 @@ typedef struct _CoglWinsysVtable
                                 const char *name);
 
   gboolean
-  (*renderer_connect) (CoglRenderer *renderer, GError **error);
+  (*renderer_connect) (CoglRenderer *renderer, CoglError **error);
 
   void
   (*renderer_disconnect) (CoglRenderer *renderer);
 
   gboolean
-  (*display_setup) (CoglDisplay *display, GError **error);
+  (*display_setup) (CoglDisplay *display, CoglError **error);
 
   void
   (*display_destroy) (CoglDisplay *display);
 
   gboolean
-  (*context_init) (CoglContext *context, GError **error);
+  (*context_init) (CoglContext *context, CoglError **error);
 
   void
   (*context_deinit) (CoglContext *context);
 
   gboolean
-  (*onscreen_init) (CoglOnscreen *onscreen, GError **error);
+  (*onscreen_init) (CoglOnscreen *onscreen, CoglError **error);
 
   void
   (*onscreen_deinit) (CoglOnscreen *onscreen);
diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c
index c71f402..d877574 100644
--- a/cogl/winsys/cogl-winsys-sdl.c
+++ b/cogl/winsys/cogl-winsys-sdl.c
@@ -65,11 +65,11 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   if (renderer->driver != COGL_DRIVER_GL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "The SDL winsys only supports the GL driver");
       return FALSE;
@@ -77,7 +77,7 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
 
   if (SDL_Init (SDL_INIT_VIDEO) == -1)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "SDL_Init failed: %s",
                    SDL_GetError ());
@@ -122,7 +122,7 @@ set_gl_attribs_from_framebuffer_config (CoglFramebufferConfig *config)
 
 static gboolean
 _cogl_winsys_display_setup (CoglDisplay *display,
-                            GError **error)
+                            CoglError **error)
 {
   CoglDisplaySdl *sdl_display;
 
@@ -141,7 +141,7 @@ _cogl_winsys_display_setup (CoglDisplay *display,
 
   if (sdl_display->surface == NULL)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_INIT,
                    "SDL_SetVideoMode failed: %s",
                    SDL_GetError ());
@@ -156,7 +156,7 @@ error:
 }
 
 static gboolean
-_cogl_winsys_context_init (CoglContext *context, GError **error)
+_cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
   return _cogl_context_update_features (context, error);
 }
@@ -183,7 +183,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
 
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
+                            CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -193,7 +193,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
 
   if (sdl_display->has_onscreen)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "SDL winsys only supports a single onscreen window");
       return FALSE;
@@ -210,7 +210,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
 
       if (sdl_display->surface == NULL)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "SDL_SetVideoMode failed: %s",
                        SDL_GetError ());
diff --git a/cogl/winsys/cogl-winsys-stub.c b/cogl/winsys/cogl-winsys-stub.c
index 3310cfe..34d0649 100644
--- a/cogl/winsys/cogl-winsys-stub.c
+++ b/cogl/winsys/cogl-winsys-stub.c
@@ -74,7 +74,7 @@ _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   renderer->winsys = &_cogl_winsys_stub_dummy_ptr;
   return TRUE;
@@ -88,14 +88,14 @@ _cogl_winsys_display_destroy (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_display_setup (CoglDisplay *display,
-                            GError **error)
+                            CoglError **error)
 {
   display->winsys = &_cogl_winsys_stub_dummy_ptr;
   return TRUE;
 }
 
 static gboolean
-_cogl_winsys_context_init (CoglContext *context, GError **error)
+_cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
   context->winsys = &_cogl_winsys_stub_dummy_ptr;
 
@@ -115,7 +115,7 @@ _cogl_winsys_context_deinit (CoglContext *context)
 
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
+                            CoglError **error)
 {
   return TRUE;
 }
diff --git a/cogl/winsys/cogl-winsys-wgl.c b/cogl/winsys/cogl-winsys-wgl.c
index 66f9ed1..bdb480b 100644
--- a/cogl/winsys/cogl-winsys-wgl.c
+++ b/cogl/winsys/cogl-winsys-wgl.c
@@ -223,7 +223,7 @@ win32_event_filter_cb (MSG *msg, void *data)
 
 static gboolean
 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
-                               GError **error)
+                               CoglError **error)
 {
   renderer->winsys = g_slice_new0 (CoglRendererWgl);
 
@@ -363,7 +363,7 @@ choose_pixel_format (CoglFramebufferConfig *config,
 }
 
 static gboolean
-create_window_class (CoglDisplay *display, GError **error)
+create_window_class (CoglDisplay *display, CoglError **error)
 {
   CoglDisplayWgl *wgl_display = display->winsys;
   char *class_name_ascii, *src;
@@ -406,7 +406,7 @@ create_window_class (CoglDisplay *display, GError **error)
 
   if (wgl_display->window_class == 0)
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_CONTEXT,
                    "Unable to register window class");
       return FALSE;
@@ -416,7 +416,7 @@ create_window_class (CoglDisplay *display, GError **error)
 }
 
 static gboolean
-create_context (CoglDisplay *display, GError **error)
+create_context (CoglDisplay *display, CoglError **error)
 {
   CoglDisplayWgl *wgl_display = display->winsys;
 
@@ -442,7 +442,7 @@ create_context (CoglDisplay *display, GError **error)
 
       if (wgl_display->dummy_hwnd == NULL)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_CONTEXT,
                        "Unable to create dummy window");
           return FALSE;
@@ -461,7 +461,7 @@ create_context (CoglDisplay *display, GError **error)
 
       if (pf == 0 || !SetPixelFormat (wgl_display->dummy_dc, pf, &pfd))
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_CONTEXT,
                        "Unable to find suitable GL pixel format");
           ReleaseDC (wgl_display->dummy_hwnd, wgl_display->dummy_dc);
@@ -476,7 +476,7 @@ create_context (CoglDisplay *display, GError **error)
 
       if (wgl_display->wgl_context == NULL)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_CONTEXT,
                        "Unable to create suitable GL context");
           return FALSE;
@@ -520,7 +520,7 @@ _cogl_winsys_display_destroy (CoglDisplay *display)
 
 static gboolean
 _cogl_winsys_display_setup (CoglDisplay *display,
-                            GError **error)
+                            CoglError **error)
 {
   CoglDisplayWgl *wgl_display;
 
@@ -578,7 +578,7 @@ get_wgl_extensions_string (HDC dc)
 }
 
 static gboolean
-update_winsys_features (CoglContext *context, GError **error)
+update_winsys_features (CoglContext *context, CoglError **error)
 {
   CoglDisplayWgl *wgl_display = context->display->winsys;
   CoglRendererWgl *wgl_renderer = context->display->renderer->winsys;
@@ -624,7 +624,7 @@ update_winsys_features (CoglContext *context, GError **error)
 }
 
 static gboolean
-_cogl_winsys_context_init (CoglContext *context, GError **error)
+_cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
   CoglContextWgl *wgl_context;
 
@@ -724,7 +724,7 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
 
 static gboolean
 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
+                            CoglError **error)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
   CoglContext *context = framebuffer->context;
@@ -780,7 +780,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
 
       if (hwnd == NULL)
         {
-          g_set_error (error, COGL_WINSYS_ERROR,
+          cogl_set_error (error, COGL_WINSYS_ERROR,
                        COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                        "Unable to create window");
           return FALSE;
@@ -805,7 +805,7 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
 
   if (pf == 0 || !SetPixelFormat (wgl_onscreen->client_dc, pf, &pfd))
     {
-      g_set_error (error, COGL_WINSYS_ERROR,
+      cogl_set_error (error, COGL_WINSYS_ERROR,
                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
                    "Error setting pixel format on the window");
 
diff --git a/configure.ac b/configure.ac
index 1c434cd..b4180f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,6 +141,23 @@ dnl Export the source code release status
 dnl ================================================================
 AC_SUBST([COGL_RELEASE_STATUS], [cogl_release_status])
 
+dnl ================================================================
+dnl Compiler stuff.
+dnl ================================================================
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AM_PROG_CC_C_O
+AC_ISC_POSIX
+AC_C_CONST
+
+dnl ================================================================
+dnl Libtool stuff.
+dnl ================================================================
+dnl AC_PROG_LIBTOOL
+dnl LIBTOOL="$LIBTOOL --preserve-dup-deps"
+LT_PREREQ([2.2.6])
+LT_INIT([disable-static])
 
 dnl ================================================================
 dnl See what platform we are building for
@@ -395,27 +412,6 @@ AC_ARG_ENABLE(
 AM_CONDITIONAL([INSTALL_EXAMPLES], [test "x$enable_examples_install" = "xyes"])
 
 dnl     ============================================================
-dnl     Should glib be used?
-dnl     ============================================================
-AC_ARG_ENABLE(
-  [glib],
-  [AC_HELP_STRING([--enable-glib=@<:@no/yes@:>@], [Enable glib support @<:@default=yes@:>@])],
-  [],
-  enable_glib=yes
-)
-AM_CONDITIONAL([USE_GLIB], [test "x$enable_glib" = "xyes"])
-
-AS_IF([test "x$enable_glib" = "xyes"],
-      [
-        COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLIB_SUPPORT"
-      ],
-      [
-        EXPERIMENTAL_CONFIG=yes
-        EXPERIMENTAL_OPTIONS="$EXPERIMENTAL_OPTIONS --disable-glib,"
-      ]
-)
-
-dnl     ============================================================
 dnl     Determine which drivers and window systems we can support
 dnl     ============================================================
 
@@ -917,25 +913,6 @@ AM_CONDITIONAL(X11_TESTS, [test "x$SUPPORT_X11" = "xyes"])
 AM_CONDITIONAL(SUPPORT_X11, [test "x$SUPPORT_X11" = "xyes"])
 AM_CONDITIONAL(SUPPORT_XLIB, [test "x$SUPPORT_XLIB" = "xyes"])
 
-
-dnl ================================================================
-dnl Compiler stuff.
-dnl ================================================================
-AC_PROG_CC
-AC_PROG_CPP
-AM_PROG_CC_C_O
-AC_ISC_POSIX
-AC_C_CONST
-
-
-dnl ================================================================
-dnl Libtool stuff.
-dnl ================================================================
-dnl AC_PROG_LIBTOOL
-dnl LIBTOOL="$LIBTOOL --preserve-dup-deps"
-LT_PREREQ([2.2.6])
-LT_INIT([disable-static])
-
 dnl ================================================================
 dnl I18n stuff.
 dnl ================================================================
@@ -965,16 +942,45 @@ dnl Check for dependency packages.
 dnl ================================================================
 
 dnl     ============================================================
-dnl     Check glib dependencies
+dnl     Should glib be used?
 dnl     ============================================================
+
 AM_PATH_GLIB_2_0([glib_req_version],
                  [have_glib=yes], [have_glib=no],
                  [gobject gthread gmodule-no-export])
-AS_IF([test "x$have_glib" = "xno"], AC_MSG_ERROR([gobject-2.0 is required]))
+AC_ARG_ENABLE(
+  [glib],
+  [AC_HELP_STRING([--enable-glib=@<:@no/yes@:>@],
+                  [Enable glib support @<:@default=yes@:>@])],
+  [],
+  enable_glib=yes
+)
+
+AS_IF([test "x$have_glib" = "xno" && test "x$enable_glib" = "xyes"],
+      [AC_MSG_ERROR([gobject-2.0 is required])])
+
+AM_CONDITIONAL([USE_GLIB], [test "x$enable_glib" = "xyes"])
+
+AS_IF([test "x$enable_glib" = "xyes"],
+      [
+        COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLIB_SUPPORT"
+        COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gobject-2.0 gmodule-no-export-2.0"
+        COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_GLIB_SUPPORT"
+      ],
+      [
+        AS_GLIBCONFIG([deps/glib])
+        COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -I\$(top_srcdir)/deps"
+        COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -I\$(top_srcdir)/deps/glib"
+        COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS -I\$(top_srcdir)/deps/gmodule"
+        EXPERIMENTAL_CONFIG=yes
+        EXPERIMENTAL_OPTIONS="$EXPERIMENTAL_OPTIONS --disable-glib,"
+      ]
+)
+
 
-COGL_PKG_REQUIRES="$COGL_PKG_REQUIRES gobject-2.0 gmodule-no-export-2.0"
 AC_SUBST(COGL_PKG_REQUIRES)
 PKG_CHECK_MODULES(COGL_DEP, [$COGL_PKG_REQUIRES])
+
 if test -n "$COGL_PKG_REQUIRES_GL"; then
   PKG_CHECK_MODULES(COGL_DEP_GL, [$COGL_PKG_REQUIRES_GL])
 
diff --git a/deps/glib/README b/deps/glib/README
new file mode 100644
index 0000000..abccaf4
--- /dev/null
+++ b/deps/glib/README
@@ -0,0 +1 @@
+These are files striped from glib 2.30.2 to build a standalone cogl.
diff --git a/deps/glib/garray.c b/deps/glib/garray.c
new file mode 100644
index 0000000..07149b0
--- /dev/null
+++ b/deps/glib/garray.c
@@ -0,0 +1,1624 @@
+/* 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 <string.h>
+#include <stdlib.h>
+
+#include "garray.h"
+
+#include "gmem.h"
+#include "gthread.h"
+#include "gmessages.h"
+#include "gqsort.h"
+
+
+/**
+ * SECTION:arrays
+ * @title: Arrays
+ * @short_description: arrays of arbitrary elements which grow
+ *                     automatically as elements are added
+ *
+ * Arrays are similar to standard C arrays, except that they grow
+ * automatically as elements are added.
+ *
+ * Array elements can be of any size (though all elements of one array
+ * are the same size), and the array can be automatically cleared to
+ * '0's and zero-terminated.
+ *
+ * To create a new array use g_array_new().
+ *
+ * To add elements to an array, use g_array_append_val(),
+ * g_array_append_vals(), g_array_prepend_val(), and
+ * g_array_prepend_vals().
+ *
+ * To access an element of an array, use g_array_index().
+ *
+ * To set the size of an array, use g_array_set_size().
+ *
+ * To free an array, use g_array_free().
+ *
+ * <example>
+ *  <title>Using a #GArray to store #gint values</title>
+ *  <programlisting>
+ *   GArray *garray;
+ *   gint i;
+ *   /<!-- -->* We create a new array to store gint values.
+ *      We don't want it zero-terminated or cleared to 0's. *<!-- -->/
+ *   garray = g_array_new (FALSE, FALSE, sizeof (gint));
+ *   for (i = 0; i &lt; 10000; i++)
+ *     g_array_append_val (garray, i);
+ *   for (i = 0; i &lt; 10000; i++)
+ *     if (g_array_index (garray, gint, i) != i)
+ *       g_print ("ERROR: got &percnt;d instead of &percnt;d\n",
+ *                g_array_index (garray, gint, i), i);
+ *   g_array_free (garray, TRUE);
+ *  </programlisting>
+ * </example>
+ **/
+
+#define MIN_ARRAY_SIZE  16
+
+typedef struct _GRealArray  GRealArray;
+
+/**
+ * GArray:
+ * @data: a pointer to the element data. The data may be moved as
+ *        elements are added to the #GArray.
+ * @len: the number of elements in the #GArray not including the
+ *       possible terminating zero element.
+ *
+ * Contains the public fields of an <link linkend="glib-Arrays">Array</link>.
+ **/
+struct _GRealArray
+{
+  guint8 *data;
+  guint   len;
+  guint   alloc;
+  guint   elt_size;
+  guint   zero_terminated : 1;
+  guint   clear : 1;
+  gint    ref_count;
+};
+
+/**
+ * g_array_index:
+ * @a: a #GArray.
+ * @t: the type of the elements.
+ * @i: the index of the element to return.
+ * @Returns: the element of the #GArray at the index given by @i.
+ *
+ * Returns the element of a #GArray at the given index. The return
+ * value is cast to the given type.
+ *
+ * <example>
+ *  <title>Getting a pointer to an element in a #GArray</title>
+ *  <programlisting>
+ *   EDayViewEvent *event;
+ *   /<!-- -->* This gets a pointer to the 4th element
+ *      in the array of EDayViewEvent structs. *<!-- -->/
+ *   event = &amp;g_array_index (events, EDayViewEvent, 3);
+ *  </programlisting>
+ * </example>
+ **/
+
+#define g_array_elt_len(array,i) ((array)->elt_size * (i))
+#define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i)))
+#define g_array_elt_zero(array, pos, len) 				\
+  (memset (g_array_elt_pos ((array), pos), 0,  g_array_elt_len ((array), len)))
+#define g_array_zero_terminate(array) G_STMT_START{			\
+  if ((array)->zero_terminated)						\
+    g_array_elt_zero ((array), (array)->len, 1);			\
+}G_STMT_END
+
+static guint g_nearest_pow        (gint        num) G_GNUC_CONST;
+static void  g_array_maybe_expand (GRealArray *array,
+				   gint        len);
+
+/**
+ * g_array_new:
+ * @zero_terminated: %TRUE if the array should have an extra element at
+ *                   the end which is set to 0.
+ * @clear_: %TRUE if #GArray elements should be automatically cleared
+ *          to 0 when they are allocated.
+ * @element_size: the size of each element in bytes.
+ * @Returns: the new #GArray.
+ *
+ * Creates a new #GArray with a reference count of 1.
+ **/
+GArray*
+g_array_new (gboolean zero_terminated,
+	     gboolean clear,
+	     guint    elt_size)
+{
+  return (GArray*) g_array_sized_new (zero_terminated, clear, elt_size, 0);
+}
+
+/**
+ * g_array_sized_new:
+ * @zero_terminated: %TRUE if the array should have an extra element at
+ *                   the end with all bits cleared.
+ * @clear_: %TRUE if all bits in the array should be cleared to 0 on
+ *          allocation.
+ * @element_size: size of each element in the array.
+ * @reserved_size: number of elements preallocated.
+ * @Returns: the new #GArray.
+ *
+ * Creates a new #GArray with @reserved_size elements preallocated and
+ * a reference count of 1. This avoids frequent reallocation, if you
+ * are going to add many elements to the array. Note however that the
+ * size of the array is still 0.
+ **/
+GArray* g_array_sized_new (gboolean zero_terminated,
+			   gboolean clear,
+			   guint    elt_size,
+			   guint    reserved_size)
+{
+  GRealArray *array = g_slice_new (GRealArray);
+
+  array->data            = NULL;
+  array->len             = 0;
+  array->alloc           = 0;
+  array->zero_terminated = (zero_terminated ? 1 : 0);
+  array->clear           = (clear ? 1 : 0);
+  array->elt_size        = elt_size;
+  array->ref_count       = 1;
+
+  if (array->zero_terminated || reserved_size != 0)
+    {
+      g_array_maybe_expand (array, reserved_size);
+      g_array_zero_terminate(array);
+    }
+
+  return (GArray*) array;
+}
+
+/**
+ * g_array_ref:
+ * @array: A #GArray.
+ *
+ * Atomically increments the reference count of @array by one. This
+ * function is MT-safe and may be called from any thread.
+ *
+ * Returns: The passed in #GArray.
+ *
+ * Since: 2.22
+ **/
+GArray *
+g_array_ref (GArray *array)
+{
+  GRealArray *rarray = (GRealArray*) array;
+  g_return_val_if_fail (array, NULL);
+
+  g_atomic_int_inc (&rarray->ref_count);
+
+  return array;
+}
+
+/**
+ * g_array_unref:
+ * @array: A #GArray.
+ *
+ * Atomically decrements the reference count of @array by one. If the
+ * reference count drops to 0, all memory allocated by the array is
+ * released. This function is MT-safe and may be called from any
+ * thread.
+ *
+ * Since: 2.22
+ **/
+void
+g_array_unref (GArray *array)
+{
+  GRealArray *rarray = (GRealArray*) array;
+  g_return_if_fail (array);
+
+  if (g_atomic_int_dec_and_test (&rarray->ref_count))
+    g_array_free (array, TRUE);
+}
+
+/**
+ * g_array_get_element_size:
+ * @array: A #GArray.
+ *
+ * Gets the size of the elements in @array.
+ *
+ * Returns: Size of each element, in bytes.
+ *
+ * Since: 2.22
+ **/
+guint
+g_array_get_element_size (GArray *array)
+{
+  GRealArray *rarray = (GRealArray*) array;
+
+  g_return_val_if_fail (array, 0);
+
+  return rarray->elt_size;
+}
+
+/**
+ * g_array_free:
+ * @array: a #GArray.
+ * @free_segment: if %TRUE the actual element data is freed as well.
+ * @Returns: the element data if @free_segment is %FALSE, otherwise
+ *           %NULL.  The element data should be freed using g_free().
+ *
+ * Frees the memory allocated for the #GArray. If @free_segment is
+ * %TRUE it frees the memory block holding the elements as well and
+ * also each element if @array has a @element_free_func set. Pass
+ * %FALSE if you want to free the #GArray wrapper but preserve the
+ * underlying array for use elsewhere. If the reference count of @array
+ * is greater than one, the #GArray wrapper is preserved but the size
+ * of @array will be set to zero.
+ *
+ * <note><para>If array elements contain dynamically-allocated memory,
+ * they should be freed separately.</para></note>
+ **/
+gchar*
+g_array_free (GArray   *farray,
+	      gboolean  free_segment)
+{
+  GRealArray *array = (GRealArray*) farray;
+  gchar* segment;
+  gboolean preserve_wrapper;
+
+  g_return_val_if_fail (array, NULL);
+
+  /* if others are holding a reference, preserve the wrapper but do free/return the data */
+  preserve_wrapper = FALSE;
+  if (g_atomic_int_get (&array->ref_count) > 1)
+    preserve_wrapper = TRUE;
+
+  if (free_segment)
+    {
+      g_free (array->data);
+      segment = NULL;
+    }
+  else
+    segment = (gchar*) array->data;
+
+  if (preserve_wrapper)
+    {
+      array->data            = NULL;
+      array->len             = 0;
+      array->alloc           = 0;
+    }
+  else
+    {
+      g_slice_free1 (sizeof (GRealArray), array);
+    }
+
+  return segment;
+}
+
+/**
+ * g_array_append_vals:
+ * @array: a #GArray.
+ * @data: a pointer to the elements to append to the end of the array.
+ * @len: the number of elements to append.
+ * @Returns: the #GArray.
+ *
+ * Adds @len elements onto the end of the array.
+ **/
+/**
+ * g_array_append_val:
+ * @a: a #GArray.
+ * @v: the value to append to the #GArray.
+ * @Returns: the #GArray.
+ *
+ * Adds the value on to the end of the array. The array will grow in
+ * size automatically if necessary.
+ *
+ * <note><para>g_array_append_val() is a macro which uses a reference
+ * to the value parameter @v. This means that you cannot use it with
+ * literal values such as "27". You must use variables.</para></note>
+ **/
+GArray*
+g_array_append_vals (GArray       *farray,
+		     gconstpointer data,
+		     guint         len)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_array_maybe_expand (array, len);
+
+  memcpy (g_array_elt_pos (array, array->len), data, 
+	  g_array_elt_len (array, len));
+
+  array->len += len;
+
+  g_array_zero_terminate (array);
+
+  return farray;
+}
+
+/**
+ * g_array_prepend_vals:
+ * @array: a #GArray.
+ * @data: a pointer to the elements to prepend to the start of the
+ *        array.
+ * @len: the number of elements to prepend.
+ * @Returns: the #GArray.
+ *
+ * Adds @len elements onto the start of the array.
+ *
+ * This operation is slower than g_array_append_vals() since the
+ * existing elements in the array have to be moved to make space for
+ * the new elements.
+ **/
+/**
+ * g_array_prepend_val:
+ * @a: a #GArray.
+ * @v: the value to prepend to the #GArray.
+ * @Returns: the #GArray.
+ *
+ * Adds the value on to the start of the array. The array will grow in
+ * size automatically if necessary.
+ *
+ * This operation is slower than g_array_append_val() since the
+ * existing elements in the array have to be moved to make space for
+ * the new element.
+ *
+ * <note><para>g_array_prepend_val() is a macro which uses a reference
+ * to the value parameter @v. This means that you cannot use it with
+ * literal values such as "27". You must use variables.</para></note>
+ **/
+GArray*
+g_array_prepend_vals (GArray        *farray,
+		      gconstpointer  data,
+		      guint          len)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_array_maybe_expand (array, len);
+
+  g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 
+	     g_array_elt_len (array, array->len));
+
+  memcpy (g_array_elt_pos (array, 0), data, g_array_elt_len (array, len));
+
+  array->len += len;
+
+  g_array_zero_terminate (array);
+
+  return farray;
+}
+
+/**
+ * g_array_insert_vals:
+ * @array: a #GArray.
+ * @index_: the index to place the elements at.
+ * @data: a pointer to the elements to insert.
+ * @len: the number of elements to insert.
+ * @Returns: the #GArray.
+ *
+ * Inserts @len elements into a #GArray at the given index.
+ **/
+/**
+ * g_array_insert_val:
+ * @a: a #GArray.
+ * @i: the index to place the element at.
+ * @v: the value to insert into the array.
+ * @Returns: the #GArray.
+ *
+ * Inserts an element into an array at the given index.
+ *
+ * <note><para>g_array_insert_val() is a macro which uses a reference
+ * to the value parameter @v. This means that you cannot use it with
+ * literal values such as "27". You must use variables.</para></note>
+ **/
+GArray*
+g_array_insert_vals (GArray        *farray,
+		     guint          index_,
+		     gconstpointer  data,
+		     guint          len)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_array_maybe_expand (array, len);
+
+  g_memmove (g_array_elt_pos (array, len + index_), 
+	     g_array_elt_pos (array, index_), 
+	     g_array_elt_len (array, array->len - index_));
+
+  memcpy (g_array_elt_pos (array, index_), data, g_array_elt_len (array, len));
+
+  array->len += len;
+
+  g_array_zero_terminate (array);
+
+  return farray;
+}
+
+/**
+ * g_array_set_size:
+ * @array: a #GArray.
+ * @length: the new size of the #GArray.
+ * @Returns: the #GArray.
+ *
+ * Sets the size of the array, expanding it if necessary. If the array
+ * was created with @clear_ set to %TRUE, the new elements are set to 0.
+ **/
+GArray*
+g_array_set_size (GArray *farray,
+		  guint   length)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  if (length > array->len)
+    {
+      g_array_maybe_expand (array, length - array->len);
+      
+      if (array->clear)
+	g_array_elt_zero (array, array->len, length - array->len);
+    }
+  else if (G_UNLIKELY (g_mem_gc_friendly) && length < array->len)
+    g_array_elt_zero (array, length, array->len - length);
+  
+  array->len = length;
+  
+  g_array_zero_terminate (array);
+  
+  return farray;
+}
+
+/**
+ * g_array_remove_index:
+ * @array: a #GArray.
+ * @index_: the index of the element to remove.
+ * @Returns: the #GArray.
+ *
+ * Removes the element at the given index from a #GArray. The following
+ * elements are moved down one place.
+ **/
+GArray*
+g_array_remove_index (GArray *farray,
+		      guint   index_)
+{
+  GRealArray* array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index_ < array->len, NULL);
+
+  if (index_ != array->len - 1)
+    g_memmove (g_array_elt_pos (array, index_),
+	       g_array_elt_pos (array, index_ + 1),
+	       g_array_elt_len (array, array->len - index_ - 1));
+  
+  array->len -= 1;
+
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    g_array_elt_zero (array, array->len, 1);
+  else
+    g_array_zero_terminate (array);
+
+  return farray;
+}
+
+/**
+ * g_array_remove_index_fast:
+ * @array: a @GArray.
+ * @index_: the index of the element to remove.
+ * @Returns: the #GArray.
+ *
+ * Removes the element at the given index from a #GArray. The last
+ * element in the array is used to fill in the space, so this function
+ * does not preserve the order of the #GArray. But it is faster than
+ * g_array_remove_index().
+ **/
+GArray*
+g_array_remove_index_fast (GArray *farray,
+			   guint   index_)
+{
+  GRealArray* array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index_ < array->len, NULL);
+
+  if (index_ != array->len - 1)
+    memcpy (g_array_elt_pos (array, index_), 
+	    g_array_elt_pos (array, array->len - 1),
+	    g_array_elt_len (array, 1));
+  
+  array->len -= 1;
+
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    g_array_elt_zero (array, array->len, 1);
+  else
+    g_array_zero_terminate (array);
+
+  return farray;
+}
+
+/**
+ * g_array_remove_range:
+ * @array: a @GArray.
+ * @index_: the index of the first element to remove.
+ * @length: the number of elements to remove.
+ * @Returns: the #GArray.
+ *
+ * Removes the given number of elements starting at the given index
+ * from a #GArray.  The following elements are moved to close the gap.
+ *
+ * Since: 2.4
+ **/
+GArray*
+g_array_remove_range (GArray *farray,
+                      guint   index_,
+                      guint   length)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_val_if_fail (array, NULL);
+  g_return_val_if_fail (index_ < array->len, NULL);
+  g_return_val_if_fail (index_ + length <= array->len, NULL);
+
+  if (index_ + length != array->len)
+    g_memmove (g_array_elt_pos (array, index_), 
+               g_array_elt_pos (array, index_ + length), 
+               (array->len - (index_ + length)) * array->elt_size);
+
+  array->len -= length;
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    g_array_elt_zero (array, array->len, length);
+  else
+    g_array_zero_terminate (array);
+
+  return farray;
+}
+
+/**
+ * g_array_sort:
+ * @array: a #GArray.
+ * @compare_func: comparison function.
+ *
+ * Sorts a #GArray using @compare_func which should be a qsort()-style
+ * comparison function (returns less than zero for first arg is less
+ * than second arg, zero for equal, greater zero if first arg is
+ * greater than second arg).
+ *
+ * If two array elements compare equal, their order in the sorted array
+ * is undefined. If you want equal elements to keep their order &#8211; i.e.
+ * you want a stable sort &#8211; you can write a comparison function that,
+ * if two elements would otherwise compare equal, compares them by
+ * their addresses.
+ **/
+void
+g_array_sort (GArray       *farray,
+	      GCompareFunc  compare_func)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_if_fail (array != NULL);
+
+  qsort (array->data,
+	 array->len,
+	 array->elt_size,
+	 compare_func);
+}
+
+/**
+ * g_array_sort_with_data:
+ * @array: a #GArray.
+ * @compare_func: comparison function.
+ * @user_data: data to pass to @compare_func.
+ *
+ * Like g_array_sort(), but the comparison function receives an extra
+ * user data argument.
+ **/
+void
+g_array_sort_with_data (GArray           *farray,
+			GCompareDataFunc  compare_func,
+			gpointer          user_data)
+{
+  GRealArray *array = (GRealArray*) farray;
+
+  g_return_if_fail (array != NULL);
+
+  g_qsort_with_data (array->data,
+		     array->len,
+		     array->elt_size,
+		     compare_func,
+		     user_data);
+}
+
+/* Returns the smallest power of 2 greater than n, or n if
+ * such power does not fit in a guint
+ */
+static guint
+g_nearest_pow (gint num)
+{
+  guint n = 1;
+
+  while (n < num && n > 0)
+    n <<= 1;
+
+  return n ? n : num;
+}
+
+static void
+g_array_maybe_expand (GRealArray *array,
+		      gint        len)
+{
+  guint want_alloc = g_array_elt_len (array, array->len + len + 
+				      array->zero_terminated);
+
+  if (want_alloc > array->alloc)
+    {
+      want_alloc = g_nearest_pow (want_alloc);
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
+
+      array->data = g_realloc (array->data, want_alloc);
+
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        memset (array->data + array->alloc, 0, want_alloc - array->alloc);
+
+      array->alloc = want_alloc;
+    }
+}
+
+/**
+ * SECTION:arrays_pointer
+ * @title: Pointer Arrays
+ * @short_description: arrays of pointers to any type of data, which
+ *                     grow automatically as new elements are added
+ *
+ * Pointer Arrays are similar to Arrays but are used only for storing
+ * pointers.
+ *
+ * <note><para>If you remove elements from the array, elements at the
+ * end of the array are moved into the space previously occupied by the
+ * removed element. This means that you should not rely on the index of
+ * particular elements remaining the same. You should also be careful
+ * when deleting elements while iterating over the array.</para></note>
+ *
+ * To create a pointer array, use g_ptr_array_new().
+ *
+ * To add elements to a pointer array, use g_ptr_array_add().
+ *
+ * To remove elements from a pointer array, use g_ptr_array_remove(),
+ * g_ptr_array_remove_index() or g_ptr_array_remove_index_fast().
+ *
+ * To access an element of a pointer array, use g_ptr_array_index().
+ *
+ * To set the size of a pointer array, use g_ptr_array_set_size().
+ *
+ * To free a pointer array, use g_ptr_array_free().
+ *
+ * <example>
+ *  <title>Using a #GPtrArray</title>
+ *  <programlisting>
+ *   GPtrArray *gparray;
+ *   gchar *string1 = "one", *string2 = "two", *string3 = "three";
+ *
+ *   gparray = g_ptr_array_new (<!-- -->);
+ *   g_ptr_array_add (gparray, (gpointer) string1);
+ *   g_ptr_array_add (gparray, (gpointer) string2);
+ *   g_ptr_array_add (gparray, (gpointer) string3);
+ *
+ *   if (g_ptr_array_index (gparray, 0) != (gpointer) string1)
+ *     g_print ("ERROR: got &percnt;p instead of &percnt;p\n",
+ *              g_ptr_array_index (gparray, 0), string1);
+ *
+ *   g_ptr_array_free (gparray, TRUE);
+ *  </programlisting>
+ * </example>
+ **/
+
+typedef struct _GRealPtrArray  GRealPtrArray;
+
+/**
+ * GPtrArray:
+ * @pdata: points to the array of pointers, which may be moved when the
+ *         array grows.
+ * @len: number of pointers in the array.
+ *
+ * Contains the public fields of a pointer array.
+ **/
+struct _GRealPtrArray
+{
+  gpointer     *pdata;
+  guint         len;
+  guint         alloc;
+  gint          ref_count;
+  GDestroyNotify element_free_func;
+};
+
+/**
+ * g_ptr_array_index:
+ * @array: a #GPtrArray.
+ * @index_: the index of the pointer to return.
+ * @Returns: the pointer at the given index.
+ *
+ * Returns the pointer at the given index of the pointer array.
+ **/
+
+static void g_ptr_array_maybe_expand (GRealPtrArray *array,
+				      gint           len);
+
+/**
+ * g_ptr_array_new:
+ * @Returns: the new #GPtrArray.
+ *
+ * Creates a new #GPtrArray with a reference count of 1.
+ **/
+GPtrArray*
+g_ptr_array_new (void)
+{
+  return g_ptr_array_sized_new (0);
+}
+
+/**
+ * g_ptr_array_sized_new:
+ * @reserved_size: number of pointers preallocated.
+ * @Returns: the new #GPtrArray.
+ *
+ * Creates a new #GPtrArray with @reserved_size pointers preallocated
+ * and a reference count of 1. This avoids frequent reallocation, if
+ * you are going to add many pointers to the array. Note however that
+ * the size of the array is still 0.
+ **/
+GPtrArray*  
+g_ptr_array_sized_new (guint reserved_size)
+{
+  GRealPtrArray *array = g_slice_new (GRealPtrArray);
+
+  array->pdata = NULL;
+  array->len = 0;
+  array->alloc = 0;
+  array->ref_count = 1;
+  array->element_free_func = NULL;
+
+  if (reserved_size != 0)
+    g_ptr_array_maybe_expand (array, reserved_size);
+
+  return (GPtrArray*) array;  
+}
+
+/**
+ * g_ptr_array_new_with_free_func:
+ * @element_free_func: A function to free elements with destroy @array or %NULL.
+ *
+ * Creates a new #GPtrArray with a reference count of 1 and use @element_free_func
+ * for freeing each element when the array is destroyed either via
+ * g_ptr_array_unref(), when g_ptr_array_free() is called with @free_segment
+ * set to %TRUE or when removing elements.
+ *
+ * Returns: A new #GPtrArray.
+ *
+ * Since: 2.22
+ **/
+GPtrArray *
+g_ptr_array_new_with_free_func (GDestroyNotify element_free_func)
+{
+  GPtrArray *array;
+
+  array = g_ptr_array_new ();
+  g_ptr_array_set_free_func (array, element_free_func);
+  return array;
+}
+
+/**
+ * g_ptr_array_new_full:
+ * @reserved_size: number of pointers preallocated.
+ * @element_free_func: A function to free elements with destroy @array or %NULL.
+ *
+ * Creates a new #GPtrArray with @reserved_size pointers preallocated
+ * and a reference count of 1. This avoids frequent reallocation, if
+ * you are going to add many pointers to the array. Note however that
+ * the size of the array is still 0. It also set @element_free_func
+ * for freeing each element when the array is destroyed either via
+ * g_ptr_array_unref(), when g_ptr_array_free() is called with @free_segment
+ * set to %TRUE or when removing elements.
+ *
+ * Returns: A new #GPtrArray.
+ *
+ * Since: 2.30
+ **/
+GPtrArray *
+g_ptr_array_new_full (guint          reserved_size,
+                      GDestroyNotify element_free_func)
+{
+  GPtrArray *array;
+
+  array = g_ptr_array_sized_new (reserved_size);
+  g_ptr_array_set_free_func (array, element_free_func);
+  return array;
+}
+
+/**
+ * g_ptr_array_set_free_func:
+ * @array: A #GPtrArray.
+ * @element_free_func: A function to free elements with destroy @array or %NULL.
+ *
+ * Sets a function for freeing each element when @array is destroyed
+ * either via g_ptr_array_unref(), when g_ptr_array_free() is called
+ * with @free_segment set to %TRUE or when removing elements.
+ *
+ * Since: 2.22
+ **/
+void
+g_ptr_array_set_free_func (GPtrArray        *array,
+                           GDestroyNotify    element_free_func)
+{
+  GRealPtrArray* rarray = (GRealPtrArray*) array;
+
+  g_return_if_fail (array);
+
+  rarray->element_free_func = element_free_func;
+}
+
+/**
+ * g_ptr_array_ref:
+ * @array: A #GArray.
+ *
+ * Atomically increments the reference count of @array by one. This
+ * function is MT-safe and may be called from any thread.
+ *
+ * Returns: The passed in #GPtrArray.
+ *
+ * Since: 2.22
+ **/
+GPtrArray *
+g_ptr_array_ref (GPtrArray *array)
+{
+  GRealPtrArray *rarray = (GRealPtrArray*) array;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_atomic_int_inc (&rarray->ref_count);
+
+  return array;
+}
+
+/**
+ * g_ptr_array_unref:
+ * @array: A #GPtrArray.
+ *
+ * Atomically decrements the reference count of @array by one. If the
+ * reference count drops to 0, the effect is the same as calling
+ * g_ptr_array_free() with @free_segment set to %TRUE. This function
+ * is MT-safe and may be called from any thread.
+ *
+ * Since: 2.22
+ **/
+void
+g_ptr_array_unref (GPtrArray *array)
+{
+  GRealPtrArray *rarray = (GRealPtrArray*) array;
+  g_return_if_fail (array);
+
+  if (g_atomic_int_dec_and_test (&rarray->ref_count))
+    g_ptr_array_free (array, TRUE);
+}
+
+/**
+ * g_ptr_array_free:
+ * @array: a #GPtrArray.
+ * @free_seg: if %TRUE the actual pointer array is freed as well.
+ * @Returns: the pointer array if @free_seg is %FALSE, otherwise %NULL.
+ *           The pointer array should be freed using g_free().
+ *
+ * Frees the memory allocated for the #GPtrArray. If @free_seg is %TRUE
+ * it frees the memory block holding the elements as well. Pass %FALSE
+ * if you want to free the #GPtrArray wrapper but preserve the
+ * underlying array for use elsewhere. If the reference count of @array
+ * is greater than one, the #GPtrArray wrapper is preserved but the
+ * size of @array will be set to zero.
+ *
+ * <note><para>If array contents point to dynamically-allocated
+ * memory, they should be freed separately if @free_seg is %TRUE and no
+ * #GDestroyNotify function has been set for @array.</para></note>
+ **/
+gpointer*
+g_ptr_array_free (GPtrArray *farray,
+		  gboolean   free_segment)
+{
+  GRealPtrArray *array = (GRealPtrArray*) farray;
+  gpointer* segment;
+  gboolean preserve_wrapper;
+
+  g_return_val_if_fail (array, NULL);
+
+  /* if others are holding a reference, preserve the wrapper but do free/return the data */
+  preserve_wrapper = FALSE;
+  if (g_atomic_int_get (&array->ref_count) > 1)
+    preserve_wrapper = TRUE;
+
+  if (free_segment)
+    {
+      if (array->element_free_func != NULL)
+        g_ptr_array_foreach (farray, (GFunc) array->element_free_func, NULL);
+      g_free (array->pdata);
+      segment = NULL;
+    }
+  else
+    segment = array->pdata;
+
+  if (preserve_wrapper)
+    {
+      array->pdata = NULL;
+      array->len = 0;
+      array->alloc = 0;
+    }
+  else
+    {
+      g_slice_free1 (sizeof (GRealPtrArray), array);
+    }
+
+  return segment;
+}
+
+static void
+g_ptr_array_maybe_expand (GRealPtrArray *array,
+			  gint           len)
+{
+  if ((array->len + len) > array->alloc)
+    {
+      guint old_alloc = array->alloc;
+      array->alloc = g_nearest_pow (array->len + len);
+      array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
+      array->pdata = g_realloc (array->pdata, sizeof (gpointer) * array->alloc);
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        for ( ; old_alloc < array->alloc; old_alloc++)
+          array->pdata [old_alloc] = NULL;
+    }
+}
+
+/**
+ * g_ptr_array_set_size:
+ * @array: a #GPtrArray.
+ * @length: the new length of the pointer array.
+ *
+ * Sets the size of the array. When making the array larger,
+ * newly-added elements will be set to %NULL. When making it smaller,
+ * if @array has a non-%NULL #GDestroyNotify function then it will be
+ * called for the removed elements.
+ **/
+void
+g_ptr_array_set_size  (GPtrArray *farray,
+		       gint	  length)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  if (length > array->len)
+    {
+      int i;
+      g_ptr_array_maybe_expand (array, (length - array->len));
+      /* This is not 
+       *     memset (array->pdata + array->len, 0,
+       *            sizeof (gpointer) * (length - array->len));
+       * to make it really portable. Remember (void*)NULL needn't be
+       * bitwise zero. It of course is silly not to use memset (..,0,..).
+       */
+      for (i = array->len; i < length; i++)
+	array->pdata[i] = NULL;
+    }
+  else if (length < array->len)
+    g_ptr_array_remove_range (farray, length, array->len - length);
+
+  array->len = length;
+}
+
+/**
+ * g_ptr_array_remove_index:
+ * @array: a #GPtrArray.
+ * @index_: the index of the pointer to remove.
+ * @Returns: the pointer which was removed.
+ *
+ * Removes the pointer at the given index from the pointer array. The
+ * following elements are moved down one place. If @array has a
+ * non-%NULL #GDestroyNotify function it is called for the removed
+ * element.
+ **/
+gpointer
+g_ptr_array_remove_index (GPtrArray *farray,
+			  guint      index_)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  gpointer result;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index_ < array->len, NULL);
+
+  result = array->pdata[index_];
+  
+  if (array->element_free_func != NULL)
+    array->element_free_func (array->pdata[index_]);
+
+  if (index_ != array->len - 1)
+    g_memmove (array->pdata + index_, array->pdata + index_ + 1, 
+               sizeof (gpointer) * (array->len - index_ - 1));
+  
+  array->len -= 1;
+
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    array->pdata[array->len] = NULL;
+
+  return result;
+}
+
+/**
+ * g_ptr_array_remove_index_fast:
+ * @array: a #GPtrArray.
+ * @index_: the index of the pointer to remove.
+ * @Returns: the pointer which was removed.
+ *
+ * Removes the pointer at the given index from the pointer array. The
+ * last element in the array is used to fill in the space, so this
+ * function does not preserve the order of the array. But it is faster
+ * than g_ptr_array_remove_index(). If @array has a non-%NULL
+ * #GDestroyNotify function it is called for the removed element.
+ **/
+gpointer
+g_ptr_array_remove_index_fast (GPtrArray *farray,
+			       guint      index_)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  gpointer result;
+
+  g_return_val_if_fail (array, NULL);
+
+  g_return_val_if_fail (index_ < array->len, NULL);
+
+  result = array->pdata[index_];
+
+  if (array->element_free_func != NULL)
+    array->element_free_func (array->pdata[index_]);
+
+  if (index_ != array->len - 1)
+    array->pdata[index_] = array->pdata[array->len - 1];
+
+  array->len -= 1;
+
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    array->pdata[array->len] = NULL;
+
+  return result;
+}
+
+/**
+ * g_ptr_array_remove_range:
+ * @array: a @GPtrArray.
+ * @index_: the index of the first pointer to remove.
+ * @length: the number of pointers to remove.
+ *
+ * Removes the given number of pointers starting at the given index
+ * from a #GPtrArray.  The following elements are moved to close the
+ * gap. If @array has a non-%NULL #GDestroyNotify function it is called
+ * for the removed elements.
+ *
+ * Since: 2.4
+ **/
+void
+g_ptr_array_remove_range (GPtrArray *farray,
+                          guint      index_,
+                          guint      length)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  guint n;
+
+  g_return_if_fail (array);
+  g_return_if_fail (index_ < array->len);
+  g_return_if_fail (index_ + length <= array->len);
+
+  if (array->element_free_func != NULL)
+    {
+      for (n = index_; n < index_ + length; n++)
+        array->element_free_func (array->pdata[n]);
+    }
+
+  if (index_ + length != array->len)
+    {
+      g_memmove (&array->pdata[index_],
+                 &array->pdata[index_ + length], 
+                 (array->len - (index_ + length)) * sizeof (gpointer));
+    }
+
+  array->len -= length;
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    {
+      guint i;
+      for (i = 0; i < length; i++)
+        array->pdata[array->len + i] = NULL;
+    }
+}
+
+/**
+ * g_ptr_array_remove:
+ * @array: a #GPtrArray.
+ * @data: the pointer to remove.
+ * @Returns: %TRUE if the pointer is removed. %FALSE if the pointer is
+ *           not found in the array.
+ *
+ * Removes the first occurrence of the given pointer from the pointer
+ * array. The following elements are moved down one place. If @array
+ * has a non-%NULL #GDestroyNotify function it is called for the
+ * removed element.
+ *
+ * It returns %TRUE if the pointer was removed, or %FALSE if the
+ * pointer was not found.
+ **/
+gboolean
+g_ptr_array_remove (GPtrArray *farray,
+		    gpointer   data)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  guint i;
+
+  g_return_val_if_fail (array, FALSE);
+
+  for (i = 0; i < array->len; i += 1)
+    {
+      if (array->pdata[i] == data)
+	{
+	  g_ptr_array_remove_index (farray, i);
+	  return TRUE;
+	}
+    }
+
+  return FALSE;
+}
+
+/**
+ * g_ptr_array_remove_fast:
+ * @array: a #GPtrArray.
+ * @data: the pointer to remove.
+ * @Returns: %TRUE if the pointer was found in the array.
+ *
+ * Removes the first occurrence of the given pointer from the pointer
+ * array. The last element in the array is used to fill in the space,
+ * so this function does not preserve the order of the array. But it is
+ * faster than g_ptr_array_remove(). If @array has a non-%NULL
+ * #GDestroyNotify function it is called for the removed element.
+ *
+ * It returns %TRUE if the pointer was removed, or %FALSE if the
+ * pointer was not found.
+ **/
+gboolean
+g_ptr_array_remove_fast (GPtrArray *farray,
+			 gpointer   data)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+  guint i;
+
+  g_return_val_if_fail (array, FALSE);
+
+  for (i = 0; i < array->len; i += 1)
+    {
+      if (array->pdata[i] == data)
+	{
+	  g_ptr_array_remove_index_fast (farray, i);
+	  return TRUE;
+	}
+    }
+
+  return FALSE;
+}
+
+/**
+ * g_ptr_array_add:
+ * @array: a #GPtrArray.
+ * @data: the pointer to add.
+ *
+ * Adds a pointer to the end of the pointer array. The array will grow
+ * in size automatically if necessary.
+ **/
+void
+g_ptr_array_add (GPtrArray *farray,
+		 gpointer   data)
+{
+  GRealPtrArray* array = (GRealPtrArray*) farray;
+
+  g_return_if_fail (array);
+
+  g_ptr_array_maybe_expand (array, 1);
+
+  array->pdata[array->len++] = data;
+}
+
+/**
+ * g_ptr_array_sort:
+ * @array: a #GPtrArray.
+ * @compare_func: comparison function.
+ *
+ * Sorts the array, using @compare_func which should be a qsort()-style
+ * comparison function (returns less than zero for first arg is less
+ * than second arg, zero for equal, greater than zero if irst arg is
+ * greater than second arg).
+ *
+ * If two array elements compare equal, their order in the sorted array
+ * is undefined. If you want equal elements to keep their order &#8211; i.e.
+ * you want a stable sort &#8211; you can write a comparison function that,
+ * if two elements would otherwise compare equal, compares them by
+ * their addresses.
+ *
+ * <note><para>The comparison function for g_ptr_array_sort() doesn't
+ * take the pointers from the array as arguments, it takes pointers to
+ * the pointers in the array.</para></note>
+ **/
+void
+g_ptr_array_sort (GPtrArray    *array,
+		  GCompareFunc  compare_func)
+{
+  g_return_if_fail (array != NULL);
+
+  qsort (array->pdata,
+	 array->len,
+	 sizeof (gpointer),
+	 compare_func);
+}
+
+/**
+ * g_ptr_array_sort_with_data:
+ * @array: a #GPtrArray.
+ * @compare_func: comparison function.
+ * @user_data: data to pass to @compare_func.
+ *
+ * Like g_ptr_array_sort(), but the comparison function has an extra
+ * user data argument.
+ *
+ * <note><para>The comparison function for g_ptr_array_sort_with_data()
+ * doesn't take the pointers from the array as arguments, it takes
+ * pointers to the pointers in the array.</para></note>
+ **/
+void
+g_ptr_array_sort_with_data (GPtrArray        *array,
+			    GCompareDataFunc  compare_func,
+			    gpointer          user_data)
+{
+  g_return_if_fail (array != NULL);
+
+  g_qsort_with_data (array->pdata,
+		     array->len,
+		     sizeof (gpointer),
+		     compare_func,
+		     user_data);
+}
+
+/**
+ * g_ptr_array_foreach:
+ * @array: a #GPtrArray
+ * @func: the function to call for each array element
+ * @user_data: user data to pass to the function
+ * 
+ * Calls a function for each element of a #GPtrArray.
+ *
+ * Since: 2.4
+ **/
+void
+g_ptr_array_foreach (GPtrArray *array,
+                     GFunc      func,
+                     gpointer   user_data)
+{
+  guint i;
+
+  g_return_if_fail (array);
+
+  for (i = 0; i < array->len; i++)
+    (*func) (array->pdata[i], user_data);
+}
+
+/**
+ * SECTION:arrays_byte
+ * @title: Byte Arrays
+ * @short_description: arrays of bytes, which grow automatically as
+ *                     elements are added
+ *
+ * #GByteArray is based on #GArray, to provide arrays of bytes which
+ * grow automatically as elements are added.
+ *
+ * To create a new #GByteArray use g_byte_array_new().
+ *
+ * To add elements to a #GByteArray, use g_byte_array_append(), and
+ * g_byte_array_prepend().
+ *
+ * To set the size of a #GByteArray, use g_byte_array_set_size().
+ *
+ * To free a #GByteArray, use g_byte_array_free().
+ *
+ * <example>
+ *  <title>Using a #GByteArray</title>
+ *  <programlisting>
+ *   GByteArray *gbarray;
+ *   gint i;
+ *
+ *   gbarray = g_byte_array_new (<!-- -->);
+ *   for (i = 0; i &lt; 10000; i++)
+ *     g_byte_array_append (gbarray, (guint8*) "abcd", 4);
+ *
+ *   for (i = 0; i &lt; 10000; i++)
+ *     {
+ *       g_assert (gbarray->data[4*i] == 'a');
+ *       g_assert (gbarray->data[4*i+1] == 'b');
+ *       g_assert (gbarray->data[4*i+2] == 'c');
+ *       g_assert (gbarray->data[4*i+3] == 'd');
+ *     }
+ *
+ *   g_byte_array_free (gbarray, TRUE);
+ *  </programlisting>
+ * </example>
+ **/
+
+/**
+ * GByteArray:
+ * @data: a pointer to the element data. The data may be moved as
+ *        elements are added to the #GByteArray.
+ * @len: the number of elements in the #GByteArray.
+ *
+ * The <structname>GByteArray</structname> struct allows access to the
+ * public fields of a <structname>GByteArray</structname>.
+ **/
+
+/**
+ * g_byte_array_new:
+ * @Returns: the new #GByteArray.
+ *
+ * Creates a new #GByteArray with a reference count of 1.
+ **/
+GByteArray* g_byte_array_new (void)
+{
+  return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, 0);
+}
+
+/**
+ * g_byte_array_sized_new:
+ * @reserved_size: number of bytes preallocated.
+ * @Returns: the new #GByteArray.
+ *
+ * Creates a new #GByteArray with @reserved_size bytes preallocated.
+ * This avoids frequent reallocation, if you are going to add many
+ * bytes to the array. Note however that the size of the array is still
+ * 0.
+ **/
+GByteArray* g_byte_array_sized_new (guint reserved_size)
+{
+  return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, reserved_size);
+}
+
+/**
+ * g_byte_array_free:
+ * @array: a #GByteArray.
+ * @free_segment: if %TRUE the actual byte data is freed as well.
+ * @Returns: the element data if @free_segment is %FALSE, otherwise
+ *           %NULL.  The element data should be freed using g_free().
+ *
+ * Frees the memory allocated by the #GByteArray. If @free_segment is
+ * %TRUE it frees the actual byte data. If the reference count of
+ * @array is greater than one, the #GByteArray wrapper is preserved but
+ * the size of @array will be set to zero.
+ **/
+guint8*	    g_byte_array_free     (GByteArray *array,
+			           gboolean    free_segment)
+{
+  return (guint8*) g_array_free ((GArray*) array, free_segment);
+}
+
+/**
+ * g_byte_array_ref:
+ * @array: A #GByteArray.
+ *
+ * Atomically increments the reference count of @array by one. This
+ * function is MT-safe and may be called from any thread.
+ *
+ * Returns: The passed in #GByteArray.
+ *
+ * Since: 2.22
+ **/
+GByteArray *
+g_byte_array_ref (GByteArray *array)
+{
+  return (GByteArray *) g_array_ref ((GArray *) array);
+}
+
+/**
+ * g_byte_array_unref:
+ * @array: A #GByteArray.
+ *
+ * Atomically decrements the reference count of @array by one. If the
+ * reference count drops to 0, all memory allocated by the array is
+ * released. This function is MT-safe and may be called from any
+ * thread.
+ *
+ * Since: 2.22
+ **/
+void
+g_byte_array_unref (GByteArray *array)
+{
+  g_array_unref ((GArray *) array);
+}
+
+/**
+ * g_byte_array_append:
+ * @array: a #GByteArray.
+ * @data: the byte data to be added.
+ * @len: the number of bytes to add.
+ * @Returns: the #GByteArray.
+ *
+ * Adds the given bytes to the end of the #GByteArray. The array will
+ * grow in size automatically if necessary.
+ **/
+GByteArray* g_byte_array_append   (GByteArray   *array,
+				   const guint8 *data,
+				   guint         len)
+{
+  g_array_append_vals ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+/**
+ * g_byte_array_prepend:
+ * @array: a #GByteArray.
+ * @data: the byte data to be added.
+ * @len: the number of bytes to add.
+ * @Returns: the #GByteArray.
+ *
+ * Adds the given data to the start of the #GByteArray. The array will
+ * grow in size automatically if necessary.
+ **/
+GByteArray* g_byte_array_prepend  (GByteArray   *array,
+				   const guint8 *data,
+				   guint         len)
+{
+  g_array_prepend_vals ((GArray*) array, (guint8*)data, len);
+
+  return array;
+}
+
+/**
+ * g_byte_array_set_size:
+ * @array: a #GByteArray.
+ * @length: the new size of the #GByteArray.
+ * @Returns: the #GByteArray.
+ *
+ * Sets the size of the #GByteArray, expanding it if necessary.
+ **/
+GByteArray* g_byte_array_set_size (GByteArray *array,
+				   guint       length)
+{
+  g_array_set_size ((GArray*) array, length);
+
+  return array;
+}
+
+/**
+ * g_byte_array_remove_index:
+ * @array: a #GByteArray.
+ * @index_: the index of the byte to remove.
+ * @Returns: the #GByteArray.
+ *
+ * Removes the byte at the given index from a #GByteArray. The
+ * following bytes are moved down one place.
+ **/
+GByteArray* g_byte_array_remove_index (GByteArray *array,
+				       guint       index_)
+{
+  g_array_remove_index ((GArray*) array, index_);
+
+  return array;
+}
+
+/**
+ * g_byte_array_remove_index_fast:
+ * @array: a #GByteArray.
+ * @index_: the index of the byte to remove.
+ * @Returns: the #GByteArray.
+ *
+ * Removes the byte at the given index from a #GByteArray. The last
+ * element in the array is used to fill in the space, so this function
+ * does not preserve the order of the #GByteArray. But it is faster
+ * than g_byte_array_remove_index().
+ **/
+GByteArray* g_byte_array_remove_index_fast (GByteArray *array,
+					    guint       index_)
+{
+  g_array_remove_index_fast ((GArray*) array, index_);
+
+  return array;
+}
+
+/**
+ * g_byte_array_remove_range:
+ * @array: a @GByteArray.
+ * @index_: the index of the first byte to remove.
+ * @length: the number of bytes to remove.
+ * @Returns: the #GByteArray.
+ *
+ * Removes the given number of bytes starting at the given index from a
+ * #GByteArray.  The following elements are moved to close the gap.
+ *
+ * Since: 2.4
+ **/
+GByteArray*
+g_byte_array_remove_range (GByteArray *array,
+                           guint       index_,
+                           guint       length)
+{
+  g_return_val_if_fail (array, NULL);
+  g_return_val_if_fail (index_ < array->len, NULL);
+  g_return_val_if_fail (index_ + length <= array->len, NULL);
+
+  return (GByteArray *)g_array_remove_range ((GArray*) array, index_, length);
+}
+
+/**
+ * g_byte_array_sort:
+ * @array: a #GByteArray.
+ * @compare_func: comparison function.
+ *
+ * Sorts a byte array, using @compare_func which should be a
+ * qsort()-style comparison function (returns less than zero for first
+ * arg is less than second arg, zero for equal, greater than zero if
+ * first arg is greater than second arg).
+ *
+ * If two array elements compare equal, their order in the sorted array
+ * is undefined. If you want equal elements to keep their order &#8211; i.e.
+ * you want a stable sort &#8211; you can write a comparison function that,
+ * if two elements would otherwise compare equal, compares them by
+ * their addresses.
+ **/
+void
+g_byte_array_sort (GByteArray   *array,
+		   GCompareFunc  compare_func)
+{
+  g_array_sort ((GArray *) array, compare_func);
+}
+
+/**
+ * g_byte_array_sort_with_data:
+ * @array: a #GByteArray.
+ * @compare_func: comparison function.
+ * @user_data: data to pass to @compare_func.
+ *
+ * Like g_byte_array_sort(), but the comparison function takes an extra
+ * user data argument.
+ **/
+void
+g_byte_array_sort_with_data (GByteArray       *array,
+			     GCompareDataFunc  compare_func,
+			     gpointer          user_data)
+{
+  g_array_sort_with_data ((GArray *) array, compare_func, user_data);
+}
diff --git a/deps/glib/garray.h b/deps/glib/garray.h
new file mode 100644
index 0000000..8221806
--- /dev/null
+++ b/deps/glib/garray.h
@@ -0,0 +1,181 @@
+/* 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_ARRAY_H__
+#define __G_ARRAY_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GArray		GArray;
+typedef struct _GByteArray	GByteArray;
+typedef struct _GPtrArray	GPtrArray;
+
+struct _GArray
+{
+  gchar *data;
+  guint len;
+};
+
+struct _GByteArray
+{
+  guint8 *data;
+  guint	  len;
+};
+
+struct _GPtrArray
+{
+  gpointer *pdata;
+  guint	    len;
+};
+
+/* Resizable arrays. remove fills any cleared spot and shortens the
+ * array, while preserving the order. remove_fast will distort the
+ * order by moving the last element to the position of the removed.
+ */
+
+#define g_array_append_val(a,v)	  g_array_append_vals (a, &(v), 1)
+#define g_array_prepend_val(a,v)  g_array_prepend_vals (a, &(v), 1)
+#define g_array_insert_val(a,i,v) g_array_insert_vals (a, i, &(v), 1)
+#define g_array_index(a,t,i)      (((t*) (void *) (a)->data) [(i)])
+
+GArray* g_array_new               (gboolean          zero_terminated,
+				   gboolean          clear_,
+				   guint             element_size);
+GArray* g_array_sized_new         (gboolean          zero_terminated,
+				   gboolean          clear_,
+				   guint             element_size,
+				   guint             reserved_size);
+gchar*  g_array_free              (GArray           *array,
+				   gboolean          free_segment);
+GArray *g_array_ref               (GArray           *array);
+void    g_array_unref             (GArray           *array);
+guint   g_array_get_element_size  (GArray           *array);
+GArray* g_array_append_vals       (GArray           *array,
+				   gconstpointer     data,
+				   guint             len);
+GArray* g_array_prepend_vals      (GArray           *array,
+				   gconstpointer     data,
+				   guint             len);
+GArray* g_array_insert_vals       (GArray           *array,
+				   guint             index_,
+				   gconstpointer     data,
+				   guint             len);
+GArray* g_array_set_size          (GArray           *array,
+				   guint             length);
+GArray* g_array_remove_index      (GArray           *array,
+				   guint             index_);
+GArray* g_array_remove_index_fast (GArray           *array,
+				   guint             index_);
+GArray* g_array_remove_range      (GArray           *array,
+				   guint             index_,
+				   guint             length);
+void    g_array_sort              (GArray           *array,
+				   GCompareFunc      compare_func);
+void    g_array_sort_with_data    (GArray           *array,
+				   GCompareDataFunc  compare_func,
+				   gpointer          user_data);
+
+/* Resizable pointer array.  This interface is much less complicated
+ * than the above.  Add appends a pointer.  Remove fills any cleared 
+ * spot and shortens the array. remove_fast will again distort order.  
+ */
+#define    g_ptr_array_index(array,index_) ((array)->pdata)[index_]
+GPtrArray* g_ptr_array_new                (void);
+GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify    element_free_func);
+GPtrArray* g_ptr_array_sized_new          (guint             reserved_size);
+GPtrArray* g_ptr_array_new_full           (guint             reserved_size,
+					   GDestroyNotify    element_free_func);
+gpointer*  g_ptr_array_free               (GPtrArray        *array,
+					   gboolean          free_seg);
+GPtrArray* g_ptr_array_ref                (GPtrArray        *array);
+void       g_ptr_array_unref              (GPtrArray        *array);
+void       g_ptr_array_set_free_func      (GPtrArray        *array,
+                                           GDestroyNotify    element_free_func);
+void       g_ptr_array_set_size           (GPtrArray        *array,
+					   gint              length);
+gpointer   g_ptr_array_remove_index       (GPtrArray        *array,
+					   guint             index_);
+gpointer   g_ptr_array_remove_index_fast  (GPtrArray        *array,
+					   guint             index_);
+gboolean   g_ptr_array_remove             (GPtrArray        *array,
+					   gpointer          data);
+gboolean   g_ptr_array_remove_fast        (GPtrArray        *array,
+					   gpointer          data);
+void       g_ptr_array_remove_range       (GPtrArray        *array,
+					   guint             index_,
+					   guint             length);
+void       g_ptr_array_add                (GPtrArray        *array,
+					   gpointer          data);
+void       g_ptr_array_sort               (GPtrArray        *array,
+					   GCompareFunc      compare_func);
+void       g_ptr_array_sort_with_data     (GPtrArray        *array,
+					   GCompareDataFunc  compare_func,
+					   gpointer          user_data);
+void       g_ptr_array_foreach            (GPtrArray        *array,
+					   GFunc             func,
+					   gpointer          user_data);
+
+
+/* Byte arrays, an array of guint8.  Implemented as a GArray,
+ * but type-safe.
+ */
+
+GByteArray* g_byte_array_new               (void);
+GByteArray* g_byte_array_sized_new         (guint             reserved_size);
+guint8*     g_byte_array_free              (GByteArray       *array,
+					    gboolean          free_segment);
+GByteArray *g_byte_array_ref               (GByteArray       *array);
+void        g_byte_array_unref             (GByteArray       *array);
+GByteArray* g_byte_array_append            (GByteArray       *array,
+					    const guint8     *data,
+					    guint             len);
+GByteArray* g_byte_array_prepend           (GByteArray       *array,
+					    const guint8     *data,
+					    guint             len);
+GByteArray* g_byte_array_set_size          (GByteArray       *array,
+					    guint             length);
+GByteArray* g_byte_array_remove_index      (GByteArray       *array,
+					    guint             index_);
+GByteArray* g_byte_array_remove_index_fast (GByteArray       *array,
+					    guint             index_);
+GByteArray* g_byte_array_remove_range      (GByteArray       *array,
+					    guint             index_,
+					    guint             length);
+void        g_byte_array_sort              (GByteArray       *array,
+					    GCompareFunc      compare_func);
+void        g_byte_array_sort_with_data    (GByteArray       *array,
+					    GCompareDataFunc  compare_func,
+					    gpointer          user_data);
+
+G_END_DECLS
+
+#endif /* __G_ARRAY_H__ */
diff --git a/deps/glib/gdataset.c b/deps/glib/gdataset.c
new file mode 100644
index 0000000..ce6d1b7
--- /dev/null
+++ b/deps/glib/gdataset.c
@@ -0,0 +1,1355 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gdataset.c: Generic dataset mechanism, similar to GtkObject data.
+ * Copyright (C) 1998 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.
+ */
+
+/*
+ * 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 ; except for g_data*_foreach()
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gdataset.h"
+#include "gbitlock.h"
+
+#include "gdatasetprivate.h"
+#include "ghash.h"
+#include "gquark.h"
+#include "gstrfuncs.h"
+#include "gtestutils.h"
+#include "gthread.h"
+#include "glib_trace.h"
+
+/**
+ * SECTION:datasets
+ * @title: Datasets
+ * @short_description: associate groups of data elements with
+ *                     particular memory locations
+ *
+ * Datasets associate groups of data elements with particular memory
+ * locations. These are useful if you need to associate data with a
+ * structure returned from an external library. Since you cannot modify
+ * the structure, you use its location in memory as the key into a
+ * dataset, where you can associate any number of data elements with it.
+ *
+ * There are two forms of most of the dataset functions. The first form
+ * uses strings to identify the data elements associated with a
+ * location. The second form uses #GQuark identifiers, which are
+ * created with a call to g_quark_from_string() or
+ * g_quark_from_static_string(). The second form is quicker, since it
+ * does not require looking up the string in the hash table of #GQuark
+ * identifiers.
+ *
+ * There is no function to create a dataset. It is automatically
+ * created as soon as you add elements to it.
+ *
+ * To add data elements to a dataset use g_dataset_id_set_data(),
+ * g_dataset_id_set_data_full(), g_dataset_set_data() and
+ * g_dataset_set_data_full().
+ *
+ * To get data elements from a dataset use g_dataset_id_get_data() and
+ * g_dataset_get_data().
+ *
+ * To iterate over all data elements in a dataset use
+ * g_dataset_foreach() (not thread-safe).
+ *
+ * To remove data elements from a dataset use
+ * g_dataset_id_remove_data() and g_dataset_remove_data().
+ *
+ * To destroy a dataset, use g_dataset_destroy().
+ **/
+
+/**
+ * SECTION:datalist
+ * @title: Keyed Data Lists
+ * @short_description: lists of data elements which are accessible by a
+ *                     string or GQuark identifier
+ *
+ * Keyed data lists provide lists of arbitrary data elements which can
+ * be accessed either with a string or with a #GQuark corresponding to
+ * the string.
+ *
+ * The #GQuark methods are quicker, since the strings have to be
+ * converted to #GQuarks anyway.
+ *
+ * Data lists are used for associating arbitrary data with #GObjects,
+ * using g_object_set_data() and related functions.
+ *
+ * To create a datalist, use g_datalist_init().
+ *
+ * To add data elements to a datalist use g_datalist_id_set_data(),
+ * g_datalist_id_set_data_full(), g_datalist_set_data() and
+ * g_datalist_set_data_full().
+ *
+ * To get data elements from a datalist use g_datalist_id_get_data()
+ * and g_datalist_get_data().
+ *
+ * To iterate over all data elements in a datalist use
+ * g_datalist_foreach() (not thread-safe).
+ *
+ * To remove data elements from a datalist use
+ * g_datalist_id_remove_data() and g_datalist_remove_data().
+ *
+ * To remove all data elements from a datalist, use g_datalist_clear().
+ **/
+
+/**
+ * GData:
+ *
+ * The #GData struct is an opaque data structure to represent a <link
+ * linkend="glib-Keyed-Data-Lists">Keyed Data List</link>. It should
+ * only be accessed via the following functions.
+ **/
+
+/**
+ * GDestroyNotify:
+ * @data: the data element.
+ *
+ * Specifies the type of function which is called when a data element
+ * is destroyed. It is passed the pointer to the data element and
+ * should free any memory and resources allocated for it.
+ **/
+
+/* --- defines --- */
+#define	G_QUARK_BLOCK_SIZE			(2048)
+
+#define G_DATALIST_FLAGS_MASK_INTERNAL 0x7
+
+/* datalist pointer accesses have to be carried out atomically */
+#define G_DATALIST_GET_POINTER(datalist)						\
+  ((GData*) ((gsize) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK_INTERNAL))
+
+#define G_DATALIST_SET_POINTER(datalist, pointer)       G_STMT_START {                  \
+  gpointer _oldv, _newv;                                                                \
+  do {                                                                                  \
+    _oldv = g_atomic_pointer_get (datalist);                                            \
+    _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK_INTERNAL) | (gsize) pointer);     \
+  } while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, _oldv, _newv));   \
+} G_STMT_END
+
+/* --- structures --- */
+typedef struct {
+  GQuark          key;
+  gpointer        data;
+  GDestroyNotify  destroy;
+} GDataElt;
+
+typedef struct _GDataset GDataset;
+struct _GData
+{
+  guint32  len;     /* Number of elements */
+  guint32  alloc;   /* Number of allocated elements */
+  GDataElt data[1]; /* Flexible array */
+};
+
+struct _GDataset
+{
+  gconstpointer location;
+  GData        *datalist;
+};
+
+
+/* --- prototypes --- */
+static inline GDataset*	g_dataset_lookup		(gconstpointer	  dataset_location);
+static inline void	g_datalist_clear_i		(GData		**datalist);
+static void		g_dataset_destroy_internal	(GDataset	 *dataset);
+static inline gpointer	g_data_set_internal		(GData     	**datalist,
+							 GQuark   	  key_id,
+							 gpointer         data,
+							 GDestroyNotify   destroy_func,
+							 GDataset	 *dataset);
+static void		g_data_initialize		(void);
+static inline GQuark	g_quark_new			(gchar  	*string);
+
+
+/* Locking model: 
+ * Each standalone GDataList is protected by a bitlock in the datalist pointer,
+ * which protects that modification of the non-flags part of the datalist pointer
+ * and the contents of the datalist.
+ *
+ * For GDataSet we have a global lock g_dataset_global that protects
+ * the global dataset hash and cache, and additionally it protects the
+ * datalist such that we can avoid to use the bit lock in a few places
+ * where it is easy.
+ */
+
+/* --- variables --- */
+G_LOCK_DEFINE_STATIC (g_dataset_global);
+static GHashTable   *g_dataset_location_ht = NULL;
+static GDataset     *g_dataset_cached = NULL; /* should this be
+						 threadspecific? */
+G_LOCK_DEFINE_STATIC (g_quark_global);
+static GHashTable   *g_quark_ht = NULL;
+static gchar       **g_quarks = NULL;
+static int           g_quark_seq_id = 0;
+
+/* --- functions --- */
+
+#define DATALIST_LOCK_BIT 2
+
+static void
+g_datalist_lock (GData **datalist)
+{
+  g_pointer_bit_lock ((void **)datalist, DATALIST_LOCK_BIT);
+}
+
+static void
+g_datalist_unlock (GData **datalist)
+{
+  g_pointer_bit_unlock ((void **)datalist, DATALIST_LOCK_BIT);
+}
+
+/* Called with the datalist lock held, or the dataset global
+ * lock for dataset lists
+ */
+static void
+g_datalist_clear_i (GData **datalist)
+{
+  GData *data;
+  gint i;
+
+  data = G_DATALIST_GET_POINTER (datalist);
+  G_DATALIST_SET_POINTER (datalist, NULL);
+
+  if (data)
+    {
+      G_UNLOCK (g_dataset_global);
+      for (i = 0; i < data->len; i++)
+        {
+          if (data->data[i].data && data->data[i].destroy)
+            data->data[i].destroy (data->data[i].data);
+        }
+      G_LOCK (g_dataset_global);
+
+      g_free (data);
+    }
+
+}
+
+/**
+ * g_datalist_clear:
+ * @datalist: a datalist.
+ *
+ * Frees all the data elements of the datalist.
+ * The data elements' destroy functions are called
+ * if they have been set.
+ **/
+void
+g_datalist_clear (GData **datalist)
+{
+  GData *data;
+  gint i;
+
+  g_return_if_fail (datalist != NULL);
+
+  g_datalist_lock (datalist);
+
+  data = G_DATALIST_GET_POINTER (datalist);
+  G_DATALIST_SET_POINTER (datalist, NULL);
+
+  g_datalist_unlock (datalist);
+
+  if (data)
+    {
+      for (i = 0; i < data->len; i++)
+        {
+          if (data->data[i].data && data->data[i].destroy)
+            data->data[i].destroy (data->data[i].data);
+        }
+
+      g_free (data);
+    }
+}
+
+/* HOLDS: g_dataset_global_lock */
+static inline GDataset*
+g_dataset_lookup (gconstpointer	dataset_location)
+{
+  register GDataset *dataset;
+  
+  if (g_dataset_cached && g_dataset_cached->location == dataset_location)
+    return g_dataset_cached;
+  
+  dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
+  if (dataset)
+    g_dataset_cached = dataset;
+  
+  return dataset;
+}
+
+/* HOLDS: g_dataset_global_lock */
+static void
+g_dataset_destroy_internal (GDataset *dataset)
+{
+  register gconstpointer dataset_location;
+  
+  dataset_location = dataset->location;
+  while (dataset)
+    {
+      if (G_DATALIST_GET_POINTER(&dataset->datalist) == NULL)
+	{
+	  if (dataset == g_dataset_cached)
+	    g_dataset_cached = NULL;
+	  g_hash_table_remove (g_dataset_location_ht, dataset_location);
+	  g_slice_free (GDataset, dataset);
+	  break;
+	}
+      
+      g_datalist_clear_i (&dataset->datalist);
+      dataset = g_dataset_lookup (dataset_location);
+    }
+}
+
+/**
+ * g_dataset_destroy:
+ * @dataset_location: the location identifying the dataset.
+ *
+ * Destroys the dataset, freeing all memory allocated, and calling any
+ * destroy functions set for data elements.
+ */
+void
+g_dataset_destroy (gconstpointer  dataset_location)
+{
+  g_return_if_fail (dataset_location != NULL);
+  
+  G_LOCK (g_dataset_global);
+  if (g_dataset_location_ht)
+    {
+      register GDataset *dataset;
+
+      dataset = g_dataset_lookup (dataset_location);
+      if (dataset)
+	g_dataset_destroy_internal (dataset);
+    }
+  G_UNLOCK (g_dataset_global);
+}
+
+/* HOLDS: g_dataset_global_lock if dataset != null */
+static inline gpointer
+g_data_set_internal (GData	  **datalist,
+		     GQuark         key_id,
+		     gpointer       new_data,
+		     GDestroyNotify new_destroy_func,
+		     GDataset	   *dataset)
+{
+  GData *d, *old_d;
+  GDataElt old, *data, *data_last, *data_end;
+
+  g_datalist_lock (datalist);
+
+  d = G_DATALIST_GET_POINTER (datalist);
+
+  if (new_data == NULL) /* remove */
+    {
+      if (d)
+	{
+	  data = d->data;
+	  data_last = data + d->len - 1;
+	  while (data <= data_last)
+	    {
+	      if (data->key == key_id)
+		{
+		  old = *data;
+		  if (data != data_last)
+		    *data = *data_last;
+		  d->len--;
+
+		  /* We don't bother to shrink, but if all data are now gone
+		   * we at least free the memory
+                   */
+		  if (d->len == 0)
+		    {
+		      G_DATALIST_SET_POINTER (datalist, NULL);
+		      g_free (d);
+
+		      /* the dataset destruction *must* be done
+		       * prior to invocation of the data destroy function
+		       */
+		      if (dataset)
+			g_dataset_destroy_internal (dataset);
+		    }
+
+		  g_datalist_unlock (datalist);
+
+		  /* We found and removed an old value
+		   * the GData struct *must* already be unlinked
+		   * when invoking the destroy function.
+		   * we use (new_data==NULL && new_destroy_func!=NULL) as
+		   * a special hint combination to "steal"
+		   * data without destroy notification
+		   */
+		  if (old.destroy && !new_destroy_func)
+		    {
+		      if (dataset)
+			G_UNLOCK (g_dataset_global);
+		      old.destroy (old.data);
+		      if (dataset)
+			G_LOCK (g_dataset_global);
+		      old.data = NULL;
+		    }
+
+		  return old.data;
+		}
+	      data++;
+	    }
+	}
+    }
+  else
+    {
+      old.data = NULL;
+      if (d)
+	{
+	  data = d->data;
+	  data_end = data + d->len;
+	  while (data < data_end)
+	    {
+	      if (data->key == key_id)
+		{
+		  if (!data->destroy)
+		    {
+		      data->data = new_data;
+		      data->destroy = new_destroy_func;
+		      g_datalist_unlock (datalist);
+		    }
+		  else
+		    {
+		      old = *data;
+		      data->data = new_data;
+		      data->destroy = new_destroy_func;
+
+		      g_datalist_unlock (datalist);
+
+		      /* We found and replaced an old value
+		       * the GData struct *must* already be unlinked
+		       * when invoking the destroy function.
+		       */
+		      if (dataset)
+			G_UNLOCK (g_dataset_global);
+		      old.destroy (old.data);
+		      if (dataset)
+			G_LOCK (g_dataset_global);
+		    }
+		  return NULL;
+		}
+	      data++;
+	    }
+	}
+
+      /* The key was not found, insert it */
+      old_d = d;
+      if (d == NULL)
+	{
+	  d = g_malloc (sizeof (GData));
+	  d->len = 0;
+	  d->alloc = 1;
+	}
+      else if (d->len == d->alloc)
+	{
+	  d->alloc = d->alloc * 2;
+	  d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt));
+	}
+      if (old_d != d)
+	G_DATALIST_SET_POINTER (datalist, d);
+
+      d->data[d->len].key = key_id;
+      d->data[d->len].data = new_data;
+      d->data[d->len].destroy = new_destroy_func;
+      d->len++;
+    }
+
+  g_datalist_unlock (datalist);
+
+  return NULL;
+
+}
+
+/**
+ * g_dataset_id_set_data_full:
+ * @dataset_location: the location identifying the dataset.
+ * @key_id: the #GQuark id to identify the data element.
+ * @data: the data element.
+ * @destroy_func: the function to call when the data element is
+ *                removed. This function will be called with the data
+ *                element and can be used to free any memory allocated
+ *                for it.
+ *
+ * Sets the data element associated with the given #GQuark id, and also
+ * the function to call when the data element is destroyed. Any
+ * previous data with the same key is removed, and its destroy function
+ * is called.
+ **/
+/**
+ * g_dataset_set_data_full:
+ * @l: the location identifying the dataset.
+ * @k: the string to identify the data element.
+ * @d: the data element.
+ * @f: the function to call when the data element is removed. This
+ *     function will be called with the data element and can be used to
+ *     free any memory allocated for it.
+ *
+ * Sets the data corresponding to the given string identifier, and the
+ * function to call when the data element is destroyed.
+ **/
+/**
+ * g_dataset_id_set_data:
+ * @l: the location identifying the dataset.
+ * @k: the #GQuark id to identify the data element.
+ * @d: the data element.
+ *
+ * Sets the data element associated with the given #GQuark id. Any
+ * previous data with the same key is removed, and its destroy function
+ * is called.
+ **/
+/**
+ * g_dataset_set_data:
+ * @l: the location identifying the dataset.
+ * @k: the string to identify the data element.
+ * @d: the data element.
+ *
+ * Sets the data corresponding to the given string identifier.
+ **/
+/**
+ * g_dataset_id_remove_data:
+ * @l: the location identifying the dataset.
+ * @k: the #GQuark id identifying the data element.
+ *
+ * Removes a data element from a dataset. The data element's destroy
+ * function is called if it has been set.
+ **/
+/**
+ * g_dataset_remove_data:
+ * @l: the location identifying the dataset.
+ * @k: the string identifying the data element.
+ *
+ * Removes a data element corresponding to a string. Its destroy
+ * function is called if it has been set.
+ **/
+void
+g_dataset_id_set_data_full (gconstpointer  dataset_location,
+			    GQuark         key_id,
+			    gpointer       data,
+			    GDestroyNotify destroy_func)
+{
+  register GDataset *dataset;
+  
+  g_return_if_fail (dataset_location != NULL);
+  if (!data)
+    g_return_if_fail (destroy_func == NULL);
+  if (!key_id)
+    {
+      if (data)
+	g_return_if_fail (key_id > 0);
+      else
+	return;
+    }
+  
+  G_LOCK (g_dataset_global);
+  if (!g_dataset_location_ht)
+    g_data_initialize ();
+ 
+  dataset = g_dataset_lookup (dataset_location);
+  if (!dataset)
+    {
+      dataset = g_slice_new (GDataset);
+      dataset->location = dataset_location;
+      g_datalist_init (&dataset->datalist);
+      g_hash_table_insert (g_dataset_location_ht, 
+			   (gpointer) dataset->location,
+			   dataset);
+    }
+  
+  g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
+  G_UNLOCK (g_dataset_global);
+}
+
+/**
+ * g_datalist_id_set_data_full:
+ * @datalist: a datalist.
+ * @key_id: the #GQuark to identify the data element.
+ * @data: the data element or %NULL to remove any previous element
+ *        corresponding to @key_id.
+ * @destroy_func: the function to call when the data element is
+ *                removed. This function will be called with the data
+ *                element and can be used to free any memory allocated
+ *                for it. If @data is %NULL, then @destroy_func must
+ *                also be %NULL.
+ *
+ * Sets the data corresponding to the given #GQuark id, and the
+ * function to be called when the element is removed from the datalist.
+ * Any previous data with the same key is removed, and its destroy
+ * function is called.
+ **/
+/**
+ * g_datalist_set_data_full:
+ * @dl: a datalist.
+ * @k: the string to identify the data element.
+ * @d: the data element, or %NULL to remove any previous element
+ *     corresponding to @k.
+ * @f: the function to call when the data element is removed. This
+ *     function will be called with the data element and can be used to
+ *     free any memory allocated for it. If @d is %NULL, then @f must
+ *     also be %NULL.
+ *
+ * Sets the data element corresponding to the given string identifier,
+ * and the function to be called when the data element is removed.
+ **/
+/**
+ * g_datalist_id_set_data:
+ * @dl: a datalist.
+ * @q: the #GQuark to identify the data element.
+ * @d: the data element, or %NULL to remove any previous element
+ *     corresponding to @q.
+ *
+ * Sets the data corresponding to the given #GQuark id. Any previous
+ * data with the same key is removed, and its destroy function is
+ * called.
+ **/
+/**
+ * g_datalist_set_data:
+ * @dl: a datalist.
+ * @k: the string to identify the data element.
+ * @d: the data element, or %NULL to remove any previous element
+ *     corresponding to @k.
+ *
+ * Sets the data element corresponding to the given string identifier.
+ **/
+/**
+ * g_datalist_id_remove_data:
+ * @dl: a datalist.
+ * @q: the #GQuark identifying the data element.
+ *
+ * Removes an element, using its #GQuark identifier.
+ **/
+/**
+ * g_datalist_remove_data:
+ * @dl: a datalist.
+ * @k: the string identifying the data element.
+ *
+ * Removes an element using its string identifier. The data element's
+ * destroy function is called if it has been set.
+ **/
+void
+g_datalist_id_set_data_full (GData	  **datalist,
+			     GQuark         key_id,
+			     gpointer       data,
+			     GDestroyNotify destroy_func)
+{
+  g_return_if_fail (datalist != NULL);
+  if (!data)
+    g_return_if_fail (destroy_func == NULL);
+  if (!key_id)
+    {
+      if (data)
+	g_return_if_fail (key_id > 0);
+      else
+	return;
+    }
+
+  g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
+}
+
+/**
+ * g_dataset_id_remove_no_notify:
+ * @dataset_location: the location identifying the dataset.
+ * @key_id: the #GQuark ID identifying the data element.
+ * @Returns: the data previously stored at @key_id, or %NULL if none.
+ *
+ * Removes an element, without calling its destroy notification
+ * function.
+ **/
+/**
+ * g_dataset_remove_no_notify:
+ * @l: the location identifying the dataset.
+ * @k: the string identifying the data element.
+ *
+ * Removes an element, without calling its destroy notifier.
+ **/
+gpointer
+g_dataset_id_remove_no_notify (gconstpointer  dataset_location,
+			       GQuark         key_id)
+{
+  gpointer ret_data = NULL;
+
+  g_return_val_if_fail (dataset_location != NULL, NULL);
+  
+  G_LOCK (g_dataset_global);
+  if (key_id && g_dataset_location_ht)
+    {
+      GDataset *dataset;
+  
+      dataset = g_dataset_lookup (dataset_location);
+      if (dataset)
+	ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
+    } 
+  G_UNLOCK (g_dataset_global);
+
+  return ret_data;
+}
+
+/**
+ * g_datalist_id_remove_no_notify:
+ * @datalist: a datalist.
+ * @key_id: the #GQuark identifying a data element.
+ * @Returns: the data previously stored at @key_id, or %NULL if none.
+ *
+ * Removes an element, without calling its destroy notification
+ * function.
+ **/
+/**
+ * g_datalist_remove_no_notify:
+ * @dl: a datalist.
+ * @k: the string identifying the data element.
+ *
+ * Removes an element, without calling its destroy notifier.
+ **/
+gpointer
+g_datalist_id_remove_no_notify (GData	**datalist,
+				GQuark    key_id)
+{
+  gpointer ret_data = NULL;
+
+  g_return_val_if_fail (datalist != NULL, NULL);
+
+  if (key_id)
+    ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
+
+  return ret_data;
+}
+
+/**
+ * g_dataset_id_get_data:
+ * @dataset_location: the location identifying the dataset.
+ * @key_id: the #GQuark id to identify the data element.
+ * @Returns: the data element corresponding to the #GQuark, or %NULL if
+ *           it is not found.
+ *
+ * Gets the data element corresponding to a #GQuark.
+ **/
+/**
+ * g_dataset_get_data:
+ * @l: the location identifying the dataset.
+ * @k: the string identifying the data element.
+ * @Returns: the data element corresponding to the string, or %NULL if
+ *           it is not found.
+ *
+ * Gets the data element corresponding to a string.
+ **/
+gpointer
+g_dataset_id_get_data (gconstpointer  dataset_location,
+		       GQuark         key_id)
+{
+  gpointer retval = NULL;
+
+  g_return_val_if_fail (dataset_location != NULL, NULL);
+  
+  G_LOCK (g_dataset_global);
+  if (key_id && g_dataset_location_ht)
+    {
+      GDataset *dataset;
+      
+      dataset = g_dataset_lookup (dataset_location);
+      if (dataset)
+	retval = g_datalist_id_get_data (&dataset->datalist, key_id);
+    }
+  G_UNLOCK (g_dataset_global);
+ 
+  return retval;
+}
+
+/**
+ * g_datalist_id_get_data:
+ * @datalist: a datalist.
+ * @key_id: the #GQuark identifying a data element.
+ * @Returns: the data element, or %NULL if it is not found.
+ *
+ * Retrieves the data element corresponding to @key_id.
+ **/
+gpointer
+g_datalist_id_get_data (GData	 **datalist,
+			GQuark     key_id)
+{
+  gpointer res = NULL;
+
+  g_return_val_if_fail (datalist != NULL, NULL);
+  if (key_id)
+    {
+      GData *d;
+      GDataElt *data, *data_end;
+
+      g_datalist_lock (datalist);
+
+      d = G_DATALIST_GET_POINTER (datalist);
+      if (d)
+	{
+	  data = d->data;
+	  data_end = data + d->len;
+	  while (data < data_end)
+	    {
+	      if (data->key == key_id)
+		{
+		  res = data->data;
+		  break;
+		}
+	      data++;
+	    }
+	}
+
+      g_datalist_unlock (datalist);
+    }
+
+  return res;
+}
+
+/**
+ * g_datalist_get_data:
+ * @datalist: a datalist.
+ * @key: the string identifying a data element.
+ * @Returns: the data element, or %NULL if it is not found.
+ *
+ * Gets a data element, using its string identifer. This is slower than
+ * g_datalist_id_get_data() because it compares strings.
+ **/
+gpointer
+g_datalist_get_data (GData	 **datalist,
+		     const gchar *key)
+{
+  gpointer res = NULL;
+  GData *d;
+  GDataElt *data, *data_end;
+
+  g_return_val_if_fail (datalist != NULL, NULL);
+
+  g_datalist_lock (datalist);
+
+  d = G_DATALIST_GET_POINTER (datalist);
+  if (d)
+    {
+      data = d->data;
+      data_end = data + d->len;
+      while (data < data_end)
+	{
+	  if (strcmp (g_quark_to_string (data->key), key) == 0)
+	    {
+	      res = data->data;
+	      break;
+	    }
+	  data++;
+	}
+    }
+
+  g_datalist_unlock (datalist);
+
+  return res;
+}
+
+/**
+ * GDataForeachFunc:
+ * @key_id: the #GQuark id to identifying the data element.
+ * @data: the data element.
+ * @user_data: user data passed to g_dataset_foreach().
+ *
+ * Specifies the type of function passed to g_dataset_foreach(). It is
+ * called with each #GQuark id and associated data element, together
+ * with the @user_data parameter supplied to g_dataset_foreach().
+ **/
+
+/**
+ * g_dataset_foreach:
+ * @dataset_location: the location identifying the dataset.
+ * @func: the function to call for each data element.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each data element which is associated
+ * with the given location. Note that this function is NOT thread-safe.
+ * So unless @datalist can be protected from any modifications during
+ * invocation of this function, it should not be called.
+ **/
+void
+g_dataset_foreach (gconstpointer    dataset_location,
+		   GDataForeachFunc func,
+		   gpointer         user_data)
+{
+  register GDataset *dataset;
+  
+  g_return_if_fail (dataset_location != NULL);
+  g_return_if_fail (func != NULL);
+
+  G_LOCK (g_dataset_global);
+  if (g_dataset_location_ht)
+    {
+      dataset = g_dataset_lookup (dataset_location);
+      G_UNLOCK (g_dataset_global);
+      if (dataset)
+	g_datalist_foreach (&dataset->datalist, func, user_data);
+    }
+  else
+    {
+      G_UNLOCK (g_dataset_global);
+    }
+}
+
+/**
+ * g_datalist_foreach:
+ * @datalist: a datalist.
+ * @func: the function to call for each data element.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each data element of the datalist. The
+ * function is called with each data element's #GQuark id and data,
+ * together with the given @user_data parameter. Note that this
+ * function is NOT thread-safe. So unless @datalist can be protected
+ * from any modifications during invocation of this function, it should
+ * not be called.
+ **/
+void
+g_datalist_foreach (GData	   **datalist,
+		    GDataForeachFunc func,
+		    gpointer         user_data)
+{
+  GData *d;
+  int i, j, len;
+  GQuark *keys;
+
+  g_return_if_fail (datalist != NULL);
+  g_return_if_fail (func != NULL);
+
+  d = G_DATALIST_GET_POINTER (datalist);
+  if (d == NULL) 
+    return;
+
+  /* We make a copy of the keys so that we can handle it changing
+     in the callback */
+  len = d->len;
+  keys = g_new (GQuark, len);
+  for (i = 0; i < len; i++)
+    keys[i] = d->data[i].key;
+  
+  for (i = 0; i < len; i++)
+    {
+      /* A previous callback might have removed a later item, so always check that
+	 it still exists before calling */
+      d = G_DATALIST_GET_POINTER (datalist);
+      
+      if (d == NULL)
+	break;
+      for (j = 0; j < d->len; j++)
+	{
+	  if (d->data[j].key == keys[i]) {
+	    func (d->data[i].key, d->data[i].data, user_data);
+	    break;
+	  }
+	}
+    }
+  g_free (keys);
+}
+
+/**
+ * g_datalist_init:
+ * @datalist: a pointer to a pointer to a datalist.
+ *
+ * Resets the datalist to %NULL. It does not free any memory or call
+ * any destroy functions.
+ **/
+void
+g_datalist_init (GData **datalist)
+{
+  g_return_if_fail (datalist != NULL);
+
+  g_atomic_pointer_set (datalist, NULL);
+}
+
+/**
+ * g_datalist_set_flags:
+ * @datalist: pointer to the location that holds a list
+ * @flags: the flags to turn on. The values of the flags are
+ *   restricted by %G_DATALIST_FLAGS_MASK (currently
+ *   3; giving two possible boolean flags).
+ *   A value for @flags that doesn't fit within the mask is
+ *   an error.
+ * 
+ * Turns on flag values for a data list. This function is used
+ * to keep a small number of boolean flags in an object with
+ * a data list without using any additional space. It is
+ * not generally useful except in circumstances where space
+ * is very tight. (It is used in the base #GObject type, for
+ * example.)
+ *
+ * Since: 2.8
+ **/
+void
+g_datalist_set_flags (GData **datalist,
+		      guint   flags)
+{
+  g_return_if_fail (datalist != NULL);
+  g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
+
+  g_atomic_pointer_or (datalist, (gsize)flags);
+}
+
+/**
+ * g_datalist_unset_flags:
+ * @datalist: pointer to the location that holds a list
+ * @flags: the flags to turn off. The values of the flags are
+ *   restricted by %G_DATALIST_FLAGS_MASK (currently
+ *   3: giving two possible boolean flags).
+ *   A value for @flags that doesn't fit within the mask is
+ *   an error.
+ * 
+ * Turns off flag values for a data list. See g_datalist_unset_flags()
+ *
+ * Since: 2.8
+ **/
+void
+g_datalist_unset_flags (GData **datalist,
+			guint   flags)
+{
+  g_return_if_fail (datalist != NULL);
+  g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
+
+  g_atomic_pointer_and (datalist, ~(gsize)flags);
+}
+
+/**
+ * g_datalist_get_flags:
+ * @datalist: pointer to the location that holds a list
+ * 
+ * Gets flags values packed in together with the datalist.
+ * See g_datalist_set_flags().
+ * 
+ * Return value: the flags of the datalist
+ *
+ * Since: 2.8
+ **/
+guint
+g_datalist_get_flags (GData **datalist)
+{
+  g_return_val_if_fail (datalist != NULL, 0);
+  
+  return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
+}
+
+/* HOLDS: g_dataset_global_lock */
+static void
+g_data_initialize (void)
+{
+  g_return_if_fail (g_dataset_location_ht == NULL);
+
+  g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
+  g_dataset_cached = NULL;
+}
+
+/**
+ * SECTION:quarks
+ * @title: Quarks
+ * @short_description: a 2-way association between a string and a
+ *                     unique integer identifier
+ *
+ * Quarks are associations between strings and integer identifiers.
+ * Given either the string or the #GQuark identifier it is possible to
+ * retrieve the other.
+ *
+ * Quarks are used for both <link
+ * linkend="glib-Datasets">Datasets</link> and <link
+ * linkend="glib-Keyed-Data-Lists">Keyed Data Lists</link>.
+ *
+ * To create a new quark from a string, use g_quark_from_string() or
+ * g_quark_from_static_string().
+ *
+ * To find the string corresponding to a given #GQuark, use
+ * g_quark_to_string().
+ *
+ * To find the #GQuark corresponding to a given string, use
+ * g_quark_try_string().
+ *
+ * Another use for the string pool maintained for the quark functions
+ * is string interning, using g_intern_string() or
+ * g_intern_static_string(). An interned string is a canonical
+ * representation for a string. One important advantage of interned
+ * strings is that they can be compared for equality by a simple
+ * pointer comparison, rather than using strcmp().
+ **/
+
+/**
+ * GQuark:
+ *
+ * A GQuark is a non-zero integer which uniquely identifies a
+ * particular string. A GQuark value of zero is associated to %NULL.
+ **/
+
+/**
+ * g_quark_try_string:
+ * @string: (allow-none): a string.
+ * @Returns: the #GQuark associated with the string, or 0 if @string is
+ *           %NULL or there is no #GQuark associated with it.
+ *
+ * Gets the #GQuark associated with the given string, or 0 if string is
+ * %NULL or it has no associated #GQuark.
+ *
+ * If you want the GQuark to be created if it doesn't already exist,
+ * use g_quark_from_string() or g_quark_from_static_string().
+ **/
+GQuark
+g_quark_try_string (const gchar *string)
+{
+  GQuark quark = 0;
+
+  if (string == NULL)
+    return 0;
+
+  G_LOCK (g_quark_global);
+  if (g_quark_ht)
+    quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
+  G_UNLOCK (g_quark_global);
+  
+  return quark;
+}
+
+#define QUARK_STRING_BLOCK_SIZE (4096 - sizeof (gsize))
+static char *quark_block = NULL;
+static int quark_block_offset = 0;
+
+/* HOLDS: g_quark_global_lock */
+static char *
+quark_strdup(const gchar *string)
+{
+  gchar *copy;
+  gsize len;
+
+  len = strlen (string) + 1;
+
+  /* For strings longer than half the block size, fall back
+     to strdup so that we fill our blocks at least 50%. */
+  if (len > QUARK_STRING_BLOCK_SIZE / 2)
+    return g_strdup (string);
+
+  if (quark_block == NULL ||
+      QUARK_STRING_BLOCK_SIZE - quark_block_offset < len)
+    {
+      quark_block = g_malloc (QUARK_STRING_BLOCK_SIZE);
+      quark_block_offset = 0;
+    }
+
+  copy = quark_block + quark_block_offset;
+  memcpy (copy, string, len);
+  quark_block_offset += len;
+
+  return copy;
+}
+
+/* HOLDS: g_quark_global_lock */
+static inline GQuark
+g_quark_from_string_internal (const gchar *string, 
+			      gboolean     duplicate)
+{
+  GQuark quark = 0;
+  
+  if (g_quark_ht)
+    quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
+  
+  if (!quark)
+    {
+      quark = g_quark_new (duplicate ? quark_strdup (string) : (gchar *)string);
+      TRACE(GLIB_QUARK_NEW(string, quark));
+    }
+
+  return quark;
+}
+
+/**
+ * g_quark_from_string:
+ * @string: (allow-none): a string.
+ * @Returns: the #GQuark identifying the string, or 0 if @string is
+ *           %NULL.
+ *
+ * Gets the #GQuark identifying the given string. If the string does
+ * not currently have an associated #GQuark, a new #GQuark is created,
+ * using a copy of the string.
+ **/
+GQuark
+g_quark_from_string (const gchar *string)
+{
+  GQuark quark;
+  
+  if (!string)
+    return 0;
+  
+  G_LOCK (g_quark_global);
+  quark = g_quark_from_string_internal (string, TRUE);
+  G_UNLOCK (g_quark_global);
+  
+  return quark;
+}
+
+/**
+ * g_quark_from_static_string:
+ * @string: (allow-none): a string.
+ * @Returns: the #GQuark identifying the string, or 0 if @string is
+ *           %NULL.
+ *
+ * Gets the #GQuark identifying the given (static) string. If the
+ * string does not currently have an associated #GQuark, a new #GQuark
+ * is created, linked to the given string.
+ *
+ * Note that this function is identical to g_quark_from_string() except
+ * that if a new #GQuark is created the string itself is used rather
+ * than a copy. This saves memory, but can only be used if the string
+ * will <emphasis>always</emphasis> exist. It can be used with
+ * statically allocated strings in the main program, but not with
+ * statically allocated memory in dynamically loaded modules, if you
+ * expect to ever unload the module again (e.g. do not use this
+ * function in GTK+ theme engines).
+ **/
+GQuark
+g_quark_from_static_string (const gchar *string)
+{
+  GQuark quark;
+  
+  if (!string)
+    return 0;
+  
+  G_LOCK (g_quark_global);
+  quark = g_quark_from_string_internal (string, FALSE);
+  G_UNLOCK (g_quark_global);
+
+  return quark;
+}
+
+/**
+ * g_quark_to_string:
+ * @quark: a #GQuark.
+ * @Returns: the string associated with the #GQuark.
+ *
+ * Gets the string associated with the given #GQuark.
+ **/
+const gchar *
+g_quark_to_string (GQuark quark)
+{
+  gchar* result = NULL;
+  gchar **quarks;
+  gint quark_seq_id;
+
+  quark_seq_id = g_atomic_int_get (&g_quark_seq_id);
+  quarks = g_atomic_pointer_get (&g_quarks);
+
+  if (quark < quark_seq_id)
+    result = quarks[quark];
+
+  return result;
+}
+
+/* HOLDS: g_quark_global_lock */
+static inline GQuark
+g_quark_new (gchar *string)
+{
+  GQuark quark;
+  gchar **g_quarks_new;
+  
+  if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
+    {
+      g_quarks_new = g_new (gchar*, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
+      if (g_quark_seq_id != 0)
+	memcpy (g_quarks_new, g_quarks, sizeof (char *) * g_quark_seq_id);
+      memset (g_quarks_new + g_quark_seq_id, 0, sizeof (char *) * G_QUARK_BLOCK_SIZE);
+      /* This leaks the old quarks array. Its unfortunate, but it allows
+	 us to do lockless lookup of the arrays, and there shouldn't be that
+	 many quarks in an app */
+      g_atomic_pointer_set (&g_quarks, g_quarks_new);
+    }
+  if (!g_quark_ht)
+    {
+      g_assert (g_quark_seq_id == 0);
+      g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
+      g_quarks[g_quark_seq_id] = NULL;
+      g_atomic_int_inc (&g_quark_seq_id);
+    }
+
+  quark = g_quark_seq_id;
+  g_atomic_pointer_set (&g_quarks[quark], string);
+  g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
+  g_atomic_int_inc (&g_quark_seq_id);
+
+  return quark;
+}
+
+/**
+ * g_intern_string:
+ * @string: (allow-none): a string
+ * 
+ * Returns a canonical representation for @string. Interned strings can
+ * be compared for equality by comparing the pointers, instead of using strcmp().
+ * 
+ * Returns: a canonical representation for the string
+ *
+ * Since: 2.10
+ */
+const gchar *
+g_intern_string (const gchar *string)
+{
+  const gchar *result;
+  GQuark quark;
+
+  if (!string)
+    return NULL;
+
+  G_LOCK (g_quark_global);
+  quark = g_quark_from_string_internal (string, TRUE);
+  result = g_quarks[quark];
+  G_UNLOCK (g_quark_global);
+
+  return result;
+}
+
+/**
+ * g_intern_static_string:
+ * @string: (allow-none): a static string
+ * 
+ * Returns a canonical representation for @string. Interned strings can
+ * be compared for equality by comparing the pointers, instead of using strcmp().
+ * g_intern_static_string() does not copy the string, therefore @string must
+ * not be freed or modified. 
+ * 
+ * Returns: a canonical representation for the string
+ *
+ * Since: 2.10
+ */
+const gchar *
+g_intern_static_string (const gchar *string)
+{
+  GQuark quark;
+  const gchar *result;
+
+  if (!string)
+    return NULL;
+
+  G_LOCK (g_quark_global);
+  quark = g_quark_from_string_internal (string, FALSE);
+  result = g_quarks[quark];
+  G_UNLOCK (g_quark_global);
+
+  return result;
+}
diff --git a/deps/glib/gdataset.h b/deps/glib/gdataset.h
new file mode 100644
index 0000000..4451c38
--- /dev/null
+++ b/deps/glib/gdataset.h
@@ -0,0 +1,122 @@
+/* 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_DATASET_H__
+#define __G_DATASET_H__
+
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GData           GData;
+
+typedef void            (*GDataForeachFunc)     (GQuark         key_id,
+                                                 gpointer       data,
+                                                 gpointer       user_data);
+
+/* Keyed Data List
+ */
+void     g_datalist_init                (GData            **datalist);
+void     g_datalist_clear               (GData            **datalist);
+gpointer g_datalist_id_get_data         (GData            **datalist,
+					 GQuark             key_id);
+void     g_datalist_id_set_data_full    (GData            **datalist,
+					 GQuark             key_id,
+					 gpointer           data,
+					 GDestroyNotify     destroy_func);
+gpointer g_datalist_id_remove_no_notify (GData            **datalist,
+					 GQuark             key_id);
+void     g_datalist_foreach             (GData            **datalist,
+					 GDataForeachFunc   func,
+					 gpointer           user_data);
+
+/**
+ * G_DATALIST_FLAGS_MASK:
+ *
+ * A bitmask that restricts the possible flags passed to
+ * g_datalist_set_flags(). Passing a flags value where
+ * flags & ~G_DATALIST_FLAGS_MASK != 0 is an error.
+ */
+#define G_DATALIST_FLAGS_MASK 0x3
+
+void     g_datalist_set_flags           (GData            **datalist,
+					 guint              flags);
+void     g_datalist_unset_flags         (GData            **datalist,
+					 guint              flags);
+guint    g_datalist_get_flags           (GData            **datalist);
+
+#define   g_datalist_id_set_data(dl, q, d)      \
+     g_datalist_id_set_data_full ((dl), (q), (d), NULL)
+#define   g_datalist_id_remove_data(dl, q)      \
+     g_datalist_id_set_data ((dl), (q), NULL)
+#define   g_datalist_set_data_full(dl, k, d, f) \
+     g_datalist_id_set_data_full ((dl), g_quark_from_string (k), (d), (f))
+#define   g_datalist_remove_no_notify(dl, k)    \
+     g_datalist_id_remove_no_notify ((dl), g_quark_try_string (k))
+#define   g_datalist_set_data(dl, k, d)         \
+     g_datalist_set_data_full ((dl), (k), (d), NULL)
+#define   g_datalist_remove_data(dl, k)         \
+     g_datalist_id_set_data ((dl), g_quark_try_string (k), NULL)
+
+
+/* Location Associated Keyed Data
+ */
+void      g_dataset_destroy             (gconstpointer    dataset_location);
+gpointer  g_dataset_id_get_data         (gconstpointer    dataset_location,
+                                         GQuark           key_id);
+gpointer  g_datalist_get_data            (GData	 **datalist,
+					  const gchar *key);
+void      g_dataset_id_set_data_full    (gconstpointer    dataset_location,
+                                         GQuark           key_id,
+                                         gpointer         data,
+                                         GDestroyNotify   destroy_func);
+gpointer  g_dataset_id_remove_no_notify (gconstpointer    dataset_location,
+                                         GQuark           key_id);
+void      g_dataset_foreach             (gconstpointer    dataset_location,
+                                         GDataForeachFunc func,
+                                         gpointer         user_data);
+#define   g_dataset_id_set_data(l, k, d)        \
+     g_dataset_id_set_data_full ((l), (k), (d), NULL)
+#define   g_dataset_id_remove_data(l, k)        \
+     g_dataset_id_set_data ((l), (k), NULL)
+#define   g_dataset_get_data(l, k)              \
+     (g_dataset_id_get_data ((l), g_quark_try_string (k)))
+#define   g_dataset_set_data_full(l, k, d, f)   \
+     g_dataset_id_set_data_full ((l), g_quark_from_string (k), (d), (f))
+#define   g_dataset_remove_no_notify(l, k)      \
+     g_dataset_id_remove_no_notify ((l), g_quark_try_string (k))
+#define   g_dataset_set_data(l, k, d)           \
+     g_dataset_set_data_full ((l), (k), (d), NULL)
+#define   g_dataset_remove_data(l, k)           \
+     g_dataset_id_set_data ((l), g_quark_try_string (k), NULL)
+
+G_END_DECLS
+
+#endif /* __G_DATASET_H__ */
diff --git a/deps/glib/gdatasetprivate.h b/deps/glib/gdatasetprivate.h
new file mode 100644
index 0000000..80d0ccf
--- /dev/null
+++ b/deps/glib/gdatasetprivate.h
@@ -0,0 +1,44 @@
+/* GLIB - Library of useful routines for C programming
+ * gdataset-private.h: Internal macros for accessing dataset values
+ * Copyright (C) 2005  Red Hat
+ *
+ * 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/. 
+ */
+
+#ifndef __G_DATASETPRIVATE_H__
+#define __G_DATASETPRIVATE_H__
+
+#include <gatomic.h>
+
+G_BEGIN_DECLS
+
+/* GET_FLAGS is implemented via atomic pointer access, to allow memory
+ * barriers to take effect without acquiring the global dataset mutex.
+ */
+#define G_DATALIST_GET_FLAGS(datalist)				\
+  ((gsize) g_atomic_pointer_get (datalist) & G_DATALIST_FLAGS_MASK)
+
+
+G_END_DECLS
+
+#endif /* __G_DATASETPRIVATE_H__ */
diff --git a/deps/glib/gerror.c b/deps/glib/gerror.c
new file mode 100644
index 0000000..015d709
--- /dev/null
+++ b/deps/glib/gerror.c
@@ -0,0 +1,711 @@
+/* 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/.
+ */
+
+/**
+ * SECTION:error_reporting
+ * @Title: Error Reporting
+ * @Short_description: a system for reporting errors
+ *
+ * GLib provides a standard method of reporting errors from a called
+ * function to the calling code. (This is the same problem solved by
+ * exceptions in other languages.) It's important to understand that
+ * this method is both a <emphasis>data type</emphasis> (the #GError
+ * object) and a <emphasis>set of rules.</emphasis> If you use #GError
+ * incorrectly, then your code will not properly interoperate with other
+ * code that uses #GError, and users of your API will probably get confused.
+ *
+ * First and foremost: <emphasis>#GError should only be used to report
+ * recoverable runtime errors, never to report programming
+ * errors.</emphasis> If the programmer has screwed up, then you should
+ * use g_warning(), g_return_if_fail(), g_assert(), g_error(), or some
+ * similar facility. (Incidentally, remember that the g_error() function
+ * should <emphasis>only</emphasis> be used for programming errors, it
+ * should not be used to print any error reportable via #GError.)
+ *
+ * Examples of recoverable runtime errors are "file not found" or
+ * "failed to parse input." Examples of programming errors are "NULL
+ * passed to strcmp()" or "attempted to free the same pointer twice."
+ * These two kinds of errors are fundamentally different: runtime errors
+ * should be handled or reported to the user, programming errors should
+ * be eliminated by fixing the bug in the program. This is why most
+ * functions in GLib and GTK+ do not use the #GError facility.
+ *
+ * Functions that can fail take a return location for a #GError as their
+ * last argument. For example:
+ * |[
+ * gboolean g_file_get_contents (const gchar  *filename,
+ *                               gchar       **contents,
+ *                               gsize        *length,
+ *                               GError      **error);
+ * ]|
+ * If you pass a non-%NULL value for the <literal>error</literal>
+ * argument, it should point to a location where an error can be placed.
+ * For example:
+ * |[
+ * gchar *contents;
+ * GError *err = NULL;
+ * g_file_get_contents ("foo.txt", &amp;contents, NULL, &amp;err);
+ * g_assert ((contents == NULL &amp;&amp; err != NULL) || (contents != NULL &amp;&amp; err == NULL));
+ * if (err != NULL)
+ *   {
+ *     /&ast; Report error to user, and free error &ast;/
+ *     g_assert (contents == NULL);
+ *     fprintf (stderr, "Unable to read file: &percnt;s\n", err->message);
+ *     g_error_free (err);
+ *   }
+ * else
+ *   {
+ *     /&ast; Use file contents &ast;/
+ *     g_assert (contents != NULL);
+ *   }
+ * ]|
+ * Note that <literal>err != NULL</literal> in this example is a
+ * <emphasis>reliable</emphasis> indicator of whether
+ * g_file_get_contents() failed. Additionally, g_file_get_contents()
+ * returns a boolean which indicates whether it was successful.
+ *
+ * Because g_file_get_contents() returns %FALSE on failure, if you
+ * are only interested in whether it failed and don't need to display
+ * an error message, you can pass %NULL for the <literal>error</literal>
+ * argument:
+ * |[
+ * if (g_file_get_contents ("foo.txt", &amp;contents, NULL, NULL)) /&ast; ignore errors &ast;/
+ *   /&ast; no error occurred &ast;/ ;
+ * else
+ *   /&ast; error &ast;/ ;
+ * ]|
+ *
+ * The #GError object contains three fields: <literal>domain</literal>
+ * indicates the module the error-reporting function is located in,
+ * <literal>code</literal> indicates the specific error that occurred,
+ * and <literal>message</literal> is a user-readable error message with
+ * as many details as possible. Several functions are provided to deal
+ * with an error received from a called function: g_error_matches()
+ * returns %TRUE if the error matches a given domain and code,
+ * g_propagate_error() copies an error into an error location (so the
+ * calling function will receive it), and g_clear_error() clears an
+ * error location by freeing the error and resetting the location to
+ * %NULL. To display an error to the user, simply display
+ * <literal>error-&gt;message</literal>, perhaps along with additional
+ * context known only to the calling function (the file being opened,
+ * or whatever -- though in the g_file_get_contents() case,
+ * <literal>error-&gt;message</literal> already contains a filename).
+ *
+ * When implementing a function that can report errors, the basic
+ * tool is g_set_error(). Typically, if a fatal error occurs you
+ * want to g_set_error(), then return immediately. g_set_error()
+ * does nothing if the error location passed to it is %NULL.
+ * Here's an example:
+ * |[
+ * gint
+ * foo_open_file (GError **error)
+ * {
+ *   gint fd;
+ *
+ *   fd = open ("file.txt", O_RDONLY);
+ *
+ *   if (fd &lt; 0)
+ *     {
+ *       g_set_error (error,
+ *                    FOO_ERROR,                 /&ast; error domain &ast;/
+ *                    FOO_ERROR_BLAH,            /&ast; error code &ast;/
+ *                    "Failed to open file: &percnt;s", /&ast; error message format string &ast;/
+ *                    g_strerror (errno));
+ *       return -1;
+ *     }
+ *   else
+ *     return fd;
+ * }
+ * ]|
+ *
+ * Things are somewhat more complicated if you yourself call another
+ * function that can report a #GError. If the sub-function indicates
+ * fatal errors in some way other than reporting a #GError, such as
+ * by returning %TRUE on success, you can simply do the following:
+ * |[
+ * gboolean
+ * my_function_that_can_fail (GError **err)
+ * {
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   if (!sub_function_that_can_fail (err))
+ *     {
+ *       /&ast; assert that error was set by the sub-function &ast;/
+ *       g_assert (err == NULL || *err != NULL);
+ *       return FALSE;
+ *     }
+ *
+ *   /&ast; otherwise continue, no error occurred &ast;/
+ *   g_assert (err == NULL || *err == NULL);
+ * }
+ * ]|
+ *
+ * If the sub-function does not indicate errors other than by
+ * reporting a #GError, you need to create a temporary #GError
+ * since the passed-in one may be %NULL. g_propagate_error() is
+ * intended for use in this case.
+ * |[
+ * gboolean
+ * my_function_that_can_fail (GError **err)
+ * {
+ *   GError *tmp_error;
+ *
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   tmp_error = NULL;
+ *   sub_function_that_can_fail (&amp;tmp_error);
+ *
+ *   if (tmp_error != NULL)
+ *     {
+ *       /&ast; store tmp_error in err, if err != NULL,
+ *        &ast; otherwise call g_error_free() on tmp_error
+ *        &ast;/
+ *       g_propagate_error (err, tmp_error);
+ *       return FALSE;
+ *     }
+ *
+ *   /&ast; otherwise continue, no error occurred &ast;/
+ * }
+ * ]|
+ *
+ * Error pileups are always a bug. For example, this code is incorrect:
+ * |[
+ * gboolean
+ * my_function_that_can_fail (GError **err)
+ * {
+ *   GError *tmp_error;
+ *
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   tmp_error = NULL;
+ *   sub_function_that_can_fail (&amp;tmp_error);
+ *   other_function_that_can_fail (&amp;tmp_error);
+ *
+ *   if (tmp_error != NULL)
+ *     {
+ *       g_propagate_error (err, tmp_error);
+ *       return FALSE;
+ *     }
+ * }
+ * ]|
+ * <literal>tmp_error</literal> should be checked immediately after
+ * sub_function_that_can_fail(), and either cleared or propagated
+ * upward. The rule is: <emphasis>after each error, you must either
+ * handle the error, or return it to the calling function</emphasis>.
+ * Note that passing %NULL for the error location is the equivalent
+ * of handling an error by always doing nothing about it. So the
+ * following code is fine, assuming errors in sub_function_that_can_fail()
+ * are not fatal to my_function_that_can_fail():
+ * |[
+ * gboolean
+ * my_function_that_can_fail (GError **err)
+ * {
+ *   GError *tmp_error;
+ *
+ *   g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+ *
+ *   sub_function_that_can_fail (NULL); /&ast; ignore errors &ast;/
+ *
+ *   tmp_error = NULL;
+ *   other_function_that_can_fail (&amp;tmp_error);
+ *
+ *   if (tmp_error != NULL)
+ *     {
+ *       g_propagate_error (err, tmp_error);
+ *       return FALSE;
+ *     }
+ * }
+ * ]|
+ *
+ * Note that passing %NULL for the error location
+ * <emphasis>ignores</emphasis> errors; it's equivalent to
+ * <literal>try { sub_function_that_can_fail (); } catch (...) {}</literal>
+ * in C++. It does <emphasis>not</emphasis> mean to leave errors
+ * unhandled; it means to handle them by doing nothing.
+ *
+ * Error domains and codes are conventionally named as follows:
+ * <itemizedlist>
+ * <listitem><para>
+ *   The error domain is called
+ *   <literal>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR</literal>,
+ *   for example %G_SPAWN_ERROR or %G_THREAD_ERROR:
+ *   |[
+ * #define G_SPAWN_ERROR g_spawn_error_quark ()
+ *
+ * GQuark
+ * g_spawn_error_quark (void)
+ * {
+ *   return g_quark_from_static_string ("g-spawn-error-quark");
+ * }
+ *   ]|
+ * </para></listitem>
+ * <listitem><para>
+ *   The quark function for the error domain is called
+ *   <literal>&lt;namespace&gt;_&lt;module&gt;_error_quark</literal>,
+ *   for example g_spawn_error_quark() or %g_thread_error_quark().
+ * </para></listitem>
+ * <listitem><para>
+ *   The error codes are in an enumeration called
+ *   <literal>&lt;Namespace&gt;&lt;Module&gt;Error</literal>;
+ *   for example,#GThreadError or #GSpawnError.
+ * </para></listitem>
+ * <listitem><para>
+ *   Members of the error code enumeration are called
+ *   <literal>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR_&lt;CODE&gt;</literal>,
+ *   for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN.
+ * </para></listitem>
+ * <listitem><para>
+ *   If there's a "generic" or "unknown" error code for unrecoverable
+ *   errors it doesn't make sense to distinguish with specific codes,
+ *   it should be called <literal>&lt;NAMESPACE&gt;_&lt;MODULE&gt;_ERROR_FAILED</literal>,
+ *   for example %G_SPAWN_ERROR_FAILED or %G_THREAD_ERROR_FAILED.
+ * </para></listitem>
+ * </itemizedlist>
+ *
+ * Summary of rules for use of #GError:
+ * <itemizedlist>
+ * <listitem><para>
+ *   Do not report programming errors via #GError.
+ * </para></listitem>
+ * <listitem><para>
+ *   The last argument of a function that returns an error should
+ *   be a location where a #GError can be placed (i.e. "#GError** error").
+ *   If #GError is used with varargs, the #GError** should be the last
+ *   argument before the "...".
+ * </para></listitem>
+ * <listitem><para>
+ *   The caller may pass %NULL for the #GError** if they are not interested
+ *   in details of the exact error that occurred.
+ * </para></listitem>
+ * <listitem><para>
+ *   If %NULL is passed for the #GError** argument, then errors should
+ *   not be returned to the caller, but your function should still
+ *   abort and return if an error occurs. That is, control flow should
+ *   not be affected by whether the caller wants to get a #GError.
+ * </para></listitem>
+ * <listitem><para>
+ *   If a #GError is reported, then your function by definition
+ *   <emphasis>had a fatal failure and did not complete whatever
+ *   it was supposed to do</emphasis>. If the failure was not fatal,
+ *   then you handled it and you should not report it. If it was fatal,
+ *   then you must report it and discontinue whatever you were doing
+ *   immediately.
+ * </para></listitem>
+ * <listitem><para>
+ *   A #GError* must be initialized to %NULL before passing its address
+ *   to a function that can report errors.
+ * </para></listitem>
+ * <listitem><para>
+ *   "Piling up" errors is always a bug. That is, if you assign a
+ *   new #GError to a #GError* that is non-%NULL, thus overwriting
+ *   the previous error, it indicates that you should have aborted
+ *   the operation instead of continuing. If you were able to continue,
+ *   you should have cleared the previous error with g_clear_error().
+ *   g_set_error() will complain if you pile up errors.
+ * </para></listitem>
+ * <listitem><para>
+ *   By convention, if you return a boolean value indicating success
+ *   then %TRUE means success and %FALSE means failure. If %FALSE is
+ *   returned, the error <emphasis>must</emphasis> be set to a non-%NULL
+ *   value.
+ * </para></listitem>
+ * <listitem><para>
+ *   A %NULL return value is also frequently used to mean that an error
+ *   occurred. You should make clear in your documentation whether %NULL
+ *   is a valid return value in non-error cases; if %NULL is a valid value,
+ *   then users must check whether an error was returned to see if the
+ *   function succeeded.
+ * </para></listitem>
+ * <listitem><para>
+ *   When implementing a function that can report errors, you may want
+ *   to add a check at the top of your function that the error return
+ *   location is either %NULL or contains a %NULL error (e.g.
+ *   <literal>g_return_if_fail (error == NULL || *error == NULL);</literal>).
+ * </para></listitem>
+ * </itemizedlist>
+ */
+
+#include "config.h"
+
+#include "gerror.h"
+
+#include "gstrfuncs.h"
+#include "gtestutils.h"
+
+/**
+ * g_error_new_valist:
+ * @domain: error domain
+ * @code: error code
+ * @format: printf()-style format for error message
+ * @args: #va_list of parameters for the message format
+ *
+ * Creates a new #GError with the given @domain and @code,
+ * and a message formatted with @format.
+ *
+ * Returns: a new #GError
+ *
+ * Since: 2.22
+ */
+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
+ * @...: 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 or %NULL
+ * @domain: an error domain
+ * @code: an error code
+ *
+ * Returns %TRUE if @error matches @domain and @code, %FALSE
+ * otherwise. In particular, when @error is %NULL, %FALSE will
+ * be returned.
+ *
+ * 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
+ * @...: 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);
+    }
+}
diff --git a/deps/glib/gerror.h b/deps/glib/gerror.h
new file mode 100644
index 0000000..871f310
--- /dev/null
+++ b/deps/glib/gerror.h
@@ -0,0 +1,107 @@
+/* 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 <stdarg.h>
+
+#include <glib/gquark.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GError:
+ * @domain: error domain, e.g. #G_FILE_ERROR
+ * @code: error code, e.g. %G_FILE_ERROR_NOENT
+ * @message: human-readable informative error message
+ *
+ * The <structname>GError</structname> structure contains
+ * information about an error that has occurred.
+ */
+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);
+GError*  g_error_new_valist    (GQuark         domain,
+                                gint           code,
+                                const gchar   *format,
+                                va_list        args);
+
+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/deps/glib/ghash.c b/deps/glib/ghash.c
new file mode 100644
index 0000000..02c0d7b
--- /dev/null
+++ b/deps/glib/ghash.c
@@ -0,0 +1,1575 @@
+/* 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 <string.h>  /* memset */
+
+#include "ghash.h"
+
+#include "gstrfuncs.h"
+#include "gatomic.h"
+#include "gtestutils.h"
+
+
+/**
+ * SECTION:hash_tables
+ * @title: Hash Tables
+ * @short_description: associations between keys and values so that
+ *                     given a key the value can be found quickly
+ *
+ * A #GHashTable provides associations between keys and values which is
+ * optimized so that given a key, the associated value can be found
+ * very quickly.
+ *
+ * Note that neither keys nor values are copied when inserted into the
+ * #GHashTable, so they must exist for the lifetime of the #GHashTable.
+ * This means that the use of static strings is OK, but temporary
+ * strings (i.e. those created in buffers and those returned by GTK+
+ * widgets) should be copied with g_strdup() before being inserted.
+ *
+ * If keys or values are dynamically allocated, you must be careful to
+ * ensure that they are freed when they are removed from the
+ * #GHashTable, and also when they are overwritten by new insertions
+ * into the #GHashTable. It is also not advisable to mix static strings
+ * and dynamically-allocated strings in a #GHashTable, because it then
+ * becomes difficult to determine whether the string should be freed.
+ *
+ * To create a #GHashTable, use g_hash_table_new().
+ *
+ * To insert a key and value into a #GHashTable, use
+ * g_hash_table_insert().
+ *
+ * To lookup a value corresponding to a given key, use
+ * g_hash_table_lookup() and g_hash_table_lookup_extended().
+ *
+ * g_hash_table_lookup_extended() can also be used to simply
+ * check if a key is present in the hash table.
+ *
+ * To remove a key and value, use g_hash_table_remove().
+ *
+ * To call a function for each key and value pair use
+ * g_hash_table_foreach() or use a iterator to iterate over the
+ * key/value pairs in the hash table, see #GHashTableIter.
+ *
+ * To destroy a #GHashTable use g_hash_table_destroy().
+ *
+ * <example>
+ * <title>Using a GHashTable as a set</title>
+ * <para>
+ * A common use-case for hash tables is to store information about
+ * a set of keys, without associating any particular value with each
+ * key. GHashTable optimizes one way of doing so: If you store only
+ * key-value pairs where key == value, then GHashTable does not
+ * allocate memory to store the values, which can be a considerable
+ * space saving, if your set is large.
+ * </para>
+ * <programlisting>
+ * GHashTable *
+ * set_new (GHashFunc      hash_func,
+ *          GEqualFunc     equal_func,
+ *          GDestroyNotify destroy)
+ * {
+ *   return g_hash_table_new_full (hash_func, equal_func, destroy, NULL);
+ * }
+ *
+ * void
+ * set_insert (GHashTable *set,
+ *             gpointer    element)
+ * {
+ *   g_hash_table_insert (set, element, element);
+ * }
+ *
+ * gboolean
+ * set_contains (GHashTable *set,
+ *               gpointer    element)
+ * {
+ *   return g_hash_table_lookup_extended (set, element, NULL, NULL);
+ * }
+ *
+ * gboolean
+ * set_remove (GHashTable *set,
+ *             gpointer    element)
+ * {
+ *   return g_hash_table_remove (set, element);
+ * }
+ * </programlisting>
+ * </example>
+ */
+
+/**
+ * GHashTable:
+ *
+ * The #GHashTable struct is an opaque data structure to represent a
+ * <link linkend="glib-Hash-Tables">Hash Table</link>. It should only be
+ * accessed via the following functions.
+ **/
+
+/**
+ * GHashFunc:
+ * @key: a key.
+ * @Returns: the hash value corresponding to the key.
+ *
+ * Specifies the type of the hash function which is passed to
+ * g_hash_table_new() when a #GHashTable is created.
+ *
+ * The function is passed a key and should return a #guint hash value.
+ * The functions g_direct_hash(), g_int_hash() and g_str_hash() provide
+ * hash functions which can be used when the key is a #gpointer, #gint,
+ * and #gchar* respectively.
+ *
+ * <!-- FIXME: Need more here. --> The hash values should be evenly
+ * distributed over a fairly large range? The modulus is taken with the
+ * hash table size (a prime number) to find the 'bucket' to place each
+ * key into. The function should also be very fast, since it is called
+ * for each key lookup.
+ **/
+
+/**
+ * GHFunc:
+ * @key: a key.
+ * @value: the value corresponding to the key.
+ * @user_data: user data passed to g_hash_table_foreach().
+ *
+ * Specifies the type of the function passed to g_hash_table_foreach().
+ * It is called with each key/value pair, together with the @user_data
+ * parameter which is passed to g_hash_table_foreach().
+ **/
+
+/**
+ * GHRFunc:
+ * @key: a key.
+ * @value: the value associated with the key.
+ * @user_data: user data passed to g_hash_table_remove().
+ * @Returns: %TRUE if the key/value pair should be removed from the
+ *           #GHashTable.
+ *
+ * Specifies the type of the function passed to
+ * g_hash_table_foreach_remove(). It is called with each key/value
+ * pair, together with the @user_data parameter passed to
+ * g_hash_table_foreach_remove(). It should return %TRUE if the
+ * key/value pair should be removed from the #GHashTable.
+ **/
+
+/**
+ * GEqualFunc:
+ * @a: a value.
+ * @b: a value to compare with.
+ * @Returns: %TRUE if @a = @b; %FALSE otherwise.
+ *
+ * Specifies the type of a function used to test two values for
+ * equality. The function should return %TRUE if both values are equal
+ * and %FALSE otherwise.
+ **/
+
+/**
+ * GHashTableIter:
+ *
+ * A GHashTableIter structure represents an iterator that can be used
+ * to iterate over the elements of a #GHashTable. GHashTableIter
+ * structures are typically allocated on the stack and then initialized
+ * with g_hash_table_iter_init().
+ **/
+
+#define HASH_TABLE_MIN_SHIFT 3  /* 1 << 3 == 8 buckets */
+
+#define UNUSED_HASH_VALUE 0
+#define TOMBSTONE_HASH_VALUE 1
+#define HASH_IS_UNUSED(h_) ((h_) == UNUSED_HASH_VALUE)
+#define HASH_IS_TOMBSTONE(h_) ((h_) == TOMBSTONE_HASH_VALUE)
+#define HASH_IS_REAL(h_) ((h_) >= 2)
+
+struct _GHashTable
+{
+  gint             size;
+  gint             mod;
+  guint            mask;
+  gint             nnodes;
+  gint             noccupied;  /* nnodes + tombstones */
+
+  gpointer        *keys;
+  guint           *hashes;
+  gpointer        *values;
+
+  GHashFunc        hash_func;
+  GEqualFunc       key_equal_func;
+  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;
+  gpointer     dummy1;
+  gpointer     dummy2;
+  int          position;
+  gboolean     dummy3;
+  int          version;
+} RealIter;
+
+/* Each table size has an associated prime modulo (the first prime
+ * lower than the table size) used to find the initial bucket. Probing
+ * then works modulo 2^n. The prime modulo is necessary to get a
+ * good distribution with poor hash functions. */
+static const gint prime_mod [] =
+{
+  1,          /* For 1 << 0 */
+  2,
+  3,
+  7,
+  13,
+  31,
+  61,
+  127,
+  251,
+  509,
+  1021,
+  2039,
+  4093,
+  8191,
+  16381,
+  32749,
+  65521,      /* For 1 << 16 */
+  131071,
+  262139,
+  524287,
+  1048573,
+  2097143,
+  4194301,
+  8388593,
+  16777213,
+  33554393,
+  67108859,
+  134217689,
+  268435399,
+  536870909,
+  1073741789,
+  2147483647  /* For 1 << 31 */
+};
+
+static void
+g_hash_table_set_shift (GHashTable *hash_table, gint shift)
+{
+  gint i;
+  guint mask = 0;
+
+  hash_table->size = 1 << shift;
+  hash_table->mod  = prime_mod [shift];
+
+  for (i = 0; i < shift; i++)
+    {
+      mask <<= 1;
+      mask |= 1;
+    }
+
+  hash_table->mask = mask;
+}
+
+static gint
+g_hash_table_find_closest_shift (gint n)
+{
+  gint i;
+
+  for (i = 0; n; i++)
+    n >>= 1;
+
+  return i;
+}
+
+static void
+g_hash_table_set_shift_from_size (GHashTable *hash_table, gint size)
+{
+  gint shift;
+
+  shift = g_hash_table_find_closest_shift (size);
+  shift = MAX (shift, HASH_TABLE_MIN_SHIFT);
+
+  g_hash_table_set_shift (hash_table, shift);
+}
+
+/*
+ * g_hash_table_lookup_node:
+ * @hash_table: our #GHashTable
+ * @key: the key to lookup against
+ * @hash_return: key hash return location
+ * Return value: index of the described node
+ *
+ * Performs a lookup in the hash table, preserving extra information
+ * usually needed for insertion.
+ *
+ * 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 the index of that entry in the table, and if not, the
+ * index of an unused node (empty or tombstone) where the key can be
+ * inserted.
+ *
+ * The computed hash value is returned in the variable pointed to
+ * by @hash_return. This is to save insertions from having to compute
+ * the hash record again for the new record.
+ */
+static inline guint
+g_hash_table_lookup_node (GHashTable    *hash_table,
+                          gconstpointer  key,
+                          guint         *hash_return)
+{
+  guint node_index;
+  guint node_hash;
+  guint hash_value;
+  guint first_tombstone = 0;
+  gboolean have_tombstone = FALSE;
+  guint step = 0;
+
+  hash_value = hash_table->hash_func (key);
+  if (G_UNLIKELY (!HASH_IS_REAL (hash_value)))
+    hash_value = 2;
+
+  *hash_return = hash_value;
+
+  node_index = hash_value % hash_table->mod;
+  node_hash = hash_table->hashes[node_index];
+
+  while (!HASH_IS_UNUSED (node_hash))
+    {
+      /* We first check if our full hash values
+       * are equal so we can avoid calling the full-blown
+       * key equality function in most cases.
+       */
+      if (node_hash == hash_value)
+        {
+          gpointer node_key = hash_table->keys[node_index];
+
+          if (hash_table->key_equal_func)
+            {
+              if (hash_table->key_equal_func (node_key, key))
+                return node_index;
+            }
+          else if (node_key == key)
+            {
+              return node_index;
+            }
+        }
+      else if (HASH_IS_TOMBSTONE (node_hash) && !have_tombstone)
+        {
+          first_tombstone = node_index;
+          have_tombstone = TRUE;
+        }
+
+      step++;
+      node_index += step;
+      node_index &= hash_table->mask;
+      node_hash = hash_table->hashes[node_index];
+    }
+
+  if (have_tombstone)
+    return first_tombstone;
+
+  return node_index;
+}
+
+/*
+ * g_hash_table_remove_node:
+ * @hash_table: our #GHashTable
+ * @node: pointer to node to remove
+ * @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 replaced by a tombstone. 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.
+ */
+static void
+g_hash_table_remove_node (GHashTable   *hash_table,
+                          int           i,
+                          gboolean      notify)
+{
+  gpointer key;
+  gpointer value;
+
+  key = hash_table->keys[i];
+  value = hash_table->values[i];
+
+  /* Erect tombstone */
+  hash_table->hashes[i] = TOMBSTONE_HASH_VALUE;
+
+  /* Be GC friendly */
+  hash_table->keys[i] = NULL;
+  hash_table->values[i] = NULL;
+
+  hash_table->nnodes--;
+
+  if (notify && hash_table->key_destroy_func)
+    hash_table->key_destroy_func (key);
+
+  if (notify && hash_table->value_destroy_func)
+    hash_table->value_destroy_func (value);
+
+}
+
+/*
+ * 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)
+{
+  int i;
+  gpointer key;
+  gpointer value;
+
+  hash_table->nnodes = 0;
+  hash_table->noccupied = 0;
+
+  if (!notify ||
+      (hash_table->key_destroy_func == NULL &&
+       hash_table->value_destroy_func == NULL))
+    {
+      memset (hash_table->hashes, 0, hash_table->size * sizeof (guint));
+      memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer));
+      memset (hash_table->values, 0, hash_table->size * sizeof (gpointer));
+
+      return;
+    }
+
+  for (i = 0; i < hash_table->size; i++)
+    {
+      if (HASH_IS_REAL (hash_table->hashes[i]))
+        {
+          key = hash_table->keys[i];
+          value = hash_table->values[i];
+
+          hash_table->hashes[i] = UNUSED_HASH_VALUE;
+          hash_table->keys[i] = NULL;
+          hash_table->values[i] = NULL;
+
+          if (hash_table->key_destroy_func != NULL)
+            hash_table->key_destroy_func (key);
+
+          if (hash_table->value_destroy_func != NULL)
+            hash_table->value_destroy_func (value);
+        }
+      else if (HASH_IS_TOMBSTONE (hash_table->hashes[i]))
+        {
+          hash_table->hashes[i] = UNUSED_HASH_VALUE;
+        }
+    }
+}
+
+/*
+ * 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.
+ *
+ * This function may "resize" the hash table to its current size, with
+ * the side effect of cleaning up tombstones and otherwise optimizing
+ * the probe sequences.
+ */
+static void
+g_hash_table_resize (GHashTable *hash_table)
+{
+  gpointer *new_keys;
+  gpointer *new_values;
+  guint *new_hashes;
+  gint old_size;
+  gint i;
+
+  old_size = hash_table->size;
+  g_hash_table_set_shift_from_size (hash_table, hash_table->nnodes * 2);
+
+  new_keys = g_new0 (gpointer, hash_table->size);
+  if (hash_table->keys == hash_table->values)
+    new_values = new_keys;
+  else
+    new_values = g_new0 (gpointer, hash_table->size);
+  new_hashes = g_new0 (guint, hash_table->size);
+
+  for (i = 0; i < old_size; i++)
+    {
+      guint node_hash = hash_table->hashes[i];
+      guint hash_val;
+      guint step = 0;
+
+      if (!HASH_IS_REAL (node_hash))
+        continue;
+
+      hash_val = node_hash % hash_table->mod;
+
+      while (!HASH_IS_UNUSED (new_hashes[hash_val]))
+        {
+          step++;
+          hash_val += step;
+          hash_val &= hash_table->mask;
+        }
+
+      new_hashes[hash_val] = hash_table->hashes[i];
+      new_keys[hash_val] = hash_table->keys[i];
+      new_values[hash_val] = hash_table->values[i];
+    }
+
+  if (hash_table->keys != hash_table->values)
+    g_free (hash_table->values);
+
+  g_free (hash_table->keys);
+  g_free (hash_table->hashes);
+
+  hash_table->keys = new_keys;
+  hash_table->values = new_values;
+  hash_table->hashes = new_hashes;
+
+  hash_table->noccupied = hash_table->nnodes;
+}
+
+/*
+ * 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 noccupied = hash_table->noccupied;
+  gint size = hash_table->size;
+
+  if ((size > hash_table->nnodes * 4 && size > 1 << HASH_TABLE_MIN_SHIFT) ||
+      (size <= noccupied + (noccupied / 16)))
+    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(),
+ *   g_int64_hash(), g_double_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(), g_int64_equal(), g_double_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);
+  g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
+  hash_table->nnodes             = 0;
+  hash_table->noccupied          = 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->keys               = g_new0 (gpointer, hash_table->size);
+  hash_table->values             = hash_table->keys;
+  hash_table->hashes             = g_new0 (guint, 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->position = -1;
+#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;
+  gint position;
+
+  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
+  g_return_val_if_fail (ri->position < ri->hash_table->size, FALSE);
+
+  position = ri->position;
+
+  do
+    {
+      position++;
+      if (position >= ri->hash_table->size)
+        {
+          ri->position = position;
+          return FALSE;
+        }
+    }
+  while (!HASH_IS_REAL (ri->hash_table->hashes[position]));
+
+  if (key != NULL)
+    *key = ri->hash_table->keys[position];
+  if (value != NULL)
+    *value = ri->hash_table->values[position];
+
+  ri->position = position;
+  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)
+{
+  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->position >= 0);
+  g_return_if_fail (ri->position < ri->hash_table->size);
+
+  g_hash_table_remove_node (ri->hash_table, ri->position, notify);
+
+#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_insert_node:
+ * @hash_table: our #GHashTable
+ * @node_index: pointer to node to insert/replace
+ * @key_hash: key hash
+ * @key: key to replace with, or %NULL
+ * @value: value to replace with
+ * @keep_new_key: whether to replace the key in the node with @key
+ * @reusing_key: whether @key was taken out of the existing node
+ *
+ * Inserts a value at @node_index in the hash table and updates it.
+ *
+ * If @key has been taken out of the existing node (ie it is not
+ * passed in via a g_hash_table_insert/replace) call, then @reusing_key
+ * should be %TRUE.
+ */
+static void
+g_hash_table_insert_node (GHashTable *hash_table,
+                          guint       node_index,
+                          guint       key_hash,
+                          gpointer    key,
+                          gpointer    value,
+                          gboolean    keep_new_key,
+                          gboolean    reusing_key)
+{
+  guint old_hash;
+  gpointer old_key;
+  gpointer old_value;
+
+  if (G_UNLIKELY (hash_table->keys == hash_table->values && key != value))
+    hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
+
+  old_hash = hash_table->hashes[node_index];
+  old_key = hash_table->keys[node_index];
+  old_value = hash_table->values[node_index];
+
+  if (HASH_IS_REAL (old_hash))
+    {
+      if (keep_new_key)
+        hash_table->keys[node_index] = key;
+      hash_table->values[node_index] = value;
+    }
+  else
+    {
+      hash_table->keys[node_index] = key;
+      hash_table->values[node_index] = value;
+      hash_table->hashes[node_index] = key_hash;
+
+      hash_table->nnodes++;
+
+      if (HASH_IS_UNUSED (old_hash))
+        {
+          /* We replaced an empty node, and not a tombstone */
+          hash_table->noccupied++;
+          g_hash_table_maybe_resize (hash_table);
+        }
+
+#ifndef G_DISABLE_ASSERT
+      hash_table->version++;
+#endif
+    }
+
+  if (HASH_IS_REAL (old_hash))
+    {
+      if (hash_table->key_destroy_func && !reusing_key)
+        hash_table->key_destroy_func (keep_new_key ? old_key : key);
+      if (hash_table->value_destroy_func)
+        hash_table->value_destroy_func (old_value);
+    }
+}
+
+/**
+ * g_hash_table_iter_replace:
+ * @iter: an initialized #GHashTableIter.
+ * @value: the value to replace with
+ *
+ * Replaces the value currently pointed to by the iterator
+ * from its associated #GHashTable. Can only be called after
+ * g_hash_table_iter_next() returned %TRUE.
+ *
+ * If you supplied a @value_destroy_func when creating the #GHashTable,
+ * the old value is freed using that function.
+ *
+ * Since: 2.29.9
+ **/
+void
+g_hash_table_iter_replace (GHashTableIter *iter,
+                           gpointer        value)
+{
+  RealIter *ri;
+  guint node_hash;
+  gpointer key;
+
+  ri = (RealIter *) iter;
+
+  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->position >= 0);
+  g_return_if_fail (ri->position < ri->hash_table->size);
+
+  node_hash = ri->hash_table->hashes[ri->position];
+  key = ri->hash_table->keys[ri->position];
+
+  g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE, TRUE);
+
+#ifndef G_DISABLE_ASSERT
+  ri->version++;
+  ri->hash_table->version++;
+#endif
+}
+
+/**
+ * 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_atomic_int_inc (&hash_table->ref_count);
+
+  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);
+
+  if (g_atomic_int_dec_and_test (&hash_table->ref_count))
+    {
+      g_hash_table_remove_all_nodes (hash_table, TRUE);
+      if (hash_table->keys != hash_table->values)
+        g_free (hash_table->values);
+      g_free (hash_table->keys);
+      g_free (hash_table->hashes);
+      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_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)
+{
+  guint node_index;
+  guint node_hash;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+
+  node_index = g_hash_table_lookup_node (hash_table, key, &node_hash);
+
+  return HASH_IS_REAL (hash_table->hashes[node_index])
+    ? hash_table->values[node_index]
+    : NULL;
+}
+
+/**
+ * g_hash_table_lookup_extended:
+ * @hash_table: a #GHashTable
+ * @lookup_key: the key to look up
+ * @orig_key: return location for the original key, or %NULL
+ * @value: return location for the value associated with the key, or %NULL
+ *
+ * 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().
+ *
+ * You can actually pass %NULL for @lookup_key to test
+ * whether the %NULL key exists, provided the hash and equal functions
+ * of @hash_table are %NULL-safe.
+ *
+ * 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)
+{
+  guint node_index;
+  guint node_hash;
+
+  g_return_val_if_fail (hash_table != NULL, FALSE);
+
+  node_index = g_hash_table_lookup_node (hash_table, lookup_key, &node_hash);
+
+  if (!HASH_IS_REAL (hash_table->hashes[node_index]))
+    return FALSE;
+
+  if (orig_key)
+    *orig_key = hash_table->keys[node_index];
+
+  if (value)
+    *value = hash_table->values[node_index];
+
+  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)
+{
+  guint key_hash;
+  guint node_index;
+
+  g_return_if_fail (hash_table != NULL);
+
+  node_index = g_hash_table_lookup_node (hash_table, key, &key_hash);
+
+  g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key, FALSE);
+}
+
+/**
+ * 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)
+{
+  guint node_index;
+  guint node_hash;
+
+  g_return_val_if_fail (hash_table != NULL, FALSE);
+
+  node_index = g_hash_table_lookup_node (hash_table, key, &node_hash);
+
+  if (!HASH_IS_REAL (hash_table->hashes[node_index]))
+    return FALSE;
+
+  g_hash_table_remove_node (hash_table, node_index, 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)
+{
+  guint deleted = 0;
+  gint i;
+#ifndef G_DISABLE_ASSERT
+  gint version = hash_table->version;
+#endif
+
+  for (i = 0; i < hash_table->size; i++)
+    {
+      guint node_hash = hash_table->hashes[i];
+      gpointer node_key = hash_table->keys[i];
+      gpointer node_value = hash_table->values[i];
+
+      if (HASH_IS_REAL (node_hash) &&
+          (* func) (node_key, node_value, user_data))
+        {
+          g_hash_table_remove_node (hash_table, i, notify);
+          deleted++;
+        }
+
+#ifndef G_DISABLE_ASSERT
+      g_return_val_if_fail (version == hash_table->version, 0);
+#endif
+    }
+
+  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 #GHashTableIter 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 #GHashTableIter 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)
+{
+  gint i;
+#ifndef G_DISABLE_ASSERT
+  gint version = hash_table->version;
+#endif
+
+  g_return_if_fail (hash_table != NULL);
+  g_return_if_fail (func != NULL);
+
+  for (i = 0; i < hash_table->size; i++)
+    {
+      guint node_hash = hash_table->hashes[i];
+      gpointer node_key = hash_table->keys[i];
+      gpointer node_value = hash_table->values[i];
+
+      if (HASH_IS_REAL (node_hash))
+        (* func) (node_key, node_value, user_data);
+
+#ifndef G_DISABLE_ASSERT
+      g_return_if_fail (version == hash_table->version);
+#endif
+    }
+}
+
+/**
+ * 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 @predicate 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)
+{
+  gint i;
+#ifndef G_DISABLE_ASSERT
+  gint version = hash_table->version;
+#endif
+  gboolean match;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+  g_return_val_if_fail (predicate != NULL, NULL);
+
+  match = FALSE;
+
+  for (i = 0; i < hash_table->size; i++)
+    {
+      guint node_hash = hash_table->hashes[i];
+      gpointer node_key = hash_table->keys[i];
+      gpointer node_value = hash_table->values[i];
+
+      if (HASH_IS_REAL (node_hash))
+        match = predicate (node_key, node_value, user_data);
+
+#ifndef G_DISABLE_ASSERT
+      g_return_val_if_fail (version == hash_table->version, NULL);
+#endif
+
+      if (match)
+        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)
+{
+  gint i;
+  GList *retval;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+
+  retval = NULL;
+  for (i = 0; i < hash_table->size; i++)
+    {
+      if (HASH_IS_REAL (hash_table->hashes[i]))
+        retval = g_list_prepend (retval, hash_table->keys[i]);
+    }
+
+  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)
+{
+  gint i;
+  GList *retval;
+
+  g_return_val_if_fail (hash_table != NULL, NULL);
+
+  retval = NULL;
+  for (i = 0; i < hash_table->size; i++)
+    {
+      if (HASH_IS_REAL (hash_table->hashes[i]))
+        retval = g_list_prepend (retval, hash_table->values[i]);
+    }
+
+  return retval;
+}
diff --git a/deps/glib/ghash.h b/deps/glib/ghash.h
new file mode 100644
index 0000000..3bc8226
--- /dev/null
+++ b/deps/glib/ghash.h
@@ -0,0 +1,168 @@
+/* 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_replace      (GHashTableIter *iter,
+					    gpointer	    value);
+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
+
+/**
+ * g_hash_table_freeze:
+ * @hash_table: a #GHashTable
+ *
+ * This function is deprecated and will be removed in the next major
+ * release of GLib. It does nothing.
+ **/
+#define g_hash_table_freeze(hash_table) ((void)0)
+
+/**
+ * g_hash_table_thaw:
+ * @hash_table: a #GHashTable
+ *
+ * This function is deprecated and will be removed in the next major
+ * release of GLib. It does nothing.
+ **/
+#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);
+
+gboolean g_int64_equal (gconstpointer  v1,
+                        gconstpointer  v2);
+guint    g_int64_hash  (gconstpointer  v);
+
+gboolean g_double_equal (gconstpointer  v1,
+                         gconstpointer  v2);
+guint    g_double_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/deps/glib/ghook.c b/deps/glib/ghook.c
new file mode 100644
index 0000000..1406b58
--- /dev/null
+++ b/deps/glib/ghook.c
@@ -0,0 +1,636 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * GHook: Callback maintenance functions
+ * Copyright (C) 1998 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.
+ */
+
+/*
+ * 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 "ghook.h"
+
+#include "gtestutils.h"
+
+
+/* --- functions --- */
+static void
+default_finalize_hook (GHookList *hook_list,
+		       GHook     *hook)
+{
+  GDestroyNotify destroy = hook->destroy;
+
+  if (destroy)
+    {
+      hook->destroy = NULL;
+      destroy (hook->data);
+    }
+}
+
+void
+g_hook_list_init (GHookList *hook_list,
+		  guint	     hook_size)
+{
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_size >= sizeof (GHook));
+  
+  hook_list->seq_id = 1;
+  hook_list->hook_size = hook_size;
+  hook_list->is_setup = TRUE;
+  hook_list->hooks = NULL;
+  hook_list->dummy3 = NULL;
+  hook_list->finalize_hook = default_finalize_hook;
+  hook_list->dummy[0] = NULL;
+  hook_list->dummy[1] = NULL;
+}
+
+void
+g_hook_list_clear (GHookList *hook_list)
+{
+  g_return_if_fail (hook_list != NULL);
+  
+  if (hook_list->is_setup)
+    {
+      GHook *hook;
+      
+      hook_list->is_setup = FALSE;
+      
+      hook = hook_list->hooks;
+      if (!hook)
+	{
+	  /* destroy hook_list->hook_memchunk */
+	}
+      else
+	do
+	  {
+	    GHook *tmp;
+	    
+	    g_hook_ref (hook_list, hook);
+	    g_hook_destroy_link (hook_list, hook);
+	    tmp = hook->next;
+	    g_hook_unref (hook_list, hook);
+	    hook = tmp;
+	  }
+	while (hook);
+    }
+}
+
+GHook*
+g_hook_alloc (GHookList *hook_list)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  g_return_val_if_fail (hook_list->is_setup, NULL);
+  
+  hook = g_slice_alloc0 (hook_list->hook_size);
+  hook->data = NULL;
+  hook->next = NULL;
+  hook->prev = NULL;
+  hook->flags = G_HOOK_FLAG_ACTIVE;
+  hook->ref_count = 0;
+  hook->hook_id = 0;
+  hook->func = NULL;
+  hook->destroy = NULL;
+  
+  return hook;
+}
+
+void
+g_hook_free (GHookList *hook_list,
+	     GHook     *hook)
+{
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+  g_return_if_fail (hook != NULL);
+  g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
+  g_return_if_fail (!G_HOOK_IN_CALL (hook));
+
+  if(hook_list->finalize_hook != NULL)
+      hook_list->finalize_hook (hook_list, hook);
+  g_slice_free1 (hook_list->hook_size, hook);
+}
+
+void
+g_hook_destroy_link (GHookList *hook_list,
+		     GHook     *hook)
+{
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook != NULL);
+
+  hook->flags &= ~G_HOOK_FLAG_ACTIVE;
+  if (hook->hook_id)
+    {
+      hook->hook_id = 0;
+      g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
+    }
+}
+
+gboolean
+g_hook_destroy (GHookList   *hook_list,
+		gulong	     hook_id)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, FALSE);
+  g_return_val_if_fail (hook_id > 0, FALSE);
+  
+  hook = g_hook_get (hook_list, hook_id);
+  if (hook)
+    {
+      g_hook_destroy_link (hook_list, hook);
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+void
+g_hook_unref (GHookList *hook_list,
+	      GHook	*hook)
+{
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook != NULL);
+  g_return_if_fail (hook->ref_count > 0);
+  
+  hook->ref_count--;
+  if (!hook->ref_count)
+    {
+      g_return_if_fail (hook->hook_id == 0);
+      g_return_if_fail (!G_HOOK_IN_CALL (hook));
+
+      if (hook->prev)
+	hook->prev->next = hook->next;
+      else
+	hook_list->hooks = hook->next;
+      if (hook->next)
+	{
+	  hook->next->prev = hook->prev;
+	  hook->next = NULL;
+	}
+      hook->prev = NULL;
+
+      if (!hook_list->is_setup)
+	{
+	  hook_list->is_setup = TRUE;
+	  g_hook_free (hook_list, hook);
+	  hook_list->is_setup = FALSE;
+      
+	  if (!hook_list->hooks)
+	    {
+	      /* destroy hook_list->hook_memchunk */
+	    }
+	}
+      else
+	g_hook_free (hook_list, hook);
+    }
+}
+
+GHook *
+g_hook_ref (GHookList *hook_list,
+	    GHook     *hook)
+{
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  g_return_val_if_fail (hook != NULL, NULL);
+  g_return_val_if_fail (hook->ref_count > 0, NULL);
+  
+  hook->ref_count++;
+
+  return hook;
+}
+
+void
+g_hook_prepend (GHookList *hook_list,
+		GHook	  *hook)
+{
+  g_return_if_fail (hook_list != NULL);
+  
+  g_hook_insert_before (hook_list, hook_list->hooks, hook);
+}
+
+void
+g_hook_insert_before (GHookList *hook_list,
+		      GHook	*sibling,
+		      GHook	*hook)
+{
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+  g_return_if_fail (hook != NULL);
+  g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
+  g_return_if_fail (hook->ref_count == 0);
+  
+  hook->hook_id = hook_list->seq_id++;
+  hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
+  
+  if (sibling)
+    {
+      if (sibling->prev)
+	{
+	  hook->prev = sibling->prev;
+	  hook->prev->next = hook;
+	  hook->next = sibling;
+	  sibling->prev = hook;
+	}
+      else
+	{
+	  hook_list->hooks = hook;
+	  hook->next = sibling;
+	  sibling->prev = hook;
+	}
+    }
+  else
+    {
+      if (hook_list->hooks)
+	{
+	  sibling = hook_list->hooks;
+	  while (sibling->next)
+	    sibling = sibling->next;
+	  hook->prev = sibling;
+	  sibling->next = hook;
+	}
+      else
+	hook_list->hooks = hook;
+    }
+}
+
+void
+g_hook_list_invoke (GHookList *hook_list,
+		    gboolean   may_recurse)
+{
+  GHook *hook;
+  
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+
+  hook = g_hook_first_valid (hook_list, may_recurse);
+  while (hook)
+    {
+      GHookFunc func;
+      gboolean was_in_call;
+      
+      func = (GHookFunc) hook->func;
+      
+      was_in_call = G_HOOK_IN_CALL (hook);
+      hook->flags |= G_HOOK_FLAG_IN_CALL;
+      func (hook->data);
+      if (!was_in_call)
+	hook->flags &= ~G_HOOK_FLAG_IN_CALL;
+      
+      hook = g_hook_next_valid (hook_list, hook, may_recurse);
+    }
+}
+
+void
+g_hook_list_invoke_check (GHookList *hook_list,
+			  gboolean   may_recurse)
+{
+  GHook *hook;
+  
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+  
+  hook = g_hook_first_valid (hook_list, may_recurse);
+  while (hook)
+    {
+      GHookCheckFunc func;
+      gboolean was_in_call;
+      gboolean need_destroy;
+      
+      func = (GHookCheckFunc) hook->func;
+      
+      was_in_call = G_HOOK_IN_CALL (hook);
+      hook->flags |= G_HOOK_FLAG_IN_CALL;
+      need_destroy = !func (hook->data);
+      if (!was_in_call)
+	hook->flags &= ~G_HOOK_FLAG_IN_CALL;
+      if (need_destroy)
+	g_hook_destroy_link (hook_list, hook);
+      
+      hook = g_hook_next_valid (hook_list, hook, may_recurse);
+    }
+}
+
+void
+g_hook_list_marshal_check (GHookList	       *hook_list,
+			   gboolean		may_recurse,
+			   GHookCheckMarshaller marshaller,
+			   gpointer		data)
+{
+  GHook *hook;
+  
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+  g_return_if_fail (marshaller != NULL);
+  
+  hook = g_hook_first_valid (hook_list, may_recurse);
+  while (hook)
+    {
+      gboolean was_in_call;
+      gboolean need_destroy;
+      
+      was_in_call = G_HOOK_IN_CALL (hook);
+      hook->flags |= G_HOOK_FLAG_IN_CALL;
+      need_destroy = !marshaller (hook, data);
+      if (!was_in_call)
+	hook->flags &= ~G_HOOK_FLAG_IN_CALL;
+      if (need_destroy)
+	g_hook_destroy_link (hook_list, hook);
+      
+      hook = g_hook_next_valid (hook_list, hook, may_recurse);
+    }
+}
+
+void
+g_hook_list_marshal (GHookList		     *hook_list,
+		     gboolean		      may_recurse,
+		     GHookMarshaller	      marshaller,
+		     gpointer		      data)
+{
+  GHook *hook;
+  
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+  g_return_if_fail (marshaller != NULL);
+  
+  hook = g_hook_first_valid (hook_list, may_recurse);
+  while (hook)
+    {
+      gboolean was_in_call;
+      
+      was_in_call = G_HOOK_IN_CALL (hook);
+      hook->flags |= G_HOOK_FLAG_IN_CALL;
+      marshaller (hook, data);
+      if (!was_in_call)
+	hook->flags &= ~G_HOOK_FLAG_IN_CALL;
+      
+      hook = g_hook_next_valid (hook_list, hook, may_recurse);
+    }
+}
+
+GHook*
+g_hook_first_valid (GHookList *hook_list,
+		    gboolean   may_be_in_call)
+{
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  
+  if (hook_list->is_setup)
+    {
+      GHook *hook;
+      
+      hook = hook_list->hooks;
+      if (hook)
+	{
+	  g_hook_ref (hook_list, hook);
+	  if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
+	    return hook;
+	  else
+	    return g_hook_next_valid (hook_list, hook, may_be_in_call);
+	}
+    }
+  
+  return NULL;
+}
+
+GHook*
+g_hook_next_valid (GHookList *hook_list,
+		   GHook     *hook,
+		   gboolean   may_be_in_call)
+{
+  GHook *ohook = hook;
+
+  g_return_val_if_fail (hook_list != NULL, NULL);
+
+  if (!hook)
+    return NULL;
+  
+  hook = hook->next;
+  while (hook)
+    {
+      if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
+	{
+	  g_hook_ref (hook_list, hook);
+	  g_hook_unref (hook_list, ohook);
+	  
+	  return hook;
+	}
+      hook = hook->next;
+    }
+  g_hook_unref (hook_list, ohook);
+
+  return NULL;
+}
+
+GHook*
+g_hook_get (GHookList *hook_list,
+	    gulong     hook_id)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  g_return_val_if_fail (hook_id > 0, NULL);
+  
+  hook = hook_list->hooks;
+  while (hook)
+    {
+      if (hook->hook_id == hook_id)
+	return hook;
+      hook = hook->next;
+    }
+  
+  return NULL;
+}
+
+GHook*
+g_hook_find (GHookList	  *hook_list,
+	     gboolean	   need_valids,
+	     GHookFindFunc func,
+	     gpointer	   data)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  g_return_val_if_fail (func != NULL, NULL);
+  
+  hook = hook_list->hooks;
+  while (hook)
+    {
+      GHook *tmp;
+
+      /* test only non-destroyed hooks */
+      if (!hook->hook_id)
+	{
+	  hook = hook->next;
+	  continue;
+	}
+      
+      g_hook_ref (hook_list, hook);
+      
+      if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook)))
+	{
+	  g_hook_unref (hook_list, hook);
+	  
+	  return hook;
+	}
+
+      tmp = hook->next;
+      g_hook_unref (hook_list, hook);
+      hook = tmp;
+    }
+  
+  return NULL;
+}
+
+GHook*
+g_hook_find_data (GHookList *hook_list,
+		  gboolean   need_valids,
+		  gpointer   data)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  
+  hook = hook_list->hooks;
+  while (hook)
+    {
+      /* test only non-destroyed hooks */
+      if (hook->data == data &&
+	  hook->hook_id &&
+	  (!need_valids || G_HOOK_ACTIVE (hook)))
+	return hook;
+
+      hook = hook->next;
+    }
+  
+  return NULL;
+}
+
+GHook*
+g_hook_find_func (GHookList *hook_list,
+		  gboolean   need_valids,
+		  gpointer   func)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  g_return_val_if_fail (func != NULL, NULL);
+  
+  hook = hook_list->hooks;
+  while (hook)
+    {
+      /* test only non-destroyed hooks */
+      if (hook->func == func &&
+	  hook->hook_id &&
+	  (!need_valids || G_HOOK_ACTIVE (hook)))
+	return hook;
+
+      hook = hook->next;
+    }
+  
+  return NULL;
+}
+
+GHook*
+g_hook_find_func_data (GHookList *hook_list,
+		       gboolean	  need_valids,
+		       gpointer	  func,
+		       gpointer	  data)
+{
+  GHook *hook;
+  
+  g_return_val_if_fail (hook_list != NULL, NULL);
+  g_return_val_if_fail (func != NULL, NULL);
+  
+  hook = hook_list->hooks;
+  while (hook)
+    {
+      /* test only non-destroyed hooks */
+      if (hook->data == data &&
+	  hook->func == func &&
+	  hook->hook_id &&
+	  (!need_valids || G_HOOK_ACTIVE (hook)))
+	return hook;
+
+      hook = hook->next;
+    }
+  
+  return NULL;
+}
+
+void
+g_hook_insert_sorted (GHookList	      *hook_list,
+		      GHook	      *hook,
+		      GHookCompareFunc func)
+{
+  GHook *sibling;
+  
+  g_return_if_fail (hook_list != NULL);
+  g_return_if_fail (hook_list->is_setup);
+  g_return_if_fail (hook != NULL);
+  g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
+  g_return_if_fail (hook->func != NULL);
+  g_return_if_fail (func != NULL);
+
+  /* first non-destroyed hook */
+  sibling = hook_list->hooks;
+  while (sibling && !sibling->hook_id)
+    sibling = sibling->next;
+  
+  while (sibling)
+    {
+      GHook *tmp;
+      
+      g_hook_ref (hook_list, sibling);
+      if (func (hook, sibling) <= 0 && sibling->hook_id)
+	{
+	  g_hook_unref (hook_list, sibling);
+	  break;
+	}
+
+      /* next non-destroyed hook */
+      tmp = sibling->next;
+      while (tmp && !tmp->hook_id)
+	tmp = tmp->next;
+
+      g_hook_unref (hook_list, sibling);
+      sibling = tmp;
+    }
+  
+  g_hook_insert_before (hook_list, sibling, hook);
+}
+
+gint
+g_hook_compare_ids (GHook *new_hook,
+		    GHook *sibling)
+{
+  if (new_hook->hook_id < sibling->hook_id)
+    return -1;
+  else if (new_hook->hook_id > sibling->hook_id)
+    return 1;
+  
+  return 0;
+}
diff --git a/deps/glib/ghook.h b/deps/glib/ghook.h
new file mode 100644
index 0000000..5577fc3
--- /dev/null
+++ b/deps/glib/ghook.h
@@ -0,0 +1,181 @@
+/* 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_HOOK_H__
+#define __G_HOOK_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+
+/* --- typedefs --- */
+typedef struct _GHook		GHook;
+typedef struct _GHookList	GHookList;
+
+typedef gint		(*GHookCompareFunc)	(GHook		*new_hook,
+						 GHook		*sibling);
+typedef gboolean	(*GHookFindFunc)	(GHook		*hook,
+						 gpointer	 data);
+typedef void		(*GHookMarshaller)	(GHook		*hook,
+						 gpointer	 marshal_data);
+typedef gboolean	(*GHookCheckMarshaller)	(GHook		*hook,
+						 gpointer	 marshal_data);
+typedef void		(*GHookFunc)		(gpointer	 data);
+typedef gboolean	(*GHookCheckFunc)	(gpointer	 data);
+typedef void		(*GHookFinalizeFunc)	(GHookList      *hook_list,
+						 GHook          *hook);
+typedef enum
+{
+  G_HOOK_FLAG_ACTIVE	    = 1 << 0,
+  G_HOOK_FLAG_IN_CALL	    = 1 << 1,
+  G_HOOK_FLAG_MASK	    = 0x0f
+} GHookFlagMask;
+#define G_HOOK_FLAG_USER_SHIFT	(4)
+
+
+/* --- structures --- */
+struct _GHookList
+{
+  gulong	    seq_id;
+  guint		    hook_size : 16;
+  guint		    is_setup : 1;
+  GHook		   *hooks;
+  gpointer	    dummy3;
+  GHookFinalizeFunc finalize_hook;
+  gpointer	    dummy[2];
+};
+struct _GHook
+{
+  gpointer	 data;
+  GHook		*next;
+  GHook		*prev;
+  guint		 ref_count;
+  gulong	 hook_id;
+  guint		 flags;
+  gpointer	 func;
+  GDestroyNotify destroy;
+};
+
+
+/* --- macros --- */
+#define	G_HOOK(hook)			((GHook*) (hook))
+#define	G_HOOK_FLAGS(hook)		(G_HOOK (hook)->flags)
+#define	G_HOOK_ACTIVE(hook)		((G_HOOK_FLAGS (hook) & \
+					  G_HOOK_FLAG_ACTIVE) != 0)
+#define	G_HOOK_IN_CALL(hook)		((G_HOOK_FLAGS (hook) & \
+					  G_HOOK_FLAG_IN_CALL) != 0)
+#define G_HOOK_IS_VALID(hook)		(G_HOOK (hook)->hook_id != 0 && \
+					 (G_HOOK_FLAGS (hook) & \
+                                          G_HOOK_FLAG_ACTIVE))
+#define G_HOOK_IS_UNLINKED(hook)	(G_HOOK (hook)->next == NULL && \
+					 G_HOOK (hook)->prev == NULL && \
+					 G_HOOK (hook)->hook_id == 0 && \
+					 G_HOOK (hook)->ref_count == 0)
+
+
+/* --- prototypes --- */
+/* callback maintenance functions */
+void	 g_hook_list_init		(GHookList		*hook_list,
+					 guint			 hook_size);
+void	 g_hook_list_clear		(GHookList		*hook_list);
+GHook*	 g_hook_alloc			(GHookList		*hook_list);
+void	 g_hook_free			(GHookList		*hook_list,
+					 GHook			*hook);
+GHook *	 g_hook_ref			(GHookList		*hook_list,
+					 GHook			*hook);
+void	 g_hook_unref			(GHookList		*hook_list,
+					 GHook			*hook);
+gboolean g_hook_destroy			(GHookList		*hook_list,
+					 gulong			 hook_id);
+void	 g_hook_destroy_link		(GHookList		*hook_list,
+					 GHook			*hook);
+void	 g_hook_prepend			(GHookList		*hook_list,
+					 GHook			*hook);
+void	 g_hook_insert_before		(GHookList		*hook_list,
+					 GHook			*sibling,
+					 GHook			*hook);
+void	 g_hook_insert_sorted		(GHookList		*hook_list,
+					 GHook			*hook,
+					 GHookCompareFunc	 func);
+GHook*	 g_hook_get			(GHookList		*hook_list,
+					 gulong			 hook_id);
+GHook*	 g_hook_find			(GHookList		*hook_list,
+					 gboolean		 need_valids,
+					 GHookFindFunc		 func,
+					 gpointer		 data);
+GHook*	 g_hook_find_data		(GHookList		*hook_list,
+					 gboolean		 need_valids,
+					 gpointer		 data);
+GHook*	 g_hook_find_func		(GHookList		*hook_list,
+					 gboolean		 need_valids,
+					 gpointer		 func);
+GHook*	 g_hook_find_func_data		(GHookList		*hook_list,
+					 gboolean		 need_valids,
+					 gpointer		 func,
+					 gpointer		 data);
+/* return the first valid hook, and increment its reference count */
+GHook*	 g_hook_first_valid		(GHookList		*hook_list,
+					 gboolean		 may_be_in_call);
+/* return the next valid hook with incremented reference count, and
+ * decrement the reference count of the original hook
+ */
+GHook*	 g_hook_next_valid		(GHookList		*hook_list,
+					 GHook			*hook,
+					 gboolean		 may_be_in_call);
+/* GHookCompareFunc implementation to insert hooks sorted by their id */
+gint	 g_hook_compare_ids		(GHook			*new_hook,
+					 GHook			*sibling);
+/* convenience macros */
+#define	 g_hook_append( hook_list, hook )  \
+     g_hook_insert_before ((hook_list), NULL, (hook))
+/* invoke all valid hooks with the (*GHookFunc) signature.
+ */
+void	 g_hook_list_invoke		(GHookList		*hook_list,
+					 gboolean		 may_recurse);
+/* invoke all valid hooks with the (*GHookCheckFunc) signature,
+ * and destroy the hook if FALSE is returned.
+ */
+void	 g_hook_list_invoke_check	(GHookList		*hook_list,
+					 gboolean		 may_recurse);
+/* invoke a marshaller on all valid hooks.
+ */
+void	 g_hook_list_marshal		(GHookList		*hook_list,
+					 gboolean		 may_recurse,
+					 GHookMarshaller	 marshaller,
+					 gpointer		 marshal_data);
+void	 g_hook_list_marshal_check	(GHookList		*hook_list,
+					 gboolean		 may_recurse,
+					 GHookCheckMarshaller	 marshaller,
+					 gpointer		 marshal_data);
+
+G_END_DECLS
+
+#endif /* __G_HOOK_H__ */
diff --git a/deps/glib/glib.h b/deps/glib/glib.h
new file mode 100644
index 0000000..7c1b46e
--- /dev/null
+++ b/deps/glib/glib.h
@@ -0,0 +1,21 @@
+#ifndef __GLIB_H__
+#define __GLIB_H__
+
+#define __GLIB_H_INSIDE__
+
+#include "gtypes.h"
+#include "glibconfig.h"
+#include "gmacros.h"
+#include "gquark.h"
+#include "gstrfuncs.h"
+#include "gmessages.h"
+#include "gmem.h"
+#include "gslice.h"
+#include "gstring.h"
+#include "ghook.h"
+#include "garray.h"
+#include "gslist.h"
+#include "glist.h"
+#include "ghash.h"
+
+#endif /* __GLIB_H__ */
diff --git a/deps/glib/glibconfig.h b/deps/glib/glibconfig.h
new file mode 100644
index 0000000..4bfe19e
--- /dev/null
+++ b/deps/glib/glibconfig.h
@@ -0,0 +1,227 @@
+/* glibconfig.h
+ *
+ * This is a generated file.  Please modify 'configure.ac'
+ */
+
+#ifndef __G_LIBCONFIG_H__
+#define __G_LIBCONFIG_H__
+
+#include <glib/gmacros.h>
+
+#include <limits.h>
+#include <float.h>
+#define GLIB_HAVE_ALLOCA_H
+#define GLIB_HAVE_SYS_POLL_H
+
+/* Specifies that GLib's g_print*() functions wrap the
+ * system printf functions.  This is useful to know, for example,
+ * when using glibc's register_printf_function().
+ */
+#define GLIB_USING_SYSTEM_PRINTF
+
+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 */
+
+G_GNUC_EXTENSION typedef signed long long gint64;
+G_GNUC_EXTENSION typedef unsigned long long guint64;
+
+#define G_GINT64_CONSTANT(val)	(G_GNUC_EXTENSION (val##LL))
+#define G_GUINT64_CONSTANT(val)	(G_GNUC_EXTENSION (val##ULL))
+#define G_GINT64_MODIFIER "ll"
+#define G_GINT64_FORMAT "lli"
+#define G_GUINT64_FORMAT "llu"
+
+#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
+
+typedef gint64 goffset;
+#define G_MINOFFSET	G_MININT64
+#define G_MAXOFFSET	G_MAXINT64
+
+#define G_GOFFSET_MODIFIER      G_GINT64_MODIFIER
+#define G_GOFFSET_FORMAT        G_GINT64_FORMAT
+#define G_GOFFSET_CONSTANT(val) G_GINT64_CONSTANT(val)
+
+
+#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;
+
+#define G_GINTPTR_MODIFIER      ""
+#define G_GINTPTR_FORMAT        "i"
+#define G_GUINTPTR_FORMAT       "u"
+
+#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 30
+#define GLIB_MICRO_VERSION 2
+
+#define G_OS_UNIX
+
+
+#define G_VA_COPY	va_copy
+
+#ifdef	__cplusplus
+#define	G_HAVE_INLINE	1
+#else	/* !__cplusplus */
+#define G_HAVE_INLINE 1
+#define G_HAVE___INLINE 1
+#define G_HAVE___INLINE__ 1
+#endif	/* !__cplusplus */
+
+#ifdef	__cplusplus
+#define G_CAN_INLINE	1
+#else	/* !__cplusplus */
+#define G_CAN_INLINE	1
+#endif
+
+#ifndef __cplusplus
+# define G_HAVE_ISO_VARARGS 1
+#endif
+#ifdef __cplusplus
+# define G_HAVE_ISO_VARARGS 1
+#endif
+
+/* 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
+
+#define G_HAVE_GNUC_VISIBILITY 1
+#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define G_GNUC_INTERNAL __attribute__((visibility("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define G_GNUC_INTERNAL __hidden
+#elif defined (__GNUC__) && defined (G_HAVE_GNUC_VISIBILITY)
+#define G_GNUC_INTERNAL __attribute__((visibility("hidden")))
+#else
+#define G_GNUC_INTERNAL
+#endif
+
+#define G_THREADS_ENABLED
+#define G_THREADS_IMPL_POSIX
+typedef struct _GStaticMutex GStaticMutex;
+struct _GStaticMutex
+{
+  struct _GMutex *runtime_mutex;
+  union {
+    char   pad[24];
+    double dummy_double;
+    void  *dummy_pointer;
+    long   dummy_long;
+  } static_mutex;
+};
+#define	G_STATIC_MUTEX_INIT	{ NULL, { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } }
+#define	g_static_mutex_get_mutex(mutex) \
+  (g_thread_use_default_impl ? ((GMutex*)(gpointer) ((mutex)->static_mutex.pad)) : \
+   g_static_mutex_get_mutex_impl_shortcut (&((mutex)->runtime_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
+{
+  char   data[4];
+  double dummy_double;
+  void  *dummy_pointer;
+  long   dummy_long;
+};
+
+#define G_ATOMIC_OP_USE_GCC_BUILTINS 1
+
+#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 GSIZE_TO_LE(val)	((gsize) GUINT32_TO_LE (val))
+#define GSSIZE_TO_LE(val)	((gssize) GINT32_TO_LE (val))
+#define GSIZE_TO_BE(val)	((gsize) GUINT32_TO_BE (val))
+#define GSSIZE_TO_BE(val)	((gssize) GINT32_TO_BE (val))
+#define G_BYTE_ORDER G_LITTLE_ENDIAN
+
+#define G_MODULE_SUFFIX "so"
+
+/* 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 int GPid;
+
+G_END_DECLS
+
+#endif /* GLIBCONFIG_H */
diff --git a/deps/glib/glist.c b/deps/glib/glist.c
new file mode 100644
index 0000000..1e3dd86
--- /dev/null
+++ b/deps/glib/glist.c
@@ -0,0 +1,1170 @@
+/* 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 "glist.h"
+
+#include "gtestutils.h"
+
+/**
+ * SECTION:linked_lists_double
+ * @title: Doubly-Linked Lists
+ * @short_description: linked lists containing integer values or
+ *                     pointers to data, with the ability to iterate
+ *                     over the list in both directions
+ *
+ * The #GList structure and its associated functions provide a standard
+ * doubly-linked list data structure.
+ *
+ * Each element in the list contains a piece of data, together with
+ * pointers which link to the previous and next elements in the list.
+ * Using these pointers it is possible to move through the list in both
+ * directions (unlike the <link
+ * linkend="glib-Singly-Linked-Lists">Singly-Linked Lists</link> which
+ * only allows movement through the list in the forward direction).
+ *
+ * The data contained in each element can be either integer values, by
+ * using one of the <link linkend="glib-Type-Conversion-Macros">Type
+ * Conversion Macros</link>, or simply pointers to any type of data.
+ *
+ * List elements are allocated from the <link
+ * linkend="glib-Memory-Slices">slice allocator</link>, which is more
+ * efficient than allocating elements individually.
+ *
+ * Note that most of the #GList functions expect to be passed a pointer
+ * to the first element in the list. The functions which insert
+ * elements return the new start of the list, which may have changed.
+ *
+ * There is no function to create a #GList. %NULL is considered to be
+ * the empty list so you simply set a #GList* to %NULL.
+ *
+ * To add elements, use g_list_append(), g_list_prepend(),
+ * g_list_insert() and g_list_insert_sorted().
+ *
+ * To remove elements, use g_list_remove().
+ *
+ * To find elements in the list use g_list_first(), g_list_last(),
+ * g_list_next(), g_list_previous(), g_list_nth(), g_list_nth_data(),
+ * g_list_find() and g_list_find_custom().
+ *
+ * To find the index of an element use g_list_position() and
+ * g_list_index().
+ *
+ * To call a function for each element in the list use g_list_foreach().
+ *
+ * To free the entire list, use g_list_free().
+ **/
+
+/**
+ * GList:
+ * @data: holds the element's data, which can be a pointer to any kind
+ *        of data, or any integer value using the <link
+ *        linkend="glib-Type-Conversion-Macros">Type Conversion
+ *        Macros</link>.
+ * @next: contains the link to the next element in the list.
+ * @prev: contains the link to the previous element in the list.
+ *
+ * The #GList struct is used for each element in a doubly-linked list.
+ **/
+
+/**
+ * g_list_previous:
+ * @list: an element in a #GList.
+ * @Returns: the previous element, or %NULL if there are no previous
+ *           elements.
+ *
+ * A convenience macro to get the previous element in a #GList.
+ **/
+
+/**
+ * g_list_next:
+ * @list: an element in a #GList.
+ * @Returns: the next element, or %NULL if there are no more elements.
+ *
+ * A convenience macro to get the next element in a #GList.
+ **/
+
+
+
+/**
+ * g_list_push_allocator:
+ * @allocator: the #GAllocator to use when allocating #GList elements.
+ *
+ * Sets the allocator to use to allocate #GList elements. Use
+ * g_list_pop_allocator() to restore the previous allocator.
+ *
+ * Note that this function is not available if GLib has been compiled
+ * with <option>--disable-mem-pools</option>
+ *
+ * Deprecated:2.10: It does nothing, since #GList has been converted
+ *                  to the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link>
+ **/
+void g_list_push_allocator (gpointer dummy) { /* present for binary compat only */ }
+
+/**
+ * g_list_pop_allocator:
+ *
+ * Restores the previous #GAllocator, used when allocating #GList
+ * elements.
+ *
+ * Note that this function is not available if GLib has been compiled
+ * with <option>--disable-mem-pools</option>
+ *
+ * Deprecated:2.10: It does nothing, since #GList has been converted
+ *                  to the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link>
+ **/
+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)
+
+/**
+ * g_list_alloc:
+ * @Returns: a pointer to the newly-allocated #GList element.
+ *
+ * Allocates space for one #GList element. It is called by
+ * g_list_append(), g_list_prepend(), g_list_insert() and
+ * g_list_insert_sorted() and so is rarely used on its own.
+ **/
+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, 
+ * you should either use g_list_free_full() or free them manually
+ * 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().
+ */
+/**
+ * g_list_free1:
+ *
+ * Another name for g_list_free_1().
+ **/
+void
+g_list_free_1 (GList *list)
+{
+  _g_list_free1 (list);
+}
+
+/**
+ * g_list_free_full:
+ * @list: a pointer to a #GList
+ * @free_func: the function to be called to free each element's data
+ *
+ * Convenience method, which frees all the memory used by a #GList, and
+ * calls the specified destroy function on every element's data.
+ *
+ * Since: 2.28
+ */
+void
+g_list_free_full (GList          *list,
+		  GDestroyNotify  free_func)
+{
+  g_list_foreach (list, (GFunc) free_func, NULL);
+  g_list_free (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.
+ */
+/**
+ * GFunc:
+ * @data: the element's data.
+ * @user_data: user data passed to g_list_foreach() or
+ *             g_slist_foreach().
+ *
+ * Specifies the type of functions passed to g_list_foreach() and
+ * g_slist_foreach().
+ **/
+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
+ */
+/**
+ * GCompareFunc:
+ * @a: a value.
+ * @b: a value to compare with.
+ * @Returns: negative value if @a &lt; @b; zero if @a = @b; positive
+ *           value if @a > @b.
+ *
+ * Specifies the type of a comparison function used to compare two
+ * values.  The function should return a negative integer if the first
+ * value comes before the second, 0 if they are equal, or a positive
+ * integer if the first value comes after the second.
+ **/
+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
+ */
+/**
+ * GCompareDataFunc:
+ * @a: a value.
+ * @b: a value to compare with.
+ * @user_data: user data to pass to comparison function.
+ * @Returns: negative value if @a &lt; @b; zero if @a = @b; positive
+ *           value if @a > @b.
+ *
+ * Specifies the type of a comparison function used to compare two
+ * values.  The function should return a negative integer if the first
+ * value comes before the second, 0 if they are equal, or a positive
+ * integer if the first value comes after the second.
+ **/
+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);
+}
diff --git a/deps/glib/glist.h b/deps/glib/glist.h
new file mode 100644
index 0000000..275005c
--- /dev/null
+++ b/deps/glib/glist.h
@@ -0,0 +1,122 @@
+/* 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
+void     g_list_free_full               (GList            *list,
+					 GDestroyNotify    free_func);
+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/deps/glib/gmacros.h b/deps/glib/gmacros.h
new file mode 100644
index 0000000..50a03ed
--- /dev/null
+++ b/deps/glib/gmacros.h
@@ -0,0 +1,290 @@
+/* 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__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define G_GNUC_DEPRECATED_FOR(f)                        \
+  __attribute__((deprecated("Use " #f " instead")))
+#else
+#define G_GNUC_DEPRECATED_FOR(f)        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
+
+#ifndef __GI_SCANNER__ /* The static assert macro really confuses the introspection parser */
+#define G_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2
+#define G_PASTE(identifier1,identifier2)      G_PASTE_ARGS (identifier1, identifier2)
+#ifdef __COUNTER__
+#define G_STATIC_ASSERT(expr) typedef char G_PASTE (_GStaticAssertCompileTimeAssertion_, __COUNTER__)[(expr) ? 1 : -1]
+#else
+#define G_STATIC_ASSERT(expr) typedef char G_PASTE (_GStaticAssertCompileTimeAssertion_, __LINE__)[(expr) ? 1 : -1]
+#endif
+#define G_STATIC_ASSERT_EXPR(expr) ((void) sizeof (char[(expr) ? 1 : -1]))
+#endif
+
+/* 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) 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
+
+/* Deprecated -- do not use. */
+#ifndef G_DISABLE_DEPRECATED
+#ifdef G_DISABLE_CONST_RETURNS
+#define G_CONST_RETURN
+#else
+#define G_CONST_RETURN const
+#endif
+#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)                   \
+ G_GNUC_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/deps/glib/gmem.c b/deps/glib/gmem.c
new file mode 100644
index 0000000..a657f73
--- /dev/null
+++ b/deps/glib/gmem.c
@@ -0,0 +1,1397 @@
+/* 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 "gmem.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include "gbacktrace.h"
+#include "gtestutils.h"
+#include "gthread.h"
+#include "glib_trace.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.ac 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,
+};
+
+/**
+ * SECTION:memory
+ * @Short_Description: general memory-handling
+ * @Title: Memory Allocation
+ * 
+ * These functions provide support for allocating and freeing memory.
+ * 
+ * <note>
+ * If any call to allocate memory fails, the application is terminated.
+ * This also means that there is no need to check if the call succeeded.
+ * </note>
+ * 
+ * <note>
+ * It's important to match g_malloc() with g_free(), plain malloc() with free(),
+ * and (if you're using C++) new with delete and new[] with delete[]. Otherwise
+ * bad things can happen, since these allocators may use different memory
+ * pools (and new/delete call constructors and destructors). See also
+ * g_mem_set_vtable().
+ * </note>
+ */
+
+/* --- functions --- */
+/**
+ * g_malloc:
+ * @n_bytes: the number of bytes to allocate
+ * 
+ * Allocates @n_bytes bytes of memory.
+ * If @n_bytes is 0 it returns %NULL.
+ * 
+ * Returns: a pointer to the allocated memory
+ */
+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);
+      TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 0));
+      if (mem)
+	return mem;
+
+      g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_bytes);
+    }
+
+  TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 0, 0));
+
+  return NULL;
+}
+
+/**
+ * g_malloc0:
+ * @n_bytes: the number of bytes to allocate
+ * 
+ * Allocates @n_bytes bytes of memory, initialized to 0's.
+ * If @n_bytes is 0 it returns %NULL.
+ * 
+ * Returns: a pointer to the allocated memory
+ */
+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);
+      TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 1, 0));
+      if (mem)
+	return mem;
+
+      g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_bytes);
+    }
+
+  TRACE(GLIB_MEM_ALLOC((void*) NULL, (int) n_bytes, 1, 0));
+
+  return NULL;
+}
+
+/**
+ * g_realloc:
+ * @mem: the memory to reallocate
+ * @n_bytes: new size of the memory in bytes
+ * 
+ * Reallocates the memory pointed to by @mem, so that it now has space for
+ * @n_bytes bytes of memory. It returns the new address of the memory, which may
+ * have been moved. @mem may be %NULL, in which case it's considered to
+ * have zero-length. @n_bytes may be 0, in which case %NULL will be returned
+ * and @mem will be freed unless it is %NULL.
+ * 
+ * Returns: the new address of the allocated memory
+ */
+gpointer
+g_realloc (gpointer mem,
+	   gsize    n_bytes)
+{
+  gpointer newmem;
+
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    {
+      newmem = glib_mem_vtable.realloc (mem, n_bytes);
+      TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 0));
+      if (newmem)
+	return newmem;
+
+      g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_bytes);
+    }
+
+  if (mem)
+    glib_mem_vtable.free (mem);
+
+  TRACE (GLIB_MEM_REALLOC((void*) NULL, (void*)mem, 0, 0));
+
+  return NULL;
+}
+
+/**
+ * g_free:
+ * @mem: the memory to free
+ * 
+ * Frees the memory pointed to by @mem.
+ * If @mem is %NULL it simply returns.
+ */
+void
+g_free (gpointer mem)
+{
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (mem))
+    glib_mem_vtable.free (mem);
+  TRACE(GLIB_MEM_FREE((void*) mem));
+}
+
+/**
+ * g_try_malloc:
+ * @n_bytes: number of bytes to allocate.
+ * 
+ * Attempts to allocate @n_bytes, and returns %NULL on failure.
+ * Contrast with g_malloc(), which aborts the program on failure.
+ * 
+ * Returns: the allocated memory, or %NULL.
+ */
+gpointer
+g_try_malloc (gsize n_bytes)
+{
+  gpointer mem;
+
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    mem = glib_mem_vtable.try_malloc (n_bytes);
+  else
+    mem = NULL;
+
+  TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 1));
+
+  return mem;
+}
+
+/**
+ * g_try_malloc0:
+ * @n_bytes: number of bytes to allocate
+ * 
+ * Attempts to allocate @n_bytes, initialized to 0's, and returns %NULL on
+ * failure. Contrast with g_malloc0(), which aborts the program on failure.
+ * 
+ * Since: 2.8
+ * Returns: the allocated memory, or %NULL
+ */
+gpointer
+g_try_malloc0 (gsize n_bytes)
+{
+  gpointer mem;
+
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    mem = glib_mem_vtable.try_malloc (n_bytes);
+  else
+    mem = NULL;
+
+  if (mem)
+    memset (mem, 0, n_bytes);
+
+  return mem;
+}
+
+/**
+ * g_try_realloc:
+ * @mem: previously-allocated memory, or %NULL.
+ * @n_bytes: number of bytes to allocate.
+ * 
+ * Attempts to realloc @mem to a new size, @n_bytes, and returns %NULL
+ * on failure. Contrast with g_realloc(), which aborts the program
+ * on failure. If @mem is %NULL, behaves the same as g_try_malloc().
+ * 
+ * Returns: the allocated memory, or %NULL.
+ */
+gpointer
+g_try_realloc (gpointer mem,
+	       gsize    n_bytes)
+{
+  gpointer newmem;
+
+  if (G_UNLIKELY (!g_mem_initialized))
+    g_mem_init_nomessage();
+  if (G_LIKELY (n_bytes))
+    newmem = glib_mem_vtable.try_realloc (mem, n_bytes);
+  else
+    {
+      newmem = NULL;
+      if (mem)
+	glib_mem_vtable.free (mem);
+    }
+
+  TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 1));
+
+  return newmem;
+}
+
+
+#define SIZE_OVERFLOWS(a,b) (G_UNLIKELY ((b) > 0 && (a) > G_MAXSIZE / (b)))
+
+/**
+ * g_malloc_n:
+ * @n_blocks: the number of blocks to allocate
+ * @n_block_bytes: the size of each block in bytes
+ * 
+ * This function is similar to g_malloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+ * but care is taken to detect possible overflow during multiplication.
+ * 
+ * Since: 2.24
+ * Returns: a pointer to the allocated memory
+ */
+gpointer
+g_malloc_n (gsize n_blocks,
+	    gsize n_block_bytes)
+{
+  if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+    {
+      if (G_UNLIKELY (!g_mem_initialized))
+	g_mem_init_nomessage();
+
+      g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_blocks, n_block_bytes);
+    }
+
+  return g_malloc (n_blocks * n_block_bytes);
+}
+
+/**
+ * g_malloc0_n:
+ * @n_blocks: the number of blocks to allocate
+ * @n_block_bytes: the size of each block in bytes
+ * 
+ * This function is similar to g_malloc0(), allocating (@n_blocks * @n_block_bytes) bytes,
+ * but care is taken to detect possible overflow during multiplication.
+ * 
+ * Since: 2.24
+ * Returns: a pointer to the allocated memory
+ */
+gpointer
+g_malloc0_n (gsize n_blocks,
+	     gsize n_block_bytes)
+{
+  if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+    {
+      if (G_UNLIKELY (!g_mem_initialized))
+	g_mem_init_nomessage();
+
+      g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_blocks, n_block_bytes);
+    }
+
+  return g_malloc0 (n_blocks * n_block_bytes);
+}
+
+/**
+ * g_realloc_n:
+ * @mem: the memory to reallocate
+ * @n_blocks: the number of blocks to allocate
+ * @n_block_bytes: the size of each block in bytes
+ * 
+ * This function is similar to g_realloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+ * but care is taken to detect possible overflow during multiplication.
+ * 
+ * Since: 2.24
+ * Returns: the new address of the allocated memory
+ */
+gpointer
+g_realloc_n (gpointer mem,
+	     gsize    n_blocks,
+	     gsize    n_block_bytes)
+{
+  if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+    {
+      if (G_UNLIKELY (!g_mem_initialized))
+	g_mem_init_nomessage();
+
+      g_error ("%s: overflow allocating %"G_GSIZE_FORMAT"*%"G_GSIZE_FORMAT" bytes",
+               G_STRLOC, n_blocks, n_block_bytes);
+    }
+
+  return g_realloc (mem, n_blocks * n_block_bytes);
+}
+
+/**
+ * g_try_malloc_n:
+ * @n_blocks: the number of blocks to allocate
+ * @n_block_bytes: the size of each block in bytes
+ * 
+ * This function is similar to g_try_malloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+ * but care is taken to detect possible overflow during multiplication.
+ * 
+ * Since: 2.24
+ * Returns: the allocated memory, or %NULL.
+ */
+gpointer
+g_try_malloc_n (gsize n_blocks,
+		gsize n_block_bytes)
+{
+  if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+    return NULL;
+
+  return g_try_malloc (n_blocks * n_block_bytes);
+}
+
+/**
+ * g_try_malloc0_n:
+ * @n_blocks: the number of blocks to allocate
+ * @n_block_bytes: the size of each block in bytes
+ * 
+ * This function is similar to g_try_malloc0(), allocating (@n_blocks * @n_block_bytes) bytes,
+ * but care is taken to detect possible overflow during multiplication.
+ * 
+ * Since: 2.24
+ * Returns: the allocated memory, or %NULL
+ */
+gpointer
+g_try_malloc0_n (gsize n_blocks,
+		 gsize n_block_bytes)
+{
+  if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+    return NULL;
+
+  return g_try_malloc0 (n_blocks * n_block_bytes);
+}
+
+/**
+ * g_try_realloc_n:
+ * @mem: previously-allocated memory, or %NULL.
+ * @n_blocks: the number of blocks to allocate
+ * @n_block_bytes: the size of each block in bytes
+ * 
+ * This function is similar to g_try_realloc(), allocating (@n_blocks * @n_block_bytes) bytes,
+ * but care is taken to detect possible overflow during multiplication.
+ * 
+ * Since: 2.24
+ * Returns: the allocated memory, or %NULL.
+ */
+gpointer
+g_try_realloc_n (gpointer mem,
+		 gsize    n_blocks,
+		 gsize    n_block_bytes)
+{
+  if (SIZE_OVERFLOWS (n_blocks, n_block_bytes))
+    return NULL;
+
+  return g_try_realloc (mem, n_blocks * n_block_bytes);
+}
+
+
+
+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;
+}
+
+/**
+ * g_mem_set_vtable:
+ * @vtable: table of memory allocation routines.
+ * 
+ * Sets the #GMemVTable to use for memory allocation. You can use this to provide
+ * custom memory allocation routines. <emphasis>This function must be called
+ * before using any other GLib functions.</emphasis> The @vtable only needs to
+ * provide malloc(), realloc(), and free() functions; GLib can provide default
+ * implementations of the others. The malloc() and realloc() implementations
+ * should return %NULL on failure, GLib will handle error-checking for you.
+ * @vtable is copied, so need not persist after this function has been called.
+ */
+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
+/**
+ * glib_mem_profiler_table:
+ * 
+ * A #GMemVTable containing profiling variants of the memory
+ * allocation functions. Use them together with g_mem_profile()
+ * in order to get information about the memory allocation pattern
+ * of your program.
+ */
+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");
+}
+
+/**
+ * g_mem_profile:
+ * @void:
+ * 
+ * Outputs a summary of memory usage.
+ * 
+ * It outputs the frequency of allocations of different sizes,
+ * the total number of bytes which have been allocated,
+ * the total number of bytes which have been freed,
+ * and the difference between the previous two values, i.e. the number of bytes
+ * still in use.
+ * 
+ * Note that this function will not output anything unless you have
+ * previously installed the #glib_mem_profiler_table with g_mem_set_vtable().
+ */
+
+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 --- */
+/**
+ * SECTION:allocators
+ * @title: Memory Allocators
+ * @short_description: deprecated way to allocate chunks of memory for
+ *                     GList, GSList and GNode
+ *
+ * Prior to 2.10, #GAllocator was used as an efficient way to allocate
+ * small pieces of memory for use with the #GList, #GSList and #GNode
+ * data structures. Since 2.10, it has been completely replaced by the
+ * <link linkend="glib-Memory-Slices">slice allocator</link> and
+ * deprecated.
+ **/
+
+/**
+ * SECTION:memory_chunks
+ * @title: Memory Chunks
+ * @short_description: deprecated way to allocate groups of equal-sized
+ *                     chunks of memory
+ *
+ * Memory chunks provide an space-efficient way to allocate equal-sized
+ * pieces of memory, called atoms. However, due to the administrative
+ * overhead (in particular for #G_ALLOC_AND_FREE, and when used from
+ * multiple threads), they are in practise often slower than direct use
+ * of g_malloc(). Therefore, memory chunks have been deprecated in
+ * favor of the <link linkend="glib-Memory-Slices">slice
+ * allocator</link>, which has been added in 2.10. All internal uses of
+ * memory chunks in GLib have been converted to the
+ * <literal>g_slice</literal> API.
+ *
+ * There are two types of memory chunks, #G_ALLOC_ONLY, and
+ * #G_ALLOC_AND_FREE. <itemizedlist> <listitem><para> #G_ALLOC_ONLY
+ * chunks only allow allocation of atoms. The atoms can never be freed
+ * individually. The memory chunk can only be free in its entirety.
+ * </para></listitem> <listitem><para> #G_ALLOC_AND_FREE chunks do
+ * allow atoms to be freed individually. The disadvantage of this is
+ * that the memory chunk has to keep track of which atoms have been
+ * freed. This results in more memory being used and a slight
+ * degradation in performance. </para></listitem> </itemizedlist>
+ *
+ * To create a memory chunk use g_mem_chunk_new() or the convenience
+ * macro g_mem_chunk_create().
+ *
+ * To allocate a new atom use g_mem_chunk_alloc(),
+ * g_mem_chunk_alloc0(), or the convenience macros g_chunk_new() or
+ * g_chunk_new0().
+ *
+ * To free an atom use g_mem_chunk_free(), or the convenience macro
+ * g_chunk_free(). (Atoms can only be freed if the memory chunk is
+ * created with the type set to #G_ALLOC_AND_FREE.)
+ *
+ * To free any blocks of memory which are no longer being used, use
+ * g_mem_chunk_clean(). To clean all memory chunks, use g_blow_chunks().
+ *
+ * To reset the memory chunk, freeing all of the atoms, use
+ * g_mem_chunk_reset().
+ *
+ * To destroy a memory chunk, use g_mem_chunk_destroy().
+ *
+ * To help debug memory chunks, use g_mem_chunk_info() and
+ * g_mem_chunk_print().
+ *
+ * <example>
+ *  <title>Using a #GMemChunk</title>
+ *  <programlisting>
+ *   GMemChunk *mem_chunk;
+ *   gchar *mem[10000];
+ *   gint i;
+ *
+ *   /<!-- -->* Create a GMemChunk with atoms 50 bytes long, and memory
+ *      blocks holding 100 bytes. Note that this means that only 2 atoms
+ *      fit into each memory block and so isn't very efficient. *<!-- -->/
+ *   mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE);
+ *   /<!-- -->* Now allocate 10000 atoms. *<!-- -->/
+ *   for (i = 0; i &lt; 10000; i++)
+ *     {
+ *       mem[i] = g_chunk_new (gchar, mem_chunk);
+ *       /<!-- -->* Fill in the atom memory with some junk. *<!-- -->/
+ *       for (j = 0; j &lt; 50; j++)
+ *         mem[i][j] = i * j;
+ *     }
+ *   /<!-- -->* Now free all of the atoms. Note that since we are going to
+ *      destroy the GMemChunk, this wouldn't normally be used. *<!-- -->/
+ *   for (i = 0; i &lt; 10000; i++)
+ *     {
+ *       g_mem_chunk_free (mem_chunk, mem[i]);
+ *     }
+ *   /<!-- -->* We are finished with the GMemChunk, so we destroy it. *<!-- -->/
+ *   g_mem_chunk_destroy (mem_chunk);
+ *  </programlisting>
+ * </example>
+ *
+ * <example>
+ *  <title>Using a #GMemChunk with data structures</title>
+ *  <programlisting>
+ *    GMemChunk *array_mem_chunk;
+ *    GRealArray *array;
+ *    /<!-- -->* Create a GMemChunk to hold GRealArray structures, using
+ *       the g_mem_chunk_create(<!-- -->) convenience macro. We want 1024 atoms in each
+ *       memory block, and we want to be able to free individual atoms. *<!-- -->/
+ *    array_mem_chunk = g_mem_chunk_create (GRealArray, 1024, G_ALLOC_AND_FREE);
+ *    /<!-- -->* Allocate one atom, using the g_chunk_new(<!-- -->) convenience macro. *<!-- -->/
+ *    array = g_chunk_new (GRealArray, array_mem_chunk);
+ *    /<!-- -->* We can now use array just like a normal pointer to a structure. *<!-- -->/
+ *    array->data            = NULL;
+ *    array->len             = 0;
+ *    array->alloc           = 0;
+ *    array->zero_terminated = (zero_terminated ? 1 : 0);
+ *    array->clear           = (clear ? 1 : 0);
+ *    array->elt_size        = elt_size;
+ *    /<!-- -->* We can free the element, so it can be reused. *<!-- -->/
+ *    g_chunk_free (array, array_mem_chunk);
+ *    /<!-- -->* We destroy the GMemChunk when we are finished with it. *<!-- -->/
+ *    g_mem_chunk_destroy (array_mem_chunk);
+ *  </programlisting>
+ * </example>
+ **/
+
+#ifndef G_ALLOC_AND_FREE
+
+/**
+ * GAllocator:
+ *
+ * The #GAllocator struct contains private data. and should only be
+ * accessed using the following functions.
+ **/
+typedef struct _GAllocator GAllocator;
+
+/**
+ * GMemChunk:
+ *
+ * The #GMemChunk struct is an opaque data structure representing a
+ * memory chunk. It should be accessed only through the use of the
+ * following functions.
+ **/
+typedef struct _GMemChunk  GMemChunk;
+
+/**
+ * G_ALLOC_ONLY:
+ *
+ * Specifies the type of a #GMemChunk. Used in g_mem_chunk_new() and
+ * g_mem_chunk_create() to specify that atoms will never be freed
+ * individually.
+ **/
+#define G_ALLOC_ONLY	  1
+
+/**
+ * G_ALLOC_AND_FREE:
+ *
+ * Specifies the type of a #GMemChunk. Used in g_mem_chunk_new() and
+ * g_mem_chunk_create() to specify that atoms will be freed
+ * individually.
+ **/
+#define G_ALLOC_AND_FREE  2
+#endif
+
+struct _GMemChunk {
+  guint alloc_size;           /* the size of an atom */
+};
+
+/**
+ * g_mem_chunk_new:
+ * @name: a string to identify the #GMemChunk. It is not copied so it
+ *        should be valid for the lifetime of the #GMemChunk. It is
+ *        only used in g_mem_chunk_print(), which is used for debugging.
+ * @atom_size: the size, in bytes, of each element in the #GMemChunk.
+ * @area_size: the size, in bytes, of each block of memory allocated to
+ *             contain the atoms.
+ * @type: the type of the #GMemChunk.  #G_ALLOC_AND_FREE is used if the
+ *        atoms will be freed individually.  #G_ALLOC_ONLY should be
+ *        used if atoms will never be freed individually.
+ *        #G_ALLOC_ONLY is quicker, since it does not need to track
+ *        free atoms, but it obviously wastes memory if you no longer
+ *        need many of the atoms.
+ * @Returns: the new #GMemChunk.
+ *
+ * Creates a new #GMemChunk.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+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;
+}
+
+/**
+ * g_mem_chunk_destroy:
+ * @mem_chunk: a #GMemChunk.
+ *
+ * Frees all of the memory allocated for a #GMemChunk.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void
+g_mem_chunk_destroy (GMemChunk *mem_chunk)
+{
+  g_return_if_fail (mem_chunk != NULL);
+  
+  g_slice_free (GMemChunk, mem_chunk);
+}
+
+/**
+ * g_mem_chunk_alloc:
+ * @mem_chunk: a #GMemChunk.
+ * @Returns: a pointer to the allocated atom.
+ *
+ * Allocates an atom of memory from a #GMemChunk.
+ *
+ * Deprecated:2.10: Use g_slice_alloc() instead
+ **/
+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);
+}
+
+/**
+ * g_mem_chunk_alloc0:
+ * @mem_chunk: a #GMemChunk.
+ * @Returns: a pointer to the allocated atom.
+ *
+ * Allocates an atom of memory from a #GMemChunk, setting the memory to
+ * 0.
+ *
+ * Deprecated:2.10: Use g_slice_alloc0() instead
+ **/
+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);
+}
+
+/**
+ * g_mem_chunk_free:
+ * @mem_chunk: a #GMemChunk.
+ * @mem: a pointer to the atom to free.
+ *
+ * Frees an atom in a #GMemChunk. This should only be called if the
+ * #GMemChunk was created with #G_ALLOC_AND_FREE. Otherwise it will
+ * simply return.
+ *
+ * Deprecated:2.10: Use g_slice_free1() instead
+ **/
+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);
+}
+
+/**
+ * g_mem_chunk_clean:
+ * @mem_chunk: a #GMemChunk.
+ *
+ * Frees any blocks in a #GMemChunk which are no longer being used.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void	g_mem_chunk_clean	(GMemChunk *mem_chunk)	{}
+
+/**
+ * g_mem_chunk_reset:
+ * @mem_chunk: a #GMemChunk.
+ *
+ * Resets a GMemChunk to its initial state. It frees all of the
+ * currently allocated blocks of memory.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void	g_mem_chunk_reset	(GMemChunk *mem_chunk)	{}
+
+
+/**
+ * g_mem_chunk_print:
+ * @mem_chunk: a #GMemChunk.
+ *
+ * Outputs debugging information for a #GMemChunk. It outputs the name
+ * of the #GMemChunk (set with g_mem_chunk_new()), the number of bytes
+ * used, and the number of blocks of memory allocated.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void	g_mem_chunk_print	(GMemChunk *mem_chunk)	{}
+
+
+/**
+ * g_mem_chunk_info:
+ *
+ * Outputs debugging information for all #GMemChunk objects currently
+ * in use. It outputs the number of #GMemChunk objects currently
+ * allocated, and calls g_mem_chunk_print() to output information on
+ * each one.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void	g_mem_chunk_info	(void)			{}
+
+/**
+ * g_blow_chunks:
+ *
+ * Calls g_mem_chunk_clean() on all #GMemChunk objects.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void	g_blow_chunks		(void)			{}
+
+/**
+ * g_chunk_new0:
+ * @type: the type of the #GMemChunk atoms, typically a structure name.
+ * @chunk: a #GMemChunk.
+ * @Returns: a pointer to the allocated atom, cast to a pointer to
+ *           @type.
+ *
+ * A convenience macro to allocate an atom of memory from a #GMemChunk.
+ * It calls g_mem_chunk_alloc0() and casts the returned atom to a
+ * pointer to the given type, avoiding a type cast in the source code.
+ *
+ * Deprecated:2.10: Use g_slice_new0() instead
+ **/
+
+/**
+ * g_chunk_free:
+ * @mem: a pointer to the atom to be freed.
+ * @mem_chunk: a #GMemChunk.
+ *
+ * A convenience macro to free an atom of memory from a #GMemChunk. It
+ * simply switches the arguments and calls g_mem_chunk_free() It is
+ * included simply to complement the other convenience macros,
+ * g_chunk_new() and g_chunk_new0().
+ *
+ * Deprecated:2.10: Use g_slice_free() instead
+ **/
+
+/**
+ * g_chunk_new:
+ * @type: the type of the #GMemChunk atoms, typically a structure name.
+ * @chunk: a #GMemChunk.
+ * @Returns: a pointer to the allocated atom, cast to a pointer to
+ *           @type.
+ *
+ * A convenience macro to allocate an atom of memory from a #GMemChunk.
+ * It calls g_mem_chunk_alloc() and casts the returned atom to a
+ * pointer to the given type, avoiding a type cast in the source code.
+ *
+ * Deprecated:2.10: Use g_slice_new() instead
+ **/
+
+/**
+ * g_mem_chunk_create:
+ * @type: the type of the atoms, typically a structure name.
+ * @pre_alloc: the number of atoms to store in each block of memory.
+ * @alloc_type: the type of the #GMemChunk.  #G_ALLOC_AND_FREE is used
+ *              if the atoms will be freed individually.  #G_ALLOC_ONLY
+ *              should be used if atoms will never be freed
+ *              individually.  #G_ALLOC_ONLY is quicker, since it does
+ *              not need to track free atoms, but it obviously wastes
+ *              memory if you no longer need many of the atoms.
+ * @Returns: the new #GMemChunk.
+ *
+ * A convenience macro for creating a new #GMemChunk. It calls
+ * g_mem_chunk_new(), using the given type to create the #GMemChunk
+ * name. The atom size is determined using
+ * <function>sizeof()</function>, and the area size is calculated by
+ * multiplying the @pre_alloc parameter with the atom size.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+
+
+/**
+ * g_allocator_new:
+ * @name: the name of the #GAllocator. This name is used to set the
+ *        name of the #GMemChunk used by the #GAllocator, and is only
+ *        used for debugging.
+ * @n_preallocs: the number of elements in each block of memory
+ *               allocated.  Larger blocks mean less calls to
+ *               g_malloc(), but some memory may be wasted.  (GLib uses
+ *               128 elements per block by default.) The value must be
+ *               between 1 and 65535.
+ * @Returns: a new #GAllocator.
+ *
+ * Creates a new #GAllocator.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+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;
+}
+
+/**
+ * g_allocator_free:
+ * @allocator: a #GAllocator.
+ *
+ * Frees all of the memory allocated by the #GAllocator.
+ *
+ * Deprecated:2.10: Use the <link linkend="glib-Memory-Slices">slice
+ *                  allocator</link> instead
+ **/
+void
+g_allocator_free (GAllocator *allocator)
+{
+}
+
+#ifdef ENABLE_GC_FRIENDLY_DEFAULT
+gboolean g_mem_gc_friendly = TRUE;
+#else
+/**
+ * g_mem_gc_friendly:
+ * 
+ * This variable is %TRUE if the <envar>G_DEBUG</envar> environment variable
+ * includes the key <link linkend="G_DEBUG">gc-friendly</link>.
+ */
+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
+}
diff --git a/deps/glib/gmem.h b/deps/glib/gmem.h
new file mode 100644
index 0000000..a8ff4ac
--- /dev/null
+++ b/deps/glib/gmem.h
@@ -0,0 +1,309 @@
+/* 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
+
+/**
+ * GMemVTable:
+ * @malloc: function to use for allocating memory.
+ * @realloc: function to use for reallocating memory.
+ * @free: function to use to free memory.
+ * @calloc: function to use for allocating zero-filled memory.
+ * @try_malloc: function to use for allocating memory without a default error handler.
+ * @try_realloc: function to use for reallocating memory without a default error handler.
+ * 
+ * A set of functions used to perform memory allocation. The same #GMemVTable must
+ * be used for all allocations in the same program; a call to g_mem_set_vtable(),
+ * if it exists, should be prior to any use of GLib.
+ */
+typedef struct _GMemVTable GMemVTable;
+
+
+#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG
+/**
+ * G_MEM_ALIGN:
+ *
+ * Indicates the number of bytes to which memory will be aligned on the
+ * current platform.
+ */
+#  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
+ */
+
+void	 g_free	          (gpointer	 mem);
+
+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;
+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;
+
+gpointer g_malloc_n       (gsize	 n_blocks,
+			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_malloc0_n      (gsize	 n_blocks,
+			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_realloc_n      (gpointer	 mem,
+			   gsize	 n_blocks,
+			   gsize	 n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_try_malloc_n   (gsize	 n_blocks,
+			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_try_malloc0_n  (gsize	 n_blocks,
+			   gsize	 n_block_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE2(1,2);
+gpointer g_try_realloc_n  (gpointer	 mem,
+			   gsize	 n_blocks,
+			   gsize	 n_block_bytes) G_GNUC_WARN_UNUSED_RESULT;
+
+
+/* Optimise: avoid the call to the (slower) _n function if we can
+ * determine at compile-time that no overflow happens.
+ */
+#if defined (__GNUC__) && (__GNUC__ >= 2) && defined (__OPTIMIZE__)
+#  define _G_NEW(struct_type, n_structs, func) \
+	(struct_type *) (G_GNUC_EXTENSION ({			\
+	  gsize __n = (gsize) (n_structs);			\
+	  gsize __s = sizeof (struct_type);			\
+	  gpointer __p;						\
+	  if (__s == 1)						\
+	    __p = g_##func (__n);				\
+	  else if (__builtin_constant_p (__n) &&		\
+	           (__s == 0 || __n <= G_MAXSIZE / __s))	\
+	    __p = g_##func (__n * __s);				\
+	  else							\
+	    __p = g_##func##_n (__n, __s);			\
+	  __p;							\
+	}))
+#  define _G_RENEW(struct_type, mem, n_structs, func) \
+	(struct_type *) (G_GNUC_EXTENSION ({			\
+	  gsize __n = (gsize) (n_structs);			\
+	  gsize __s = sizeof (struct_type);			\
+	  gpointer __p = (gpointer) (mem);			\
+	  if (__s == 1)						\
+	    __p = g_##func (__p, __n);				\
+	  else if (__builtin_constant_p (__n) &&		\
+	           (__s == 0 || __n <= G_MAXSIZE / __s))	\
+	    __p = g_##func (__p, __n * __s);			\
+	  else							\
+	    __p = g_##func##_n (__p, __n, __s);			\
+	  __p;							\
+	}))
+
+#else
+
+/* Unoptimised version: always call the _n() function. */
+
+#define _G_NEW(struct_type, n_structs, func) \
+        ((struct_type *) g_##func##_n ((n_structs), sizeof (struct_type)))
+#define _G_RENEW(struct_type, mem, n_structs, func) \
+        ((struct_type *) g_##func##_n (mem, (n_structs), sizeof (struct_type)))
+
+#endif
+
+/**
+ * g_new:
+ * @struct_type: the type of the elements to allocate
+ * @n_structs: the number of elements to allocate
+ * 
+ * Allocates @n_structs elements of type @struct_type.
+ * The returned pointer is cast to a pointer to the given type.
+ * If @n_structs is 0 it returns %NULL.
+ * Care is taken to avoid overflow when calculating the size of the allocated block.
+ * 
+ * Since the returned pointer is already casted to the right type,
+ * it is normally unnecessary to cast it explicitly, and doing
+ * so might hide memory allocation errors.
+ * 
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type
+ */
+#define g_new(struct_type, n_structs)			_G_NEW (struct_type, n_structs, malloc)
+/**
+ * g_new0:
+ * @struct_type: the type of the elements to allocate.
+ * @n_structs: the number of elements to allocate.
+ * 
+ * Allocates @n_structs elements of type @struct_type, initialized to 0's.
+ * The returned pointer is cast to a pointer to the given type.
+ * If @n_structs is 0 it returns %NULL.
+ * Care is taken to avoid overflow when calculating the size of the allocated block.
+ * 
+ * Since the returned pointer is already casted to the right type,
+ * it is normally unnecessary to cast it explicitly, and doing
+ * so might hide memory allocation errors.
+ * 
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type.
+ */
+#define g_new0(struct_type, n_structs)			_G_NEW (struct_type, n_structs, malloc0)
+/**
+ * g_renew:
+ * @struct_type: the type of the elements to allocate
+ * @mem: the currently allocated memory
+ * @n_structs: the number of elements to allocate
+ * 
+ * Reallocates the memory pointed to by @mem, so that it now has space for
+ * @n_structs elements of type @struct_type. It returns the new address of
+ * the memory, which may have been moved.
+ * Care is taken to avoid overflow when calculating the size of the allocated block.
+ * 
+ * Returns: a pointer to the new allocated memory, cast to a pointer to @struct_type
+ */
+#define g_renew(struct_type, mem, n_structs)		_G_RENEW (struct_type, mem, n_structs, realloc)
+/**
+ * g_try_new:
+ * @struct_type: the type of the elements to allocate
+ * @n_structs: the number of elements to allocate
+ * 
+ * Attempts to allocate @n_structs elements of type @struct_type, and returns
+ * %NULL on failure. Contrast with g_new(), which aborts the program on failure.
+ * The returned pointer is cast to a pointer to the given type.
+ * The function returns %NULL when @n_structs is 0 of if an overflow occurs.
+ * 
+ * Since: 2.8
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type
+ */
+#define g_try_new(struct_type, n_structs)		_G_NEW (struct_type, n_structs, try_malloc)
+/**
+ * g_try_new0:
+ * @struct_type: the type of the elements to allocate
+ * @n_structs: the number of elements to allocate
+ * 
+ * Attempts to allocate @n_structs elements of type @struct_type, initialized
+ * to 0's, and returns %NULL on failure. Contrast with g_new0(), which aborts
+ * the program on failure.
+ * The returned pointer is cast to a pointer to the given type.
+ * The function returns %NULL when @n_structs is 0 of if an overflow occurs.
+ * 
+ * Since: 2.8
+ * Returns: a pointer to the allocated memory, cast to a pointer to @struct_type
+ */
+#define g_try_new0(struct_type, n_structs)		_G_NEW (struct_type, n_structs, try_malloc0)
+/**
+ * g_try_renew:
+ * @struct_type: the type of the elements to allocate
+ * @mem: the currently allocated memory
+ * @n_structs: the number of elements to allocate
+ * 
+ * Attempts to reallocate the memory pointed to by @mem, so that it now has
+ * space for @n_structs elements of type @struct_type, and returns %NULL on
+ * failure. Contrast with g_renew(), which aborts the program on failure.
+ * It returns the new address of the memory, which may have been moved.
+ * The function returns %NULL if an overflow occurs.
+ * 
+ * Since: 2.8
+ * Returns: a pointer to the new allocated memory, cast to a pointer to @struct_type
+ */
+#define g_try_renew(struct_type, mem, n_structs)	_G_RENEW (struct_type, mem, n_structs, try_realloc)
+
+
+/* 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/deps/glib/gmessages.c b/deps/glib/gmessages.c
new file mode 100644
index 0000000..a3b223e
--- /dev/null
+++ b/deps/glib/gmessages.c
@@ -0,0 +1,1218 @@
+/* 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
+ */
+
+/**
+ * SECTION:warnings
+ * @Title: Message Output and Debugging Functions
+ * @Short_description: functions to output messages and help debug applications
+ *
+ * These functions provide support for outputting messages.
+ *
+ * The <function>g_return</function> family of macros (g_return_if_fail(),
+ * g_return_val_if_fail(), g_return_if_reached(), g_return_val_if_reached())
+ * should only be used for programming errors, a typical use case is
+ * checking for invalid parameters at the beginning of a public function.
+ * They should not be used if you just mean "if (error) return", they
+ * should only be used if you mean "if (bug in program) return".
+ * The program behavior is generally considered undefined after one
+ * of these checks fails. They are not intended for normal control
+ * flow, only to give a perhaps-helpful warning before giving up.
+ */
+
+#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 "gmessages.h"
+
+#include "gbacktrace.h"
+#include "gconvert.h"
+#include "gdebug.h"
+#include "gmem.h"
+#include "gprintfint.h"
+#include "gtestutils.h"
+#include "gthread.h"
+#include "gthreadprivate.h"
+#include "gstrfuncs.h"
+#include "gstring.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;
+static GTestLogFatalFunc fatal_log_func = NULL;
+static gpointer          fatal_log_data;
+
+/* --- 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;
+}
+
+/**
+ * g_test_log_set_fatal_handler:
+ * @log_func: the log handler function.
+ * @user_data: data passed to the log handler.
+ *
+ * Installs a non-error fatal log handler which can be
+ * used to decide whether log messages which are counted
+ * as fatal abort the program.
+ *
+ * The use case here is that you are running a test case
+ * that depends on particular libraries or circumstances
+ * and cannot prevent certain known critical or warning
+ * messages. So you install a handler that compares the
+ * domain and message to precisely not abort in such a case.
+ *
+ * Note that the handler is reset at the beginning of
+ * any test case, so you have to set it inside each test
+ * function which needs the special behavior.
+ *
+ * This handler has no effect on g_error messages.
+ *
+ * Since: 2.22
+ **/
+void
+g_test_log_set_fatal_handler (GTestLogFatalFunc log_func,
+                              gpointer          user_data)
+{
+  g_mutex_lock (g_messages_lock);
+  fatal_log_func = log_func;
+  fatal_log_data = user_data;
+  g_mutex_unlock (g_messages_lock);
+}
+
+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;
+          gboolean masquerade_fatal = FALSE;
+
+	  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];
+              gsize size G_GNUC_UNUSED;
+              va_list args2;
+
+              G_VA_COPY (args2, args1);
+	      size = _g_vsnprintf (buffer, 1024, format, args2);
+              va_end (args2);
+
+	      log_func (log_domain, test_level, buffer, data);
+	    }
+	  else
+	    {
+	      gchar *msg;
+              va_list args2;
+
+              G_VA_COPY (args2, args1);
+              msg = g_strdup_vprintf (format, args2);
+              va_end (args2);
+
+	      log_func (log_domain, test_level, msg, data);
+
+              if ((test_level & G_LOG_FLAG_FATAL)
+                && !(test_level & G_LOG_LEVEL_ERROR))
+                {
+                  masquerade_fatal = fatal_log_func
+                    && !fatal_log_func (log_domain, test_level, msg, fatal_log_data);
+                }
+
+	      g_free (msg);
+	    }
+
+	  if ((test_level & G_LOG_FLAG_FATAL) && !masquerade_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 (!(test_level & G_LOG_FLAG_RECURSION))
+		G_BREAKPOINT ();
+	      else
+		abort ();
+#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)
+{
+  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)
+{
+  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
+  int fd;
+
+  /* we cannot 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);
+}
+
+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)
+{
+  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);
+    }
+  g_string_append (gstring, "\n");
+
+  string = g_string_free (gstring, FALSE);
+
+  write_string (fd, string);
+  g_free (string);
+}
+
+/**
+ * g_set_print_handler:
+ * @func: the new print handler
+ *
+ * Sets the print handler.
+ *
+ * Any messages passed to g_print() will be output via
+ * the new handler. The default handler simply outputs
+ * the message to stdout. By providing your own handler
+ * you can redirect the output, to a GTK+ widget or a
+ * log file for example.
+ *
+ * Returns: the old print handler
+ */
+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;
+}
+
+/**
+ * g_print:
+ * @format: the message format. See the printf() documentation
+ * @...: the parameters to insert into the format string
+ *
+ * Outputs a formatted message via the print handler.
+ * The default print handler simply outputs the message to stdout.
+ *
+ * g_print() should not be used from within libraries for debugging
+ * messages, since it may be redirected by applications to special
+ * purpose message windows or even files. Instead, libraries should
+ * use g_log(), or the convenience functions g_message(), g_warning()
+ * and g_error().
+ */
+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);
+}
+
+/**
+ * g_set_printerr_handler:
+ * @func: the new error message handler
+ *
+ * Sets the handler for printing error messages.
+ *
+ * Any messages passed to g_printerr() will be output via
+ * the new handler. The default handler simply outputs the
+ * message to stderr. By providing your own handler you can
+ * redirect the output, to a GTK+ widget or a log file for
+ * example.
+ *
+ * Returns: the old error message handler
+ */
+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;
+}
+
+/**
+ * g_printerr:
+ * @format: the message format. See the printf() documentation
+ * @...: the parameters to insert into the format string
+ *
+ * Outputs a formatted message via the error message handler.
+ * The default handler simply outputs the message to stderr.
+ *
+ * g_printerr() should not be used from within libraries.
+ * Instead g_log() should be used, or the convenience functions
+ * g_message(), g_warning() and g_error().
+ */
+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);
+    }
+}
diff --git a/deps/glib/gmessages.h b/deps/glib/gmessages.h
new file mode 100644
index 0000000..c5220e3
--- /dev/null
+++ b/deps/glib/gmessages.h
@@ -0,0 +1,405 @@
+/* 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().
+ * Put space before ending semicolon to avoid C++ build warnings.
+ */
+#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__ */
+
+/**
+ * GPrintFunc:
+ * @string: the message to output
+ *
+ * Specifies the type of the print handler functions.
+ * These are called with the complete formatted string to output.
+ */
+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);
+
+/**
+ * g_warn_if_reached:
+ *
+ * Logs a critical warning.
+ *
+ * Since: 2.16
+ */
+#define g_warn_if_reached() \
+  do { \
+    g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); \
+  } while (0)
+
+/**
+ * g_warn_if_fail:
+ * @expr: the expression to check
+ *
+ * Logs a warning if the expression is not true.
+ *
+ * Since: 2.16
+ */
+#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
+
+/**
+ * g_return_if_fail:
+ * @expr: the expression to check
+ *
+ * Verifies that the expression evaluates to %TRUE.  If the expression
+ * evaluates to %FALSE, a critical message is logged and the current
+ * function returns.  This can only be used in functions which do not
+ * return a value.
+ *
+ * If G_DISABLE_CHECKS is defined then the check is not performed.  You
+ * should therefore not depend on any side effects of @expr.
+ */
+#define g_return_if_fail(expr) G_STMT_START{ (void)0; }G_STMT_END
+
+/**
+ * g_return_val_if_fail:
+ * @expr: the expression to check
+ * @val: the value to return from the current function
+ *       if the expression is not true
+ *
+ * Verifies that the expression evaluates to %TRUE.  If the expression
+ * evaluates to %FALSE, a critical message is logged and @val is
+ * returned from the current function.
+ *
+ * If G_DISABLE_CHECKS is defined then the check is not performed.  You
+ * should therefore not depend on any side effects of @expr.
+ */
+#define g_return_val_if_fail(expr,val) G_STMT_START{ (void)0; }G_STMT_END
+
+/**
+ * g_return_if_reached:
+ *
+ * Logs a critical message and returns from the current function.
+ * This can only be used in functions which do not return a value.
+ */
+#define g_return_if_reached() G_STMT_START{ return; }G_STMT_END
+
+/**
+ * g_return_val_if_reached:
+ * @val: the value to return from the current function
+ *
+ * Logs a critical message and returns @val.
+ */
+#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/deps/glib/gprintf.c b/deps/glib/gprintf.c
new file mode 100644
index 0000000..346fd95
--- /dev/null
+++ b/deps/glib/gprintf.c
@@ -0,0 +1,340 @@
+/* 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"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gprintf.h"
+#include "gprintfint.h"
+
+
+/**
+ * g_printf:
+ * @format: a standard printf() format string, but notice 
+ *          <link linkend="string-precision">string precision pitfalls</link>.
+ * @...: 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>.
+ * @...: 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>.
+ * @...: 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.
+ *
+ * Note that it is usually better to use g_snprintf(), to avoid the
+ * risk of buffer overflow.
+ *
+ * See also g_strdup_printf().
+ *
+ * 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>.
+ * @...: 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;
+}
diff --git a/deps/glib/gprintf.h b/deps/glib/gprintf.h
new file mode 100644
index 0000000..d96870f
--- /dev/null
+++ b/deps/glib/gprintf.h
@@ -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/deps/glib/gprintfint.h b/deps/glib/gprintfint.h
new file mode 100644
index 0000000..0c975a1
--- /dev/null
+++ b/deps/glib/gprintfint.h
@@ -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/deps/glib/gquark.h b/deps/glib/gquark.h
new file mode 100644
index 0000000..324c956
--- /dev/null
+++ b/deps/glib/gquark.h
@@ -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);
+const gchar *         g_quark_to_string          (GQuark       quark) G_GNUC_CONST;
+
+const gchar *         g_intern_string            (const gchar *string);
+const gchar *         g_intern_static_string     (const gchar *string);
+
+G_END_DECLS
+
+#endif /* __G_QUARK_H__ */
diff --git a/deps/glib/gslice.c b/deps/glib/gslice.c
new file mode 100644
index 0000000..2160772
--- /dev/null
+++ b/deps/glib/gslice.c
@@ -0,0 +1,1495 @@
+/* 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"
+#include "glibconfig.h"
+
+#if     defined HAVE_POSIX_MEMALIGN && defined POSIX_MEMALIGN_WITH_COMPLIANT_ALLOCS
+#  define HAVE_COMPLIANT_POSIX_MEMALIGN 1
+#endif
+
+#if defined(HAVE_COMPLIANT_POSIX_MEMALIGN) && !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600       /* posix_memalign() */
+#endif
+#include <stdlib.h>             /* posix_memalign() */
+#include <string.h>
+#include <errno.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 */
+
+#include "gslice.h"
+
+#include "gmain.h"
+#include "gmem.h"               /* gslice.h */
+#include "gstrfuncs.h"
+#include "gutils.h"
+#include "gtestutils.h"
+#include "gthread.h"
+#include "gthreadprivate.h"
+#include "glib_trace.h"
+
+/* 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 */
+
+/* --- auxiliary 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
+  if (allocator->config.always_malloc)
+    {
+      allocator->contention_counters = NULL;
+      allocator->magazines = NULL;
+      allocator->slab_stack = NULL;
+    }
+  else
+    {
+      allocator->contention_counters = g_new0 (guint, MAX_SLAB_INDEX (allocator));
+      allocator->magazines = g_new0 (ChunkLink*, MAX_SLAB_INDEX (allocator));
+      allocator->slab_stack = g_new0 (SlabInfo*, MAX_SLAB_INDEX (allocator));
+    }
+
+  allocator->magazine_mutex = NULL;     /* _g_slice_thread_init_nomessage() */
+  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->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);
+
+  TRACE (GLIB_SLICE_ALLOC((void*)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);
+    }
+  TRACE (GLIB_SLICE_FREE((void*)mem_block, mem_size));
+}
+
+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 address */
+  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 address */
+  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 */
diff --git a/deps/glib/gslice.h b/deps/glib/gslice.h
new file mode 100644
index 0000000..962199e
--- /dev/null
+++ b/deps/glib/gslice.h
@@ -0,0 +1,86 @@
+/* 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__
+
+#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/deps/glib/gslist.c b/deps/glib/gslist.c
new file mode 100644
index 0000000..1de9c57
--- /dev/null
+++ b/deps/glib/gslist.c
@@ -0,0 +1,1082 @@
+/* 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 "gslist.h"
+#include "gtestutils.h"
+
+/**
+ * SECTION:linked_lists_single
+ * @title: Singly-Linked Lists
+ * @short_description: linked lists containing integer values or
+ *                     pointers to data, limited to iterating over the
+ *                     list in one direction
+ *
+ * The #GSList structure and its associated functions provide a
+ * standard singly-linked list data structure.
+ *
+ * Each element in the list contains a piece of data, together with a
+ * pointer which links to the next element in the list. Using this
+ * pointer it is possible to move through the list in one direction
+ * only (unlike the <link
+ * linkend="glib-Doubly-Linked-Lists">Doubly-Linked Lists</link> which
+ * allow movement in both directions).
+ *
+ * The data contained in each element can be either integer values, by
+ * using one of the <link linkend="glib-Type-Conversion-Macros">Type
+ * Conversion Macros</link>, or simply pointers to any type of data.
+ *
+ * List elements are allocated from the <link
+ * linkend="glib-Memory-Slices">slice allocator</link>, which is more
+ * efficient than allocating elements individually.
+ *
+ * Note that most of the #GSList functions expect to be passed a
+ * pointer to the first element in the list. The functions which insert
+ * elements return the new start of the list, which may have changed.
+ *
+ * There is no function to create a #GSList. %NULL is considered to be
+ * the empty list so you simply set a #GSList* to %NULL.
+ *
+ * To add elements, use g_slist_append(), g_slist_prepend(),
+ * g_slist_insert() and g_slist_insert_sorted().
+ *
+ * To remove elements, use g_slist_remove().
+ *
+ * To find elements in the list use g_slist_last(), g_slist_next(),
+ * g_slist_nth(), g_slist_nth_data(), g_slist_find() and
+ * g_slist_find_custom().
+ *
+ * To find the index of an element use g_slist_position() and
+ * g_slist_index().
+ *
+ * To call a function for each element in the list use
+ * g_slist_foreach().
+ *
+ * To free the entire list, use g_slist_free().
+ **/
+
+/**
+ * GSList:
+ * @data: holds the element's data, which can be a pointer to any kind
+ *        of data, or any integer value using the <link
+ *        linkend="glib-Type-Conversion-Macros">Type Conversion
+ *        Macros</link>.
+ * @next: contains the link to the next element in the list.
+ *
+ * The #GSList struct is used for each element in the singly-linked
+ * list.
+ **/
+
+/**
+ * g_slist_next:
+ * @slist: an element in a #GSList.
+ * @Returns: the next element, or %NULL if there are no more elements.
+ *
+ * A convenience macro to get the next element in a #GSList.
+ **/
+
+
+/**
+ * g_slist_push_allocator:
+ * @dummy: the #GAllocator to use when allocating #GSList elements.
+ *
+ * Sets the allocator to use to allocate #GSList elements. Use
+ * g_slist_pop_allocator() to restore the previous allocator.
+ *
+ * Note that this function is not available if GLib has been compiled
+ * with <option>--disable-mem-pools</option>
+ *
+ * Deprecated: 2.10: It does nothing, since #GSList has been converted
+ *                   to the <link linkend="glib-Memory-Slices">slice
+ *                   allocator</link>
+ **/
+void g_slist_push_allocator (gpointer dummy) { /* present for binary compat only */ }
+
+/**
+ * g_slist_pop_allocator:
+ *
+ * Restores the previous #GAllocator, used when allocating #GSList
+ * elements.
+ *
+ * Note that this function is not available if GLib has been compiled
+ * with <option>--disable-mem-pools</option>
+ *
+ * Deprecated: 2.10: It does nothing, since #GSList has been converted
+ *                   to the <link linkend="glib-Memory-Slices">slice
+ *                   allocator</link>
+ **/
+void g_slist_pop_allocator  (void)           { /* present for binary compat only */ }
+
+#define _g_slist_alloc0()       g_slice_new0 (GSList)
+#define _g_slist_alloc()        g_slice_new (GSList)
+#define _g_slist_free1(slist)   g_slice_free (GSList, slist)
+
+/**
+ * g_slist_alloc:
+ * @Returns: a pointer to the newly-allocated #GSList element.
+ *
+ * Allocates space for one #GSList element. It is called by the
+ * g_slist_append(), g_slist_prepend(), g_slist_insert() and
+ * g_slist_insert_sorted() functions and so is rarely used on its own.
+ **/
+GSList*
+g_slist_alloc (void)
+{
+  return _g_slist_alloc0 ();
+}
+
+/**
+ * g_slist_free:
+ * @list: a #GSList
+ *
+ * Frees all of the memory used by a #GSList.
+ * The freed elements are returned to the slice allocator.
+ *
+ * <note><para>
+ * If list elements contain dynamically-allocated memory,
+ * you should either use g_slist_free_full() or free them manually
+ * first.
+ * </para></note>
+ */
+void
+g_slist_free (GSList *list)
+{
+  g_slice_free_chain (GSList, list, next);
+}
+
+/**
+ * g_slist_free_1:
+ * @list: a #GSList element
+ *
+ * Frees one #GSList element.
+ * It is usually used after g_slist_remove_link().
+ */
+/**
+ * g_slist_free1:
+ *
+ * A macro which does the same as g_slist_free_1().
+ *
+ * Since: 2.10
+ **/
+void
+g_slist_free_1 (GSList *list)
+{
+  _g_slist_free1 (list);
+}
+
+/**
+ * g_slist_free_full:
+ * @list: a pointer to a #GSList
+ * @free_func: the function to be called to free each element's data
+ *
+ * Convenience method, which frees all the memory used by a #GSList, and
+ * calls the specified destroy function on every element's data.
+ *
+ * Since: 2.28
+ **/
+void
+g_slist_free_full (GSList         *list,
+		   GDestroyNotify  free_func)
+{
+  g_slist_foreach (list, (GFunc) free_func, NULL);
+  g_slist_free (list);
+}
+
+/**
+ * g_slist_append:
+ * @list: a #GSList
+ * @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_slist_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;/
+ * GSList *list = NULL, *number_list = NULL;
+ *
+ * /&ast; This is a list of strings. &ast;/
+ * list = g_slist_append (list, "first");
+ * list = g_slist_append (list, "second");
+ *
+ * /&ast; This is a list of integers. &ast;/
+ * number_list = g_slist_append (number_list, GINT_TO_POINTER (27));
+ * number_list = g_slist_append (number_list, GINT_TO_POINTER (14));
+ * ]|
+ *
+ * Returns: the new start of the #GSList
+ */
+GSList*
+g_slist_append (GSList   *list,
+                gpointer  data)
+{
+  GSList *new_list;
+  GSList *last;
+
+  new_list = _g_slist_alloc ();
+  new_list->data = data;
+  new_list->next = NULL;
+
+  if (list)
+    {
+      last = g_slist_last (list);
+      /* g_assert (last != NULL); */
+      last->next = new_list;
+
+      return list;
+    }
+  else
+    return new_list;
+}
+
+/**
+ * g_slist_prepend:
+ * @list: a #GSList
+ * @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;/
+ * GSList *list = NULL;
+ * list = g_slist_prepend (list, "last");
+ * list = g_slist_prepend (list, "first");
+ * ]|
+ *
+ * Returns: the new start of the #GSList
+ */
+GSList*
+g_slist_prepend (GSList   *list,
+                 gpointer  data)
+{
+  GSList *new_list;
+
+  new_list = _g_slist_alloc ();
+  new_list->data = data;
+  new_list->next = list;
+
+  return new_list;
+}
+
+/**
+ * g_slist_insert:
+ * @list: a #GSList
+ * @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 #GSList
+ */
+GSList*
+g_slist_insert (GSList   *list,
+                gpointer  data,
+                gint      position)
+{
+  GSList *prev_list;
+  GSList *tmp_list;
+  GSList *new_list;
+
+  if (position < 0)
+    return g_slist_append (list, data);
+  else if (position == 0)
+    return g_slist_prepend (list, data);
+
+  new_list = _g_slist_alloc ();
+  new_list->data = data;
+
+  if (!list)
+    {
+      new_list->next = NULL;
+      return new_list;
+    }
+
+  prev_list = NULL;
+  tmp_list = list;
+
+  while ((position-- > 0) && tmp_list)
+    {
+      prev_list = tmp_list;
+      tmp_list = tmp_list->next;
+    }
+
+  if (prev_list)
+    {
+      new_list->next = prev_list->next;
+      prev_list->next = new_list;
+    }
+  else
+    {
+      new_list->next = list;
+      list = new_list;
+    }
+
+  return list;
+}
+
+/**
+ * g_slist_insert_before:
+ * @slist: a #GSList
+ * @sibling: node to insert @data before
+ * @data: data to put in the newly-inserted node
+ *
+ * Inserts a node before @sibling containing @data.
+ *
+ * Returns: the new head of the list.
+ */
+GSList*
+g_slist_insert_before (GSList  *slist,
+                       GSList  *sibling,
+                       gpointer data)
+{
+  if (!slist)
+    {
+      slist = _g_slist_alloc ();
+      slist->data = data;
+      slist->next = NULL;
+      g_return_val_if_fail (sibling == NULL, slist);
+      return slist;
+    }
+  else
+    {
+      GSList *node, *last = NULL;
+
+      for (node = slist; node; last = node, node = last->next)
+        if (node == sibling)
+          break;
+      if (!last)
+        {
+          node = _g_slist_alloc ();
+          node->data = data;
+          node->next = slist;
+
+          return node;
+        }
+      else
+        {
+          node = _g_slist_alloc ();
+          node->data = data;
+          node->next = last->next;
+          last->next = node;
+
+          return slist;
+        }
+    }
+}
+
+/**
+ * g_slist_concat:
+ * @list1: a #GSList
+ * @list2: the #GSList to add to the end of the first #GSList
+ *
+ * Adds the second #GSList onto the end of the first #GSList.
+ * Note that the elements of the second #GSList are not copied.
+ * They are used directly.
+ *
+ * Returns: the start of the new #GSList
+ */
+GSList *
+g_slist_concat (GSList *list1, GSList *list2)
+{
+  if (list2)
+    {
+      if (list1)
+        g_slist_last (list1)->next = list2;
+      else
+        list1 = list2;
+    }
+
+  return list1;
+}
+
+/**
+ * g_slist_remove:
+ * @list: a #GSList
+ * @data: the data of the element to remove
+ *
+ * Removes an element from a #GSList.
+ * If two elements contain the same data, only the first is removed.
+ * If none of the elements contain the data, the #GSList is unchanged.
+ *
+ * Returns: the new start of the #GSList
+ */
+GSList*
+g_slist_remove (GSList        *list,
+                gconstpointer  data)
+{
+  GSList *tmp, *prev = NULL;
+
+  tmp = list;
+  while (tmp)
+    {
+      if (tmp->data == data)
+        {
+          if (prev)
+            prev->next = tmp->next;
+          else
+            list = tmp->next;
+
+          g_slist_free_1 (tmp);
+          break;
+        }
+      prev = tmp;
+      tmp = prev->next;
+    }
+
+  return list;
+}
+
+/**
+ * g_slist_remove_all:
+ * @list: a #GSList
+ * @data: data to remove
+ *
+ * Removes all list nodes with data equal to @data.
+ * Returns the new head of the list. Contrast with
+ * g_slist_remove() which removes only the first node
+ * matching the given data.
+ *
+ * Returns: new head of @list
+ */
+GSList*
+g_slist_remove_all (GSList        *list,
+                    gconstpointer  data)
+{
+  GSList *tmp, *prev = NULL;
+
+  tmp = list;
+  while (tmp)
+    {
+      if (tmp->data == data)
+        {
+          GSList *next = tmp->next;
+
+          if (prev)
+            prev->next = next;
+          else
+            list = next;
+
+          g_slist_free_1 (tmp);
+          tmp = next;
+        }
+      else
+        {
+          prev = tmp;
+          tmp = prev->next;
+        }
+    }
+
+  return list;
+}
+
+static inline GSList*
+_g_slist_remove_link (GSList *list,
+                      GSList *link)
+{
+  GSList *tmp;
+  GSList *prev;
+
+  prev = NULL;
+  tmp = list;
+
+  while (tmp)
+    {
+      if (tmp == link)
+        {
+          if (prev)
+            prev->next = tmp->next;
+          if (list == tmp)
+            list = list->next;
+
+          tmp->next = NULL;
+          break;
+        }
+
+      prev = tmp;
+      tmp = tmp->next;
+    }
+
+  return list;
+}
+
+/**
+ * g_slist_remove_link:
+ * @list: a #GSList
+ * @link_: an element in the #GSList
+ *
+ * Removes an element from a #GSList, without
+ * freeing the element. The removed element's next
+ * link is set to %NULL, so that it becomes a
+ * self-contained list with one element.
+ *
+ * Returns: the new start of the #GSList, without the element
+ */
+GSList*
+g_slist_remove_link (GSList *list,
+                     GSList *link_)
+{
+  return _g_slist_remove_link (list, link_);
+}
+
+/**
+ * g_slist_delete_link:
+ * @list: a #GSList
+ * @link_: node to delete
+ *
+ * Removes the node link_ from the list and frees it.
+ * Compare this to g_slist_remove_link() which removes the node
+ * without freeing it.
+ *
+ * Returns: the new head of @list
+ */
+GSList*
+g_slist_delete_link (GSList *list,
+                     GSList *link_)
+{
+  list = _g_slist_remove_link (list, link_);
+  _g_slist_free1 (link_);
+
+  return list;
+}
+
+/**
+ * g_slist_copy:
+ * @list: a #GSList
+ *
+ * Copies a #GSList.
+ *
+ * <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 isn't.
+ * </para></note>
+ *
+ * Returns: a copy of @list
+ */
+GSList*
+g_slist_copy (GSList *list)
+{
+  GSList *new_list = NULL;
+
+  if (list)
+    {
+      GSList *last;
+
+      new_list = _g_slist_alloc ();
+      new_list->data = list->data;
+      last = new_list;
+      list = list->next;
+      while (list)
+        {
+          last->next = _g_slist_alloc ();
+          last = last->next;
+          last->data = list->data;
+          list = list->next;
+        }
+      last->next = NULL;
+    }
+
+  return new_list;
+}
+
+/**
+ * g_slist_reverse:
+ * @list: a #GSList
+ *
+ * Reverses a #GSList.
+ *
+ * Returns: the start of the reversed #GSList
+ */
+GSList*
+g_slist_reverse (GSList *list)
+{
+  GSList *prev = NULL;
+
+  while (list)
+    {
+      GSList *next = list->next;
+
+      list->next = prev;
+
+      prev = list;
+      list = next;
+    }
+
+  return prev;
+}
+
+/**
+ * g_slist_nth:
+ * @list: a #GSList
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element at the given position in a #GSList.
+ *
+ * Returns: the element, or %NULL if the position is off
+ *     the end of the #GSList
+ */
+GSList*
+g_slist_nth (GSList *list,
+             guint   n)
+{
+  while (n-- > 0 && list)
+    list = list->next;
+
+  return list;
+}
+
+/**
+ * g_slist_nth_data:
+ * @list: a #GSList
+ * @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 #GSList
+ */
+gpointer
+g_slist_nth_data (GSList   *list,
+                  guint     n)
+{
+  while (n-- > 0 && list)
+    list = list->next;
+
+  return list ? list->data : NULL;
+}
+
+/**
+ * g_slist_find:
+ * @list: a #GSList
+ * @data: the element data to find
+ *
+ * Finds the element in a #GSList which
+ * contains the given data.
+ *
+ * Returns: the found #GSList element,
+ *     or %NULL if it is not found
+ */
+GSList*
+g_slist_find (GSList        *list,
+              gconstpointer  data)
+{
+  while (list)
+    {
+      if (list->data == data)
+        break;
+      list = list->next;
+    }
+
+  return list;
+}
+
+
+/**
+ * g_slist_find_custom:
+ * @list: a #GSList
+ * @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 #GSList, 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 #GSList element's data as the first argument and the
+ * given user data.
+ *
+ * Returns: the found #GSList element, or %NULL if it is not found
+ */
+GSList*
+g_slist_find_custom (GSList        *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_slist_position:
+ * @list: a #GSList
+ * @llink: an element in the #GSList
+ *
+ * Gets the position of the given element
+ * in the #GSList (starting from 0).
+ *
+ * Returns: the position of the element in the #GSList,
+ *     or -1 if the element is not found
+ */
+gint
+g_slist_position (GSList *list,
+                  GSList *llink)
+{
+  gint i;
+
+  i = 0;
+  while (list)
+    {
+      if (list == llink)
+        return i;
+      i++;
+      list = list->next;
+    }
+
+  return -1;
+}
+
+/**
+ * g_slist_index:
+ * @list: a #GSList
+ * @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_slist_index (GSList        *list,
+               gconstpointer  data)
+{
+  gint i;
+
+  i = 0;
+  while (list)
+    {
+      if (list->data == data)
+        return i;
+      i++;
+      list = list->next;
+    }
+
+  return -1;
+}
+
+/**
+ * g_slist_last:
+ * @list: a #GSList
+ *
+ * Gets the last element in a #GSList.
+ *
+ * <note><para>
+ * This function iterates over the whole list.
+ * </para></note>
+ *
+ * Returns: the last element in the #GSList,
+ *     or %NULL if the #GSList has no elements
+ */
+GSList*
+g_slist_last (GSList *list)
+{
+  if (list)
+    {
+      while (list->next)
+        list = list->next;
+    }
+
+  return list;
+}
+
+/**
+ * g_slist_length:
+ * @list: a #GSList
+ *
+ * Gets the number of elements in a #GSList.
+ *
+ * <note><para>
+ * This function iterates over the whole list to
+ * count its elements.
+ * </para></note>
+ *
+ * Returns: the number of elements in the #GSList
+ */
+guint
+g_slist_length (GSList *list)
+{
+  guint length;
+
+  length = 0;
+  while (list)
+    {
+      length++;
+      list = list->next;
+    }
+
+  return length;
+}
+
+/**
+ * g_slist_foreach:
+ * @list: a #GSList
+ * @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 #GSList.
+ */
+void
+g_slist_foreach (GSList   *list,
+                 GFunc     func,
+                 gpointer  user_data)
+{
+  while (list)
+    {
+      GSList *next = list->next;
+      (*func) (list->data, user_data);
+      list = next;
+    }
+}
+
+static GSList*
+g_slist_insert_sorted_real (GSList   *list,
+                            gpointer  data,
+                            GFunc     func,
+                            gpointer  user_data)
+{
+  GSList *tmp_list = list;
+  GSList *prev_list = NULL;
+  GSList *new_list;
+  gint cmp;
+
+  g_return_val_if_fail (func != NULL, list);
+
+  if (!list)
+    {
+      new_list = _g_slist_alloc ();
+      new_list->data = data;
+      new_list->next = NULL;
+      return new_list;
+    }
+
+  cmp = ((GCompareDataFunc) func) (data, tmp_list->data, user_data);
+
+  while ((tmp_list->next) && (cmp > 0))
+    {
+      prev_list = tmp_list;
+      tmp_list = tmp_list->next;
+
+      cmp = ((GCompareDataFunc) func) (data, tmp_list->data, user_data);
+    }
+
+  new_list = _g_slist_alloc ();
+  new_list->data = data;
+
+  if ((!tmp_list->next) && (cmp > 0))
+    {
+      tmp_list->next = new_list;
+      new_list->next = NULL;
+      return list;
+    }
+
+  if (prev_list)
+    {
+      prev_list->next = new_list;
+      new_list->next = tmp_list;
+      return list;
+    }
+  else
+    {
+      new_list->next = list;
+      return new_list;
+    }
+}
+
+/**
+ * g_slist_insert_sorted:
+ * @list: a #GSList
+ * @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 #GSList
+ */
+GSList*
+g_slist_insert_sorted (GSList       *list,
+                       gpointer      data,
+                       GCompareFunc  func)
+{
+  return g_slist_insert_sorted_real (list, data, (GFunc) func, NULL);
+}
+
+/**
+ * g_slist_insert_sorted_with_data:
+ * @list: a #GSList
+ * @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: 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 #GSList
+ *
+ * Since: 2.10
+ */
+GSList*
+g_slist_insert_sorted_with_data (GSList           *list,
+                                 gpointer          data,
+                                 GCompareDataFunc  func,
+                                 gpointer          user_data)
+{
+  return g_slist_insert_sorted_real (list, data, (GFunc) func, user_data);
+}
+
+static GSList *
+g_slist_sort_merge (GSList   *l1,
+                    GSList   *l2,
+                    GFunc     compare_func,
+                    gpointer  user_data)
+{
+  GSList list, *l;
+  gint cmp;
+
+  l=&list;
+
+  while (l1 && l2)
+    {
+      cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
+
+      if (cmp <= 0)
+        {
+          l=l->next=l1;
+          l1=l1->next;
+        }
+      else
+        {
+          l=l->next=l2;
+          l2=l2->next;
+        }
+    }
+  l->next= l1 ? l1 : l2;
+
+  return list.next;
+}
+
+static GSList *
+g_slist_sort_real (GSList   *list,
+                   GFunc     compare_func,
+                   gpointer  user_data)
+{
+  GSList *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_slist_sort_merge (g_slist_sort_real (list, compare_func, user_data),
+                             g_slist_sort_real (l2, compare_func, user_data),
+                             compare_func,
+                             user_data);
+}
+
+/**
+ * g_slist_sort:
+ * @list: a #GSList
+ * @compare_func: the comparison function used to sort the #GSList.
+ *     This function is passed the data from 2 elements of the #GSList
+ *     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 #GSList using the given comparison function.
+ *
+ * Returns: the start of the sorted #GSList
+ */
+GSList *
+g_slist_sort (GSList       *list,
+              GCompareFunc  compare_func)
+{
+  return g_slist_sort_real (list, (GFunc) compare_func, NULL);
+}
+
+/**
+ * g_slist_sort_with_data:
+ * @list: a #GSList
+ * @compare_func: comparison function
+ * @user_data: data to pass to comparison function
+ *
+ * Like g_slist_sort(), but the sort function accepts a user data argument.
+ *
+ * Returns: new head of the list
+ */
+GSList *
+g_slist_sort_with_data (GSList           *list,
+                        GCompareDataFunc  compare_func,
+                        gpointer          user_data)
+{
+  return g_slist_sort_real (list, (GFunc) compare_func, user_data);
+}
diff --git a/deps/glib/gslist.h b/deps/glib/gslist.h
new file mode 100644
index 0000000..3731ba9
--- /dev/null
+++ b/deps/glib/gslist.h
@@ -0,0 +1,116 @@
+/* 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_SLIST_H__
+#define __G_SLIST_H__
+
+#include <glib/gmem.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GSList GSList;
+
+struct _GSList
+{
+  gpointer data;
+  GSList *next;
+};
+
+/* Singly linked lists
+ */
+GSList*  g_slist_alloc                   (void) G_GNUC_WARN_UNUSED_RESULT;
+void     g_slist_free                    (GSList           *list);
+void     g_slist_free_1                  (GSList           *list);
+#define	 g_slist_free1		         g_slist_free_1
+void     g_slist_free_full               (GSList           *list,
+					  GDestroyNotify    free_func);
+GSList*  g_slist_append                  (GSList           *list,
+					  gpointer          data) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_prepend                 (GSList           *list,
+					  gpointer          data) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_insert                  (GSList           *list,
+					  gpointer          data,
+					  gint              position) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_insert_sorted           (GSList           *list,
+					  gpointer          data,
+					  GCompareFunc      func) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_insert_sorted_with_data (GSList           *list,
+					  gpointer          data,
+					  GCompareDataFunc  func,
+					  gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_insert_before           (GSList           *slist,
+					  GSList           *sibling,
+					  gpointer          data) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_concat                  (GSList           *list1,
+					  GSList           *list2) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_remove                  (GSList           *list,
+					  gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_remove_all              (GSList           *list,
+					  gconstpointer     data) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_remove_link             (GSList           *list,
+					  GSList           *link_) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_delete_link             (GSList           *list,
+					  GSList           *link_) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_reverse                 (GSList           *list) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_copy                    (GSList           *list) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_nth                     (GSList           *list,
+					  guint             n);
+GSList*  g_slist_find                    (GSList           *list,
+					  gconstpointer     data);
+GSList*  g_slist_find_custom             (GSList           *list,
+					  gconstpointer     data,
+					  GCompareFunc      func);
+gint     g_slist_position                (GSList           *list,
+					  GSList           *llink);
+gint     g_slist_index                   (GSList           *list,
+					  gconstpointer     data);
+GSList*  g_slist_last                    (GSList           *list);
+guint    g_slist_length                  (GSList           *list);
+void     g_slist_foreach                 (GSList           *list,
+					  GFunc             func,
+					  gpointer          user_data);
+GSList*  g_slist_sort                    (GSList           *list,
+					  GCompareFunc      compare_func) G_GNUC_WARN_UNUSED_RESULT;
+GSList*  g_slist_sort_with_data          (GSList           *list,
+					  GCompareDataFunc  compare_func,
+					  gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT;
+gpointer g_slist_nth_data                (GSList           *list,
+					  guint             n);
+
+#define  g_slist_next(slist)	         ((slist) ? (((GSList *)(slist))->next) : NULL)
+
+#ifndef G_DISABLE_DEPRECATED
+void     g_slist_push_allocator          (gpointer	   dummy);
+void     g_slist_pop_allocator           (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_SLIST_H__ */
diff --git a/deps/glib/gstrfuncs.c b/deps/glib/gstrfuncs.c
new file mode 100644
index 0000000..aecde5b
--- /dev/null
+++ b/deps/glib/gstrfuncs.c
@@ -0,0 +1,3283 @@
+/* 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 <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 "gstrfuncs.h"
+
+#include "gprintf.h"
+#include "gprintfint.h"
+#include "glibintl.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;
+
+/**
+ * g_strdup:
+ * @str: the string to duplicate
+ *
+ * Duplicates a string. If @str is %NULL it returns %NULL.
+ * The returned string should be freed with g_free()
+ * when no longer needed.
+ *
+ * Returns: a newly-allocated copy of @str
+ */
+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;
+}
+
+/**
+ * g_memdup:
+ * @mem: the memory to copy.
+ * @byte_size: the number of bytes to copy.
+ *
+ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it
+ * from @mem. If @mem is %NULL it returns %NULL.
+ *
+ * Returns: a pointer to the newly-allocated copy of the memory, or %NULL if @mem
+ *  is %NULL.
+ */
+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
+}
+
+/**
+ * g_strdup_vprintf:
+ * @format: a standard printf() format string, but notice
+ *     <link linkend="string-precision">string precision pitfalls</link>
+ * @args: the list of parameters to insert into the format string
+ *
+ * Similar to the standard C vsprintf() function but safer, since it
+ * calculates the maximum space required and allocates memory to hold
+ * the result. The returned string should be freed with g_free() when
+ * no longer needed.
+ *
+ * See also g_vasprintf(), which offers the same functionality, but
+ * additionally returns the length of the allocated string.
+ *
+ * Returns: a newly-allocated string holding the result
+ */
+gchar*
+g_strdup_vprintf (const gchar *format,
+                  va_list      args)
+{
+  gchar *string = NULL;
+
+  g_vasprintf (&string, format, args);
+
+  return string;
+}
+
+/**
+ * g_strdup_printf:
+ * @format: a standard printf() format string, but notice
+ *     <link linkend="string-precision">string precision pitfalls</link>
+ * @...: the parameters to insert into the format string
+ *
+ * Similar to the standard C sprintf() function but safer, since it
+ * calculates the maximum space required and allocates memory to hold
+ * the result. The returned string should be freed with g_free() when no
+ * longer needed.
+ *
+ * Returns: a newly-allocated string holding the result
+ */
+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;
+}
+
+/**
+ * g_strconcat:
+ * @string1: the first string to add, which must not be %NULL
+ * @...: a %NULL-terminated list of strings to append to the string
+ *
+ * Concatenates all of the given strings into one long string.
+ * The returned string should be freed with g_free() when no longer needed.
+ *
+ * Note that this function is usually not the right function to use to
+ * assemble a translated message from pieces, since proper translation
+ * often requires the pieces to be reordered.
+ *
+ * <warning><para>The variable argument list <emphasis>must</emphasis> end
+ * with %NULL. If you forget the %NULL, g_strconcat() will start appending
+ * random memory junk to your string.</para></warning>
+ *
+ * Returns: a newly-allocated string containing all the string arguments
+ */
+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 seldom 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_strerror:
+ * @errnum: the system error number. See the standard C %errno
+ *     documentation
+ *
+ * Returns a string corresponding to the given error code, e.g.
+ * "no such process". You should use this function in preference to
+ * strerror(), because it returns a string in UTF-8 encoding, and since
+ * not all platforms support the strerror() function.
+ *
+ * Returns: a UTF-8 string describing the error code. If the error code
+ *     is unknown, it returns "unknown error (&lt;code&gt;)". The string
+ *     can only be used until the next call to g_strerror()
+ */
+const 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
+#if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK))
+    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_strsignal:
+ * @signum: the signal number. See the <literal>signal</literal>
+ *     documentation
+ *
+ * Returns a string describing the given signal, e.g. "Segmentation fault".
+ * You should use this function in preference to strsignal(), because it
+ * returns a string in UTF-8 encoding, and since not all platforms support
+ * the strsignal() function.
+ *
+ * Returns: a UTF-8 string describing the signal. If the signal is unknown,
+ *     it returns "unknown signal (&lt;signum&gt;)". The string can only be
+ *     used until the next call to g_strsignal()
+ */
+const 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:
+ * @dest: destination buffer
+ * @src: source buffer
+ * @dest_size: length of @dest in bytes
+ *
+ * Portability wrapper that calls strlcpy() on systems which have it,
+ * and emulates strlcpy() otherwise. Copies @src to @dest; @dest is
+ * guaranteed to be nul-terminated; @src must be nul-terminated;
+ * @dest_size is the buffer size, not the number of chars to copy.
+ *
+ * At most dest_size - 1 characters will be copied. Always nul-terminates
+ * (unless dest_size == 0). This function does <emphasis>not</emphasis>
+ * allocate memory. Unlike strncpy(), this function doesn't pad dest (so
+ * it's often faster). It returns the size of the attempted result,
+ * strlen (src), so if @retval >= @dest_size, truncation occurred.
+ *
+ * <note><para>Caveat: strlcpy() is supposedly more secure than
+ * strcpy() or strncpy(), but if you really want to avoid screwups,
+ * g_strdup() is an even better idea.</para></note>
+ *
+ * Returns: length of @src
+ */
+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:
+ * @dest: destination buffer, already containing one nul-terminated string
+ * @src: source buffer
+ * @dest_size: length of @dest buffer in bytes (not length of existing string
+ *     inside @dest)
+ *
+ * Portability wrapper that calls strlcat() on systems which have it,
+ * and emulates it otherwise. Appends nul-terminated @src string to @dest,
+ * guaranteeing nul-termination for @dest. The total size of @dest won't
+ * exceed @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).
+ *
+ * <note><para>Caveat: this is supposedly a more secure alternative to
+ * strcat() or strncat(), but for real security g_strconcat() is harder
+ * to mess up.</para></note>
+ *
+ * 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;
+}
+
+/**
+ * g_strreverse:
+ * @string: the string to reverse
+ *
+ * Reverses all of the bytes in a string. For example,
+ * <literal>g_strreverse ("abcdef")</literal> will result
+ * in "fedcba".
+ *
+ * Note that g_strreverse() doesn't work on UTF-8 strings
+ * containing multibyte characters. For that purpose, use
+ * g_utf8_strreverse().
+ *
+ * Returns: the same pointer passed in as @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)
+        {
+          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;
+}
+
+/**
+ * g_strjoinv:
+ * @separator: a string to insert between each of the strings, or %NULL
+ * @str_array: a %NULL-terminated array of strings to join
+ *
+ * Joins a number of strings together to form one long string, with the
+ * optional @separator inserted between each of them. The returned string
+ * should be freed with g_free().
+ *
+ * Returns: a newly-allocated string containing all of the strings joined
+ *     together, with @separator between them
+ */
+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;
+}
+
+/**
+ * g_strjoin:
+ * @separator: a string to insert between each of the strings, or %NULL
+ * @...: a %NULL-terminated list of strings to join
+ *
+ * Joins a number of strings together to form one long string, with the
+ * optional @separator inserted between each of them. The returned string
+ * should be freed with g_free().
+ *
+ * Returns: a newly-allocated string containing all of the strings joined
+ *     together, with @separator between them
+ */
+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
+ **/
+const 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
+ */
+const 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
+ */
+const 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
+ */
+const gchar *
+g_dgettext (const gchar *domain,
+            const gchar *msgid)
+{
+  if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
+    return msgid;
+
+  return dgettext (domain, msgid);
+}
+
+/**
+ * g_dcgettext:
+ * @domain: (allow-none): the translation domain to use, or %NULL to use
+ *   the domain set with textdomain()
+ * @msgid: message to translate
+ * @category: a locale category
+ *
+ * This is a variant of g_dgettext() that allows specifying a locale
+ * category instead of always using %LC_MESSAGES. See g_dgettext() for
+ * more information about how this functions differs from calling
+ * dcgettext() directly.
+ *
+ * Returns: the translated string for the given locale category
+ *
+ * Since: 2.26
+ */
+const gchar *
+g_dcgettext (const gchar *domain,
+             const gchar *msgid,
+             int          category)
+{
+  if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
+    return msgid;
+
+  return dcgettext (domain, msgid, category);
+}
+
+/**
+ * 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
+ */
+const 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);
+}
diff --git a/deps/glib/gstrfuncs.h b/deps/glib/gstrfuncs.h
new file mode 100644
index 0000000..8f99c55
--- /dev/null
+++ b/deps/glib/gstrfuncs.h
@@ -0,0 +1,269 @@
+/* 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/gmacros.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);
+const gchar *         g_strerror       (gint	      errnum) G_GNUC_CONST;
+const 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);
+
+const gchar *         g_strip_context  (const gchar *msgid, 
+					const gchar *msgval) G_GNUC_FORMAT(1);
+
+const gchar *         g_dgettext       (const gchar *domain,
+					const gchar *msgid) G_GNUC_FORMAT(2);
+const gchar *         g_dcgettext      (const gchar *domain,
+					const gchar *msgid,
+                                        int          category) G_GNUC_FORMAT(2);
+const gchar *         g_dngettext      (const gchar *domain,
+					const gchar *msgid,
+					const gchar *msgid_plural,
+					gulong       n) G_GNUC_FORMAT(3);
+const gchar *         g_dpgettext      (const gchar *domain,
+                                        const gchar *msgctxtid,
+                                        gsize        msgidoffset) G_GNUC_FORMAT(2);
+const 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/deps/glib/gstring.c b/deps/glib/gstring.c
new file mode 100644
index 0000000..cd4d126
--- /dev/null
+++ b/deps/glib/gstring.c
@@ -0,0 +1,1528 @@
+/* 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 "gstring.h"
+
+#include "gprintf.h"
+
+
+/**
+ * SECTION:string_chunks
+ * @title: String Chunks
+ * @short_description: efficient storage of groups of strings
+ *
+ * String chunks are used to store groups of strings. Memory is
+ * allocated in blocks, and as strings are added to the #GStringChunk
+ * they are copied into the next free position in a block. When a block
+ * is full a new block is allocated.
+ *
+ * When storing a large number of strings, string chunks are more
+ * efficient than using g_strdup() since fewer calls to malloc() are
+ * needed, and less memory is wasted in memory allocation overheads.
+ *
+ * By adding strings with g_string_chunk_insert_const() it is also
+ * possible to remove duplicates.
+ *
+ * To create a new #GStringChunk use g_string_chunk_new().
+ *
+ * To add strings to a #GStringChunk use g_string_chunk_insert().
+ *
+ * To add strings to a #GStringChunk, but without duplicating strings
+ * which are already in the #GStringChunk, use
+ * g_string_chunk_insert_const().
+ *
+ * To free the entire #GStringChunk use g_string_chunk_free(). It is
+ * not possible to free individual strings.
+ **/
+
+/**
+ * GStringChunk:
+ *
+ * An opaque data structure representing String Chunks. It should only
+ * be accessed by using the following functions.
+ **/
+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.
+ *
+ * Note that this function is primarily meant as a hash table comparison
+ * function. For a general-purpose, %NULL-safe string comparison function,
+ * see g_strcmp0().
+ *
+ * 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.
+ *
+ * This function implements the widely used "djb" hash apparently posted
+ * by Daniel Bernstein to comp.lang.c some time ago.  The 32 bit
+ * unsigned hash value starts at 5381 and for each byte 'c' in the
+ * string, is updated: <literal>hash = hash * 33 + c</literal>.  This
+ * function uses the signed value of each byte.
+ *
+ * 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)
+{
+  const signed char *p;
+  guint32 h = 5381;
+
+  for (p = v; *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';
+
+  memcpy (pos, string, size);
+
+  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.  If 
+ * it's %FALSE, the caller gains ownership of the buffer and must
+ * free it after use with g_free().
+ *
+ * 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 (len == 0 || val != NULL, string);
+
+  if (len == 0)
+    return 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, or %NULL
+ * @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 (len == 0 || 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
+ * @...: 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
+ * @...: 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
+ * @...: 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
+ * @...: 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);
+}
diff --git a/deps/glib/gstring.h b/deps/glib/gstring.h
new file mode 100644
index 0000000..404fdeb
--- /dev/null
+++ b/deps/glib/gstring.h
@@ -0,0 +1,190 @@
+/* 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_STRING_H__
+#define __G_STRING_H__
+
+#include <glib/gtypes.h>
+#include <glib/gunicode.h>
+#include <glib/gutils.h>  /* for G_CAN_INLINE */
+
+G_BEGIN_DECLS
+
+typedef struct _GString		GString;
+typedef struct _GStringChunk	GStringChunk;
+
+/**
+ * GString:
+ * @str: points to the character data. It may move as text is added.
+ *   The @str field is null-terminated and so
+ *   can be used as an ordinary C string.
+ * @len: contains the length of the string, not including the
+ *   terminating nul byte.
+ * @allocated_len: the number of bytes that can be stored in the
+ *   string before it needs to be reallocated. May be larger than @len.
+ *
+ * The #GString struct contains the public fields of a #GString.
+ */
+struct _GString
+{
+  gchar  *str;
+  gsize len;    
+  gsize allocated_len;
+};
+
+/* String Chunks
+ */
+GStringChunk* g_string_chunk_new	   (gsize size);  
+void	      g_string_chunk_free	   (GStringChunk *chunk);
+void	      g_string_chunk_clear	   (GStringChunk *chunk);
+gchar*	      g_string_chunk_insert	   (GStringChunk *chunk,
+					    const gchar	 *string);
+gchar*	      g_string_chunk_insert_len	   (GStringChunk *chunk,
+					    const gchar	 *string,
+					    gssize        len);
+gchar*	      g_string_chunk_insert_const  (GStringChunk *chunk,
+					    const gchar	 *string);
+
+
+/* Strings
+ */
+GString*     g_string_new	        (const gchar	 *init);
+GString*     g_string_new_len           (const gchar     *init,
+                                         gssize           len);   
+GString*     g_string_sized_new         (gsize            dfl_size);  
+gchar*	     g_string_free	        (GString	 *string,
+					 gboolean	  free_segment);
+gboolean     g_string_equal             (const GString	 *v,
+					 const GString 	 *v2);
+guint        g_string_hash              (const GString   *str);
+GString*     g_string_assign            (GString	 *string,
+					 const gchar	 *rval);
+GString*     g_string_truncate          (GString	 *string,
+					 gsize		  len);    
+GString*     g_string_set_size          (GString         *string,
+					 gsize            len);
+GString*     g_string_insert_len        (GString         *string,
+                                         gssize           pos,   
+                                         const gchar     *val,
+                                         gssize           len);  
+GString*     g_string_append            (GString	 *string,
+			                 const gchar	 *val);
+GString*     g_string_append_len        (GString	 *string,
+			                 const gchar	 *val,
+                                         gssize           len);  
+GString*     g_string_append_c          (GString	 *string,
+					 gchar		  c);
+GString*     g_string_append_unichar    (GString	 *string,
+					 gunichar	  wc);
+GString*     g_string_prepend           (GString	 *string,
+					 const gchar	 *val);
+GString*     g_string_prepend_c         (GString	 *string,
+					 gchar		  c);
+GString*     g_string_prepend_unichar   (GString	 *string,
+					 gunichar	  wc);
+GString*     g_string_prepend_len       (GString	 *string,
+			                 const gchar	 *val,
+                                         gssize           len);  
+GString*     g_string_insert            (GString	 *string,
+					 gssize		  pos,    
+					 const gchar	 *val);
+GString*     g_string_insert_c          (GString	 *string,
+					 gssize		  pos,    
+					 gchar		  c);
+GString*     g_string_insert_unichar    (GString	 *string,
+					 gssize		  pos,    
+					 gunichar	  wc);
+GString*     g_string_overwrite         (GString	 *string,
+					 gsize		  pos,    
+					 const gchar	 *val);
+GString*     g_string_overwrite_len     (GString	 *string,
+					 gsize		  pos,    
+					 const gchar	 *val,
+					 gssize           len);
+GString*     g_string_erase	        (GString	 *string,
+					 gssize		  pos,
+					 gssize		  len);
+GString*     g_string_ascii_down        (GString	 *string);
+GString*     g_string_ascii_up          (GString	 *string);
+void         g_string_vprintf           (GString	 *string,
+					 const gchar	 *format,
+					 va_list          args);
+void         g_string_printf            (GString	 *string,
+					 const gchar	 *format,
+					 ...) G_GNUC_PRINTF (2, 3);
+void         g_string_append_vprintf    (GString	 *string,
+					 const gchar	 *format,
+					 va_list          args);
+void         g_string_append_printf     (GString	 *string,
+					 const gchar	 *format,
+					 ...) G_GNUC_PRINTF (2, 3);
+GString *    g_string_append_uri_escaped(GString         *string,
+					 const char      *unescaped,
+					 const char      *reserved_chars_allowed,
+					 gboolean         allow_utf8);
+
+/* -- optimize g_strig_append_c --- */
+#ifdef G_CAN_INLINE
+static inline GString*
+g_string_append_c_inline (GString *gstring,
+                          gchar    c)
+{
+  if (gstring->len + 1 < gstring->allocated_len)
+    {
+      gstring->str[gstring->len++] = c;
+      gstring->str[gstring->len] = 0;
+    }
+  else
+    g_string_insert_c (gstring, -1, c);
+  return gstring;
+}
+#define g_string_append_c(gstr,c)       g_string_append_c_inline (gstr, c)
+#endif /* G_CAN_INLINE */
+
+
+#ifndef G_DISABLE_DEPRECATED
+
+/* The following two 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.
+ */
+
+GString*     g_string_down              (GString	 *string);
+GString*     g_string_up                (GString	 *string);
+
+/* These aliases are included for compatibility. */
+#define	g_string_sprintf	g_string_printf
+#define	g_string_sprintfa	g_string_append_printf
+
+#endif /* G_DISABLE_DEPRECATED */
+
+G_END_DECLS
+
+#endif /* __G_STRING_H__ */
diff --git a/deps/glib/gtypes.h b/deps/glib/gtypes.h
new file mode 100644
index 0000000..8e77563
--- /dev/null
+++ b/deps/glib/gtypes.h
@@ -0,0 +1,461 @@
+/* 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>
+#include <glib/gmacros.h>
+#include <time.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);
+
+/**
+ * GFreeFunc:
+ * @data: a data pointer
+ *
+ * Declares a type of function which takes an arbitrary
+ * data pointer argument and has no return value. It is
+ * not currently used in GLib or GTK+.
+ */
+typedef void            (*GFreeFunc)            (gpointer       data);
+
+/**
+ * GTranslateFunc:
+ * @str: the untranslated string
+ * @data: user data specified when installing the function, e.g.
+ *  in g_option_group_set_translate_func()
+ * 
+ * The type of functions which are used to translate user-visible
+ * strings, for <option>--help</option> output.
+ * 
+ * Returns: a translation of the string for the current locale.
+ *  The returned string is owned by GLib and must not be freed.
+ */
+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) \
+       (G_GNUC_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) \
+	  (G_GNUC_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) \
+	  (G_GNUC_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) \
+       (G_GNUC_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) \
+       (G_GNUC_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) \
+       (G_GNUC_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) \
+       (G_GNUC_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) \
+       (G_GNUC_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) \
+       (G_GNUC_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))
+
+#define GSIZE_FROM_LE(val)	(GSIZE_TO_LE (val))
+#define GSSIZE_FROM_LE(val)	(GSSIZE_TO_LE (val))
+#define GSIZE_FROM_BE(val)	(GSIZE_TO_BE (val))
+#define GSSIZE_FROM_BE(val)	(GSSIZE_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/deps/glib/gunicode.h b/deps/glib/gunicode.h
new file mode 100644
index 0000000..5d5d3ad
--- /dev/null
+++ b/deps/glib/gunicode.h
@@ -0,0 +1,729 @@
+/* gunicode.h - Unicode manipulation functions
+ *
+ *  Copyright (C) 1999, 2000 Tom Tromey
+ *  Copyright 2000, 2005 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_UNICODE_H__
+#define __G_UNICODE_H__
+
+#include <glib/gerror.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * gunichar:
+ *
+ * A type which can hold any UTF-32 or UCS-4 character code,
+ * also known as a Unicode code point.
+ *
+ * If you want to produce the UTF-8 representation of a #gunichar,
+ * use g_ucs4_to_utf8(). See also g_utf8_to_ucs4() for the reverse
+ * process.
+ *
+ * To print/scan values of this type as integer, use
+ * %G_GINT32_MODIFIER and/or %G_GUINT32_FORMAT.
+ *
+ * The notation to express a Unicode code point in running text is
+ * as a hexadecimal number with four to six digits and uppercase
+ * letters, prefixed by the string "U+". Leading zeros are omitted,
+ * unless the code point would have fewer than four hexadecimal digits.
+ * For example, "U+0041 LATIN CAPITAL LETTER A". To print a code point
+ * in the U+-notation, use the format string "U+\%04"G_GINT32_FORMAT"X".
+ * To scan, use the format string "U+\%06"G_GINT32_FORMAT"X".
+ *
+ * |[
+ * gunichar c;
+ * sscanf ("U+0041", "U+%06"G_GINT32_FORMAT"X", &amp;c)
+ * g_print ("Read U+%04"G_GINT32_FORMAT"X", c);
+ * ]|
+ */
+typedef guint32 gunichar;
+
+/**
+ * gunichar2:
+ *
+ * A type which can hold any UTF-16 code
+ * point<footnote id="utf16_surrogate_pairs">UTF-16 also has so called
+ * <firstterm>surrogate pairs</firstterm> to encode characters beyond
+ * the BMP as pairs of 16bit numbers. Surrogate pairs cannot be stored
+ * in a single gunichar2 field, but all GLib functions accepting gunichar2
+ * arrays will correctly interpret surrogate pairs.</footnote>.
+ *
+ * To print/scan values of this type to/from text you need to convert
+ * to/from UTF-8, using g_utf16_to_utf8()/g_utf8_to_utf16().
+ *
+ * To print/scan values of this type as integer, use
+ * %G_GINT16_MODIFIER and/or %G_GUINT16_FORMAT.
+ */
+typedef guint16 gunichar2;
+
+/**
+ * GUnicodeType:
+ * @G_UNICODE_CONTROL: General category "Other, Control" (Cc)
+ * @G_UNICODE_FORMAT: General category "Other, Format" (Cf)
+ * @G_UNICODE_UNASSIGNED: General category "Other, Not Assigned" (Cn)
+ * @G_UNICODE_PRIVATE_USE: General category "Other, Private Use" (Co)
+ * @G_UNICODE_SURROGATE: General category "Other, Surrogate" (Cs)
+ * @G_UNICODE_LOWERCASE_LETTER: General category "Letter, Lowercase" (Ll)
+ * @G_UNICODE_MODIFIER_LETTER: General category "Letter, Modifier" (Lm)
+ * @G_UNICODE_OTHER_LETTER: General category "Letter, Other" (Lo)
+ * @G_UNICODE_TITLECASE_LETTER: General category "Letter, Titlecase" (Lt)
+ * @G_UNICODE_UPPERCASE_LETTER: General category "Letter, Uppercase" (Lu)
+ * @G_UNICODE_SPACING_MARK: General category "Mark, Spacing" (Mc)
+ * @G_UNICODE_ENCLOSING_MARK: General category "Mark, Enclosing" (Me)
+ * @G_UNICODE_NON_SPACING_MARK: General category "Mark, Nonspacing" (Mn)
+ * @G_UNICODE_DECIMAL_NUMBER: General category "Number, Decimal Digit" (Nd)
+ * @G_UNICODE_LETTER_NUMBER: General category "Number, Letter" (Nl)
+ * @G_UNICODE_OTHER_NUMBER: General category "Number, Other" (No)
+ * @G_UNICODE_CONNECT_PUNCTUATION: General category "Punctuation, Connector" (Pc)
+ * @G_UNICODE_DASH_PUNCTUATION: General category "Punctuation, Dash" (Pd)
+ * @G_UNICODE_CLOSE_PUNCTUATION: General category "Punctuation, Close" (Pe)
+ * @G_UNICODE_FINAL_PUNCTUATION: General category "Punctuation, Final quote" (Pf)
+ * @G_UNICODE_INITIAL_PUNCTUATION: General category "Punctuation, Initial quote" (Pi)
+ * @G_UNICODE_OTHER_PUNCTUATION: General category "Punctuation, Other" (Po)
+ * @G_UNICODE_OPEN_PUNCTUATION: General category "Punctuation, Open" (Ps)
+ * @G_UNICODE_CURRENCY_SYMBOL: General category "Symbol, Currency" (Sc)
+ * @G_UNICODE_MODIFIER_SYMBOL: General category "Symbol, Modifier" (Sk)
+ * @G_UNICODE_MATH_SYMBOL: General category "Symbol, Math" (Sm)
+ * @G_UNICODE_OTHER_SYMBOL: General category "Symbol, Other" (So)
+ * @G_UNICODE_LINE_SEPARATOR: General category "Separator, Line" (Zl)
+ * @G_UNICODE_PARAGRAPH_SEPARATOR: General category "Separator, Paragraph" (Zp)
+ * @G_UNICODE_SPACE_SEPARATOR: General category "Separator, Space" (Zs)
+ *
+ * These are the possible character classifications from the
+ * Unicode specification.
+ * See <ulink url="http://www.unicode.org/Public/UNIDATA/UnicodeData.html";>http://www.unicode.org/Public/UNIDATA/UnicodeData.html</ulink>.
+ */
+typedef enum
+{
+  G_UNICODE_CONTROL,
+  G_UNICODE_FORMAT,
+  G_UNICODE_UNASSIGNED,
+  G_UNICODE_PRIVATE_USE,
+  G_UNICODE_SURROGATE,
+  G_UNICODE_LOWERCASE_LETTER,
+  G_UNICODE_MODIFIER_LETTER,
+  G_UNICODE_OTHER_LETTER,
+  G_UNICODE_TITLECASE_LETTER,
+  G_UNICODE_UPPERCASE_LETTER,
+  G_UNICODE_SPACING_MARK,
+  G_UNICODE_ENCLOSING_MARK,
+  G_UNICODE_NON_SPACING_MARK,
+  G_UNICODE_DECIMAL_NUMBER,
+  G_UNICODE_LETTER_NUMBER,
+  G_UNICODE_OTHER_NUMBER,
+  G_UNICODE_CONNECT_PUNCTUATION,
+  G_UNICODE_DASH_PUNCTUATION,
+  G_UNICODE_CLOSE_PUNCTUATION,
+  G_UNICODE_FINAL_PUNCTUATION,
+  G_UNICODE_INITIAL_PUNCTUATION,
+  G_UNICODE_OTHER_PUNCTUATION,
+  G_UNICODE_OPEN_PUNCTUATION,
+  G_UNICODE_CURRENCY_SYMBOL,
+  G_UNICODE_MODIFIER_SYMBOL,
+  G_UNICODE_MATH_SYMBOL,
+  G_UNICODE_OTHER_SYMBOL,
+  G_UNICODE_LINE_SEPARATOR,
+  G_UNICODE_PARAGRAPH_SEPARATOR,
+  G_UNICODE_SPACE_SEPARATOR
+} GUnicodeType;
+
+/**
+ * G_UNICODE_COMBINING_MARK:
+ *
+ * Older name for %G_UNICODE_SPACING_MARK.
+ *
+ * Deprecated: 2.30: Use %G_UNICODE_SPACING_MARK.
+ */
+#ifndef G_DISABLE_DEPRECATED
+#define G_UNICODE_COMBINING_MARK G_UNICODE_SPACING_MARK
+#endif
+
+/**
+ * GUnicodeBreakType:
+ * @G_UNICODE_BREAK_MANDATORY: Mandatory Break (BK)
+ * @G_UNICODE_BREAK_CARRIAGE_RETURN: Carriage Return (CR)
+ * @G_UNICODE_BREAK_LINE_FEED: Line Feed (LF)
+ * @G_UNICODE_BREAK_COMBINING_MARK: Attached Characters and Combining Marks (CM)
+ * @G_UNICODE_BREAK_SURROGATE: Surrogates (SG)
+ * @G_UNICODE_BREAK_ZERO_WIDTH_SPACE: Zero Width Space (ZW)
+ * @G_UNICODE_BREAK_INSEPARABLE: Inseparable (IN)
+ * @G_UNICODE_BREAK_NON_BREAKING_GLUE: Non-breaking ("Glue") (GL)
+ * @G_UNICODE_BREAK_CONTINGENT: Contingent Break Opportunity (CB)
+ * @G_UNICODE_BREAK_SPACE: Space (SP)
+ * @G_UNICODE_BREAK_AFTER: Break Opportunity After (BA)
+ * @G_UNICODE_BREAK_BEFORE: Break Opportunity Before (BB)
+ * @G_UNICODE_BREAK_BEFORE_AND_AFTER: Break Opportunity Before and After (B2)
+ * @G_UNICODE_BREAK_HYPHEN: Hyphen (HY)
+ * @G_UNICODE_BREAK_NON_STARTER: Nonstarter (NS)
+ * @G_UNICODE_BREAK_OPEN_PUNCTUATION: Opening Punctuation (OP)
+ * @G_UNICODE_BREAK_CLOSE_PUNCTUATION: Closing Punctuation (CL)
+ * @G_UNICODE_BREAK_QUOTATION: Ambiguous Quotation (QU)
+ * @G_UNICODE_BREAK_EXCLAMATION: Exclamation/Interrogation (EX)
+ * @G_UNICODE_BREAK_IDEOGRAPHIC: Ideographic (ID)
+ * @G_UNICODE_BREAK_NUMERIC: Numeric (NU)
+ * @G_UNICODE_BREAK_INFIX_SEPARATOR: Infix Separator (Numeric) (IS)
+ * @G_UNICODE_BREAK_SYMBOL: Symbols Allowing Break After (SY)
+ * @G_UNICODE_BREAK_ALPHABETIC: Ordinary Alphabetic and Symbol Characters (AL)
+ * @G_UNICODE_BREAK_PREFIX: Prefix (Numeric) (PR)
+ * @G_UNICODE_BREAK_POSTFIX: Postfix (Numeric) (PO)
+ * @G_UNICODE_BREAK_COMPLEX_CONTEXT: Complex Content Dependent (South East Asian) (SA)
+ * @G_UNICODE_BREAK_AMBIGUOUS: Ambiguous (Alphabetic or Ideographic) (AI)
+ * @G_UNICODE_BREAK_UNKNOWN: Unknown (XX)
+ * @G_UNICODE_BREAK_NEXT_LINE: Next Line (NL)
+ * @G_UNICODE_BREAK_WORD_JOINER: Word Joiner (WJ)
+ * @G_UNICODE_BREAK_HANGUL_L_JAMO: Hangul L Jamo (JL)
+ * @G_UNICODE_BREAK_HANGUL_V_JAMO: Hangul V Jamo (JV)
+ * @G_UNICODE_BREAK_HANGUL_T_JAMO: Hangul T Jamo (JT)
+ * @G_UNICODE_BREAK_HANGUL_LV_SYLLABLE: Hangul LV Syllable (H2)
+ * @G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE: Hangul LVT Syllable (H3)
+ * @G_UNICODE_BREAK_CLOSE_PARANTHESIS: Closing Parenthesis (CP). Since 2.28
+ *
+ * These are the possible line break classifications.
+ *
+ * The five Hangul types were added in Unicode 4.1, so, has been
+ * introduced in GLib 2.10. Note that new types may be added in the future.
+ * Applications should be ready to handle unknown values.
+ * They may be regarded as %G_UNICODE_BREAK_UNKNOWN.
+ *
+ * See <ulink url="http://www.unicode.org/unicode/reports/tr14/";>http://www.unicode.org/unicode/reports/tr14/</ulink>.
+ */
+typedef enum
+{
+  G_UNICODE_BREAK_MANDATORY,
+  G_UNICODE_BREAK_CARRIAGE_RETURN,
+  G_UNICODE_BREAK_LINE_FEED,
+  G_UNICODE_BREAK_COMBINING_MARK,
+  G_UNICODE_BREAK_SURROGATE,
+  G_UNICODE_BREAK_ZERO_WIDTH_SPACE,
+  G_UNICODE_BREAK_INSEPARABLE,
+  G_UNICODE_BREAK_NON_BREAKING_GLUE,
+  G_UNICODE_BREAK_CONTINGENT,
+  G_UNICODE_BREAK_SPACE,
+  G_UNICODE_BREAK_AFTER,
+  G_UNICODE_BREAK_BEFORE,
+  G_UNICODE_BREAK_BEFORE_AND_AFTER,
+  G_UNICODE_BREAK_HYPHEN,
+  G_UNICODE_BREAK_NON_STARTER,
+  G_UNICODE_BREAK_OPEN_PUNCTUATION,
+  G_UNICODE_BREAK_CLOSE_PUNCTUATION,
+  G_UNICODE_BREAK_QUOTATION,
+  G_UNICODE_BREAK_EXCLAMATION,
+  G_UNICODE_BREAK_IDEOGRAPHIC,
+  G_UNICODE_BREAK_NUMERIC,
+  G_UNICODE_BREAK_INFIX_SEPARATOR,
+  G_UNICODE_BREAK_SYMBOL,
+  G_UNICODE_BREAK_ALPHABETIC,
+  G_UNICODE_BREAK_PREFIX,
+  G_UNICODE_BREAK_POSTFIX,
+  G_UNICODE_BREAK_COMPLEX_CONTEXT,
+  G_UNICODE_BREAK_AMBIGUOUS,
+  G_UNICODE_BREAK_UNKNOWN,
+  G_UNICODE_BREAK_NEXT_LINE,
+  G_UNICODE_BREAK_WORD_JOINER,
+  G_UNICODE_BREAK_HANGUL_L_JAMO,
+  G_UNICODE_BREAK_HANGUL_V_JAMO,
+  G_UNICODE_BREAK_HANGUL_T_JAMO,
+  G_UNICODE_BREAK_HANGUL_LV_SYLLABLE,
+  G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE,
+  G_UNICODE_BREAK_CLOSE_PARANTHESIS
+} GUnicodeBreakType;
+
+/**
+ * GUnicodeScript:
+ * @G_UNICODE_SCRIPT_INVALID_CODE:
+ *                               a value never returned from g_unichar_get_script()
+ * @G_UNICODE_SCRIPT_COMMON:     a character used by multiple different scripts
+ * @G_UNICODE_SCRIPT_INHERITED:  a mark glyph that takes its script from the
+ * i                             base glyph to which it is attached
+ * @G_UNICODE_SCRIPT_ARABIC:     Arabic
+ * @G_UNICODE_SCRIPT_ARMENIAN:   Armenian
+ * @G_UNICODE_SCRIPT_BENGALI:    Bengali
+ * @G_UNICODE_SCRIPT_BOPOMOFO:   Bopomofo
+ * @G_UNICODE_SCRIPT_CHEROKEE:   Cherokee
+ * @G_UNICODE_SCRIPT_COPTIC:     Coptic
+ * @G_UNICODE_SCRIPT_CYRILLIC:   Cyrillic
+ * @G_UNICODE_SCRIPT_DESERET:    Deseret
+ * @G_UNICODE_SCRIPT_DEVANAGARI: Devanagari
+ * @G_UNICODE_SCRIPT_ETHIOPIC:   Ethiopic
+ * @G_UNICODE_SCRIPT_GEORGIAN:   Georgian
+ * @G_UNICODE_SCRIPT_GOTHIC:     Gothic
+ * @G_UNICODE_SCRIPT_GREEK:      Greek
+ * @G_UNICODE_SCRIPT_GUJARATI:   Gujarati
+ * @G_UNICODE_SCRIPT_GURMUKHI:   Gurmukhi
+ * @G_UNICODE_SCRIPT_HAN:        Han
+ * @G_UNICODE_SCRIPT_HANGUL:     Hangul
+ * @G_UNICODE_SCRIPT_HEBREW:     Hebrew
+ * @G_UNICODE_SCRIPT_HIRAGANA:   Hiragana
+ * @G_UNICODE_SCRIPT_KANNADA:    Kannada
+ * @G_UNICODE_SCRIPT_KATAKANA:   Katakana
+ * @G_UNICODE_SCRIPT_KHMER:      Khmer
+ * @G_UNICODE_SCRIPT_LAO:        Lao
+ * @G_UNICODE_SCRIPT_LATIN:      Latin
+ * @G_UNICODE_SCRIPT_MALAYALAM:  Malayalam
+ * @G_UNICODE_SCRIPT_MONGOLIAN:  Mongolian
+ * @G_UNICODE_SCRIPT_MYANMAR:    Myanmar
+ * @G_UNICODE_SCRIPT_OGHAM:      Ogham
+ * @G_UNICODE_SCRIPT_OLD_ITALIC: Old Italic
+ * @G_UNICODE_SCRIPT_ORIYA:      Oriya
+ * @G_UNICODE_SCRIPT_RUNIC:      Runic
+ * @G_UNICODE_SCRIPT_SINHALA:    Sinhala
+ * @G_UNICODE_SCRIPT_SYRIAC:     Syriac
+ * @G_UNICODE_SCRIPT_TAMIL:      Tamil
+ * @G_UNICODE_SCRIPT_TELUGU:     Telugu
+ * @G_UNICODE_SCRIPT_THAANA:     Thaana
+ * @G_UNICODE_SCRIPT_THAI:       Thai
+ * @G_UNICODE_SCRIPT_TIBETAN:    Tibetan
+ * @G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL:
+ *                               Canadian Aboriginal
+ * @G_UNICODE_SCRIPT_YI:         Yi
+ * @G_UNICODE_SCRIPT_TAGALOG:    Tagalog
+ * @G_UNICODE_SCRIPT_HANUNOO:    Hanunoo
+ * @G_UNICODE_SCRIPT_BUHID:      Buhid
+ * @G_UNICODE_SCRIPT_TAGBANWA:   Tagbanwa
+ * @G_UNICODE_SCRIPT_BRAILLE:    Braille
+ * @G_UNICODE_SCRIPT_CYPRIOT:    Cypriot
+ * @G_UNICODE_SCRIPT_LIMBU:      Limbu
+ * @G_UNICODE_SCRIPT_OSMANYA:    Osmanya
+ * @G_UNICODE_SCRIPT_SHAVIAN:    Shavian
+ * @G_UNICODE_SCRIPT_LINEAR_B:   Linear B
+ * @G_UNICODE_SCRIPT_TAI_LE:     Tai Le
+ * @G_UNICODE_SCRIPT_UGARITIC:   Ugaritic
+ * @G_UNICODE_SCRIPT_NEW_TAI_LUE:
+ *                               New Tai Lue
+ * @G_UNICODE_SCRIPT_BUGINESE:   Buginese
+ * @G_UNICODE_SCRIPT_GLAGOLITIC: Glagolitic
+ * @G_UNICODE_SCRIPT_TIFINAGH:   Tifinagh
+ * @G_UNICODE_SCRIPT_SYLOTI_NAGRI:
+ *                               Syloti Nagri
+ * @G_UNICODE_SCRIPT_OLD_PERSIAN:
+ *                               Old Persian
+ * @G_UNICODE_SCRIPT_KHAROSHTHI: Kharoshthi
+ * @G_UNICODE_SCRIPT_UNKNOWN:    an unassigned code point
+ * @G_UNICODE_SCRIPT_BALINESE:   Balinese
+ * @G_UNICODE_SCRIPT_CUNEIFORM:  Cuneiform
+ * @G_UNICODE_SCRIPT_PHOENICIAN: Phoenician
+ * @G_UNICODE_SCRIPT_PHAGS_PA:   Phags-pa
+ * @G_UNICODE_SCRIPT_NKO:        N'Ko
+ * @G_UNICODE_SCRIPT_KAYAH_LI:   Kayah Li. Since 2.16.3
+ * @G_UNICODE_SCRIPT_LEPCHA:     Lepcha. Since 2.16.3
+ * @G_UNICODE_SCRIPT_REJANG:     Rejang. Since 2.16.3
+ * @G_UNICODE_SCRIPT_SUNDANESE:  Sundanese. Since 2.16.3
+ * @G_UNICODE_SCRIPT_SAURASHTRA: Saurashtra. Since 2.16.3
+ * @G_UNICODE_SCRIPT_CHAM:       Cham. Since 2.16.3
+ * @G_UNICODE_SCRIPT_OL_CHIKI:   Ol Chiki. Since 2.16.3
+ * @G_UNICODE_SCRIPT_VAI:        Vai. Since 2.16.3
+ * @G_UNICODE_SCRIPT_CARIAN:     Carian. Since 2.16.3
+ * @G_UNICODE_SCRIPT_LYCIAN:     Lycian. Since 2.16.3
+ * @G_UNICODE_SCRIPT_LYDIAN:     Lydian. Since 2.16.3
+ * @G_UNICODE_SCRIPT_AVESTAN:    Avestan. Since 2.26
+ * @G_UNICODE_SCRIPT_BAMUM:      Bamum. Since 2.26
+ * @G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS:
+ *                               Egyptian Hieroglpyhs. Since 2.26
+ * @G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC:
+ *                               Imperial Aramaic. Since 2.26
+ * @G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI:
+ *                               Inscriptional Pahlavi. Since 2.26
+ * @G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN:
+ *                               Inscriptional Parthian. Since 2.26
+ * @G_UNICODE_SCRIPT_JAVANESE:   Javanese. Since 2.26
+ * @G_UNICODE_SCRIPT_KAITHI:     Kaithi. Since 2.26
+ * @G_UNICODE_SCRIPT_LISU:       Lisu. Since 2.26
+ * @G_UNICODE_SCRIPT_MEETEI_MAYEK:
+ *                               Meetei Mayek. Since 2.26
+ * @G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN:
+ *                               Old South Arabian. Since 2.26
+ * @G_UNICODE_SCRIPT_OLD_TURKIC: Old Turkic. Since 2.28
+ * @G_UNICODE_SCRIPT_SAMARITAN:  Samaritan. Since 2.26
+ * @G_UNICODE_SCRIPT_TAI_THAM:   Tai Tham. Since 2.26
+ * @G_UNICODE_SCRIPT_TAI_VIET:   Tai Viet. Since 2.26
+ * @G_UNICODE_SCRIPT_BATAK:      Batak. Since 2.28
+ * @G_UNICODE_SCRIPT_BRAHMI:     Brahmi. Since 2.28
+ * @G_UNICODE_SCRIPT_MANDAIC:    Mandaic. Since 2.28
+ *
+ * The #GUnicodeScript enumeration identifies different writing
+ * systems. The values correspond to the names as defined in the
+ * Unicode standard. The enumeration has been added in GLib 2.14,
+ * and is interchangeable with #PangoScript.
+ *
+ * Note that new types may be added in the future. Applications
+ * should be ready to handle unknown values.
+ * See <ulink
+ * url="http://www.unicode.org/reports/tr24/";>Unicode Standard Annex
+ * #24: Script names</ulink>.
+ */
+typedef enum
+{                         /* ISO 15924 code */
+  G_UNICODE_SCRIPT_INVALID_CODE = -1,
+  G_UNICODE_SCRIPT_COMMON       = 0,   /* Zyyy */
+  G_UNICODE_SCRIPT_INHERITED,          /* Qaai */
+  G_UNICODE_SCRIPT_ARABIC,             /* Arab */
+  G_UNICODE_SCRIPT_ARMENIAN,           /* Armn */
+  G_UNICODE_SCRIPT_BENGALI,            /* Beng */
+  G_UNICODE_SCRIPT_BOPOMOFO,           /* Bopo */
+  G_UNICODE_SCRIPT_CHEROKEE,           /* Cher */
+  G_UNICODE_SCRIPT_COPTIC,             /* Qaac */
+  G_UNICODE_SCRIPT_CYRILLIC,           /* Cyrl (Cyrs) */
+  G_UNICODE_SCRIPT_DESERET,            /* Dsrt */
+  G_UNICODE_SCRIPT_DEVANAGARI,         /* Deva */
+  G_UNICODE_SCRIPT_ETHIOPIC,           /* Ethi */
+  G_UNICODE_SCRIPT_GEORGIAN,           /* Geor (Geon, Geoa) */
+  G_UNICODE_SCRIPT_GOTHIC,             /* Goth */
+  G_UNICODE_SCRIPT_GREEK,              /* Grek */
+  G_UNICODE_SCRIPT_GUJARATI,           /* Gujr */
+  G_UNICODE_SCRIPT_GURMUKHI,           /* Guru */
+  G_UNICODE_SCRIPT_HAN,                /* Hani */
+  G_UNICODE_SCRIPT_HANGUL,             /* Hang */
+  G_UNICODE_SCRIPT_HEBREW,             /* Hebr */
+  G_UNICODE_SCRIPT_HIRAGANA,           /* Hira */
+  G_UNICODE_SCRIPT_KANNADA,            /* Knda */
+  G_UNICODE_SCRIPT_KATAKANA,           /* Kana */
+  G_UNICODE_SCRIPT_KHMER,              /* Khmr */
+  G_UNICODE_SCRIPT_LAO,                /* Laoo */
+  G_UNICODE_SCRIPT_LATIN,              /* Latn (Latf, Latg) */
+  G_UNICODE_SCRIPT_MALAYALAM,          /* Mlym */
+  G_UNICODE_SCRIPT_MONGOLIAN,          /* Mong */
+  G_UNICODE_SCRIPT_MYANMAR,            /* Mymr */
+  G_UNICODE_SCRIPT_OGHAM,              /* Ogam */
+  G_UNICODE_SCRIPT_OLD_ITALIC,         /* Ital */
+  G_UNICODE_SCRIPT_ORIYA,              /* Orya */
+  G_UNICODE_SCRIPT_RUNIC,              /* Runr */
+  G_UNICODE_SCRIPT_SINHALA,            /* Sinh */
+  G_UNICODE_SCRIPT_SYRIAC,             /* Syrc (Syrj, Syrn, Syre) */
+  G_UNICODE_SCRIPT_TAMIL,              /* Taml */
+  G_UNICODE_SCRIPT_TELUGU,             /* Telu */
+  G_UNICODE_SCRIPT_THAANA,             /* Thaa */
+  G_UNICODE_SCRIPT_THAI,               /* Thai */
+  G_UNICODE_SCRIPT_TIBETAN,            /* Tibt */
+  G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, /* Cans */
+  G_UNICODE_SCRIPT_YI,                 /* Yiii */
+  G_UNICODE_SCRIPT_TAGALOG,            /* Tglg */
+  G_UNICODE_SCRIPT_HANUNOO,            /* Hano */
+  G_UNICODE_SCRIPT_BUHID,              /* Buhd */
+  G_UNICODE_SCRIPT_TAGBANWA,           /* Tagb */
+
+  /* Unicode-4.0 additions */
+  G_UNICODE_SCRIPT_BRAILLE,            /* Brai */
+  G_UNICODE_SCRIPT_CYPRIOT,            /* Cprt */
+  G_UNICODE_SCRIPT_LIMBU,              /* Limb */
+  G_UNICODE_SCRIPT_OSMANYA,            /* Osma */
+  G_UNICODE_SCRIPT_SHAVIAN,            /* Shaw */
+  G_UNICODE_SCRIPT_LINEAR_B,           /* Linb */
+  G_UNICODE_SCRIPT_TAI_LE,             /* Tale */
+  G_UNICODE_SCRIPT_UGARITIC,           /* Ugar */
+
+  /* Unicode-4.1 additions */
+  G_UNICODE_SCRIPT_NEW_TAI_LUE,        /* Talu */
+  G_UNICODE_SCRIPT_BUGINESE,           /* Bugi */
+  G_UNICODE_SCRIPT_GLAGOLITIC,         /* Glag */
+  G_UNICODE_SCRIPT_TIFINAGH,           /* Tfng */
+  G_UNICODE_SCRIPT_SYLOTI_NAGRI,       /* Sylo */
+  G_UNICODE_SCRIPT_OLD_PERSIAN,        /* Xpeo */
+  G_UNICODE_SCRIPT_KHAROSHTHI,         /* Khar */
+
+  /* Unicode-5.0 additions */
+  G_UNICODE_SCRIPT_UNKNOWN,            /* Zzzz */
+  G_UNICODE_SCRIPT_BALINESE,           /* Bali */
+  G_UNICODE_SCRIPT_CUNEIFORM,          /* Xsux */
+  G_UNICODE_SCRIPT_PHOENICIAN,         /* Phnx */
+  G_UNICODE_SCRIPT_PHAGS_PA,           /* Phag */
+  G_UNICODE_SCRIPT_NKO,                /* Nkoo */
+
+  /* Unicode-5.1 additions */
+  G_UNICODE_SCRIPT_KAYAH_LI,           /* Kali */
+  G_UNICODE_SCRIPT_LEPCHA,             /* Lepc */
+  G_UNICODE_SCRIPT_REJANG,             /* Rjng */
+  G_UNICODE_SCRIPT_SUNDANESE,          /* Sund */
+  G_UNICODE_SCRIPT_SAURASHTRA,         /* Saur */
+  G_UNICODE_SCRIPT_CHAM,               /* Cham */
+  G_UNICODE_SCRIPT_OL_CHIKI,           /* Olck */
+  G_UNICODE_SCRIPT_VAI,                /* Vaii */
+  G_UNICODE_SCRIPT_CARIAN,             /* Cari */
+  G_UNICODE_SCRIPT_LYCIAN,             /* Lyci */
+  G_UNICODE_SCRIPT_LYDIAN,             /* Lydi */
+
+  /* Unicode-5.2 additions */
+  G_UNICODE_SCRIPT_AVESTAN,                /* Avst */
+  G_UNICODE_SCRIPT_BAMUM,                  /* Bamu */
+  G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS,   /* Egyp */
+  G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC,       /* Armi */
+  G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI,  /* Phli */
+  G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN, /* Prti */
+  G_UNICODE_SCRIPT_JAVANESE,               /* Java */
+  G_UNICODE_SCRIPT_KAITHI,                 /* Kthi */
+  G_UNICODE_SCRIPT_LISU,                   /* Lisu */
+  G_UNICODE_SCRIPT_MEETEI_MAYEK,           /* Mtei */
+  G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN,      /* Sarb */
+  G_UNICODE_SCRIPT_OLD_TURKIC,             /* Orkh */
+  G_UNICODE_SCRIPT_SAMARITAN,              /* Samr */
+  G_UNICODE_SCRIPT_TAI_THAM,               /* Lana */
+  G_UNICODE_SCRIPT_TAI_VIET,               /* Tavt */
+
+  /* Unicode-6.0 additions */
+  G_UNICODE_SCRIPT_BATAK,                  /* Batk */
+  G_UNICODE_SCRIPT_BRAHMI,                 /* Brah */
+  G_UNICODE_SCRIPT_MANDAIC                 /* Mand */
+} GUnicodeScript;
+
+guint32 g_unicode_script_to_iso15924 (GUnicodeScript script);
+GUnicodeScript g_unicode_script_from_iso15924 (guint32 iso15924);
+
+/* Returns TRUE if current locale uses UTF-8 charset.  If CHARSET is
+ * not null, sets *CHARSET to the name of the current locale's
+ * charset.  This value is statically allocated, and should be copied
+ * in case the locale's charset will be changed later using setlocale()
+ * or in some other way.
+ */
+gboolean g_get_charset (const char **charset);
+
+/* These are all analogs of the <ctype.h> functions.
+ */
+gboolean g_unichar_isalnum   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isalpha   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iscntrl   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isdigit   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isgraph   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_islower   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isprint   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_ispunct   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isspace   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isupper   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isxdigit  (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_istitle   (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_isdefined (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iswide    (gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iswide_cjk(gunichar c) G_GNUC_CONST;
+gboolean g_unichar_iszerowidth(gunichar c) G_GNUC_CONST;
+gboolean g_unichar_ismark    (gunichar c) G_GNUC_CONST;
+
+/* More <ctype.h> functions.  These convert between the three cases.
+ * See the Unicode book to understand title case.  */
+gunichar g_unichar_toupper (gunichar c) G_GNUC_CONST;
+gunichar g_unichar_tolower (gunichar c) G_GNUC_CONST;
+gunichar g_unichar_totitle (gunichar c) G_GNUC_CONST;
+
+/* If C is a digit (according to `g_unichar_isdigit'), then return its
+   numeric value.  Otherwise return -1.  */
+gint g_unichar_digit_value (gunichar c) G_GNUC_CONST;
+
+gint g_unichar_xdigit_value (gunichar c) G_GNUC_CONST;
+
+/* Return the Unicode character type of a given character.  */
+GUnicodeType g_unichar_type (gunichar c) G_GNUC_CONST;
+
+/* Return the line break property for a given character */
+GUnicodeBreakType g_unichar_break_type (gunichar c) G_GNUC_CONST;
+
+/* Returns the combining class for a given character */
+gint g_unichar_combining_class (gunichar uc) G_GNUC_CONST;
+
+gboolean g_unichar_get_mirror_char (gunichar ch,
+                                    gunichar *mirrored_ch);
+
+GUnicodeScript g_unichar_get_script (gunichar ch) G_GNUC_CONST;
+
+/* Validate a Unicode character */
+gboolean g_unichar_validate (gunichar ch) G_GNUC_CONST;
+
+/* Pairwise canonical compose/decompose */
+gboolean g_unichar_compose (gunichar  a,
+                            gunichar  b,
+                            gunichar *ch);
+gboolean g_unichar_decompose (gunichar  ch,
+                              gunichar *a,
+                              gunichar *b);
+
+gsize g_unichar_fully_decompose (gunichar  ch,
+                                 gboolean  compat,
+                                 gunichar *result,
+                                 gsize     result_len);
+
+/* Compute canonical ordering of a string in-place.  This rearranges
+   decomposed characters in the string according to their combining
+   classes.  See the Unicode manual for more information.  */
+void g_unicode_canonical_ordering (gunichar *string,
+                                   gsize     len);
+
+
+#ifndef G_DISABLE_DEPRECATED
+/* Deprecated.  Use g_unichar_fully_decompose() */
+gunichar *g_unicode_canonical_decomposition (gunichar  ch,
+                                             gsize    *result_len) G_GNUC_MALLOC;
+#endif
+
+/* Array of skip-bytes-per-initial character.
+ */
+GLIB_VAR const gchar * const g_utf8_skip;
+
+/**
+ * g_utf8_next_char:
+ * @p: Pointer to the start of a valid UTF-8 character
+ *
+ * Skips to the next character in a UTF-8 string. The string must be
+ * valid; this macro is as fast as possible, and has no error-checking.
+ * You would use this macro to iterate over a string character by
+ * character. The macro returns the start of the next UTF-8 character.
+ * Before using this macro, use g_utf8_validate() to validate strings
+ * that may contain invalid UTF-8.
+ */
+#define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(const guchar *)(p)])
+
+gunichar g_utf8_get_char           (const gchar  *p) G_GNUC_PURE;
+gunichar g_utf8_get_char_validated (const  gchar *p,
+                                    gssize        max_len) G_GNUC_PURE;
+
+gchar*   g_utf8_offset_to_pointer (const gchar *str,
+                                   glong        offset) G_GNUC_PURE;
+glong    g_utf8_pointer_to_offset (const gchar *str,
+                                   const gchar *pos) G_GNUC_PURE;
+gchar*   g_utf8_prev_char         (const gchar *p) G_GNUC_PURE;
+gchar*   g_utf8_find_next_char    (const gchar *p,
+                                   const gchar *end) G_GNUC_PURE;
+gchar*   g_utf8_find_prev_char    (const gchar *str,
+                                   const gchar *p) G_GNUC_PURE;
+
+glong    g_utf8_strlen            (const gchar *p,
+                                   gssize       max) G_GNUC_PURE;
+
+gchar   *g_utf8_substring         (const gchar *str,
+                                   glong        start_pos,
+                                   glong        end_pos) G_GNUC_MALLOC;
+
+gchar   *g_utf8_strncpy           (gchar       *dest,
+                                   const gchar *src,
+                                   gsize        n);
+
+/* Find the UTF-8 character corresponding to ch, in string p. These
+   functions are equivalants to strchr and strrchr */
+gchar* g_utf8_strchr  (const gchar *p,
+                       gssize       len,
+                       gunichar     c);
+gchar* g_utf8_strrchr (const gchar *p,
+                       gssize       len,
+                       gunichar     c);
+gchar* g_utf8_strreverse (const gchar *str,
+                          gssize len);
+
+gunichar2 *g_utf8_to_utf16     (const gchar      *str,
+                                glong             len,
+                                glong            *items_read,
+                                glong            *items_written,
+                                GError          **error) G_GNUC_MALLOC;
+gunichar * g_utf8_to_ucs4      (const gchar      *str,
+                                glong             len,
+                                glong            *items_read,
+                                glong            *items_written,
+                                GError          **error) G_GNUC_MALLOC;
+gunichar * g_utf8_to_ucs4_fast (const gchar      *str,
+                                glong             len,
+                                glong            *items_written) G_GNUC_MALLOC;
+gunichar * g_utf16_to_ucs4     (const gunichar2  *str,
+                                glong             len,
+                                glong            *items_read,
+                                glong            *items_written,
+                                GError          **error) G_GNUC_MALLOC;
+gchar*     g_utf16_to_utf8     (const gunichar2  *str,
+                                glong             len,
+                                glong            *items_read,
+                                glong            *items_written,
+                                GError          **error) G_GNUC_MALLOC;
+gunichar2 *g_ucs4_to_utf16     (const gunichar   *str,
+                                glong             len,
+                                glong            *items_read,
+                                glong            *items_written,
+                                GError          **error) G_GNUC_MALLOC;
+gchar*     g_ucs4_to_utf8      (const gunichar   *str,
+                                glong             len,
+                                glong            *items_read,
+                                glong            *items_written,
+                                GError          **error) G_GNUC_MALLOC;
+
+gint      g_unichar_to_utf8 (gunichar    c,
+                             gchar      *outbuf);
+
+gboolean g_utf8_validate (const gchar  *str,
+                          gssize        max_len,
+                          const gchar **end);
+
+gchar *g_utf8_strup   (const gchar *str,
+                       gssize       len) G_GNUC_MALLOC;
+gchar *g_utf8_strdown (const gchar *str,
+                       gssize       len) G_GNUC_MALLOC;
+gchar *g_utf8_casefold (const gchar *str,
+                        gssize       len) G_GNUC_MALLOC;
+
+/**
+ * GNormalizeMode:
+ * @G_NORMALIZE_DEFAULT: standardize differences that do not affect the
+ *     text content, such as the above-mentioned accent representation
+ * @G_NORMALIZE_NFD: another name for %G_NORMALIZE_DEFAULT
+ * @G_NORMALIZE_DEFAULT_COMPOSE: like %G_NORMALIZE_DEFAULT, but with
+ *     composed forms rather than a maximally decomposed form
+ * @G_NORMALIZE_NFC: another name for %G_NORMALIZE_DEFAULT_COMPOSE
+ * @G_NORMALIZE_ALL: beyond %G_NORMALIZE_DEFAULT also standardize the
+ *     "compatibility" characters in Unicode, such as SUPERSCRIPT THREE
+ *     to the standard forms (in this case DIGIT THREE). Formatting
+ *     information may be lost but for most text operations such
+ *     characters should be considered the same
+ * @G_NORMALIZE_NFKD: another name for %G_NORMALIZE_ALL
+ * @G_NORMALIZE_ALL_COMPOSE: like %G_NORMALIZE_ALL, but with composed
+ *     forms rather than a maximally decomposed form
+ * @G_NORMALIZE_NFKC: another name for %G_NORMALIZE_ALL_COMPOSE
+ *
+ * Defines how a Unicode string is transformed in a canonical
+ * form, standardizing such issues as whether a character with
+ * an accent is represented as a base character and combining
+ * accent or as a single precomposed character. Unicode strings
+ * should generally be normalized before comparing them.
+ */
+typedef enum {
+  G_NORMALIZE_DEFAULT,
+  G_NORMALIZE_NFD = G_NORMALIZE_DEFAULT,
+  G_NORMALIZE_DEFAULT_COMPOSE,
+  G_NORMALIZE_NFC = G_NORMALIZE_DEFAULT_COMPOSE,
+  G_NORMALIZE_ALL,
+  G_NORMALIZE_NFKD = G_NORMALIZE_ALL,
+  G_NORMALIZE_ALL_COMPOSE,
+  G_NORMALIZE_NFKC = G_NORMALIZE_ALL_COMPOSE
+} GNormalizeMode;
+
+gchar *g_utf8_normalize (const gchar   *str,
+                         gssize         len,
+                         GNormalizeMode mode) G_GNUC_MALLOC;
+
+gint   g_utf8_collate     (const gchar *str1,
+                           const gchar *str2) G_GNUC_PURE;
+gchar *g_utf8_collate_key (const gchar *str,
+                           gssize       len) G_GNUC_MALLOC;
+gchar *g_utf8_collate_key_for_filename (const gchar *str,
+                                        gssize       len) G_GNUC_MALLOC;
+
+
+/* private */
+
+gchar *_g_utf8_make_valid (const gchar *name);
+
+G_END_DECLS
+
+#endif /* __G_UNICODE_H__ */
diff --git a/deps/glib/gutils.c b/deps/glib/gutils.c
new file mode 100644
index 0000000..679bab7
--- /dev/null
+++ b/deps/glib/gutils.c
@@ -0,0 +1,3890 @@
+/* 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.
+ */
+
+/**
+ * SECTION:version
+ * @Title: Version Information
+ * @Short_description: Variables and functions to check the GLib version
+ *
+ * GLib provides version information, primarily useful in configure
+ * checks for builds that have a configure script. Applications will
+ * not typically use the features described here.
+ */
+
+/**
+ * GLIB_MAJOR_VERSION:
+ *
+ * The major version number of the GLib library.
+ *
+ * Like #glib_major_version, but from the headers used at
+ * application compile time, rather than from the library
+ * linked against at application run time.
+ */
+
+/**
+ * GLIB_MINOR_VERSION:
+ *
+ * The minor version number of the GLib library.
+ *
+ * Like #gtk_minor_version, but from the headers used at
+ * application compile time, rather than from the library
+ * linked against at application run time.
+ */
+
+/**
+ * GLIB_MICRO_VERSION:
+ *
+ * The micro version number of the GLib library.
+ *
+ * Like #gtk_micro_version, but from the headers used at
+ * application compile time, rather than from the library
+ * linked against at application run time.
+ */
+
+#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 "gutils.h"
+
+#include "gfileutils.h"
+#include "ghash.h"
+#include "gslist.h"
+#include "gprintfint.h"
+#include "gthread.h"
+#include "gthreadprivate.h"
+#include "gtestutils.h"
+#include "gunicode.h"
+#include "gstrfuncs.h"
+#include "garray.h"
+#include "glibintl.h"
+
+#ifdef G_PLATFORM_WIN32
+#include "garray.h"
+#include "gconvert.h"
+#include "gwin32.h"
+#endif
+
+
+/**
+ * SECTION:misc_utils
+ * @title: Miscellaneous Utility Functions
+ * @short_description: a selection of portable utility functions
+ *
+ * These are portable utility functions.
+ */
+
+#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
+
+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_dll_directory (void)
+{
+  gchar *retval;
+  gchar *p;
+  wchar_t wc_fn[MAX_PATH];
+
+#ifdef DLL_EXPORT
+  if (glib_dll == NULL)
+    return NULL;
+#endif
+
+  /* This code is different from that in
+   * g_win32_get_package_installation_directory_of_module() in that
+   * here we return the actual folder where the GLib DLL is. We don't
+   * do the check for it being in a "bin" or "lib" subfolder and then
+   * returning the parent of that.
+   *
+   * In a statically built GLib, glib_dll will be NULL and we will
+   * thus look up the application's .exe file's location.
+   */
+  if (!GetModuleFileNameW (glib_dll, wc_fn, MAX_PATH))
+    return NULL;
+
+  retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL);
+
+  p = strrchr (retval, G_DIR_SEPARATOR);
+  if (p == NULL)
+    {
+      /* Wtf? */
+      return NULL;
+    }
+  *p = '\0';
+
+  return retval;
+}
+
+#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: (scope async): 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: (allow-none): a list of debug options separated by colons, spaces, or
+ * commas, or %NULL.
+ * @keys: (array length=nkeys): 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.
+ *
+ * If @string is equal to "all", all flags are set.  If @string
+ * is equal to "help", all the available keys in @keys are printed
+ * out to standard error.
+ *
+ * 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 if (!g_ascii_strcasecmp (string, "help"))
+    {
+      /* using stdio directly for the reason stated above */
+      fprintf (stderr, "Supported debug values: ");
+      for (i=0; i<nkeys; i++)
+	fprintf (stderr, " %s", keys[i].key);
+      fprintf (stderr, "\n");
+    }
+  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.
+ **/
+const 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.
+ * Note that this is a somewhat vague concept on Windows.
+ *
+ * On POSIX systems, an absolute file name is well-defined. It always
+ * starts from the single root directory. For example "/usr/local".
+ *
+ * On Windows, the concepts of current drive and drive-specific
+ * current directory introduce vagueness. This function interprets as
+ * an absolute file name one that either begins with a directory
+ * separator such as "\Users\tml" or begins with the root on a drive,
+ * for example "C:\Windows". The first case also includes UNC paths
+ * such as "\\myserver\docs\foo". In all cases, either slashes or
+ * backslashes are accepted.
+ *
+ * Note that a file name relative to the current drive root does not
+ * truly specify a file uniquely over time and across processes, as
+ * the current drive is a per-process value and can be changed.
+ *
+ * File names relative the current directory on some specific drive,
+ * such as "D:foo/bar", are not interpreted as absolute by this
+ * function, but they obviously are not relative to the normal current
+ * directory as returned by getcwd() or g_get_current_dir()
+ * either. Such paths should be avoided, or need to be handled using
+ * Windows-specific code.
+ *
+ * Returns: %TRUE if @file_name is absolute. 
+ */
+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.
+ */
+const 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_bit_nth_lsf:
+ * @mask: a #gulong containing flags
+ * @nth_bit: the index of the bit to start the search from
+ *
+ * Find the position of the first bit set in @mask, searching
+ * from (but not including) @nth_bit upwards. Bits are numbered
+ * from 0 (least significant) to sizeof(#gulong) * 8 - 1 (31 or 63,
+ * usually). To start searching from the 0th bit, set @nth_bit to -1.
+ *
+ * Returns: the index of the first bit set which is higher than @nth_bit
+ */
+
+/**
+ * g_bit_nth_msf:
+ * @mask: a #gulong containing flags
+ * @nth_bit: the index of the bit to start the search from
+ *
+ * Find the position of the first bit set in @mask, searching
+ * from (but not including) @nth_bit downwards. Bits are numbered
+ * from 0 (least significant) to sizeof(#gulong) * 8 - 1 (31 or 63,
+ * usually). To start searching from the last bit, set @nth_bit to
+ * -1 or GLIB_SIZEOF_LONG * 8.
+ *
+ * Returns: the index of the first bit set which is lower than @nth_bit
+ */
+
+/**
+ * g_bit_storage:
+ * @number: a #guint
+ *
+ * Gets the number of bits used to hold @number,
+ * e.g. if @number is 4, 3 bits are needed.
+ *
+ * Returns: the number of bits used to hold @number
+ */
+
+/**
+ * g_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
+ *
+ * Deprecated: use g_path_get_dirname() instead
+ */
+
+/**
+ * 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().
+ **/
+const 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: (array zero-terminated=1) (transfer full): 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_get_environ:
+ * 
+ * Gets the list of environment variables for the current process.  The
+ * list is %NULL terminated and each item in the list is of the form
+ * 'NAME=VALUE'.
+ *
+ * This is equivalent to direct access to the 'environ' global variable,
+ * except portable.
+ *
+ * The return value is freshly allocated and it should be freed with
+ * g_strfreev() when it is no longer needed.
+ *
+ * Returns: (array zero-terminated=1) (transfer full): the list of environment variables
+ *
+ * Since: 2.28
+ */
+gchar **
+g_get_environ (void)
+{
+#ifndef G_OS_WIN32
+  return g_strdupv (environ);
+#else
+  gunichar2 *strings;
+  gchar **result;
+  gint i, n;
+
+  strings = GetEnvironmentStringsW ();
+  for (n = 0; strings[n]; n += wcslen (strings + n) + 1);
+  result = g_new (char *, n + 1);
+  for (i = 0; strings[i]; i += wcslen (strings + i) + 1)
+    result[i] = g_utf16_to_utf8 (strings + i, -1, NULL, NULL, NULL);
+  FreeEnvironmentStringsW (strings);
+  result[i] = NULL;
+
+  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 == NULL || *g_tmp_dir == '\0')
+    g_tmp_dir = g_strdup (g_getenv ("TMP"));
+  if (g_tmp_dir == NULL || *g_tmp_dir == '\0')
+    g_tmp_dir = g_strdup (g_getenv ("TEMP"));
+
+#ifdef G_OS_WIN32
+  if (g_tmp_dir == NULL || *g_tmp_dir == '\0')
+    g_tmp_dir = get_windows_directory_root ();
+#else  
+#ifdef P_tmpdir
+  if (g_tmp_dir == NULL || *g_tmp_dir == '\0')
+    {
+      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 == NULL || *g_tmp_dir == '\0')
+    {
+      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
+	     * successful.
+	     */
+	    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.
+ */
+const 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.
+ */
+const 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
+ */
+const 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 or the empty string.
+ *
+ * Returns: the directory to use for temporary files.
+ */
+const 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
+ **/
+const 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>.
+ * In this case the directory retrieved will be XDG_DATA_HOME.
+ *
+ * On Windows this is the folder to use for local (as opposed to
+ * roaming) application data. See documentation for
+ * CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
+ * what g_get_user_config_dir() returns.
+ *
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+const 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_LOCAL_APPDATA);
+#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_LOCAL_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>.
+ * In this case the directory retrieved will be XDG_CONFIG_HOME.
+ *
+ * On Windows this is the folder to use for local (as opposed to
+ * roaming) application data. See documentation for
+ * CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
+ * what g_get_user_data_dir() returns.
+ *
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+const 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>.
+ * In this case the directory retrieved will be XDG_CACHE_HOME.
+ *
+ * On Windows is the directory that serves as a common repository for
+ * temporary Internet files. A typical path is
+ * C:\Documents and Settings\username\Local Settings\Temporary Internet Files.
+ * See documentation for CSIDL_INTERNET_CACHE.
+ *
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+const 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;
+}
+
+/**
+ * g_get_user_runtime_dir:
+ *
+ * Returns a directory that is unique to the current user on the local
+ * system.
+ *
+ * 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>.  This is the directory
+ * specified in the <envar>XDG_RUNTIME_DIR</envar> environment variable.
+ * In the case that this variable is not set, GLib will issue a warning
+ * message to stderr and return the value of g_get_user_cache_dir().
+ *
+ * On Windows this is the folder to use for local (as opposed to
+ * roaming) application data. See documentation for
+ * CSIDL_LOCAL_APPDATA.  Note that on Windows it thus is the same as
+ * what g_get_user_config_dir() returns.
+ *
+ * Returns: a string owned by GLib that must not be modified or freed.
+ *
+ * Since: 2.28
+ **/
+const gchar *
+g_get_user_runtime_dir (void)
+{
+#ifndef G_OS_WIN32
+  static const gchar *runtime_dir;
+  static gsize initialised;
+
+  if (g_once_init_enter (&initialised))
+    {
+      runtime_dir = g_strdup (getenv ("XDG_RUNTIME_DIR"));
+      
+      g_once_init_leave (&initialised, 1);
+    }
+
+  if (runtime_dir)
+    return runtime_dir;
+
+  /* Both fallback for UNIX and the default
+   * in Windows: use the user cache directory.
+   */
+#endif
+
+  return g_get_user_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 (GetModuleHandle ("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);
+      if (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);
+        }
+      else
+          g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+    }
+
+  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);
+      if (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);
+        }
+      else
+          g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+    }
+  
+  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_reload_user_special_dirs_cache:
+ *
+ * Resets the cache used for g_get_user_special_dir(), so
+ * that the latest on-disk version is used. Call this only
+ * if you just changed the data on disk yourself.
+ *
+ * Due to threadsafety issues this may cause leaking of strings
+ * that were previously returned from g_get_user_special_dir()
+ * that can't be freed. We ensure to only leak the data for
+ * the directories that actually changed value though.
+ *
+ * Since: 2.22
+ */
+void
+g_reload_user_special_dirs_cache (void)
+{
+  int i;
+
+  G_LOCK (g_utils_global);
+
+  if (g_user_special_dirs != NULL)
+    {
+      /* save a copy of the pointer, to check if some memory can be preserved */
+      char **old_g_user_special_dirs = g_user_special_dirs;
+      char *old_val;
+
+      /* recreate and reload our cache */
+      g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
+      load_user_special_dirs ();
+
+      /* only leak changed directories */
+      for (i = 0; i < G_USER_N_DIRECTORIES; i++)
+        {
+	  old_val = old_g_user_special_dirs[i];
+	  if (g_strcmp0 (old_val, g_user_special_dirs[i]) == 0)
+            {
+	      /* don't leak */
+	      g_free (g_user_special_dirs[i]);
+	      g_user_special_dirs[i] = old_val;
+            }
+	  else
+            g_free (old_val);
+        }
+
+      /* free the old array */
+      g_free (old_g_user_special_dirs);
+    }
+
+  G_UNLOCK (g_utils_global);
+}
+
+/**
+ * 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
+ */
+const 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 (GetModuleHandle ("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;
+}
+
+const gchar * const *
+g_win32_get_system_data_dirs_for_module (void (*address_of_function)())
+{
+  GArray *data_dirs;
+  HMODULE hmodule;
+  static GHashTable *per_module_data_dirs = NULL;
+  gchar **retval;
+  gchar *p;
+  gchar *exe_root;
+      
+  if (address_of_function)
+    {
+      G_LOCK (g_utils_global);
+      hmodule = get_module_for_address (address_of_function);
+      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 (const gchar * const *) 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_of_function 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_of_function);
+  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_of_function)
+    {
+      if (hmodule != NULL)
+	g_hash_table_insert (per_module_data_dirs, hmodule, retval);
+      G_UNLOCK (g_utils_global);
+    }
+
+  return (const gchar * const *) 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>
+ * In this case the list of directories retrieved will be XDG_DATA_DIRS.
+ *
+ * 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: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by GLib that must 
+ *               not be modified or freed.
+ * Since: 2.6
+ **/
+const gchar * const * 
+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 (const gchar * const *) 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>.
+ * In this case the list of directories retrieved will be XDG_CONFIG_DIRS.
+ *
+ * On Windows is the directory that contains application data for all users.
+ * A typical path is C:\Documents and Settings\All Users\Application Data.
+ * This folder is used for application data that is not user specific.
+ * For example, an application can store a spell-check dictionary, a database
+ * of clip art, or a log file in the CSIDL_COMMON_APPDATA folder.
+ * This information will not roam and is available to anyone using the computer.
+ *
+ * Return value: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by GLib that must 
+ *               not be modified or freed.
+ * Since: 2.6
+ **/
+const gchar * const *
+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 (const gchar * const *) 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...
+ */
+static void
+append_locale_variants (GPtrArray *array,
+                        const gchar *locale)
+{
+  gchar *language = NULL;
+  gchar *territory = NULL;
+  gchar *codeset = NULL;
+  gchar *modifier = NULL;
+
+  guint mask;
+  guint i, j;
+
+  g_return_if_fail (locale != NULL);
+
+  mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
+
+  /* Iterate through all possible combinations, from least attractive
+   * to most attractive.
+   */
+  for (j = 0; j <= mask; ++j)
+    {
+      i = mask - j;
+
+      if ((i & ~mask) == 0)
+        {
+          gchar *val = g_strconcat (language,
+                                    (i & COMPONENT_TERRITORY) ? territory : "",
+                                    (i & COMPONENT_CODESET) ? codeset : "",
+                                    (i & COMPONENT_MODIFIER) ? modifier : "",
+                                    NULL);
+          g_ptr_array_add (array, 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);
+}
+
+/**
+ * g_get_locale_variants:
+ * @locale: a locale identifier
+ *
+ * Returns a list of derived variants of @locale, 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.
+ * This function handles territory, charset and extra locale modifiers.
+ * 
+ * For example, if @locale is "fr_BE", then the returned list
+ * is "fr_BE", "fr".
+ *
+ * If you need the list of variants for the <emphasis>current locale</emphasis>,
+ * use g_get_language_names().
+ *
+ * Returns: (transfer full) (array zero-terminated=1) (element-type utf8): a newly
+ *   allocated array of newly allocated strings with the locale variants. Free with
+ *   g_strfreev().
+ *
+ * Since: 2.28
+ */
+gchar **
+g_get_locale_variants (const gchar *locale)
+{
+  GPtrArray *array;
+
+  g_return_val_if_fail (locale != NULL, NULL);
+
+  array = g_ptr_array_sized_new (8);
+  append_locale_variants (array, locale);
+  g_ptr_array_add (array, NULL);
+
+  return (gchar **) g_ptr_array_free (array, FALSE);
+}
+
+/* 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.
+   */
+  {
+    char *locale = g_win32_getlocale ();
+    retval = g_intern_string (locale);
+    g_free (locale);
+    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: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by GLib 
+ *    that must not be modified or freed.
+ *
+ * Since: 2.6
+ **/
+const gchar * const * 
+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))
+    {
+      GPtrArray *array;
+      gchar **alist, **a;
+
+      g_free (cache->languages);
+      g_strfreev (cache->language_names);
+      cache->languages = g_strdup (value);
+
+      array = g_ptr_array_sized_new (8);
+
+      alist = g_strsplit (value, ":", 0);
+      for (a = alist; *a; a++)
+        append_locale_variants (array, unalias_lang (*a));
+      g_strfreev (alist);
+      g_ptr_array_add (array, g_strdup ("C"));
+      g_ptr_array_add (array, NULL);
+
+      cache->language_names = (gchar **) g_ptr_array_free (array, FALSE);
+    }
+
+  return (const gchar * const *) 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_int64_equal:
+ * @v1: a pointer to a #gint64 key.
+ * @v2: a pointer to a #gint64 key to compare with @v1.
+ *
+ * Compares the two #gint64 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 64-bit integers as keys in a #GHashTable.
+ * 
+ * Returns: %TRUE if the two keys match.
+ *
+ * Since: 2.22
+ */
+gboolean
+g_int64_equal (gconstpointer v1,
+               gconstpointer v2)
+{
+  return *((const gint64*) v1) == *((const gint64*) v2);
+}
+
+/**
+ * g_int64_hash:
+ * @v: a pointer to a #gint64 key
+ *
+ * Converts a pointer to a #gint64 to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func parameter, 
+ * when using pointers to 64-bit integers values as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ *
+ * Since: 2.22
+ */
+guint
+g_int64_hash (gconstpointer v)
+{
+  return (guint) *(const gint64*) v;
+}
+
+/**
+ * g_double_equal:
+ * @v1: a pointer to a #gdouble key.
+ * @v2: a pointer to a #gdouble key to compare with @v1.
+ *
+ * Compares the two #gdouble 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 doubles as keys in a #GHashTable.
+ * 
+ * Returns: %TRUE if the two keys match.
+ *
+ * Since: 2.22
+ */
+gboolean
+g_double_equal (gconstpointer v1,
+                gconstpointer v2)
+{
+  return *((const gdouble*) v1) == *((const gdouble*) v2);
+}
+
+/**
+ * g_double_hash:
+ * @v: a pointer to a #gdouble key
+ *
+ * Converts a pointer to a #gdouble to a hash value.
+ * It can be passed to g_hash_table_new() as the @hash_func parameter, 
+ * when using pointers to doubles as keys in a #GHashTable.
+ *
+ * Returns: a hash value corresponding to the key.
+ *
+ * Since: 2.22
+ */
+guint
+g_double_hash (gconstpointer v)
+{
+  return (guint) *(const gdouble*) 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.
+ */
+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 */
+
+static void
+ensure_gettext_initialized(void)
+{
+  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;
+    }
+}
+
+/**
+ * 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
+ */
+const gchar *
+glib_gettext (const gchar *str)
+{
+  ensure_gettext_initialized();
+
+  return g_dgettext (GETTEXT_PACKAGE, str);
+}
+
+/**
+ * glib_pgettext:
+ * @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 glib_gettext() which supports
+ * a disambiguating message context. See g_dpgettext() for full
+ * details.
+ *
+ * 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
+ */
+const gchar *
+glib_pgettext(const gchar *msgctxtid,
+              gsize        msgidoffset)
+{
+  ensure_gettext_initialized();
+
+  return g_dpgettext (GETTEXT_PACKAGE, msgctxtid, msgidoffset);
+}
+
+#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
+
+const 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
+
+const gchar *
+g_get_user_name (void)
+{
+  g_get_any_init_locked ();
+  return g_user_name_cp;
+}
+
+#undef g_get_real_name
+
+const gchar *
+g_get_real_name (void)
+{
+  g_get_any_init_locked ();
+  return g_real_name_cp;
+}
+
+#undef g_get_home_dir
+
+const gchar *
+g_get_home_dir (void)
+{
+  g_get_any_init_locked ();
+  return g_home_dir_cp;
+}
+
+#undef g_get_tmp_dir
+
+const gchar *
+g_get_tmp_dir (void)
+{
+  g_get_any_init_locked ();
+  return g_tmp_dir_cp;
+}
+
+#endif
diff --git a/deps/glib/gutils.h b/deps/glib/gutils.h
new file mode 100644
index 0000000..a0f3cf6
--- /dev/null
+++ b/deps/glib/gutils.h
@@ -0,0 +1,528 @@
+/* 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_UTILS_H__
+#define __G_UTILS_H__
+
+#include <glib/gtypes.h>
+#include <stdarg.h>
+
+G_BEGIN_DECLS
+
+#ifdef G_OS_WIN32
+
+/* On Win32, the canonical directory separator is the backslash, and
+ * the search path separator is the semicolon. Note that also the
+ * (forward) slash works as directory separator.
+ */
+#define G_DIR_SEPARATOR '\\'
+#define G_DIR_SEPARATOR_S "\\"
+#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
+#define G_SEARCHPATH_SEPARATOR ';'
+#define G_SEARCHPATH_SEPARATOR_S ";"
+
+#else  /* !G_OS_WIN32 */
+
+/* Unix */
+
+#define G_DIR_SEPARATOR '/'
+#define G_DIR_SEPARATOR_S "/"
+#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR)
+#define G_SEARCHPATH_SEPARATOR ':'
+#define G_SEARCHPATH_SEPARATOR_S ":"
+
+#endif /* !G_OS_WIN32 */
+
+/* Define G_VA_COPY() to do the right thing for copying va_list variables.
+ * glibconfig.h may have already defined G_VA_COPY as va_copy or __va_copy.
+ */
+#if !defined (G_VA_COPY)
+#  if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
+#    define G_VA_COPY(ap1, ap2)	  (*(ap1) = *(ap2))
+#  elif defined (G_VA_COPY_AS_ARRAY)
+#    define G_VA_COPY(ap1, ap2)	  g_memmove ((ap1), (ap2), sizeof (va_list))
+#  else /* va_list is a pointer */
+#    define G_VA_COPY(ap1, ap2)	  ((ap1) = (ap2))
+#  endif /* va_list is a pointer */
+#endif /* !G_VA_COPY */
+
+/* inlining hassle. for compilers that don't allow the `inline' keyword,
+ * mostly because of strict ANSI C compliance or dumbness, we try to fall
+ * back to either `__inline__' or `__inline'.
+ * G_CAN_INLINE is defined in glibconfig.h if the compiler seems to be 
+ * actually *capable* to do function inlining, in which case inline 
+ * function bodies do make sense. we also define G_INLINE_FUNC to properly 
+ * export the function prototypes if no inlining can be performed.
+ * inline function bodies have to be special cased with G_CAN_INLINE and a
+ * .c file specific macro to allow one compiled instance with extern linkage
+ * of the functions by defining G_IMPLEMENT_INLINES and the .c file macro.
+ */
+#if defined (G_HAVE_INLINE) && defined (__GNUC__) && defined (__STRICT_ANSI__)
+#  undef inline
+#  define inline __inline__
+#elif !defined (G_HAVE_INLINE)
+#  undef inline
+#  if defined (G_HAVE___INLINE__)
+#    define inline __inline__
+#  elif defined (G_HAVE___INLINE)
+#    define inline __inline
+#  else /* !inline && !__inline__ && !__inline */
+#    define inline  /* don't inline, then */
+#  endif
+#endif
+#ifdef G_IMPLEMENT_INLINES
+#  define G_INLINE_FUNC
+#  undef  G_CAN_INLINE
+#elif defined (__GNUC__) 
+#  define G_INLINE_FUNC static __inline __attribute__ ((unused))
+#elif defined (G_CAN_INLINE) 
+#  define G_INLINE_FUNC static inline
+#else /* can't inline */
+#  define G_INLINE_FUNC
+#endif /* !G_INLINE_FUNC */
+
+#ifndef __GTK_DOC_IGNORE__
+#ifdef G_OS_WIN32
+#define g_get_user_name g_get_user_name_utf8
+#define g_get_real_name g_get_real_name_utf8
+#define g_get_home_dir g_get_home_dir_utf8
+#define g_get_tmp_dir g_get_tmp_dir_utf8
+#endif
+#endif
+
+const gchar *         g_get_user_name        (void);
+const gchar *         g_get_real_name        (void);
+const gchar *         g_get_home_dir         (void);
+const gchar *         g_get_tmp_dir          (void);
+const gchar *         g_get_host_name	     (void);
+gchar *               g_get_prgname          (void);
+void                  g_set_prgname          (const gchar *prgname);
+const gchar *         g_get_application_name (void);
+void                  g_set_application_name (const gchar *application_name);
+
+void      g_reload_user_special_dirs_cache     (void);
+const gchar *         g_get_user_data_dir      (void);
+const gchar *         g_get_user_config_dir    (void);
+const gchar *         g_get_user_cache_dir     (void);
+const gchar * const * g_get_system_data_dirs   (void);
+
+#ifdef G_OS_WIN32
+/* This functions is not part of the public GLib API */
+const gchar * const * g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void));
+#endif
+
+#if defined (G_OS_WIN32) && defined (G_CAN_INLINE) && !defined (__cplusplus)
+/* This function is not part of the public GLib API either. Just call
+ * g_get_system_data_dirs() in your code, never mind that that is
+ * actually a macro and you will in fact call this inline function.
+ */
+static inline const gchar * const *
+_g_win32_get_system_data_dirs (void)
+{
+  return g_win32_get_system_data_dirs_for_module ((void (*)(void)) &_g_win32_get_system_data_dirs);
+}
+#define g_get_system_data_dirs _g_win32_get_system_data_dirs
+#endif
+
+const gchar * const * g_get_system_config_dirs (void);
+
+const gchar * g_get_user_runtime_dir (void);
+
+const gchar * const * g_get_language_names (void);
+
+gchar **g_get_locale_variants (const gchar *locale);
+
+/**
+ * GUserDirectory:
+ * @G_USER_DIRECTORY_DESKTOP: the user's Desktop directory
+ * @G_USER_DIRECTORY_DOCUMENTS: the user's Documents directory
+ * @G_USER_DIRECTORY_DOWNLOAD: the user's Downloads directory
+ * @G_USER_DIRECTORY_MUSIC: the user's Music directory
+ * @G_USER_DIRECTORY_PICTURES: the user's Pictures directory
+ * @G_USER_DIRECTORY_PUBLIC_SHARE: the user's shared directory
+ * @G_USER_DIRECTORY_TEMPLATES: the user's Templates directory
+ * @G_USER_DIRECTORY_VIDEOS: the user's Movies directory
+ * @G_USER_N_DIRECTORIES: the number of enum values
+ *
+ * These are logical ids for special directories which are defined
+ * depending on the platform used. You should use g_get_user_special_dir()
+ * to retrieve the full path associated to the logical id.
+ *
+ * The #GUserDirectory enumeration can be extended at later date. Not
+ * every platform has a directory for every logical id in this
+ * enumeration.
+ *
+ * Since: 2.14
+ */
+typedef enum {
+  G_USER_DIRECTORY_DESKTOP,
+  G_USER_DIRECTORY_DOCUMENTS,
+  G_USER_DIRECTORY_DOWNLOAD,
+  G_USER_DIRECTORY_MUSIC,
+  G_USER_DIRECTORY_PICTURES,
+  G_USER_DIRECTORY_PUBLIC_SHARE,
+  G_USER_DIRECTORY_TEMPLATES,
+  G_USER_DIRECTORY_VIDEOS,
+
+  G_USER_N_DIRECTORIES
+} GUserDirectory;
+
+const gchar * g_get_user_special_dir (GUserDirectory directory);
+
+/**
+ * GDebugKey:
+ * @key: the string
+ * @value: the flag
+ *
+ * Associates a string with a bit flag.
+ * Used in g_parse_debug_string().
+ */
+typedef struct _GDebugKey GDebugKey;
+struct _GDebugKey
+{
+  const gchar *key;
+  guint	       value;
+};
+
+/* Miscellaneous utility functions
+ */
+guint                 g_parse_debug_string (const gchar     *string,
+					    const GDebugKey *keys,
+					    guint            nkeys);
+
+gint                  g_snprintf           (gchar       *string,
+					    gulong       n,
+					    gchar const *format,
+					    ...) G_GNUC_PRINTF (3, 4);
+gint                  g_vsnprintf          (gchar       *string,
+					    gulong       n,
+					    gchar const *format,
+					    va_list      args);
+
+/* Check if a file name is an absolute path */
+gboolean              g_path_is_absolute   (const gchar *file_name);
+
+/* In case of absolute paths, skip the root part */
+const gchar *         g_path_skip_root     (const gchar *file_name);
+
+#ifndef G_DISABLE_DEPRECATED
+
+const gchar *         g_basename           (const gchar *file_name);
+#define g_dirname g_path_get_dirname
+
+#endif /* G_DISABLE_DEPRECATED */
+
+#ifndef __GTK_DOC_IGNORE__
+#ifdef G_OS_WIN32
+#define g_get_current_dir g_get_current_dir_utf8
+#endif
+#endif
+
+/* The returned strings are newly allocated with g_malloc() */
+gchar*                g_get_current_dir    (void);
+gchar*                g_path_get_basename  (const gchar *file_name) G_GNUC_MALLOC;
+gchar*                g_path_get_dirname   (const gchar *file_name) G_GNUC_MALLOC;
+
+/* Set the pointer at the specified location to NULL */
+void                  g_nullify_pointer    (gpointer    *nullify_location);
+
+/* return the environment string for the variable. The returned memory
+ * must not be freed. */
+#ifndef __GTK_DOC_IGNORE__
+#ifdef G_OS_WIN32
+#define g_getenv g_getenv_utf8
+#define g_setenv g_setenv_utf8
+#define g_unsetenv g_unsetenv_utf8
+#define g_find_program_in_path g_find_program_in_path_utf8
+#endif
+#endif
+
+const gchar *         g_getenv             (const gchar *variable);
+gboolean              g_setenv             (const gchar *variable,
+					    const gchar *value,
+					    gboolean     overwrite);
+void                  g_unsetenv           (const gchar *variable);
+gchar**               g_listenv            (void);
+gchar**               g_get_environ        (void);
+
+/* private */
+const gchar*	     _g_getenv_nomalloc	   (const gchar	*variable,
+					    gchar        buffer[1024]);
+
+/**
+ * GVoidFunc:
+ *
+ * Declares a type of function which takes no arguments
+ * and has no return value. It is used to specify the type
+ * function passed to g_atexit().
+ */
+typedef void (*GVoidFunc) (void);
+#ifndef ATEXIT
+# define ATEXIT(proc) g_ATEXIT(proc)
+#else
+# define G_NATIVE_ATEXIT
+#endif /* ATEXIT */
+/* we use a GLib function as a replacement for ATEXIT, so
+ * the programmer is not required to check the return value
+ * (if there is any in the implementation) and doesn't encounter
+ * missing include files.
+ */
+void	g_atexit		(GVoidFunc    func);
+
+#ifdef G_OS_WIN32
+/* It's a bad idea to wrap atexit() on Windows. If the GLib DLL calls
+ * atexit(), the function will be called when the GLib DLL is detached
+ * from the program, which is not what the caller wants. The caller
+ * wants the function to be called when it *itself* exits (or is
+ * detached, in case the caller, too, is a DLL).
+ */
+#if (defined(__MINGW_H) && !defined(_STDLIB_H_)) || (defined(_MSC_VER) && !defined(_INC_STDLIB))
+int atexit (void (*)(void));
+#endif
+#define g_atexit(func) atexit(func)
+#endif
+
+/* Look for an executable in PATH, following execvp() rules */
+gchar*  g_find_program_in_path  (const gchar *program);
+
+/* Bit tests
+ */
+G_INLINE_FUNC gint	g_bit_nth_lsf (gulong  mask,
+				       gint    nth_bit) G_GNUC_CONST;
+G_INLINE_FUNC gint	g_bit_nth_msf (gulong  mask,
+				       gint    nth_bit) G_GNUC_CONST;
+G_INLINE_FUNC guint	g_bit_storage (gulong  number) G_GNUC_CONST;
+
+/* Trash Stacks
+ * elements need to be >= sizeof (gpointer)
+ */
+typedef struct _GTrashStack     GTrashStack;
+struct _GTrashStack
+{
+  GTrashStack *next;
+};
+
+G_INLINE_FUNC void	g_trash_stack_push	(GTrashStack **stack_p,
+						 gpointer      data_p);
+G_INLINE_FUNC gpointer	g_trash_stack_pop	(GTrashStack **stack_p);
+G_INLINE_FUNC gpointer	g_trash_stack_peek	(GTrashStack **stack_p);
+G_INLINE_FUNC guint	g_trash_stack_height	(GTrashStack **stack_p);
+
+/* inline function implementations
+ */
+#if defined (G_CAN_INLINE) || defined (__G_UTILS_C__)
+G_INLINE_FUNC gint
+g_bit_nth_lsf (gulong mask,
+	       gint   nth_bit)
+{
+  if (G_UNLIKELY (nth_bit < -1))
+    nth_bit = -1;
+  while (nth_bit < ((GLIB_SIZEOF_LONG * 8) - 1))
+    {
+      nth_bit++;
+      if (mask & (1UL << nth_bit))
+	return nth_bit;
+    }
+  return -1;
+}
+G_INLINE_FUNC gint
+g_bit_nth_msf (gulong mask,
+	       gint   nth_bit)
+{
+  if (nth_bit < 0 || G_UNLIKELY (nth_bit > GLIB_SIZEOF_LONG * 8))
+    nth_bit = GLIB_SIZEOF_LONG * 8;
+  while (nth_bit > 0)
+    {
+      nth_bit--;
+      if (mask & (1UL << nth_bit))
+	return nth_bit;
+    }
+  return -1;
+}
+G_INLINE_FUNC guint
+g_bit_storage (gulong number)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
+  return G_LIKELY (number) ?
+	   ((GLIB_SIZEOF_LONG * 8U - 1) ^ __builtin_clzl(number)) + 1 : 1;
+#else
+  register guint n_bits = 0;
+  
+  do
+    {
+      n_bits++;
+      number >>= 1;
+    }
+  while (number);
+  return n_bits;
+#endif
+}
+G_INLINE_FUNC void
+g_trash_stack_push (GTrashStack **stack_p,
+		    gpointer      data_p)
+{
+  GTrashStack *data = (GTrashStack *) data_p;
+
+  data->next = *stack_p;
+  *stack_p = data;
+}
+G_INLINE_FUNC gpointer
+g_trash_stack_pop (GTrashStack **stack_p)
+{
+  GTrashStack *data;
+
+  data = *stack_p;
+  if (data)
+    {
+      *stack_p = data->next;
+      /* NULLify private pointer here, most platforms store NULL as
+       * subsequent 0 bytes
+       */
+      data->next = NULL;
+    }
+
+  return data;
+}
+G_INLINE_FUNC gpointer
+g_trash_stack_peek (GTrashStack **stack_p)
+{
+  GTrashStack *data;
+
+  data = *stack_p;
+
+  return data;
+}
+G_INLINE_FUNC guint
+g_trash_stack_height (GTrashStack **stack_p)
+{
+  GTrashStack *data;
+  guint i = 0;
+
+  for (data = *stack_p; data; data = data->next)
+    i++;
+
+  return i;
+}
+#endif  /* G_CAN_INLINE || __G_UTILS_C__ */
+
+/* Glib version.
+ * we prefix variable declarations so they can
+ * properly get exported in windows dlls.
+ */
+GLIB_VAR const guint glib_major_version;
+GLIB_VAR const guint glib_minor_version;
+GLIB_VAR const guint glib_micro_version;
+GLIB_VAR const guint glib_interface_age;
+GLIB_VAR const guint glib_binary_age;
+
+const gchar * glib_check_version (guint required_major,
+                                  guint required_minor,
+                                  guint required_micro);
+
+/**
+ * GLIB_CHECK_VERSION:
+ * @major: the major version to check for
+ * @minor: the minor version to check for
+ * @micro: the micro version to check for
+ *
+ * Checks the version of the GLib library that is being compiled
+ * against.
+ *
+ * <example>
+ * <title>Checking the version of the GLib library</title>
+ * <programlisting>
+ *   if (!GLIB_CHECK_VERSION (1, 2, 0))
+ *     g_error ("GLib version 1.2.0 or above is needed");
+ * </programlisting>
+ * </example>
+ *
+ * See glib_check_version() for a runtime check.
+ *
+ * Returns: %TRUE if the version of the GLib header files
+ * is the same as or newer than the passed-in version.
+ */
+#define GLIB_CHECK_VERSION(major,minor,micro)    \
+    (GLIB_MAJOR_VERSION > (major) || \
+     (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION > (minor)) || \
+     (GLIB_MAJOR_VERSION == (major) && GLIB_MINOR_VERSION == (minor) && \
+      GLIB_MICRO_VERSION >= (micro)))
+
+G_END_DECLS
+
+#ifndef G_DISABLE_DEPRECATED
+
+/*
+ * This macro is deprecated. This DllMain() is too complex. It is
+ * recommended to write an explicit minimal DLlMain() that just saves
+ * the handle to the DLL and then use that handle instead, for
+ * instance passing it to
+ * g_win32_get_package_installation_directory_of_module().
+ *
+ * On Windows, this macro defines a DllMain function that stores the
+ * actual DLL name that the code being compiled will be included in.
+ * STATIC should be empty or 'static'. DLL_NAME is the name of the
+ * (pointer to the) char array where the DLL name will be stored. If
+ * this is used, you must also include <windows.h>. If you need a more complex
+ * DLL entry point function, you cannot use this.
+ *
+ * On non-Windows platforms, expands to nothing.
+ */
+
+#ifndef G_PLATFORM_WIN32
+# define G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)
+#else
+# define G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)			\
+static char *dll_name;							\
+									\
+BOOL WINAPI								\
+DllMain (HINSTANCE hinstDLL,						\
+	 DWORD     fdwReason,						\
+	 LPVOID    lpvReserved)						\
+{									\
+  wchar_t wcbfr[1000];							\
+  char *tem;								\
+  switch (fdwReason)							\
+    {									\
+    case DLL_PROCESS_ATTACH:						\
+      GetModuleFileNameW ((HMODULE) hinstDLL, wcbfr, G_N_ELEMENTS (wcbfr)); \
+      tem = g_utf16_to_utf8 (wcbfr, -1, NULL, NULL, NULL);		\
+      dll_name = g_path_get_basename (tem);				\
+      g_free (tem);							\
+      break;								\
+    }									\
+									\
+  return TRUE;								\
+}
+
+#endif	/* !G_DISABLE_DEPRECATED */
+
+#endif /* G_PLATFORM_WIN32 */
+
+#endif /* __G_UTILS_H__ */
diff --git a/deps/gmodule/gmodule-dl.c b/deps/gmodule/gmodule-dl.c
new file mode 100644
index 0000000..035b2a9
--- /dev/null
+++ b/deps/gmodule/gmodule-dl.c
@@ -0,0 +1,168 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998, 2000 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.
+ */
+
+/*
+ * 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 <dlfcn.h>
+
+/* Perl includes <nlist.h> and <link.h> instead of <dlfcn.h> on some systmes? */
+
+
+/* dlerror() is not implemented on all systems
+ */
+#ifndef	G_MODULE_HAVE_DLERROR
+#  ifdef __NetBSD__
+#    define dlerror()	g_strerror (errno)
+#  else /* !__NetBSD__ */
+/* could we rely on errno's state here? */
+#    define dlerror()	"unknown dl-error"
+#  endif /* !__NetBSD__ */
+#endif	/* G_MODULE_HAVE_DLERROR */
+
+/* some flags are missing on some systems, so we provide
+ * harmless defaults.
+ * The Perl sources say, RTLD_LAZY needs to be defined as (1),
+ * at least for Solaris 1.
+ *
+ * Mandatory:
+ * RTLD_LAZY   - resolve undefined symbols as code from the dynamic library
+ *		 is executed.
+ * RTLD_NOW    - resolve all undefined symbols before dlopen returns, and fail
+ *		 if this cannot be done.
+ * Optionally:
+ * RTLD_GLOBAL - the external symbols defined in the library will be made
+ *		 available to subsequently loaded libraries.
+ */
+#ifndef	RTLD_LAZY
+#define	RTLD_LAZY	1
+#endif	/* RTLD_LAZY */
+#ifndef	RTLD_NOW
+#define	RTLD_NOW	0
+#endif	/* RTLD_NOW */
+/* some systems (OSF1 V5.0) have broken RTLD_GLOBAL linkage */
+#ifdef G_MODULE_BROKEN_RTLD_GLOBAL
+#undef	RTLD_GLOBAL
+#endif /* G_MODULE_BROKEN_RTLD_GLOBAL */
+#ifndef	RTLD_GLOBAL
+#define	RTLD_GLOBAL	0
+#endif	/* RTLD_GLOBAL */
+
+
+/* --- functions --- */
+static gchar*
+fetch_dlerror (gboolean replace_null)
+{
+  gchar *msg = dlerror ();
+
+  /* make sure we always return an error message != NULL, if
+   * expected to do so. */
+
+  if (!msg && replace_null)
+    return "unknown dl-error";
+
+  return msg;
+}
+
+static gpointer
+_g_module_open (const gchar *file_name,
+		gboolean     bind_lazy,
+		gboolean     bind_local)
+{
+  gpointer handle;
+  
+  handle = dlopen (file_name,
+		   (bind_local ? 0 : RTLD_GLOBAL) | (bind_lazy ? RTLD_LAZY : RTLD_NOW));
+  if (!handle)
+    g_module_set_error (fetch_dlerror (TRUE));
+  
+  return handle;
+}
+
+static gpointer
+_g_module_self (void)
+{
+  gpointer handle;
+  
+  /* to query symbols from the program itself, special link options
+   * are required on some systems.
+   */
+  
+  handle = dlopen (NULL, RTLD_GLOBAL | RTLD_LAZY);
+  if (!handle)
+    g_module_set_error (fetch_dlerror (TRUE));
+  
+  return handle;
+}
+
+static void
+_g_module_close (gpointer handle,
+		 gboolean is_unref)
+{
+  /* are there any systems out there that have dlopen()/dlclose()
+   * without a reference count implementation?
+   */
+  is_unref |= 1;
+  
+  if (is_unref)
+    {
+      if (dlclose (handle) != 0)
+	g_module_set_error (fetch_dlerror (TRUE));
+    }
+}
+
+static gpointer
+_g_module_symbol (gpointer     handle,
+		  const gchar *symbol_name)
+{
+  gpointer p;
+  gchar *msg;
+
+  fetch_dlerror (FALSE);
+  p = dlsym (handle, symbol_name);
+  msg = fetch_dlerror (FALSE);
+  if (msg)
+    g_module_set_error (msg);
+  
+  return p;
+}
+
+static gchar*
+_g_module_build_path (const gchar *directory,
+		      const gchar *module_name)
+{
+  if (directory && *directory) {
+    if (strncmp (module_name, "lib", 3) == 0)
+      return g_strconcat (directory, "/", module_name, NULL);
+    else
+      return g_strconcat (directory, "/lib", module_name, "." G_MODULE_SUFFIX, NULL);
+  } else if (strncmp (module_name, "lib", 3) == 0)
+    return g_strdup (module_name);
+  else
+    return g_strconcat ("lib", module_name, "." G_MODULE_SUFFIX, NULL);
+}
diff --git a/deps/gmodule/gmodule-dld.c b/deps/gmodule/gmodule-dld.c
new file mode 100644
index 0000000..401b32f
--- /dev/null
+++ b/deps/gmodule/gmodule-dld.c
@@ -0,0 +1,163 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998, 2000 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.
+ */
+
+/*
+ * 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 <dl.h>
+
+
+/* some flags are missing on some systems, so we provide
+ * harmless defaults.
+ *
+ * Mandatory:
+ * BIND_IMMEDIATE  - Resolve symbol references when the library is loaded.
+ * BIND_DEFERRED   - Delay code symbol resolution until actual reference.
+ *
+ * Optionally:
+ * BIND_FIRST	   - Place the library at the head of the symbol search order.
+ * BIND_NONFATAL   - The default BIND_IMMEDIATE behavior is to treat all unsatisfied
+ *		     symbols as fatal.	This flag allows binding of unsatisfied code
+ *		     symbols to be deferred until use.
+ *		     [Perl: For certain libraries, like DCE, deferred binding often
+ *		     causes run time problems.	Adding BIND_NONFATAL to BIND_IMMEDIATE
+ *		     still allows unresolved references in situations like this.]
+ * BIND_NOSTART	   - Do not call the initializer for the shared library when the
+ *		     library is loaded, nor on a future call to shl_unload().
+ * BIND_VERBOSE	   - Print verbose messages concerning possible unsatisfied symbols.
+ *
+ * hp9000s700/hp9000s800:
+ * BIND_RESTRICTED - Restrict symbols visible by the library to those present at
+ *		     library load time.
+ * DYNAMIC_PATH	   - Allow the loader to dynamically search for the library specified
+ *		     by the path argument.
+ */
+#ifndef	DYNAMIC_PATH
+#define	DYNAMIC_PATH	0
+#endif	/* DYNAMIC_PATH */
+#ifndef	BIND_RESTRICTED
+#define	BIND_RESTRICTED	0
+#endif	/* BIND_RESTRICTED */
+
+#define	OPT_BIND_FLAGS	(BIND_NONFATAL | BIND_VERBOSE)
+
+
+/* --- functions --- */
+
+/*
+ * shl_load() does not appear to support making symbols invisible to
+ * the global namespace.  However, the default is to put the library
+ * last in the search order, which is approximately what we want,
+ * since it will cause symbols that conflict with existing symbols to
+ * be invisible.  It is unclear if BIND_FIRST should be used when
+ * bind_local==0, since it may cause the loaded symbols to be used
+ * preferentially to the application's symbols, which is Almost
+ * Always Wrong.  --ds
+ */
+static gpointer
+_g_module_open (const gchar *file_name,
+		gboolean     bind_lazy,
+		gboolean     bind_local)
+{
+  shl_t shl_handle;
+  
+  shl_handle = shl_load (file_name,
+			 (bind_lazy ? BIND_DEFERRED : BIND_IMMEDIATE) | OPT_BIND_FLAGS, 0);
+  if (!shl_handle)
+    {
+      /* the hp-docs say we should better abort() if errno==ENOSYM ;( */
+      g_module_set_error (g_strerror (errno));
+    }
+  
+  return (gpointer) shl_handle;
+}
+
+static gpointer
+_g_module_self (void)
+{
+  shl_t shl_handle;
+  
+  shl_handle = PROG_HANDLE;
+  if (!shl_handle)
+    g_module_set_error (g_strerror (errno));
+  
+  return shl_handle;
+}
+
+static void
+_g_module_close (gpointer handle,
+		 gboolean is_unref)
+{
+  if (!is_unref)
+    {
+      if (shl_unload ((shl_t) handle) != 0)
+	g_module_set_error (g_strerror (errno));
+    }
+}
+
+static gpointer
+_g_module_symbol (gpointer     handle,
+		  const gchar *symbol_name)
+{
+  gpointer p = NULL;
+  
+  /* should we restrict lookups to TYPE_PROCEDURE?
+   */
+  if (handle == PROG_HANDLE)
+    {
+      /* PROG_HANDLE will only lookup symbols in the program itself, not honouring
+       * libraries. passing NULL as a handle will also try to lookup the symbol
+       * in currently loaded libraries. fix pointed out and supplied by:
+       * David Gero <dgero nortelnetworks com>
+       */
+      handle = NULL;
+    }
+  if (shl_findsym ((shl_t*) &handle, symbol_name, TYPE_UNDEFINED, &p) != 0 ||
+      handle == NULL || p == NULL)
+    {
+      /* the hp-docs say we should better abort() if errno==ENOSYM ;( */
+      g_module_set_error (g_strerror (errno));
+    }
+  
+  return p;
+}
+
+static gchar*
+_g_module_build_path (const gchar *directory,
+		      const gchar *module_name)
+{
+  if (directory && *directory)
+    if (strncmp (module_name, "lib", 3) == 0)
+      return g_strconcat (directory, "/", module_name, NULL);
+    else
+      return g_strconcat (directory, "/lib", module_name, ".sl", NULL);
+  else if (strncmp (module_name, "lib", 3) == 0)
+    return g_strdup (module_name);
+  else
+    return g_strconcat ("lib", module_name, ".sl", NULL);
+}
diff --git a/deps/gmodule/gmodule-dyld.c b/deps/gmodule/gmodule-dyld.c
new file mode 100644
index 0000000..1896b43
--- /dev/null
+++ b/deps/gmodule/gmodule-dyld.c
@@ -0,0 +1,154 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998, 2000 Tim Janik
+ *
+ * dyld (Darwin) GMODULE implementation
+ * Copyright (C) 2001 Dan Winship
+ *
+ * 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"
+
+#include <mach-o/dyld.h>
+
+static gpointer self_module = GINT_TO_POINTER (1);
+
+static gpointer
+_g_module_open (const gchar *file_name,
+		gboolean     bind_lazy,
+		gboolean     bind_local)
+{
+  NSObjectFileImage image;
+  NSObjectFileImageReturnCode ret;
+  NSModule module;
+  unsigned long options;
+  char *msg;
+
+  ret = NSCreateObjectFileImageFromFile (file_name, &image);
+  if (ret != NSObjectFileImageSuccess)
+    {
+      switch (ret)
+	{
+	case NSObjectFileImageInappropriateFile:
+	case NSObjectFileImageFormat:
+	  msg = g_strdup_printf ("%s is not a loadable module", file_name);
+	  break;
+
+	case NSObjectFileImageArch:
+	  msg = g_strdup_printf ("%s is not built for this architecture",
+				 file_name);
+	  break;
+
+	case NSObjectFileImageAccess:
+	  if (access (file_name, F_OK) == 0)
+	    msg = g_strdup_printf ("%s: permission denied", file_name);
+	  else
+	    msg = g_strdup_printf ("%s: no such file or directory", file_name);
+	  break;
+
+	default:
+	  msg = g_strdup_printf ("unknown error for %s", file_name);
+	  break;
+	}
+
+      g_module_set_error (msg);
+      g_free (msg);
+      return NULL;
+    }
+
+  options = NSLINKMODULE_OPTION_RETURN_ON_ERROR;
+  if (bind_local)
+    options |= NSLINKMODULE_OPTION_PRIVATE;
+  if (!bind_lazy)
+    options |= NSLINKMODULE_OPTION_BINDNOW;
+  module = NSLinkModule (image, file_name, options);
+  NSDestroyObjectFileImage (image);
+  if (!module)
+    {
+      NSLinkEditErrors c;
+      int error_number;
+      const char *file, *error;
+
+      NSLinkEditError (&c, &error_number, &file, &error);
+      msg = g_strdup_printf ("could not link %s: %s", file_name, error);
+      g_module_set_error (msg);
+      g_free (msg);
+      return NULL;
+    }
+
+  return module;
+}
+
+static gpointer
+_g_module_self (void)
+{
+  return &self_module;
+}
+
+static void
+_g_module_close (gpointer handle,
+		 gboolean is_unref)
+{
+  if (handle == &self_module)
+    return;
+
+  if (!NSUnLinkModule (handle, 0))
+    g_module_set_error ("could not unlink module");
+}
+
+static gpointer
+_g_module_symbol (gpointer     handle,
+		  const gchar *symbol_name)
+{
+  NSSymbol sym;
+  char *msg;
+
+  if (handle == &self_module)
+    {
+      if (NSIsSymbolNameDefined (symbol_name))
+	sym = NSLookupAndBindSymbol (symbol_name);
+      else
+	sym = NULL;
+    }
+  else
+    sym = NSLookupSymbolInModule (handle, symbol_name);
+
+  if (!sym)
+    {
+      msg = g_strdup_printf ("no such symbol %s", symbol_name);
+      g_module_set_error (msg);
+      g_free (msg);
+      return NULL;
+    }
+
+  return NSAddressOfSymbol (sym);
+}
+
+static gchar*
+_g_module_build_path (const gchar *directory,
+		      const gchar *module_name)
+{
+  if (directory && *directory)
+    {
+      if (strncmp (module_name, "lib", 3) == 0)
+	return g_strconcat (directory, "/", module_name, NULL);
+      else
+	return g_strconcat (directory, "/lib", module_name, "." G_MODULE_SUFFIX, NULL);
+    }
+  else if (strncmp (module_name, "lib", 3) == 0)
+    return g_strdup (module_name);
+  else
+    return g_strconcat ("lib", module_name, "." G_MODULE_SUFFIX, NULL);
+}
diff --git a/deps/gmodule/gmodule-win32.c b/deps/gmodule/gmodule-win32.c
new file mode 100644
index 0000000..439fb5d
--- /dev/null
+++ b/deps/gmodule/gmodule-win32.c
@@ -0,0 +1,202 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998, 2000 Tim Janik
+ *
+ * Win32 GMODULE implementation
+ * Copyright (C) 1998 Tor Lillqvist
+ *
+ * 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 <stdio.h>
+#include <windows.h>
+
+#include <tlhelp32.h>
+
+#ifdef G_WITH_CYGWIN
+#include <sys/cygwin.h>
+#endif
+
+static void
+set_error (const gchar *format,
+	   ...)
+{
+  gchar *error;
+  gchar *detail;
+  gchar *message;
+  va_list args;
+
+  error = g_win32_error_message (GetLastError ());
+
+  va_start (args, format);
+  detail = g_strdup_vprintf (format, args);
+  va_end (args);
+
+  message = g_strconcat (detail, error, NULL);
+
+  g_module_set_error (message);
+  g_free (message);
+  g_free (detail);
+  g_free (error);
+}
+
+/* --- functions --- */
+static gpointer
+_g_module_open (const gchar *file_name,
+		gboolean     bind_lazy,
+		gboolean     bind_local)
+{
+  HINSTANCE handle;
+  wchar_t *wfilename;
+#ifdef G_WITH_CYGWIN
+  gchar tmp[MAX_PATH];
+
+  cygwin_conv_to_win32_path(file_name, tmp);
+  file_name = tmp;
+#endif
+  wfilename = g_utf8_to_utf16 (file_name, -1, NULL, NULL, NULL);
+
+  handle = LoadLibraryW (wfilename);
+  g_free (wfilename);
+      
+  if (!handle)
+    set_error ("`%s': ", file_name);
+
+  return handle;
+}
+
+static gint dummy;
+static gpointer null_module_handle = &dummy;
+  
+static gpointer
+_g_module_self (void)
+{
+  return null_module_handle;
+}
+
+static void
+_g_module_close (gpointer handle,
+		 gboolean is_unref)
+{
+  if (handle != null_module_handle)
+    if (!FreeLibrary (handle))
+      set_error ("");
+}
+
+static gpointer
+find_in_any_module_using_toolhelp (const gchar *symbol_name)
+{
+  HANDLE snapshot; 
+  MODULEENTRY32 me32;
+
+  gpointer p;
+
+  if ((snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0)) == (HANDLE) -1)
+    return NULL;
+
+  me32.dwSize = sizeof (me32);
+  p = NULL;
+  if (Module32First (snapshot, &me32))
+    {
+      do {
+	if ((p = GetProcAddress (me32.hModule, symbol_name)) != NULL)
+	  break;
+      } while (Module32Next (snapshot, &me32));
+    }
+
+  CloseHandle (snapshot);
+
+  return p;
+}
+
+static gpointer
+find_in_any_module (const gchar *symbol_name)
+{
+  gpointer result;
+
+  if ((result = find_in_any_module_using_toolhelp (symbol_name)) == NULL)
+    return NULL;
+  else
+    return result;
+}
+
+static gpointer
+_g_module_symbol (gpointer     handle,
+		  const gchar *symbol_name)
+{
+  gpointer p;
+  
+  if (handle == null_module_handle)
+    {
+      if ((p = GetProcAddress (GetModuleHandle (NULL), symbol_name)) == NULL)
+	p = find_in_any_module (symbol_name);
+    }
+  else
+    p = GetProcAddress (handle, symbol_name);
+
+  if (!p)
+    set_error ("");
+
+  return p;
+}
+
+static gchar*
+_g_module_build_path (const gchar *directory,
+		      const gchar *module_name)
+{
+  gint k;
+
+  k = strlen (module_name);
+    
+  if (directory && *directory)
+    if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
+      return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, NULL);
+#ifdef G_WITH_CYGWIN
+    else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
+      return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
+    else
+      return g_strconcat (directory, G_DIR_SEPARATOR_S, "cyg", module_name, ".dll", NULL);
+#else
+    else if (strncmp (module_name, "lib", 3) == 0)
+      return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
+    else
+      return g_strconcat (directory, G_DIR_SEPARATOR_S, "lib", module_name, ".dll", NULL);
+#endif
+  else if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
+    return g_strdup (module_name);
+#ifdef G_WITH_CYGWIN
+  else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
+    return g_strconcat (module_name, ".dll", NULL);
+  else
+    return g_strconcat ("cyg", module_name, ".dll", NULL);
+#else
+  else if (strncmp (module_name, "lib", 3) == 0)
+    return g_strconcat (module_name, ".dll", NULL);
+  else
+    return g_strconcat ("lib", module_name, ".dll", NULL);
+#endif
+}
diff --git a/deps/gmodule/gmodule.c b/deps/gmodule/gmodule.c
new file mode 100644
index 0000000..985e7ad
--- /dev/null
+++ b/deps/gmodule/gmodule.c
@@ -0,0 +1,685 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998 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.
+ */
+
+/*
+ * 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 "gmodule.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef G_OS_WIN32
+#include <io.h>		/* For open() and close() prototypes. */
+#endif
+
+#include "gmoduleconf.h"
+#include "gstdio.h"
+
+/* We maintain a list of modules, so we can reference count them.
+ * That's needed because some platforms don't support references counts on
+ * modules e.g. the shl_* implementation of HP-UX
+ * (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html).
+ * Also, the module for the program itself is kept seperatedly for
+ * faster access and because it has special semantics.
+ */
+
+
+/* --- structures --- */
+struct _GModule
+{
+  gchar	*file_name;
+#if defined (G_OS_WIN32) && !defined(_WIN64)
+  gchar *cp_file_name;
+#endif
+  gpointer handle;
+  guint ref_count : 31;
+  guint is_resident : 1;
+  GModuleUnload unload;
+  GModule *next;
+};
+
+
+/* --- prototypes --- */
+static gpointer		_g_module_open		(const gchar	*file_name,
+						 gboolean	 bind_lazy,
+						 gboolean	 bind_local);
+static void		_g_module_close		(gpointer	 handle,
+						 gboolean	 is_unref);
+static gpointer		_g_module_self		(void);
+static gpointer		_g_module_symbol	(gpointer	 handle,
+						 const gchar	*symbol_name);
+static gchar*		_g_module_build_path	(const gchar	*directory,
+						 const gchar	*module_name);
+static inline void	g_module_set_error	(const gchar	*error);
+static inline GModule*	g_module_find_by_handle (gpointer	 handle);
+static inline GModule*	g_module_find_by_name	(const gchar	*name);
+
+
+/* --- variables --- */
+static GModule	     *modules = NULL;
+static GModule	     *main_module = NULL;
+static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;
+static gboolean	      module_debug_initialized = FALSE;
+static guint	      module_debug_flags = 0;
+
+
+/* --- inline functions --- */
+static inline GModule*
+g_module_find_by_handle (gpointer handle)
+{
+  GModule *module;
+  GModule *retval = NULL;
+  
+  if (main_module && main_module->handle == handle)
+    retval = main_module;
+  else
+    for (module = modules; module; module = module->next)
+      if (handle == module->handle)
+	{
+	  retval = module;
+	  break;
+	}
+
+  return retval;
+}
+
+static inline GModule*
+g_module_find_by_name (const gchar *name)
+{
+  GModule *module;
+  GModule *retval = NULL;
+  
+  for (module = modules; module; module = module->next)
+    if (strcmp (name, module->file_name) == 0)
+	{
+	  retval = module;
+	  break;
+	}
+
+  return retval;
+}
+
+static inline void
+g_module_set_error_unduped (gchar *error)
+{
+  g_static_private_set (&module_error_private, error, g_free);
+  errno = 0;
+}
+
+static inline void
+g_module_set_error (const gchar *error)
+{
+  g_module_set_error_unduped (g_strdup (error));
+}
+
+
+/* --- include platform specifc code --- */
+#define	SUPPORT_OR_RETURN(rv)	{ g_module_set_error (NULL); }
+#if	(G_MODULE_IMPL == G_MODULE_IMPL_DL)
+#include "gmodule-dl.c"
+#elif	(G_MODULE_IMPL == G_MODULE_IMPL_DLD)
+#include "gmodule-dld.c"
+#elif	(G_MODULE_IMPL == G_MODULE_IMPL_WIN32)
+#include "gmodule-win32.c"
+#elif	(G_MODULE_IMPL == G_MODULE_IMPL_DYLD)
+#include "gmodule-dyld.c"
+#elif	(G_MODULE_IMPL == G_MODULE_IMPL_AR)
+#include "gmodule-ar.c"
+#else
+#undef	SUPPORT_OR_RETURN
+#define	SUPPORT_OR_RETURN(rv)	{ g_module_set_error ("dynamic modules are " \
+                                              "not supported by this system"); return rv; }
+static gpointer
+_g_module_open (const gchar	*file_name,
+		gboolean	 bind_lazy,
+		gboolean	 bind_local)
+{
+  return NULL;
+}
+static void
+_g_module_close	(gpointer	 handle,
+		 gboolean	 is_unref)
+{
+}
+static gpointer
+_g_module_self (void)
+{
+  return NULL;
+}
+static gpointer
+_g_module_symbol (gpointer	 handle,
+		  const gchar	*symbol_name)
+{
+  return NULL;
+}
+static gchar*
+_g_module_build_path (const gchar *directory,
+		      const gchar *module_name)
+{
+  return NULL;
+}
+#endif	/* no implementation */
+
+/* --- functions --- */
+gboolean
+g_module_supported (void)
+{
+  SUPPORT_OR_RETURN (FALSE);
+  
+  return TRUE;
+}
+
+static gchar*
+parse_libtool_archive (const gchar* libtool_name)
+{
+  const guint TOKEN_DLNAME = G_TOKEN_LAST + 1;
+  const guint TOKEN_INSTALLED = G_TOKEN_LAST + 2;
+  const guint TOKEN_LIBDIR = G_TOKEN_LAST + 3;
+  gchar *lt_dlname = NULL;
+  gboolean lt_installed = TRUE;
+  gchar *lt_libdir = NULL;
+  gchar *name;
+  GTokenType token;
+  GScanner *scanner;
+  
+  int fd = g_open (libtool_name, O_RDONLY, 0);
+  if (fd < 0)
+    {
+      gchar *display_libtool_name = g_filename_display_name (libtool_name);
+      g_module_set_error_unduped (g_strdup_printf ("failed to open libtool archive \"%s\"", display_libtool_name));
+      g_free (display_libtool_name);
+      return NULL;
+    }
+  /* search libtool's dlname specification  */
+  scanner = g_scanner_new (NULL);
+  g_scanner_input_file (scanner, fd);
+  scanner->config->symbol_2_token = TRUE;
+  g_scanner_scope_add_symbol (scanner, 0, "dlname", 
+			      GUINT_TO_POINTER (TOKEN_DLNAME));
+  g_scanner_scope_add_symbol (scanner, 0, "installed", 
+			      GUINT_TO_POINTER (TOKEN_INSTALLED));
+  g_scanner_scope_add_symbol (scanner, 0, "libdir", 
+			      GUINT_TO_POINTER (TOKEN_LIBDIR));
+  while (!g_scanner_eof (scanner))
+    {
+      token = g_scanner_get_next_token (scanner);
+      if (token == TOKEN_DLNAME || token == TOKEN_INSTALLED || 
+	  token == TOKEN_LIBDIR)
+	{
+	  if (g_scanner_get_next_token (scanner) != '=' ||
+	      g_scanner_get_next_token (scanner) != 
+	      (token == TOKEN_INSTALLED ? 
+	       G_TOKEN_IDENTIFIER : G_TOKEN_STRING))
+	    {
+	      gchar *display_libtool_name = g_filename_display_name (libtool_name);
+	      g_module_set_error_unduped (g_strdup_printf ("unable to parse libtool archive \"%s\"", display_libtool_name));
+	      g_free (display_libtool_name);
+
+	      g_free (lt_dlname);
+	      g_free (lt_libdir);
+	      g_scanner_destroy (scanner);
+	      close (fd);
+
+	      return NULL;
+	    }
+	  else
+	    {
+	      if (token == TOKEN_DLNAME)
+		{
+		  g_free (lt_dlname);
+		  lt_dlname = g_strdup (scanner->value.v_string);
+		}
+	      else if (token == TOKEN_INSTALLED)
+		lt_installed = 
+		  strcmp (scanner->value.v_identifier, "yes") == 0;
+	      else /* token == TOKEN_LIBDIR */
+		{
+		  g_free (lt_libdir);
+		  lt_libdir = g_strdup (scanner->value.v_string);
+		}
+	    }
+	}      
+    }
+
+  if (!lt_installed)
+    {
+      gchar *dir = g_path_get_dirname (libtool_name);
+      g_free (lt_libdir);
+      lt_libdir = g_strconcat (dir, G_DIR_SEPARATOR_S ".libs", NULL);
+      g_free (dir);
+    }
+
+  name = g_strconcat (lt_libdir, G_DIR_SEPARATOR_S, lt_dlname, NULL);
+  
+  g_free (lt_dlname);
+  g_free (lt_libdir);
+  g_scanner_destroy (scanner);
+  close (fd);
+
+  return name;
+}
+
+static inline gboolean
+str_check_suffix (const gchar* string,
+		  const gchar* suffix)
+{
+  gsize string_len = strlen (string);    
+  gsize suffix_len = strlen (suffix);    
+
+  return string_len >= suffix_len && 
+    strcmp (string + string_len - suffix_len, suffix) == 0;
+}
+
+enum
+{
+  G_MODULE_DEBUG_RESIDENT_MODULES = 1 << 0,
+  G_MODULE_DEBUG_BIND_NOW_MODULES = 1 << 1
+};
+
+static void
+_g_module_debug_init (void)
+{
+  const GDebugKey keys[] = {
+    { "resident-modules", G_MODULE_DEBUG_RESIDENT_MODULES },
+    { "bind-now-modules", G_MODULE_DEBUG_BIND_NOW_MODULES }
+  };
+  const gchar *env;
+
+  env = g_getenv ("G_DEBUG");
+
+  module_debug_flags =
+    !env ? 0 : g_parse_debug_string (env, keys, G_N_ELEMENTS (keys));
+
+  module_debug_initialized = TRUE;
+}
+
+static GStaticRecMutex g_module_global_lock = G_STATIC_REC_MUTEX_INIT;
+
+GModule*
+g_module_open (const gchar    *file_name,
+	       GModuleFlags    flags)
+{
+  GModule *module;
+  gpointer handle = NULL;
+  gchar *name = NULL;
+  
+  SUPPORT_OR_RETURN (NULL);
+  
+  g_static_rec_mutex_lock (&g_module_global_lock);
+
+  if (G_UNLIKELY (!module_debug_initialized))
+    _g_module_debug_init ();
+
+  if (module_debug_flags & G_MODULE_DEBUG_BIND_NOW_MODULES)
+    flags &= ~G_MODULE_BIND_LAZY;
+
+  if (!file_name)
+    {      
+      if (!main_module)
+	{
+	  handle = _g_module_self ();
+	  if (handle)
+	    {
+	      main_module = g_new (GModule, 1);
+	      main_module->file_name = NULL;
+#if defined (G_OS_WIN32) && !defined(_WIN64)
+	      main_module->cp_file_name = NULL;
+#endif
+	      main_module->handle = handle;
+	      main_module->ref_count = 1;
+	      main_module->is_resident = TRUE;
+	      main_module->unload = NULL;
+	      main_module->next = NULL;
+	    }
+	}
+      else
+	main_module->ref_count++;
+
+      g_static_rec_mutex_unlock (&g_module_global_lock);
+      return main_module;
+    }
+  
+  /* we first search the module list by name */
+  module = g_module_find_by_name (file_name);
+  if (module)
+    {
+      module->ref_count++;
+      
+      g_static_rec_mutex_unlock (&g_module_global_lock);
+      return module;
+    }
+
+  /* check whether we have a readable file right away */
+  if (g_file_test (file_name, G_FILE_TEST_IS_REGULAR))
+    name = g_strdup (file_name);
+  /* try completing file name with standard library suffix */
+  if (!name)
+    {
+      name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL);
+      if (!g_file_test (name, G_FILE_TEST_IS_REGULAR))
+	{
+	  g_free (name);
+	  name = NULL;
+	}
+    }
+  /* try completing by appending libtool suffix */
+  if (!name)
+    {
+      name = g_strconcat (file_name, ".la", NULL);
+      if (!g_file_test (name, G_FILE_TEST_IS_REGULAR))
+	{
+	  g_free (name);
+	  name = NULL;
+	}
+    }
+  /* we can't access() the file, lets hope the platform backends finds
+   * it via library paths
+   */
+  if (!name)
+    {
+      gchar *dot = strrchr (file_name, '.');
+      gchar *slash = strrchr (file_name, G_DIR_SEPARATOR);
+      
+      /* make sure the name has a suffix */
+      if (!dot || dot < slash)
+	name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL);
+      else
+	name = g_strdup (file_name);
+    }
+
+  /* ok, try loading the module */
+  if (name)
+    {
+      /* if it's a libtool archive, figure library file to load */
+      if (str_check_suffix (name, ".la")) /* libtool archive? */
+	{
+	  gchar *real_name = parse_libtool_archive (name);
+
+	  /* real_name might be NULL, but then module error is already set */
+	  if (real_name)
+	    {
+	      g_free (name);
+	      name = real_name;
+            }
+	}
+      if (name)
+	handle = _g_module_open (name, (flags & G_MODULE_BIND_LAZY) != 0,
+			(flags & G_MODULE_BIND_LOCAL) != 0);
+    }
+  else
+    {
+      gchar *display_file_name = g_filename_display_name (file_name);
+      g_module_set_error_unduped (g_strdup_printf ("unable to access file \"%s\"", display_file_name));
+      g_free (display_file_name);
+    }
+  g_free (name);
+
+  if (handle)
+    {
+      gchar *saved_error;
+      GModuleCheckInit check_init;
+      const gchar *check_failed = NULL;
+      
+      /* search the module list by handle, since file names are not unique */
+      module = g_module_find_by_handle (handle);
+      if (module)
+	{
+	  _g_module_close (module->handle, TRUE);
+	  module->ref_count++;
+	  g_module_set_error (NULL);
+	  
+	  g_static_rec_mutex_unlock (&g_module_global_lock);
+	  return module;
+	}
+      
+      saved_error = g_strdup (g_module_error ());
+      g_module_set_error (NULL);
+      
+      module = g_new (GModule, 1);
+      module->file_name = g_strdup (file_name);
+#if defined (G_OS_WIN32) && !defined(_WIN64)
+      module->cp_file_name = g_locale_from_utf8 (file_name, -1,
+						 NULL, NULL, NULL);
+#endif
+      module->handle = handle;
+      module->ref_count = 1;
+      module->is_resident = FALSE;
+      module->unload = NULL;
+      module->next = modules;
+      modules = module;
+      
+      /* check initialization */
+      if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init) && check_init != NULL)
+	check_failed = check_init (module);
+      
+      /* we don't call unload() if the initialization check failed. */
+      if (!check_failed)
+	g_module_symbol (module, "g_module_unload", (gpointer) &module->unload);
+      
+      if (check_failed)
+	{
+	  gchar *error;
+
+	  error = g_strconcat ("GModule (", file_name, ") ",
+                               "initialization check failed: ",
+                               check_failed, NULL);
+	  g_module_close (module);
+	  module = NULL;
+	  g_module_set_error (error);
+	  g_free (error);
+	}
+      else
+	g_module_set_error (saved_error);
+
+      g_free (saved_error);
+    }
+
+  if (module != NULL &&
+      (module_debug_flags & G_MODULE_DEBUG_RESIDENT_MODULES))
+    g_module_make_resident (module);
+
+  g_static_rec_mutex_unlock (&g_module_global_lock);
+  return module;
+}
+
+#if defined (G_OS_WIN32) && !defined(_WIN64)
+
+#undef g_module_open
+
+GModule*
+g_module_open (const gchar    *file_name,
+	       GModuleFlags    flags)
+{
+  gchar *utf8_file_name = g_locale_to_utf8 (file_name, -1, NULL, NULL, NULL);
+  GModule *retval = g_module_open_utf8 (utf8_file_name, flags);
+
+  g_free (utf8_file_name);
+
+  return retval;
+}
+
+#endif
+
+gboolean
+g_module_close (GModule	       *module)
+{
+  SUPPORT_OR_RETURN (FALSE);
+  
+  g_return_val_if_fail (module != NULL, FALSE);
+  g_return_val_if_fail (module->ref_count > 0, FALSE);
+  
+  g_static_rec_mutex_lock (&g_module_global_lock);
+
+  module->ref_count--;
+  
+  if (!module->ref_count && !module->is_resident && module->unload)
+    {
+      GModuleUnload unload;
+
+      unload = module->unload;
+      module->unload = NULL;
+      unload (module);
+    }
+
+  if (!module->ref_count && !module->is_resident)
+    {
+      GModule *last;
+      GModule *node;
+      
+      last = NULL;
+      
+      node = modules;
+      while (node)
+	{
+	  if (node == module)
+	    {
+	      if (last)
+		last->next = node->next;
+	      else
+		modules = node->next;
+	      break;
+	    }
+	  last = node;
+	  node = last->next;
+	}
+      module->next = NULL;
+      
+      _g_module_close (module->handle, FALSE);
+      g_free (module->file_name);
+#if defined (G_OS_WIN32) && !defined(_WIN64)
+      g_free (module->cp_file_name);
+#endif
+      g_free (module);
+    }
+  
+  g_static_rec_mutex_unlock (&g_module_global_lock);
+  return g_module_error() == NULL;
+}
+
+void
+g_module_make_resident (GModule *module)
+{
+  g_return_if_fail (module != NULL);
+
+  module->is_resident = TRUE;
+}
+
+const gchar *
+g_module_error (void)
+{
+  return g_static_private_get (&module_error_private);
+}
+
+gboolean
+g_module_symbol (GModule	*module,
+		 const gchar	*symbol_name,
+		 gpointer	*symbol)
+{
+  const gchar *module_error;
+
+  if (symbol)
+    *symbol = NULL;
+  SUPPORT_OR_RETURN (FALSE);
+  
+  g_return_val_if_fail (module != NULL, FALSE);
+  g_return_val_if_fail (symbol_name != NULL, FALSE);
+  g_return_val_if_fail (symbol != NULL, FALSE);
+  
+  g_static_rec_mutex_lock (&g_module_global_lock);
+
+#ifdef	G_MODULE_NEED_USCORE
+  {
+    gchar *name;
+
+    name = g_strconcat ("_", symbol_name, NULL);
+    *symbol = _g_module_symbol (module->handle, name);
+    g_free (name);
+  }
+#else	/* !G_MODULE_NEED_USCORE */
+  *symbol = _g_module_symbol (module->handle, symbol_name);
+#endif	/* !G_MODULE_NEED_USCORE */
+  
+  module_error = g_module_error ();
+  if (module_error)
+    {
+      gchar *error;
+
+      error = g_strconcat ("`", symbol_name, "': ", module_error, NULL);
+      g_module_set_error (error);
+      g_free (error);
+      *symbol = NULL;
+    }
+  
+  g_static_rec_mutex_unlock (&g_module_global_lock);
+  return !module_error;
+}
+
+const gchar *
+g_module_name (GModule *module)
+{
+  g_return_val_if_fail (module != NULL, NULL);
+  
+  if (module == main_module)
+    return "main";
+  
+  return module->file_name;
+}
+
+#if defined (G_OS_WIN32) && !defined(_WIN64)
+
+#undef g_module_name
+
+const gchar *
+g_module_name (GModule *module)
+{
+  g_return_val_if_fail (module != NULL, NULL);
+  
+  if (module == main_module)
+    return "main";
+  
+  return module->cp_file_name;
+}
+
+#endif
+
+gchar*
+g_module_build_path (const gchar *directory,
+		     const gchar *module_name)
+{
+  g_return_val_if_fail (module_name != NULL, NULL);
+  
+  return _g_module_build_path (directory, module_name);
+}
diff --git a/deps/gmodule/gmodule.h b/deps/gmodule/gmodule.h
new file mode 100644
index 0000000..ead452a
--- /dev/null
+++ b/deps/gmodule/gmodule.h
@@ -0,0 +1,101 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998 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.
+ */
+
+/*
+ * 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/. 
+ */
+
+#ifndef __GMODULE_H__
+#define __GMODULE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* exporting and importing functions, this is special cased
+ * to feature Windows dll stubs.
+ */
+#define	G_MODULE_IMPORT		extern
+#ifdef G_PLATFORM_WIN32
+#  define	G_MODULE_EXPORT		__declspec(dllexport)
+#else /* !G_PLATFORM_WIN32 */
+#  define	G_MODULE_EXPORT
+#endif /* !G_PLATFORM_WIN32 */
+
+typedef enum
+{
+  G_MODULE_BIND_LAZY	= 1 << 0,
+  G_MODULE_BIND_LOCAL	= 1 << 1,
+  G_MODULE_BIND_MASK	= 0x03
+} GModuleFlags;
+
+typedef	struct _GModule			 GModule;
+typedef const gchar* (*GModuleCheckInit) (GModule	*module);
+typedef void	     (*GModuleUnload)	 (GModule	*module);
+
+#ifdef G_OS_WIN32
+#define g_module_open g_module_open_utf8
+#define g_module_name g_module_name_utf8
+#endif
+
+/* return TRUE if dynamic module loading is supported */
+gboolean	g_module_supported	   (void) G_GNUC_CONST;
+
+/* open a module `file_name' and return handle, which is NULL on error */
+GModule*              g_module_open          (const gchar  *file_name,
+					      GModuleFlags  flags);
+
+/* close a previously opened module, returns TRUE on success */
+gboolean              g_module_close         (GModule      *module);
+
+/* make a module resident so g_module_close on it will be ignored */
+void                  g_module_make_resident (GModule      *module);
+
+/* query the last module error as a string */
+const gchar *         g_module_error         (void);
+
+/* retrieve a symbol pointer from `module', returns TRUE on success */
+gboolean              g_module_symbol        (GModule      *module,
+					      const gchar  *symbol_name,
+					      gpointer     *symbol);
+
+/* retrieve the file name from an existing module */
+const gchar *         g_module_name          (GModule      *module);
+
+/* Build the actual file name containing a module. `directory' is the
+ * directory where the module file is supposed to be, or NULL or empty
+ * in which case it should either be in the current directory or, on
+ * some operating systems, in some standard place, for instance on the
+ * PATH. Hence, to be absoultely sure to get the correct module,
+ * always pass in a directory. The file name consists of the directory,
+ * if supplied, and `module_name' suitably decorated according to
+ * the operating system's conventions (for instance lib*.so or *.dll).
+ *
+ * No checks are made that the file exists, or is of correct type.
+ */
+gchar*                g_module_build_path    (const gchar  *directory,
+					      const gchar  *module_name);
+
+
+G_END_DECLS
+
+#endif /* __GMODULE_H__ */
diff --git a/deps/gmodule/gmoduleconf.h.in b/deps/gmodule/gmoduleconf.h.in
new file mode 100644
index 0000000..168cf23
--- /dev/null
+++ b/deps/gmodule/gmoduleconf.h.in
@@ -0,0 +1,54 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998 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.
+ */
+#ifndef __G_MODULE_CONF_H__
+#define __G_MODULE_CONF_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define	G_MODULE_IMPL_NONE	0
+#define	G_MODULE_IMPL_DL	1
+#define	G_MODULE_IMPL_DLD	2
+#define	G_MODULE_IMPL_WIN32	3
+#define	G_MODULE_IMPL_OS2	4
+#define	G_MODULE_IMPL_BEOS	5
+#define	G_MODULE_IMPL_DYLD	6
+#define	G_MODULE_IMPL_AR	7
+
+#define	G_MODULE_IMPL		@G_MODULE_IMPL@
+#undef	G_MODULE_HAVE_DLERROR
+#if	(@G_MODULE_HAVE_DLERROR@)
+#define	G_MODULE_HAVE_DLERROR
+#endif
+#if	(@G_MODULE_NEED_USCORE@) || defined (hp9000s300) || defined (__hp9000s300) || defined (__hp9000s300__)
+#define	G_MODULE_NEED_USCORE
+#endif
+#if	(@G_MODULE_BROKEN_RTLD_GLOBAL@)
+#define G_MODULE_BROKEN_RTLD_GLOBAL
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __G_MODULE_CONF_H__ */
diff --git a/deps/gmodule/gmoduleconf.h.win32 b/deps/gmodule/gmoduleconf.h.win32
new file mode 100644
index 0000000..18bee9b
--- /dev/null
+++ b/deps/gmodule/gmoduleconf.h.win32
@@ -0,0 +1,44 @@
+/* GMODULE - GLIB wrapper code for dynamic module loading
+ * Copyright (C) 1998 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.
+ */
+#ifndef __G_MODULE_CONF_H__
+#define __G_MODULE_CONF_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define	G_MODULE_IMPL_NONE	0
+#define	G_MODULE_IMPL_DL	1
+#define	G_MODULE_IMPL_DLD	2
+#define	G_MODULE_IMPL_WIN32	3
+#define	G_MODULE_IMPL_OS2	4
+#define	G_MODULE_IMPL_BEOS	5
+#define	G_MODULE_IMPL_DYLD	6
+
+#define	G_MODULE_IMPL		G_MODULE_IMPL_WIN32
+#undef	G_MODULE_HAVE_DLERROR
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __G_MODULE_CONF_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]