[cogl/wip/standalone: 13/13] [WIP] build: Allow cogl to build without any dependency
- From: Damien Lespiau <dlespiau src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cogl/wip/standalone: 13/13] [WIP] build: Allow cogl to build without any dependency
- Date: Mon, 27 Feb 2012 17:46:44 +0000 (UTC)
commit 189553a7f429d0835c6040332fb7705460f6120b
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-fixed.c | 6 +
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-object.c | 2 +
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 | 9 +-
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 | 91 +-
deps/glib/README | 4 +
deps/glib/galloca.h | 110 +
deps/glib/garray.c | 1624 ++++++++++++++
deps/glib/garray.h | 181 ++
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/gi18n-lib.h | 31 +
deps/glib/glib.h | 22 +
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 +
110 files changed, 29575 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 d5e7f3e..ee4c290 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 9207064..64e79f4 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 5049522..4cba4c7 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 170c1f7..082246a 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);
cogl_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", &contents, NULL, &err);
+ * g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
+ * if (err != NULL)
+ * {
+ * /* Report error to user, and free error */
+ * g_assert (contents == NULL);
+ * fprintf (stderr, "Unable to read file: %s\n", err->message);
+ * g_error_free (err);
+ * }
+ * else
+ * {
+ * /* Use file contents */
+ * 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", &contents, NULL, NULL)) /* ignore errors */
+ * /* no error occurred */ ;
+ * else
+ * /* error */ ;
+ * ]|
+ *
+ * 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->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->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 < 0)
+ * {
+ * g_set_error (error,
+ * FOO_ERROR, /* error domain */
+ * FOO_ERROR_BLAH, /* error code */
+ * "Failed to open file: %s", /* error message format string */
+ * 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))
+ * {
+ * /* assert that error was set by the sub-function */
+ * g_assert (err == NULL || *err != NULL);
+ * return FALSE;
+ * }
+ *
+ * /* otherwise continue, no error occurred */
+ * 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 (&tmp_error);
+ *
+ * if (tmp_error != NULL)
+ * {
+ * /* store tmp_error in err, if err != NULL,
+ * * otherwise call g_error_free() on tmp_error
+ * */
+ * g_propagate_error (err, tmp_error);
+ * return FALSE;
+ * }
+ *
+ * /* otherwise continue, no error occurred */
+ * }
+ * ]|
+ *
+ * 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 (&tmp_error);
+ * other_function_that_can_fail (&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); /* ignore errors */
+ *
+ * tmp_error = NULL;
+ * other_function_that_can_fail (&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><NAMESPACE>_<MODULE>_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><namespace>_<module>_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><Namespace><Module>Error</literal>;
+ * for example,#GThreadError or #GSpawnError.
+ * </para></listitem>
+ * <listitem><para>
+ * Members of the error code enumeration are called
+ * <literal><NAMESPACE>_<MODULE>_ERROR_<CODE></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><NAMESPACE>_<MODULE>_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-fixed.c b/cogl/cogl-fixed.c
index 7a00cb6..1cda9bc 100644
--- a/cogl/cogl-fixed.c
+++ b/cogl/cogl-fixed.c
@@ -27,8 +27,12 @@
#include "config.h"
#endif
+#include "cogl-defines.h"
+
+#ifdef COGL_HAS_GLIB_SUPPORT
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
+#endif
#include "cogl-fixed.h"
@@ -952,6 +956,7 @@ cogl_fixed_cos (CoglFixed angle)
return cogl_fixed_sin (a);
}
+#ifdef COGL_HAS_GLIB_SUPPORT
/* GType */
static GTypeInfo _info = {
@@ -1095,3 +1100,4 @@ cogl_fixed_get_type (void)
return _cogl_fixed_type;
}
+#endif /* COGL_HAS_GLIB_SUPPORT */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 6b00df7..744dff3 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-object.c b/cogl/cogl-object.c
index 9ae29f7..c442431 100644
--- a/cogl/cogl-object.c
+++ b/cogl/cogl-object.c
@@ -110,6 +110,7 @@ cogl_handle_unref (CoglHandle handle)
cogl_object_unref (handle);
}
+#ifdef COGL_HAS_GLIB_SUPPORT
GType
cogl_handle_get_type (void)
{
@@ -124,6 +125,7 @@ cogl_handle_get_type (void)
return our_type;
}
+#endif
/* XXX: Unlike for cogl_object_get_user_data this code will return
* an empty entry if available and no entry for the given key can be
diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c
index e439d31..e92dd1b 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 5fed142..bd5a53c 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 1c6a28b..ff6b131 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;
@@ -277,7 +277,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");
@@ -292,7 +292,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);
@@ -307,7 +307,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;
@@ -325,7 +325,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;
@@ -365,7 +365,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
{
@@ -378,7 +378,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 6332327..7ca39e7 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 ece1a42..dbeee23 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 014372e..008ab8e 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 79f5070..42944ea 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 3cefcd5..6c9af88 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 4d55d5e..4800978 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <glib/gi18n-lib.h>
+#include "cogl-defines.h"
#include "cogl-debug.h"
#include "cogl-internal.h"
#include "cogl-util.h"
@@ -982,12 +983,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)
{
@@ -1000,7 +995,9 @@ _cogl_init (void)
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
+#ifdef COGL_HAS_GLIB_SUPPORT
g_type_init ();
+#endif
_cogl_config_read ();
_cogl_debug_check_environment ();
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 60e47ff..e38bf29 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 1f42fe5..1c736b9 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;
@@ -184,7 +184,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);
@@ -194,7 +194,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;
@@ -216,7 +216,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;
@@ -258,7 +258,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;
@@ -271,7 +271,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;
@@ -282,7 +282,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;
@@ -359,7 +359,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;
@@ -394,7 +394,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;
@@ -408,7 +408,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;
@@ -431,7 +431,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 6c3ac96..c318cd9 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 c97ea55..22f79b7 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 */
_COGL_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 bd567e7..1689287 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 06f50a2..66367ae 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 ============================================================
@@ -926,25 +922,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 ================================================================
@@ -985,16 +962,44 @@ 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"
+ ],
+ [
+ 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..7e43c5b
--- /dev/null
+++ b/deps/glib/README
@@ -0,0 +1,4 @@
+These are files striped from glib 2.30.2 to build a standalone cogl. A few
+changes were done on those imported files:
+
+- gi18n-lib.h has been changed to have no-effect stubs
diff --git a/deps/glib/galloca.h b/deps/glib/galloca.h
new file mode 100644
index 0000000..8876836
--- /dev/null
+++ b/deps/glib/galloca.h
@@ -0,0 +1,110 @@
+/* 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_ALLOCA_H__
+#define __G_ALLOCA_H__
+
+#include <glib/gtypes.h>
+
+#ifdef __GNUC__
+/* GCC does the right thing */
+# undef alloca
+# define alloca(size) __builtin_alloca (size)
+#elif defined (GLIB_HAVE_ALLOCA_H)
+/* a native and working alloca.h is there */
+# include <alloca.h>
+#else /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */
+# if defined(_MSC_VER) || defined(__DMC__)
+# include <malloc.h>
+# define alloca _alloca
+# else /* !_MSC_VER && !__DMC__ */
+# ifdef _AIX
+# pragma alloca
+# else /* !_AIX */
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+G_BEGIN_DECLS
+char *alloca ();
+G_END_DECLS
+# endif /* !alloca */
+# endif /* !_AIX */
+# endif /* !_MSC_VER && !__DMC__ */
+#endif /* !__GNUC__ && !GLIB_HAVE_ALLOCA_H */
+
+/**
+ * g_alloca:
+ * @size: number of bytes to allocate.
+ *
+ * Allocates @size bytes on the stack; these bytes will be freed when the current
+ * stack frame is cleaned up. This macro essentially just wraps the alloca()
+ * function present on most UNIX variants.
+ * Thus it provides the same advantages and pitfalls as alloca():
+ * <variablelist>
+ * <varlistentry><term></term><listitem><para>
+ * + alloca() is very fast, as on most systems it's implemented by just adjusting
+ * the stack pointer register.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * + It doesn't cause any memory fragmentation, within its scope, separate alloca()
+ * blocks just build up and are released together at function end.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * - Allocation sizes have to fit into the current stack frame. For instance in a
+ * threaded environment on Linux, the per-thread stack size is limited to 2 Megabytes,
+ * so be sparse with alloca() uses.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * - Allocation failure due to insufficient stack space is not indicated with a %NULL
+ * return like e.g. with malloc(). Instead, most systems probably handle it the same
+ * way as out of stack space situations from infinite function recursion, i.e.
+ * with a segmentation fault.
+ * </para></listitem></varlistentry>
+ * <varlistentry><term></term><listitem><para>
+ * - Special care has to be taken when mixing alloca() with GNU C variable sized arrays.
+ * Stack space allocated with alloca() in the same scope as a variable sized array
+ * will be freed together with the variable sized array upon exit of that scope, and
+ * not upon exit of the enclosing function scope.
+ * </para></listitem></varlistentry>
+ * </variablelist>
+ *
+ * Returns: space for @size bytes, allocated on the stack
+ */
+#define g_alloca(size) alloca (size)
+/**
+ * g_newa:
+ * @struct_type: Type of memory chunks to be allocated
+ * @n_structs: Number of chunks to be allocated
+ *
+ * Wraps g_alloca() in a more typesafe manner.
+ *
+ * Returns: Pointer to stack space for @n_structs chunks of type @struct_type
+ */
+#define g_newa(struct_type, n_structs) ((struct_type*) g_alloca (sizeof (struct_type) * (gsize) (n_structs)))
+
+#endif /* __G_ALLOCA_H__ */
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 < 10000; i++)
+ * g_array_append_val (garray, i);
+ * for (i = 0; i < 10000; i++)
+ * if (g_array_index (garray, gint, i) != i)
+ * g_print ("ERROR: got %d instead of %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 = &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 – i.e.
+ * you want a stable sort – 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 %p instead of %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 – i.e.
+ * you want a stable sort – 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 < 10000; i++)
+ * g_byte_array_append (gbarray, (guint8*) "abcd", 4);
+ *
+ * for (i = 0; i < 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 – i.e.
+ * you want a stable sort – 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/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", &contents, NULL, &err);
+ * g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
+ * if (err != NULL)
+ * {
+ * /* Report error to user, and free error */
+ * g_assert (contents == NULL);
+ * fprintf (stderr, "Unable to read file: %s\n", err->message);
+ * g_error_free (err);
+ * }
+ * else
+ * {
+ * /* Use file contents */
+ * 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", &contents, NULL, NULL)) /* ignore errors */
+ * /* no error occurred */ ;
+ * else
+ * /* error */ ;
+ * ]|
+ *
+ * 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->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->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 < 0)
+ * {
+ * g_set_error (error,
+ * FOO_ERROR, /* error domain */
+ * FOO_ERROR_BLAH, /* error code */
+ * "Failed to open file: %s", /* error message format string */
+ * 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))
+ * {
+ * /* assert that error was set by the sub-function */
+ * g_assert (err == NULL || *err != NULL);
+ * return FALSE;
+ * }
+ *
+ * /* otherwise continue, no error occurred */
+ * 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 (&tmp_error);
+ *
+ * if (tmp_error != NULL)
+ * {
+ * /* store tmp_error in err, if err != NULL,
+ * * otherwise call g_error_free() on tmp_error
+ * */
+ * g_propagate_error (err, tmp_error);
+ * return FALSE;
+ * }
+ *
+ * /* otherwise continue, no error occurred */
+ * }
+ * ]|
+ *
+ * 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 (&tmp_error);
+ * other_function_that_can_fail (&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); /* ignore errors */
+ *
+ * tmp_error = NULL;
+ * other_function_that_can_fail (&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><NAMESPACE>_<MODULE>_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><namespace>_<module>_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><Namespace><Module>Error</literal>;
+ * for example,#GThreadError or #GSpawnError.
+ * </para></listitem>
+ * <listitem><para>
+ * Members of the error code enumeration are called
+ * <literal><NAMESPACE>_<MODULE>_ERROR_<CODE></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><NAMESPACE>_<MODULE>_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))
+ * {
+ * /* do something with key and value */
+ * }
+ * ]|
+ *
+ * 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/gi18n-lib.h b/deps/glib/gi18n-lib.h
new file mode 100644
index 0000000..1e6b133
--- /dev/null
+++ b/deps/glib/gi18n-lib.h
@@ -0,0 +1,31 @@
+/* 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_I18N_LIB_H__
+#define __G_I18N_LIB_H__
+
+#include <glib.h>
+
+#define _(String) (String)
+#define Q_(String) (String)
+#define N_(String) (String)
+#define C_(Context,String) (String)
+#define NC_(Context, String) (String)
+
+#endif /* __G_I18N_LIB_H__ */
diff --git a/deps/glib/glib.h b/deps/glib/glib.h
new file mode 100644
index 0000000..d3bb66b
--- /dev/null
+++ b/deps/glib/glib.h
@@ -0,0 +1,22 @@
+#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 "galloca.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>
+ *
+ * |[
+ * /* Notice that these are initialized to the empty list. */
+ * GList *list = NULL, *number_list = NULL;
+ *
+ * /* This is a list of strings. */
+ * list = g_list_append (list, "first");
+ * list = g_list_append (list, "second");
+ *
+ * /* This is a list of integers. */
+ * 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>
+ *
+ * |[
+ * /* Notice that it is initialized to the empty list. */
+ * 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 < @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 < @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 < 10000; i++)
+ * {
+ * mem[i] = g_chunk_new (gchar, mem_chunk);
+ * /<!-- -->* Fill in the atom memory with some junk. *<!-- -->/
+ * for (j = 0; j < 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 < 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 (¤t);
+ 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>
+ *
+ * |[
+ * /* Notice that these are initialized to the empty list. */
+ * GSList *list = NULL, *number_list = NULL;
+ *
+ * /* This is a list of strings. */
+ * list = g_slist_append (list, "first");
+ * list = g_slist_append (list, "second");
+ *
+ * /* This is a list of integers. */
+ * 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>
+ *
+ * |[
+ * /* Notice that it is initialized to the empty list. */
+ * 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 (<code>)". 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 (<signum>)". 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 < @s2,
+ * or a positive value if @s1 > @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 < @s2,
+ * or a positive value if @s1 > @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 < @s2,
+ * or a positive value if @s1 > @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 < @s2,
+ * or a positive value if @s1 > @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", &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]