summaryrefslogtreecommitdiffstats
path: root/eglib
diff options
context:
space:
mode:
Diffstat (limited to 'eglib')
-rw-r--r--eglib/Makefile.am8
-rw-r--r--eglib/glib.h1
-rw-r--r--eglib/gmain.c1977
-rw-r--r--eglib/gmain.h404
-rw-r--r--eglib/gmodule.c88
-rw-r--r--eglib/gmodule.h21
6 files changed, 2499 insertions, 0 deletions
diff --git a/eglib/Makefile.am b/eglib/Makefile.am
new file mode 100644
index 00000000..e6166090
--- /dev/null
+++ b/eglib/Makefile.am
@@ -0,0 +1,8 @@
+
+if !GLIB
+noinst_LTLIBRARIES = libeglib.la
+
+libeglib_la_SOURCES = glib.h gmain.h gmain.c gmodule.h gmodule.c
+endif
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/eglib/glib.h b/eglib/glib.h
new file mode 100644
index 00000000..5600a33e
--- /dev/null
+++ b/eglib/glib.h
@@ -0,0 +1 @@
+#include <gmain.h>
diff --git a/eglib/gmain.c b/eglib/gmain.c
new file mode 100644
index 00000000..3475fdbf
--- /dev/null
+++ b/eglib/gmain.c
@@ -0,0 +1,1977 @@
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <gmain.h>
+
+struct timeout {
+ guint id;
+ guint interval;
+ struct timeval expiration;
+ gpointer data;
+ GSourceFunc function;
+};
+
+struct _GIOChannel {
+ int fd;
+ int ref_count;
+ gboolean closed;
+ gboolean close_on_unref;
+};
+
+struct child_watch {
+ guint id;
+ GPid pid;
+ GChildWatchFunc function;
+ gpointer user_data;
+};
+
+struct _GMainContext {
+ guint next_id;
+ glong next_timeout;
+
+ GSList *timeouts;
+ GSList *proc_timeouts;
+ gboolean timeout_lock;
+
+ GSList *io_watches;
+ GSList *proc_io_watches;
+ gboolean io_lock;
+
+ GSList *child_watches;
+ GSList *proc_child_watches;
+ gboolean child_lock;
+};
+
+struct _GMainLoop {
+ gboolean is_running;
+ GMainContext *context;
+};
+
+struct _GDir
+{
+ DIR *dirp;
+};
+
+GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count,
+ gsize *bytes_read)
+{
+ int fd = channel->fd;
+ gssize result;
+
+ if (channel->closed)
+ return G_IO_STATUS_ERROR;
+
+ /* At least according to the Debian manpage for read */
+ if (count > SSIZE_MAX)
+ count = SSIZE_MAX;
+
+retry:
+ result = read (fd, buf, count);
+
+ if (result < 0) {
+ *bytes_read = 0;
+
+ switch (errno) {
+#ifdef EINTR
+ case EINTR:
+ goto retry;
+#endif
+#ifdef EAGAIN
+ case EAGAIN:
+ return G_IO_STATUS_AGAIN;
+#endif
+ default:
+ return G_IO_STATUS_ERROR;
+ }
+ }
+
+ *bytes_read = result;
+
+ return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
+}
+
+GIOError g_io_channel_write(GIOChannel *channel, const gchar *buf, gsize count,
+ gsize *bytes_written)
+{
+ int fd = channel->fd;
+ gssize result;
+
+ if (channel->closed)
+ return G_IO_STATUS_ERROR;
+
+ /* At least according to the Debian manpage for read */
+ if (count > SSIZE_MAX)
+ count = SSIZE_MAX;
+
+retry:
+ result = write(fd, buf, count);
+
+ if (result < 0) {
+ *bytes_written = 0;
+
+ switch (errno) {
+#ifdef EINTR
+ case EINTR:
+ goto retry;
+#endif
+#ifdef EAGAIN
+ case EAGAIN:
+ return G_IO_STATUS_AGAIN;
+#endif
+ default:
+ return G_IO_STATUS_ERROR;
+ }
+ }
+
+ *bytes_written = result;
+
+ return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
+}
+
+void g_io_channel_close(GIOChannel *channel)
+{
+ if (!channel || channel->closed)
+ return;
+
+ close(channel->fd);
+
+ channel->closed = TRUE;
+}
+
+void g_io_channel_unref(GIOChannel *channel)
+{
+ if (!channel)
+ return;
+
+ if (--channel->ref_count > 0)
+ return;
+
+ if (channel->close_on_unref && channel->fd >= 0)
+ g_io_channel_close(channel);
+
+ g_free(channel);
+}
+
+GIOChannel *g_io_channel_ref(GIOChannel *channel)
+{
+ channel->ref_count++;
+ return channel;
+}
+
+GIOChannel *g_io_channel_unix_new(int fd)
+{
+ GIOChannel *channel;
+
+ channel = g_new0(GIOChannel, 1);
+
+ channel->fd = fd;
+ channel->ref_count = 1;
+
+ return channel;
+}
+
+void g_io_channel_set_close_on_unref(GIOChannel *channel, gboolean do_close)
+{
+ channel->close_on_unref = do_close;
+}
+
+gint g_io_channel_unix_get_fd(GIOChannel *channel)
+{
+ if (channel->closed)
+ return -1;
+
+ return channel->fd;
+}
+
+static int set_flags(int fd, long flags)
+{
+ long arg;
+
+ arg = fcntl(fd, F_GETFL);
+ if (arg < 0)
+ return -errno;
+
+ /* Return if already set */
+ if ((arg & flags) == flags)
+ return 0;
+
+ arg |= flags;
+ if (fcntl(fd, F_SETFL, arg) < 0)
+ return -errno;
+
+ return 0;
+}
+
+GIOStatus g_io_channel_set_flags(GIOChannel *channel, GIOFlags flags,
+ GError **error)
+{
+ int err, fd;
+ long fd_flags = 0;
+
+ if (!channel || channel->closed)
+ return G_IO_STATUS_ERROR;
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ if (flags & G_IO_FLAG_APPEND)
+ fd_flags |= O_APPEND;
+ if (flags & G_IO_FLAG_NONBLOCK)
+ fd_flags |= O_NONBLOCK;
+
+ err = set_flags(fd, fd_flags);
+ if (err < 0) {
+ if (error)
+ g_set_error(error, 0, 0, "Unable to set flags: %s",
+ strerror(-err));
+ return G_IO_STATUS_ERROR;
+ }
+
+ return G_IO_STATUS_NORMAL;
+}
+
+struct io_watch {
+ guint id;
+ GIOChannel *channel;
+ gint priority;
+ GIOCondition condition;
+ short *revents;
+ GIOFunc func;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+static GMainContext *default_context = NULL;
+
+static void watch_free(struct io_watch *watch)
+{
+ if (watch->destroy)
+ watch->destroy(watch->user_data);
+ g_io_channel_unref(watch->channel);
+ g_free(watch);
+}
+
+static GMainContext *g_main_context_default()
+{
+ if (default_context)
+ return default_context;
+
+ default_context = g_new0(GMainContext, 1);
+
+ default_context->next_timeout = -1;
+ default_context->next_id = 1;
+
+ return default_context;
+}
+
+static gboolean g_io_remove_watch(GMainContext *context, guint id)
+{
+ GSList *l;
+ struct io_watch *w;
+
+ for (l = context->io_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->io_watches = g_slist_remove(context->io_watches, w);
+ watch_free(w);
+
+ return TRUE;
+ }
+
+ for (l = context->proc_io_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->proc_io_watches = g_slist_remove(context->proc_io_watches, w);
+ watch_free(w);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean g_timeout_remove(GMainContext *context, const guint id)
+{
+ GSList *l;
+ struct timeout *t;
+
+ l = context->timeouts;
+
+ while (l) {
+ t = l->data;
+ l = l->next;
+
+ if (t->id != id)
+ continue;
+
+ context->timeouts = g_slist_remove(context->timeouts, t);
+ g_free(t);
+
+ return TRUE;
+ }
+
+ l = context->proc_timeouts;
+
+ while (l) {
+ t = l->data;
+ l = l->next;
+
+ if (t->id != id)
+ continue;
+
+ context->proc_timeouts = g_slist_remove(context->proc_timeouts, t);
+ g_free(t);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int watch_prio_cmp(struct io_watch *w1, struct io_watch *w2)
+{
+ return w1->priority - w2->priority;
+}
+
+#define watch_list_add(l, w) g_slist_insert_sorted((l), (w), (GCompareFunc) watch_prio_cmp)
+
+guint g_io_add_watch_full(GIOChannel *channel, gint priority,
+ GIOCondition condition, GIOFunc func,
+ gpointer user_data, GDestroyNotify notify)
+{
+ struct io_watch *watch;
+ GMainContext *context = g_main_context_default();
+
+ watch = g_new(struct io_watch, 1);
+
+ watch->id = context->next_id++;
+ watch->channel = g_io_channel_ref(channel);
+ watch->priority = priority;
+ watch->condition = condition;
+ watch->func = func;
+ watch->user_data = user_data;
+ watch->destroy = notify;
+
+ if (context->io_lock)
+ context->proc_io_watches = watch_list_add(context->proc_io_watches, watch);
+ else
+ context->io_watches = watch_list_add(context->io_watches, watch);
+
+ return watch->id;
+}
+
+guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
+ GIOFunc func, gpointer user_data)
+{
+ return g_io_add_watch_full(channel, 0, condition,
+ func, user_data, NULL);
+}
+
+GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)
+{
+ GMainLoop *ml;
+
+ if (!context)
+ context = g_main_context_default();
+
+ ml = g_new0(GMainLoop, 1);
+
+ ml->context = context;
+ ml->is_running = is_running;
+
+ return ml;
+}
+
+static void timeout_handlers_prepare(GMainContext *context)
+{
+ GSList *l;
+ struct timeval tv;
+ glong msec, timeout = LONG_MAX;
+
+ gettimeofday(&tv, NULL);
+
+ for (l = context->timeouts; l != NULL; l = l->next) {
+ struct timeout *t = l->data;
+
+ /* calculate the remainning time */
+ msec = (t->expiration.tv_sec - tv.tv_sec) * 1000 +
+ (t->expiration.tv_usec - tv.tv_usec) / 1000;
+ if (msec < 0)
+ msec = 0;
+
+ timeout = MIN_TIMEOUT(timeout, msec);
+ }
+
+ /* set to min value found or NO timeout */
+ context->next_timeout = (timeout != LONG_MAX ? timeout : -1);
+}
+
+static int ptr_cmp(const void *t1, const void *t2)
+{
+ return t1 - t2;
+}
+
+static void timeout_handlers_check(GMainContext *context)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ context->timeout_lock = TRUE;
+
+ while (context->timeouts) {
+ struct timeout *t = context->timeouts->data;
+ glong secs, msecs;
+ gboolean ret;
+
+ if (timercmp(&tv, &t->expiration, <)) {
+ context->timeouts = g_slist_remove(context->timeouts, t);
+ context->proc_timeouts = g_slist_append(context->proc_timeouts, t);
+ continue;
+ }
+
+ ret = t->function(t->data);
+
+ /* Check if the handler was removed/freed by the callback
+ * function */
+ if (!g_slist_find_custom(context->timeouts, t, ptr_cmp))
+ continue;
+
+ context->timeouts = g_slist_remove(context->timeouts, t);
+
+ if (!ret) {
+ g_free(t);
+ continue;
+ }
+
+ /* update the next expiration time */
+ secs = t->interval / 1000;
+ msecs = t->interval - secs * 1000;
+
+ t->expiration.tv_sec = tv.tv_sec + secs;
+ t->expiration.tv_usec = tv.tv_usec + msecs * 1000;
+ if (t->expiration.tv_usec >= 1000000) {
+ t->expiration.tv_usec -= 1000000;
+ t->expiration.tv_sec++;
+ }
+
+ context->proc_timeouts = g_slist_append(context->proc_timeouts, t);
+ }
+
+ context->timeouts = context->proc_timeouts;
+ context->proc_timeouts = NULL;
+ context->timeout_lock = FALSE;
+}
+
+void g_main_loop_run(GMainLoop *loop)
+{
+ int open_max = sysconf(_SC_OPEN_MAX);
+ struct pollfd *ufds;
+ GMainContext *context = loop->context;
+
+ ufds = g_new(struct pollfd, open_max);
+
+ loop->is_running = TRUE;
+
+ while (loop->is_running) {
+ int nfds;
+ GSList *l;
+ struct io_watch *w;
+
+ for (nfds = 0, l = context->io_watches; l != NULL; l = l->next, nfds++) {
+ w = l->data;
+ ufds[nfds].fd = w->channel->fd;
+ ufds[nfds].events = w->condition;
+ ufds[nfds].revents = 0;
+ w->revents = &ufds[nfds].revents;
+ }
+
+ /* calculate the next timeout */
+ timeout_handlers_prepare(context);
+
+ if (poll(ufds, nfds, context->next_timeout) < 0)
+ continue;
+
+ context->io_lock = TRUE;
+
+ while (context->io_watches) {
+ gboolean ret;
+
+ w = context->io_watches->data;
+
+ if (!*w->revents) {
+ context->io_watches = g_slist_remove(context->io_watches, w);
+ context->proc_io_watches = watch_list_add(context->proc_io_watches, w);
+ continue;
+ }
+
+ ret = w->func(w->channel, *w->revents, w->user_data);
+
+ /* Check if the watch was removed/freed by the callback
+ * function */
+ if (!g_slist_find_custom(context->io_watches, w, ptr_cmp))
+ continue;
+
+ context->io_watches = g_slist_remove(context->io_watches, w);
+
+ if (!ret) {
+ watch_free(w);
+ continue;
+ }
+
+ context->proc_io_watches = watch_list_add(context->proc_io_watches, w);
+ }
+
+ context->io_watches = context->proc_io_watches;
+ context->proc_io_watches = NULL;
+ context->io_lock = FALSE;
+
+ /* check expired timers */
+ timeout_handlers_check(loop->context);
+ }
+
+ g_free(ufds);
+}
+
+void g_main_loop_quit(GMainLoop *loop)
+{
+ loop->is_running = FALSE;
+}
+
+void g_main_loop_unref(GMainLoop *loop)
+{
+ if (!loop->context)
+ return;
+
+ g_slist_foreach(loop->context->io_watches, (GFunc)watch_free, NULL);
+ g_slist_free(loop->context->io_watches);
+
+ g_slist_foreach(loop->context->timeouts, (GFunc)g_free, NULL);
+ g_slist_free(loop->context->timeouts);
+
+ g_free(loop->context);
+ loop->context = NULL;
+}
+
+guint g_timeout_add(guint interval, GSourceFunc function, gpointer data)
+{
+ GMainContext *context = g_main_context_default();
+ struct timeval tv;
+ guint secs;
+ guint msecs;
+ struct timeout *t;
+
+ t = g_new0(struct timeout, 1);
+
+ t->interval = interval;
+ t->function = function;
+ t->data = data;
+
+ gettimeofday(&tv, NULL);
+
+ secs = interval /1000;
+ msecs = interval - secs * 1000;
+
+ t->expiration.tv_sec = tv.tv_sec + secs;
+ t->expiration.tv_usec = tv.tv_usec + msecs * 1000;
+
+ if (t->expiration.tv_usec >= 1000000) {
+ t->expiration.tv_usec -= 1000000;
+ t->expiration.tv_sec++;
+ }
+
+ /* attach the timeout the default context */
+ t->id = context->next_id++;
+
+ if (context->timeout_lock)
+ context->proc_timeouts = g_slist_prepend(context->proc_timeouts, t);
+ else
+ context->timeouts = g_slist_prepend(context->timeouts, t);
+
+ return t->id;
+}
+
+guint g_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data)
+{
+ return g_timeout_add(interval, function, data);
+}
+
+guint g_idle_add(GSourceFunc function, gpointer data)
+{
+ return g_timeout_add(1, function, data);
+}
+
+/* GError */
+
+GError* g_error_new_literal(GQuark domain, gint code, const gchar *message)
+{
+ GError *err;
+
+ err = g_new(GError, 1);
+
+ err->domain = domain;
+ err->code = code;
+ err->message = g_strdup(message);
+
+ return err;
+}
+
+void g_set_error(GError **err, GQuark domain, gint code,
+ const gchar *format, ...)
+{
+ gchar msg[1024];
+ va_list ap;
+
+ if (!err)
+ return;
+
+ va_start(ap, format);
+
+ vsnprintf(msg, sizeof(msg) - 1, format, ap);
+
+ va_end(ap);
+
+ *err = g_error_new_literal(domain, code, msg);
+}
+
+void g_error_free(GError *err)
+{
+ g_free(err->message);
+ g_free(err);
+}
+
+/* Spawning related functions */
+
+static int child_watch_pipe[2] = { -1, -1 };
+
+static void sigchld_handler(int signal)
+{
+ int ret;
+ ret = write(child_watch_pipe[1], "B", 1);
+}
+
+static gboolean child_watch_remove(GMainContext *context, guint id)
+{
+ GSList *l;
+ struct child_watch *w;
+
+ for (l = context->child_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->child_watches =
+ g_slist_remove(context->child_watches, w);
+ g_free(w);
+
+ return TRUE;
+ }
+
+ for (l = context->proc_child_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->proc_child_watches =
+ g_slist_remove(context->proc_child_watches, w);
+ g_free(w);
+
+ return TRUE;
+ }
+
+
+ return FALSE;
+}
+
+static gboolean child_watch(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+ int ret;
+ char b[20];
+ GMainContext *context = g_main_context_default();
+
+ ret = read(child_watch_pipe[0], b, 20);
+
+ context->child_lock = TRUE;
+
+ while (context->child_watches) {
+ gint status;
+ struct child_watch *w = context->child_watches->data;
+
+ if (waitpid(w->pid, &status, WNOHANG) <= 0) {
+ context->child_watches =
+ g_slist_remove(context->child_watches, w);
+ context->proc_child_watches =
+ watch_list_add(context->proc_child_watches, w);
+ continue;
+ }
+
+ w->function(w->pid, status, w->user_data);
+
+ /* Check if the callback already removed us */
+ if (!g_slist_find(context->child_watches, w))
+ continue;
+
+ context->child_watches = g_slist_remove(context->child_watches, w);
+ g_free(w);
+ }
+
+ context->child_watches = context->proc_child_watches;
+ context->proc_child_watches = NULL;
+ context->child_lock = FALSE;
+
+ return TRUE;
+}
+
+static void init_child_pipe(void)
+{
+ struct sigaction action;
+ GIOChannel *io;
+
+ if (pipe(child_watch_pipe) < 0) {
+ fprintf(stderr, "Unable to initialize child watch pipe: %s (%d)\n",
+ strerror(errno), errno);
+ abort();
+ }
+
+ fcntl(child_watch_pipe[1], F_SETFL,
+ O_NONBLOCK | fcntl(child_watch_pipe[1], F_GETFL));
+
+ action.sa_handler = sigchld_handler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &action, NULL);
+
+ io = g_io_channel_unix_new(child_watch_pipe[0]);
+ g_io_add_watch(io, G_IO_IN, child_watch, NULL);
+ g_io_channel_unref(io);
+}
+
+static void exec_child(const gchar *working_directory,
+ gchar **argv, gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data)
+{
+ int null;
+
+ if (working_directory && chdir(working_directory) < 0)
+ _exit(EXIT_FAILURE);
+
+ if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) {
+ int open_max, fd, ret;
+
+ ret = 0;
+ open_max = sysconf(_SC_OPEN_MAX);
+ for (fd = 3; fd < open_max && ret == 0; fd++)
+ ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
+ }
+
+ null = open("/dev/null", O_RDWR);
+ if (!(flags & G_SPAWN_CHILD_INHERITS_STDIN))
+ dup2(null, STDIN_FILENO);
+ if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
+ dup2(null, STDOUT_FILENO);
+ if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
+ dup2(null, STDERR_FILENO);
+ if (null > 2)
+ close(null);
+
+ if (child_setup)
+ child_setup(user_data);
+
+ if (envp)
+ execve(argv[0], argv, envp);
+ else
+ execv(argv[0], argv);
+
+ /* exec failed if we get here */
+ _exit(EXIT_FAILURE);
+}
+
+gboolean g_spawn_async(const gchar *working_directory,
+ gchar **argv, gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ GError **error)
+{
+ GPid pid;
+
+ if (access(argv[0], X_OK) < 0) {
+ g_set_error(error, 0, 0, "%s is not executable", argv[0]);
+ return FALSE;
+ }
+
+ if (child_watch_pipe[0] < 0)
+ init_child_pipe();
+
+ /* Flush output streams so child doesn't get them */
+ fflush(NULL);
+
+ switch (pid = fork()) {
+ case -1:
+ g_set_error(error, 0, 0, "fork failed: %s", strerror(errno));
+ return FALSE;
+ case 0:
+ exec_child(working_directory, argv, envp, flags,
+ child_setup, user_data);
+ break;
+ default:
+ if (child_pid)
+ *child_pid = pid;
+ return TRUE;
+ }
+
+ /* Never reached */
+ return FALSE;
+}
+
+void g_spawn_close_pid(GPid pid)
+{
+ return;
+}
+
+guint g_child_watch_add(GPid pid, GChildWatchFunc func, gpointer user_data)
+{
+ struct child_watch *w;
+ GMainContext *context = g_main_context_default();
+
+ if (child_watch_pipe[0] < 0)
+ init_child_pipe();
+
+ w = g_new(struct child_watch, 1);
+
+ w->id = context->next_id++;
+ w->pid = pid;
+ w->function = func;
+ w->user_data = user_data;
+
+ if (context->child_lock)
+ context->proc_child_watches =
+ watch_list_add(context->proc_child_watches, w);
+ else
+ context->child_watches =
+ watch_list_add(context->child_watches, w);
+
+ return w->id;
+}
+
+gboolean g_source_remove(guint tag)
+{
+ GMainContext *context = g_main_context_default();
+
+ if (g_io_remove_watch(context, tag))
+ return TRUE;
+
+ if (g_timeout_remove(context, tag))
+ return TRUE;
+
+ if (child_watch_remove(context, tag))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* UTF-8 Validation: approximate copy/paste from glib2. */
+
+#define UNICODE_VALID(c) \
+ ((c) < 0x110000 && \
+ (((c) & 0xFFFFF800) != 0xD800) && \
+ ((c) < 0xFDD0 || (c) > 0xFDEF) && \
+ ((c) & 0xFFFE) != 0xFFFE)
+
+#define CONTINUATION_CHAR(c, val) \
+ do { \
+ if (((c) & 0xc0) != 0x80) /* 10xxxxxx */ \
+ goto failed; \
+ (val) <<= 6; \
+ (val) |= (c) & 0x3f; \
+ } while (0)
+
+#define INCREMENT_AND_CHECK_MAX(p, i, max_len) \
+ do { \
+ (i)++; \
+ if ((p)[(i)] == '\0' || ((max_len) >= 0 && (i) >= (max_len))) \
+ goto failed; \
+ } while (0)
+
+
+gboolean g_utf8_validate(const gchar *str, gssize max_len, const gchar **end)
+{
+ unsigned long val, min, i;
+ const unsigned char *p, *last;
+
+ min = val = 0;
+
+ for (p = (unsigned char *) str, i = 0; p[i]; i++) {
+ if (max_len >= 0 && i >= max_len)
+ break;
+
+ if (p[i] < 128)
+ continue;
+
+ last = &p[i];
+
+ if ((p[i] & 0xe0) == 0xc0) { /* 110xxxxx */
+ if ((p[i] & 0x1e) == 0)
+ goto failed;
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ if ((p[i] & 0xc0) != 0x80)
+ goto failed; /* 10xxxxxx */
+ } else {
+ if ((p[i] & 0xf0) == 0xe0) {
+ /* 1110xxxx */
+ min = (1 << 11);
+ val = p[i] & 0x0f;
+ goto two_remaining;
+ } else if ((p[i] & 0xf8) == 0xf0) {
+ /* 11110xxx */
+ min = (1 << 16);
+ val = p[i] & 0x07;
+ } else
+ goto failed;
+
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ CONTINUATION_CHAR(p[i], val);
+two_remaining:
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ CONTINUATION_CHAR(p[i], val);
+
+ INCREMENT_AND_CHECK_MAX(p, i, max_len);
+ CONTINUATION_CHAR(p[i], val);
+
+ if (val < min || !UNICODE_VALID(val))
+ goto failed;
+ }
+ }
+
+ if (end)
+ *end = (const gchar *) &p[i];
+
+ return TRUE;
+
+failed:
+ if (end)
+ *end = (const gchar *) last;
+
+ return FALSE;
+}
+
+/* GSList functions */
+
+GSList *g_slist_append(GSList *list, void *data)
+{
+ GSList *entry, *tail;
+
+ entry = g_new(GSList, 1);
+
+ entry->data = data;
+ entry->next = NULL;
+
+ if (!list)
+ return entry;
+
+ /* Find the end of the list */
+ for (tail = list; tail->next; tail = tail->next);
+
+ tail->next = entry;
+
+ return list;
+}
+
+GSList *g_slist_prepend(GSList *list, void *data)
+{
+ GSList *entry;
+
+ entry = g_new(GSList, 1);
+
+ entry->data = data;
+ entry->next = list;
+
+ return entry;
+}
+
+GSList *g_slist_insert_sorted(GSList *list, void *data, GCompareFunc cmp_func)
+{
+ GSList *tmp, *prev, *entry;
+ int cmp;
+
+ entry = g_new(GSList, 1);
+
+ entry->data = data;
+ entry->next = NULL;
+
+ if (!list)
+ return entry;
+
+ prev = NULL;
+ tmp = list;
+
+ cmp = cmp_func(data, tmp->data);
+
+ while (tmp->next && cmp > 0) {
+ prev = tmp;
+ tmp = tmp->next;
+
+ cmp = cmp_func(data, tmp->data);
+ }
+
+ if (!tmp->next && cmp > 0) {
+ tmp->next = entry;
+ return list;
+ }
+
+ if (prev) {
+ prev->next = entry;
+ entry->next = tmp;
+ return list;
+ } else {
+ entry->next = list;
+ return entry;
+ }
+}
+
+GSList *g_slist_remove(GSList *list, void *data)
+{
+ GSList *l, *next, *prev = NULL, *match = NULL;
+
+ if (!list)
+ return NULL;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (l->data == data) {
+ match = l;
+ break;
+ }
+ prev = l;
+ }
+
+ if (!match)
+ return list;
+
+ next = match->next;
+
+ g_free(match);
+
+ /* If the head was removed, return the next element */
+ if (!prev)
+ return next;
+
+ prev->next = next;
+
+ return list;
+}
+
+GSList *g_slist_find(GSList *list, gconstpointer data)
+{
+ GSList *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (l->data == data)
+ return l;
+ }
+
+ return NULL;
+}
+
+GSList *g_slist_find_custom(GSList *list, const void *data,
+ GCompareFunc cmp_func)
+{
+ GSList *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ if (!cmp_func(l->data, data))
+ return l;
+ }
+
+ return NULL;
+}
+
+static GSList *g_slist_sort_merge(GSList *l1, GSList *l2,
+ GCompareFunc cmp_func)
+{
+ GSList list, *l;
+ int cmp;
+
+ l = &list;
+
+ while (l1 && l2) {
+ cmp = cmp_func(l1->data, l2->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;
+}
+
+GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func)
+{
+ GSList *l1, *l2;
+
+ if (!list || !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(list, cmp_func),
+ g_slist_sort(l2, cmp_func), cmp_func);
+}
+
+int g_slist_length(GSList *list)
+{
+ int len;
+
+ for (len = 0; list != NULL; list = list->next)
+ len++;
+
+ return len;
+}
+
+void g_slist_foreach(GSList *list, GFunc func, void *user_data)
+{
+ while (list) {
+ GSList *next = list->next;
+ func(list->data, user_data);
+ list = next;
+ }
+}
+
+void g_slist_free(GSList *list)
+{
+ GSList *l, *next;
+
+ for (l = list; l != NULL; l = next) {
+ next = l->next;
+ g_free(l);
+ }
+}
+
+GSList *g_slist_nth(GSList *list, guint n)
+{
+ while (n-- > 0 && list)
+ list = list->next;
+
+ return list;
+}
+
+gpointer g_slist_nth_data(GSList *list, guint n)
+{
+ while (n-- > 0 && list)
+ list = list->next;
+
+ return list ? list->data : NULL;
+}
+
+gint g_slist_position(GSList *list, GSList *link)
+{
+ gint i;
+
+ for (i = 0; list; list = list->next, i++) {
+ if (list == link)
+ return i;
+ }
+
+ return -1;
+}
+
+GSList* g_slist_last(GSList *list)
+{
+ if (list)
+ while (list->next)
+ list = list->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;
+}
+
+GSList* g_slist_delete_link(GSList *list, GSList *link)
+{
+ list = _g_slist_remove_link(list, link);
+ g_free(link);
+
+ return list;
+}
+
+/* Memory allocation functions */
+
+gpointer g_malloc(gulong n_bytes)
+{
+ gpointer mem;
+
+ if (!n_bytes)
+ return NULL;
+
+ mem = malloc((size_t) n_bytes);
+ if (!mem) {
+ fprintf(stderr, "g_malloc: failed to allocate %lu bytes",
+ n_bytes);
+ abort();
+ }
+
+ return mem;
+}
+
+gpointer g_malloc0(gulong n_bytes)
+{
+ gpointer mem;
+
+ if (!n_bytes)
+ return NULL;
+
+ mem = g_malloc(n_bytes);
+
+ memset(mem, 0, (size_t) n_bytes);
+
+ return mem;
+}
+
+gpointer g_try_malloc(gulong n_bytes)
+{
+ if (!n_bytes)
+ return NULL;
+
+ return malloc((size_t) n_bytes);
+}
+
+gpointer g_try_malloc0(gulong n_bytes)
+{
+ gpointer mem;
+
+ mem = g_try_malloc(n_bytes);
+ if (mem)
+ memset(mem, 0, (size_t) n_bytes);
+
+ return mem;
+}
+
+gpointer g_realloc(gpointer mem, gulong n_bytes)
+{
+ mem = realloc(mem, n_bytes);
+ if (!mem) {
+ fprintf(stderr, "g_realloc: failed to allocate %lu bytes",
+ n_bytes);
+ abort();
+ }
+
+ return mem;
+}
+
+void g_free(gpointer mem)
+{
+ if (mem)
+ free(mem);
+}
+
+gchar *g_strdup(const gchar *str)
+{
+ gchar *s;
+
+ if (!str)
+ return NULL;
+
+ s = strdup(str);
+ if (!s) {
+ fprintf(stderr, "strdup: failed to allocate new string");
+ abort();
+ }
+
+ return s;
+}
+
+gchar *g_strdup_printf(const gchar *format, ...)
+{
+ va_list args;
+ gchar buffer[1024];
+ gint length;
+
+ va_start(args, format);
+ length = vsnprintf(buffer, sizeof(buffer) - 1, format, args);
+ va_end(args);
+
+ return g_strdup(buffer);
+}
+
+gchar *g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delim)
+{
+ register gchar *c;
+
+ if (!string)
+ return NULL;
+
+ for (c = string; *c; c++)
+ if (strchr(delimiters, *c))
+ *c = new_delim;
+
+ return string;
+}
+
+gchar *g_strconcat(const gchar *string1, ...)
+{
+ gsize l;
+ va_list args;
+ gchar *s, *concat;
+
+ 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);
+ concat[0] = '\0';
+
+ va_start(args, string1);
+ s = va_arg(args, gchar*);
+ while (s) {
+ strcat(concat, s);
+ s = va_arg(args, gchar *);
+ }
+ va_end (args);
+
+ return concat;
+}
+
+gsize g_strlcat(gchar *dest, const gchar *src, gsize dest_size)
+{
+ gchar *d = dest;
+ const gchar *s = src;
+ gsize bytes_left = dest_size;
+ gsize dlength; /* Logically, MIN(strlen(d), dest_size) */
+
+ if (!d || !s)
+ return 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 NULL */
+}
+
+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;
+
+ if (string == NULL || delimiter == NULL || delimiter[0] == '\0')
+ return NULL;
+
+ if (max_tokens < 1)
+ max_tokens = INT_MAX;
+
+ remainder = string;
+ s = strstr(remainder, delimiter);
+ if (s) {
+ gsize delimiter_len = strlen(delimiter);
+
+ while (--max_tokens && s) {
+ gsize len;
+ gchar *tmp;
+
+ len = s - remainder;
+ tmp = g_new(char, len);
+ memcpy(tmp, remainder, len);
+ string_list = g_slist_prepend(string_list, tmp);
+ 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;
+}
+
+gchar *g_ascii_strup(const gchar *str, gssize len)
+{
+ int i;
+ gchar *s;
+
+ s = g_strdup(str);
+ if (!s)
+ return NULL;
+
+ if (len < 0)
+ len = strlen(s);
+
+ for (i = 0; i < len; i++)
+ s[i] = toupper(s[i]);
+
+ return s;
+}
+
+gboolean g_str_equal(gconstpointer v1, gconstpointer v2)
+{
+ const gchar *string1 = v1;
+ const gchar *string2 = v2;
+
+ return strcmp(string1, string2) == 0;
+}
+
+gboolean g_str_has_prefix(const gchar *str, const gchar *prefix)
+{
+ int str_len;
+ int prefix_len;
+
+ if (str == NULL || prefix == NULL)
+ return FALSE;
+
+ str_len = strlen (str);
+ prefix_len = strlen (prefix);
+
+ if (str_len < prefix_len)
+ return FALSE;
+
+ return strncmp(str, prefix, prefix_len) == 0;
+}
+
+gboolean g_str_has_suffix(const gchar *str, const gchar *suffix)
+{
+ int str_len;
+ int suffix_len;
+
+ if (!str || !suffix)
+ return 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;
+}
+
+void g_strfreev(gchar **str_array)
+{
+ int i;
+
+ if (str_array == NULL)
+ return;
+
+ for(i = 0; str_array[i] != NULL; i++)
+ g_free(str_array[i]);
+
+ g_free(str_array);
+}
+
+/* GKeyFile */
+
+struct _GKeyFile {
+ gchar *filename;
+};
+
+GKeyFile *g_key_file_new(void)
+{
+ return g_new0(GKeyFile, 1);
+}
+
+void g_key_file_free(GKeyFile *key_file)
+{
+ g_free(key_file->filename);
+ g_free(key_file);
+}
+
+gboolean g_key_file_load_from_file(GKeyFile *key_file,
+ const gchar *file,
+ GKeyFileFlags flags,
+ GError **error)
+{
+ key_file->filename = g_strdup(file);
+ return TRUE;
+}
+
+static char *next_line(const char *ptr)
+{
+ char *nl;
+
+ nl = strchr(ptr, '\n');
+ if (!nl)
+ return NULL;
+
+ if (nl[1] == '\0')
+ return NULL;
+
+ return nl + 1;
+}
+
+gchar *g_key_file_get_string(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error)
+{
+ struct stat st;
+ char *map, *line, *group = NULL, *value = NULL;
+ off_t size;
+ size_t key_len, group_len;
+ int fd, err = 0;
+
+ fd = open(key_file->filename, O_RDONLY);
+ if (fd < 0) {
+ g_set_error(error, 0, 0, "%s: %s", key_file->filename,
+ strerror(errno));
+ return NULL;
+ }
+
+ if (flock(fd, LOCK_SH) < 0) {
+ err = errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
+
+ group_len = strlen(group_name);
+ key_len = strlen(key);
+
+ for (line = map; line != NULL; line = next_line(line)) {
+ int i;
+ size_t to_copy, value_len;
+ char tmp[1024], *nl;
+
+ if (*line == '#')
+ continue;
+
+ if (!group) {
+ if (line[0] != '[' || strncmp(line + 1, group_name, group_len))
+ continue;
+ if (line[group_len + 1] == ']')
+ group = line + 1;
+ continue;
+ }
+
+ if (strncmp(line, key, key_len))
+ continue;
+
+ for (i = key_len; line[i] != '\n'; i++) {
+ if (line[i] == '=')
+ break;
+ if (!isspace(line[i]))
+ break;
+ }
+
+ if (line[i] != '=')
+ continue;
+
+ nl = strchr(line, '\n');
+ if (!nl)
+ continue;
+
+ value_len = nl - (line + i + 1);
+ to_copy = value_len > (sizeof(tmp) - 1) ? sizeof(tmp) - 1 : value_len;
+ memset(tmp, 0, sizeof(tmp));
+ strncpy(tmp, line + i + 1, to_copy);
+
+ value = g_strdup(tmp);
+ break;
+ }
+
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+
+ if (err)
+ g_set_error(error, 0, 0, "%s: %s", key_file->filename,
+ strerror(err));
+ else if (!group)
+ g_set_error(error, 0, 0, "%s: group %s not found",
+ key_file->filename, group_name);
+ else if (!value)
+ g_set_error(error, 0, 0, "%s: key %s not found",
+ key_file->filename, key);
+
+ return value;
+}
+
+gboolean g_key_file_get_boolean(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = g_key_file_get_string(key_file, group_name, key, error);
+ if (!str)
+ return FALSE;
+
+ if (strcmp(str, "true") == 0 || strcmp(str, "1") == 0)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ g_free(str);
+
+ return ret;
+}
+
+gint g_key_file_get_integer(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error)
+{
+ int ret;
+ gchar *str;
+
+ str = g_key_file_get_string(key_file, group_name, key, error);
+ if (!str)
+ return 0;
+
+ ret = atoi(str);
+
+ g_free(str);
+
+ return ret;
+}
+
+gchar **g_key_file_get_string_list(GKeyFile *key_file, const gchar *group_name,
+ const gchar *key, gsize *length,
+ GError **error)
+{
+ gchar *str, *item, **list;
+ int items = 0;
+
+ str = g_key_file_get_string(key_file, group_name, key, error);
+ if (!str)
+ return NULL;
+
+ items = 0;
+ list = g_new0(char *, 1);
+
+ item = strtok(str, ",");
+ while (item) {
+ items++;
+
+ list = g_renew(char *, list, items + 1);
+
+ list[items - 1] = g_strdup(item);
+ list[items] = NULL;
+
+ item = strtok(NULL, ",");
+ }
+
+ g_free(str);
+
+ return list;
+}
+
+/* GString */
+
+#define MY_MAXSIZE ((gsize)-1)
+
+static gsize nearest_power(gsize base, gsize num)
+{
+ gsize n = base;
+
+ if (num > MY_MAXSIZE / 2)
+ return MY_MAXSIZE;
+
+ while (n < num)
+ n <<= 1;
+
+ return n;
+}
+
+static void g_string_maybe_expand(GString *string, gsize len)
+{
+ if (string->len + len < string->allocated_len)
+ return;
+
+ string->allocated_len = nearest_power(1, string->len + len + 1);
+ string->str = g_realloc(string->str, string->allocated_len);
+}
+
+static GString *g_string_sized_new(gsize dfl_size)
+{
+ GString *string;
+
+ string = g_new0(GString, 1);
+
+ g_string_maybe_expand(string, dfl_size);
+ string->str[0] = '\0';
+
+ return string;
+}
+
+static GString *g_string_append_len(GString *string, const gchar *val, gssize len)
+{
+ g_string_maybe_expand(string, len);
+
+ if (len == 1)
+ string->str[string->len] = *val;
+ else
+ memcpy(string->str + string->len, val, len);
+
+ string->len += len;
+ string->str[string->len] = '\0';
+
+ return string;
+}
+
+GString *g_string_new(const gchar *init)
+{
+ GString *string;
+ gint len;
+
+ if (init == NULL || *init == '\0')
+ return g_string_sized_new(2);
+
+ len = strlen(init);
+ string = g_string_sized_new(len + 2);
+
+ g_string_append_len(string, init, len);
+
+ return string;
+}
+
+void g_string_append_printf(GString *string, const gchar *format, ...)
+{
+ gchar buffer[1024];
+ gint length;
+ va_list args;
+
+ va_start(args, format);
+ length = vsnprintf(buffer, sizeof(buffer) - 1, format, args);
+ va_end(args);
+
+ g_string_append_len(string, buffer, length);
+}
+
+gchar *g_string_free(GString *string, gboolean free_segment)
+{
+ gchar *segment;
+
+ if (free_segment) {
+ g_free(string->str);
+ segment = NULL;
+ } else
+ segment = string->str;
+
+ g_free(string);
+
+ return segment;
+}
+
+/* GMarkup */
+
+struct _GMarkupParseContext {
+ char dummy;
+};
+
+GMarkupParseContext *g_markup_parse_context_new(const GMarkupParser *parser,
+ GMarkupParseFlags flags,
+ gpointer user_data,
+ GDestroyNotify user_data_dnotify)
+{
+ return g_new0(GMarkupParseContext, 1);
+}
+
+gboolean g_markup_parse_context_parse(GMarkupParseContext *context,
+ const gchar *text, gssize text_len,
+ GError **error)
+{
+ g_set_error(error, 0, 0, "Not implemented");
+ return FALSE;
+}
+
+void g_markup_parse_context_free(GMarkupParseContext *context)
+{
+ g_free(context);
+}
+
+static gchar *g_build_pathname_va(const gchar *first_element,
+ va_list args, gpointer *data)
+{
+ gchar result[PATH_MAX], *element;
+
+ strncpy(result, first_element, PATH_MAX);
+ element = va_arg(args, gchar *);
+
+ while (element) {
+ g_strlcat(result, "/", PATH_MAX);
+ g_strlcat(result, element, PATH_MAX);
+ element = va_arg(args, gchar *);
+ }
+
+ va_end(args);
+
+ return g_strdup(result);
+}
+
+gchar *g_build_filename(const gchar *first_element, ...)
+{
+ gchar *str;
+ va_list args;
+
+ va_start(args, first_element);
+ str = g_build_pathname_va(first_element, args, NULL);
+ va_end(args);
+
+ return str;
+}
+
+/* GDir */
+
+GDir *g_dir_open(const gchar *path, guint flags, GError **error)
+{
+ GDir *dir;
+
+ if (path == NULL)
+ return NULL;
+
+ dir = g_new(GDir, 1);
+
+ dir->dirp = opendir(path);
+
+ if (dir->dirp)
+ return dir;
+
+ /* error case */
+ g_set_error(error, 0, 0, "Error opening directory '%s': %s",
+ path, strerror(errno));
+
+ g_free(dir);
+
+ return NULL;
+}
+
+const gchar *g_dir_read_name(GDir *dir)
+{
+ struct dirent *entry;
+
+ if (dir == NULL)
+ return NULL;
+
+ entry = readdir(dir->dirp);
+
+ while (entry && (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0))
+ entry = readdir(dir->dirp);
+
+ return entry ? entry->d_name : NULL;
+}
+
+void g_dir_close(GDir *dir)
+{
+ if (dir == NULL)
+ return;
+
+ closedir(dir->dirp);
+ g_free(dir);
+}
diff --git a/eglib/gmain.h b/eglib/gmain.h
new file mode 100644
index 00000000..fa218da4
--- /dev/null
+++ b/eglib/gmain.h
@@ -0,0 +1,404 @@
+#ifndef __GMAIN_H
+#define __GMAIN_H
+
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+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 uint8_t guint8;
+typedef uint16_t guint16;
+typedef uint32_t guint32;
+
+typedef float gfloat;
+typedef double gdouble;
+
+typedef void * gpointer;
+typedef const void * gconstpointer;
+
+typedef size_t gsize;
+typedef ssize_t gssize;
+
+#define GPOINTER_TO_INT(p) ((gint) (glong) (p))
+#define GPOINTER_TO_UINT(p) ((guint) (gulong) (p))
+
+#define GINT_TO_POINTER(i) ((gpointer) (glong) (i))
+#define GUINT_TO_POINTER(u) ((gpointer) (gulong) (u))
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX INT_MAX
+#endif
+
+#define g_ntohs(val) ntohs(val)
+#define g_ntohl(val) ntohl(val)
+#define g_htons(val) htons(val)
+#define g_htonl(val) htonl(val)
+
+typedef pid_t GPid;
+
+#define MIN_TIMEOUT(a, b) (((a) < (b)) ? (a) : (b))
+
+typedef struct _GIOChannel GIOChannel;
+
+typedef gboolean (*GSourceFunc) (gpointer data);
+
+typedef struct _GMainContext GMainContext;
+
+typedef struct _GMainLoop GMainLoop;
+
+typedef enum {
+ G_IO_ERROR_NONE,
+ G_IO_ERROR_AGAIN,
+ G_IO_ERROR_INVAL,
+ G_IO_ERROR_UNKNOWN
+} GIOError;
+
+typedef enum {
+ G_IO_STATUS_ERROR = -1,
+ G_IO_STATUS_NORMAL = 0,
+ G_IO_STATUS_EOF = 1,
+ G_IO_STATUS_AGAIN = 2
+} GIOStatus;
+
+typedef enum {
+ G_IO_FLAG_APPEND = 1 << 0,
+ G_IO_FLAG_NONBLOCK = 1 << 1,
+ G_IO_FLAG_IS_READABLE = 1 << 2,
+ G_IO_FLAG_IS_WRITEABLE = 1 << 3,
+ G_IO_FLAG_IS_SEEKABLE = 1 << 4,
+ G_IO_FLAG_MASK = (1 << 5) - 1,
+ G_IO_FLAG_GET_MASK = G_IO_FLAG_MASK,
+ G_IO_FLAG_SET_MASK = G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK
+} GIOFlags;
+
+#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)))
+
+/* GError */
+
+typedef guint32 GQuark;
+
+typedef struct {
+ GQuark domain;
+ gint code;
+ gchar *message;
+} GError;
+
+void g_set_error(GError **err, GQuark domain, gint code,
+ const gchar *format, ...);
+GError* g_error_new_literal(GQuark domain, gint code, const gchar *message);
+void g_error_free(GError *err);
+
+typedef enum {
+ G_IO_IN = POLLIN,
+ G_IO_OUT = POLLOUT,
+ G_IO_PRI = POLLPRI,
+ G_IO_ERR = POLLERR,
+ G_IO_HUP = POLLHUP,
+ G_IO_NVAL = POLLNVAL
+} GIOCondition;
+
+#define G_PRIORITY_HIGH -100
+#define G_PRIORITY_DEFAULT 0
+#define G_PRIORITY_HIGH_IDLE 100
+#define G_PRIORITY_DEFAULT_IDLE 200
+#define G_PRIORITY_LOW 300
+
+typedef void (*GDestroyNotify) (gpointer data);
+typedef gboolean (*GIOFunc) (GIOChannel *source, GIOCondition condition,
+ gpointer data);
+
+GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count,
+ gsize *bytes_read);
+GIOError g_io_channel_write(GIOChannel *channel, const gchar *buf, gsize count,
+ gsize *bytes_written);
+
+void g_io_channel_close(GIOChannel *channel);
+
+GIOChannel *g_io_channel_unix_new(int fd);
+GIOChannel *g_io_channel_ref(GIOChannel *channel);
+void g_io_channel_unref(GIOChannel *channel);
+void g_io_channel_set_close_on_unref(GIOChannel *channel, gboolean do_close);
+gint g_io_channel_unix_get_fd(GIOChannel *channel);
+GIOStatus g_io_channel_set_flags(GIOChannel *channel, GIOFlags flags,
+ GError **error);
+guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
+ GIOFunc func, gpointer user_data);
+guint g_io_add_watch_full(GIOChannel *channel, gint priority,
+ GIOCondition condition, GIOFunc func,
+ gpointer user_data, GDestroyNotify notify);
+
+GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running);
+void g_main_loop_run(GMainLoop *loop);
+void g_main_loop_quit(GMainLoop *loop);
+void g_main_loop_unref(GMainLoop *loop);
+guint g_timeout_add(guint interval, GSourceFunc function, gpointer data);
+guint g_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
+guint g_idle_add(GSourceFunc function, gpointer data);
+gboolean g_source_remove(guint tag);
+
+/* Spawning related functions */
+
+typedef enum {
+ G_SPAWN_LEAVE_DESCRIPTORS_OPEN = 1 << 0,
+ G_SPAWN_DO_NOT_REAP_CHILD = 1 << 1,
+ /* look for argv[0] in the path i.e. use execvp() */
+ G_SPAWN_SEARCH_PATH = 1 << 2,
+ /* Dump output to /dev/null */
+ G_SPAWN_STDOUT_TO_DEV_NULL = 1 << 3,
+ G_SPAWN_STDERR_TO_DEV_NULL = 1 << 4,
+ G_SPAWN_CHILD_INHERITS_STDIN = 1 << 5,
+ G_SPAWN_FILE_AND_ARGV_ZERO = 1 << 6
+} GSpawnFlags;
+
+typedef void (*GSpawnChildSetupFunc) (gpointer user_data);
+
+gboolean g_spawn_async(const gchar *working_directory,
+ gchar **argv, gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ GError **error);
+
+void g_spawn_close_pid(GPid pid);
+
+typedef void (*GChildWatchFunc) (GPid pid, gint status, gpointer data);
+
+guint g_child_watch_add(GPid pid, GChildWatchFunc func, gpointer user_data);
+
+gboolean g_utf8_validate(const gchar *str, gssize max_len, const gchar **end);
+
+#define g_main_new(is_running) g_main_loop_new(NULL, is_running);
+#define g_main_run(loop) g_main_loop_run(loop)
+#define g_main_quit(loop) g_main_loop_quit(loop)
+#define g_main_unref(loop) g_main_loop_unref(loop)
+
+/* GSList declarations */
+
+typedef struct _GSList {
+ void *data;
+ struct _GSList *next;
+} GSList;
+
+typedef int (*GCompareFunc)(const void *a, const void *b);
+typedef void (*GFunc)(void *data, void *user_data);
+
+GSList *g_slist_append(GSList *list, void *data);
+
+GSList *g_slist_prepend(GSList *list, void *data);
+
+GSList *g_slist_insert_sorted(GSList *list, void *data, GCompareFunc cmp_func);
+
+GSList *g_slist_remove(GSList *list, void *data);
+
+GSList *g_slist_find(GSList *list, gconstpointer data);
+
+GSList *g_slist_find_custom(GSList *list, const void *data,
+ GCompareFunc cmp_func);
+
+GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func);
+
+int g_slist_length(GSList *list);
+
+void g_slist_foreach(GSList *list, GFunc func, void *user_data);
+void g_slist_free(GSList *list);
+GSList *g_slist_delete_link(GSList *list, GSList *link);
+
+GSList *g_slist_nth(GSList *list, guint n);
+gpointer g_slist_nth_data(GSList *list, guint n);
+int g_slist_position(GSList *list, GSList *link);
+GSList* g_slist_last(GSList *list);
+
+#define g_slist_next(l) ((l)->next)
+
+/* Memory allocation related */
+
+gpointer g_malloc(gulong n_bytes);
+gpointer g_malloc0(gulong n_bytes);
+gpointer g_try_malloc(gulong n_bytes);
+gpointer g_try_malloc0(gulong n_bytes);
+gpointer g_realloc(gpointer mem, gulong n_bytes);
+
+void g_free(gpointer mem);
+
+gchar *g_strdup(const gchar *str);
+gchar* g_strdup_printf(const gchar *format, ...);
+gchar* g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delim);
+gchar *g_strconcat(const gchar *string1, ...);
+gsize g_strlcat(gchar *dest, const gchar *src, gsize dest_size);
+gchar **g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens);
+gchar *g_ascii_strup(const gchar *str, gssize len);
+gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
+gboolean g_str_has_prefix(const gchar *str, const gchar *prefix);
+gboolean g_str_has_suffix(const gchar *str, const gchar *suffix);
+void g_strfreev(gchar **str_array);
+
+#define g_new(struct_type, n_structs) \
+ ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_new0(struct_type, n_structs) \
+ ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_new(struct_type, n_structs) \
+ ((struct_type *) g_try_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_try_new0(struct_type, n_structs) \
+ ((struct_type *) g_try_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+#define g_renew(struct_type, mem, n_structs) \
+ ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
+
+/* GKeyFile */
+
+typedef enum {
+ G_KEY_FILE_NONE = 0,
+ G_KEY_FILE_KEEP_COMMENTS = 1 << 0,
+ G_KEY_FILE_KEEP_TRANSLATIONS = 1 << 1
+} GKeyFileFlags;
+
+typedef struct _GKeyFile GKeyFile;
+
+GKeyFile *g_key_file_new(void);
+
+void g_key_file_free(GKeyFile *key_file);
+
+gboolean g_key_file_load_from_file(GKeyFile *key_file,
+ const gchar *file,
+ GKeyFileFlags flags,
+ GError **error);
+
+gchar *g_key_file_get_string(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+
+gboolean g_key_file_get_boolean(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+
+gint g_key_file_get_integer(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key,
+ GError **error);
+
+gchar **g_key_file_get_string_list(GKeyFile *key_file,
+ const gchar *group_name,
+ const gchar *key, gsize *length,
+ GError **error);
+/* GString */
+
+typedef struct {
+ gchar *str;
+ gsize len;
+ gsize allocated_len;
+} GString;
+
+GString *g_string_new(const gchar *init);
+
+void g_string_append_printf(GString *string, const gchar *format, ...);
+
+gchar *g_string_free(GString *string, gboolean free_segment);
+
+/* GMarkup */
+
+typedef enum {
+ G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG = 1 << 0,
+ G_MARKUP_TREAT_CDATA_AS_TEXT = 1 << 1
+} GMarkupParseFlags;
+
+typedef struct _GMarkupParseContext GMarkupParseContext;
+typedef struct _GMarkupParser GMarkupParser;
+
+struct _GMarkupParser {
+ /* Called for open tags <foo bar="baz"> */
+ void (*start_element) (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for close tags </foo> */
+ void (*end_element) (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for character data */
+ /* text is not nul-terminated */
+ void (*text) (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+ /* Called for strings that should be re-saved verbatim in this same
+ * position, but are not otherwise interpretable. At the moment
+ * this includes comments and processing instructions.
+ */
+ /* text is not nul-terminated. */
+ void (*passthrough) (GMarkupParseContext *context,
+ const gchar *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error);
+
+ /* Called on error, including one set by other
+ * methods in the vtable. The GError should not be freed.
+ */
+ void (*error) (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data);
+};
+
+GMarkupParseContext *g_markup_parse_context_new(const GMarkupParser *parser,
+ GMarkupParseFlags flags,
+ gpointer user_data,
+ GDestroyNotify user_data_dnotify);
+
+gboolean g_markup_parse_context_parse(GMarkupParseContext *context,
+ const gchar *text, gssize text_len,
+ GError **error);
+
+void g_markup_parse_context_free(GMarkupParseContext *context);
+
+/* GDir */
+
+typedef struct _GDir GDir;
+
+GDir *g_dir_open(const gchar *path, guint flags, GError **error);
+const gchar *g_dir_read_name(GDir *dir);
+void g_dir_close(GDir *dir);
+
+/* Various */
+
+gchar *g_build_filename(const gchar *first_element, ...);
+
+#endif /* __GMAIN_H */
diff --git a/eglib/gmodule.c b/eglib/gmodule.c
new file mode 100644
index 00000000..7224a9f6
--- /dev/null
+++ b/eglib/gmodule.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <gmain.h>
+#include <gmodule.h>
+
+struct _GModule {
+ void *handle;
+ gchar *file_name;
+};
+
+static const char *dl_error_string = NULL;
+
+GModule *g_module_open(const gchar *file_name, GModuleFlags flags)
+{
+ GModule *module;
+
+ module = g_try_new0(GModule, 1);
+ if (module == NULL) {
+ dl_error_string = strerror(ENOMEM);
+ return NULL;
+ }
+
+ module->handle = dlopen(file_name, flags);
+
+ if (module->handle == NULL) {
+ dl_error_string = dlerror();
+ g_free(module);
+ return NULL;
+ }
+
+ module->file_name = g_strdup(file_name);
+
+ return module;
+}
+
+gboolean g_module_symbol(GModule *module, const gchar *symbol_name,
+ gpointer *symbol)
+{
+ void *sym;
+
+ dlerror();
+ sym = dlsym(module->handle, symbol_name);
+ dl_error_string = dlerror();
+
+ if (dl_error_string != NULL)
+ return FALSE;
+
+ *symbol = sym;
+
+ return TRUE;
+}
+
+gboolean g_module_close(GModule *module)
+{
+ if (dlclose(module->handle) != 0) {
+ dl_error_string = dlerror();
+ return FALSE;
+ }
+
+ g_free(module->file_name);
+ g_free(module);
+
+ return TRUE;
+}
+
+const gchar *g_module_error(void)
+{
+ const char *str;
+
+ str = dl_error_string;
+ dl_error_string = NULL;
+
+ return str;
+}
+
+const gchar *g_module_name(GModule *module)
+{
+ if (module == NULL)
+ return NULL;
+
+ return module->file_name;
+}
diff --git a/eglib/gmodule.h b/eglib/gmodule.h
new file mode 100644
index 00000000..e392d5c8
--- /dev/null
+++ b/eglib/gmodule.h
@@ -0,0 +1,21 @@
+#ifndef __GMODULE_H
+#define __GMODULE_H
+
+#include <gmain.h>
+
+typedef struct _GModule GModule;
+
+typedef enum {
+ G_MODULE_BIND_LAZY = 1 << 0,
+ G_MODULE_BIND_LOCAL = 1 << 1,
+ G_MODULE_BIND_MASK = 0x03
+} GModuleFlags;
+
+GModule *g_module_open(const gchar *file_name, GModuleFlags flags);
+gboolean g_module_symbol(GModule *module, const gchar *symbol_name,
+ gpointer *symbol);
+const gchar *g_module_name(GModule *module);
+gboolean g_module_close(GModule *module);
+const gchar *g_module_error(void);
+
+#endif /* __GMODULE_H */