summaryrefslogtreecommitdiffstats
path: root/eglib
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2007-01-20 06:03:26 +0000
committerMarcel Holtmann <marcel@holtmann.org>2007-01-20 06:03:26 +0000
commit8a9d1780d1e3548bae13eaaae56afdcf99ed297d (patch)
tree9a212a661f2cca74c7518e8087523854dc54d023 /eglib
parent1c62e7ed6ef51305a5a625ee070de8d2428c4e9a (diff)
Add main loop and single list functions
Diffstat (limited to 'eglib')
-rw-r--r--eglib/Makefile.am2
-rw-r--r--eglib/glib.h1
-rw-r--r--eglib/gmain.c815
-rw-r--r--eglib/gmain.h139
4 files changed, 956 insertions, 1 deletions
diff --git a/eglib/Makefile.am b/eglib/Makefile.am
index 4d41ad92..009c70e1 100644
--- a/eglib/Makefile.am
+++ b/eglib/Makefile.am
@@ -2,7 +2,7 @@
if !GLIB
noinst_LTLIBRARIES = libeglib.la
-libeglib_la_SOURCES = glib.h
+libeglib_la_SOURCES = glib.h gmain.h gmain.c
endif
MAINTAINERCLEANFILES = Makefile.in
diff --git a/eglib/glib.h b/eglib/glib.h
index e69de29b..5600a33e 100644
--- a/eglib/glib.h
+++ 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..a3bf3760
--- /dev/null
+++ b/eglib/gmain.c
@@ -0,0 +1,815 @@
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <gmain.h>
+
+struct timeout {
+ guint id;
+ guint interval;
+ struct timeval expiration;
+ gpointer data;
+ GSourceFunc function;
+};
+
+struct _GIOChannel {
+ int fd;
+ gboolean closed;
+ gboolean close_on_unref;
+};
+
+struct _GMainContext {
+ guint next_id;
+ glong next_timeout;
+
+ GSList *timeouts;
+ GSList *proc_timeouts;
+ gboolean timeout_lock;
+
+ GSList *watches;
+ GSList *proc_watches;
+ gboolean watch_lock;
+};
+
+struct _GMainLoop {
+ gboolean is_running;
+ GMainContext *context;
+};
+
+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;
+}
+
+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->close_on_unref && channel->fd >= 0)
+ g_io_channel_close(channel);
+
+ free(channel);
+}
+
+GIOChannel *g_io_channel_unix_new(int fd)
+{
+ GIOChannel *channel;
+
+ channel = malloc(sizeof(GIOChannel));
+ if (!channel)
+ return NULL;
+
+ memset(channel, 0, sizeof(GIOChannel));
+
+ channel->fd = fd;
+
+ 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;
+}
+
+struct 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 watch *watch)
+{
+ if (watch->destroy)
+ watch->destroy(watch->user_data);
+ free(watch);
+}
+
+static GMainContext *g_main_context_default()
+{
+ if (default_context)
+ return default_context;
+
+ default_context = malloc(sizeof(GMainContext));
+ if (!default_context)
+ return NULL;
+
+ memset(default_context, 0, sizeof(GMainContext));
+
+ default_context->next_timeout = -1;
+ default_context->next_id = 1;
+
+ return default_context;
+}
+
+void g_io_remove_watch(guint id)
+{
+ GMainContext *context = g_main_context_default();
+ GSList *l;
+ struct watch *w;
+
+ if (!context)
+ return;
+
+ for (l = context->watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->watches = g_slist_remove(context->watches, w);
+ watch_free(w);
+
+ return;
+ }
+
+ for (l = context->proc_watches; l != NULL; l = l->next) {
+ w = l->data;
+
+ if (w->id != id)
+ continue;
+
+ context->proc_watches = g_slist_remove(context->proc_watches, w);
+ watch_free(w);
+
+ return;
+ }
+}
+
+int watch_prio_cmp(struct watch *w1, struct 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 watch *watch;
+ GMainContext *context = g_main_context_default();
+
+ if (!context)
+ return 0;
+
+ watch = malloc(sizeof(struct watch));
+ if (!watch)
+ return 0;
+
+ watch->id = context->next_id++;
+ watch->channel = channel;
+ watch->priority = priority;
+ watch->condition = condition;
+ watch->func = func;
+ watch->user_data = user_data;
+ watch->destroy = notify;
+
+ if (context->watch_lock)
+ context->proc_watches = watch_list_add(context->proc_watches, watch);
+ else
+ context->watches = watch_list_add(context->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();
+
+ if (!context)
+ return NULL;
+
+ ml = malloc(sizeof(GMainLoop));
+ if (!ml)
+ return NULL;
+
+ memset(ml, 0, sizeof(GMainLoop));
+
+ 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) {
+ 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 = malloc(open_max * sizeof(struct pollfd));
+ if (!ufds)
+ return;
+
+ loop->is_running = TRUE;
+
+ while (loop->is_running) {
+ int nfds;
+ GSList *l;
+ struct watch *w;
+
+ for (nfds = 0, l = context->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->watch_lock = TRUE;
+
+ while (context->watches) {
+ gboolean ret;
+
+ w = context->watches->data;
+
+ if (!*w->revents) {
+ context->watches = g_slist_remove(context->watches, w);
+ context->proc_watches = watch_list_add(context->proc_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->watches, w, ptr_cmp))
+ continue;
+
+ context->watches = g_slist_remove(context->watches, w);
+
+ if (!ret) {
+ watch_free(w);
+ continue;
+ }
+
+ context->proc_watches = watch_list_add(context->proc_watches, w);
+ }
+
+ context->watches = context->proc_watches;
+ context->proc_watches = NULL;
+ context->watch_lock = FALSE;
+
+ /* check expired timers */
+ timeout_handlers_check(loop->context);
+ }
+
+ 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->watches, (GFunc)watch_free, NULL);
+ g_slist_free(loop->context->watches);
+
+ g_slist_foreach(loop->context->timeouts, (GFunc)free, NULL);
+ g_slist_free(loop->context->timeouts);
+
+ 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;
+
+ if (!context || !function)
+ return 0;
+
+ t = malloc(sizeof(*t));
+
+ if (!t)
+ return 0;
+
+ memset(t, 0, sizeof(*t));
+ 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;
+}
+
+gint g_timeout_remove(const guint id)
+{
+ GMainContext *context = g_main_context_default();
+ GSList *l;
+ struct timeout *t;
+
+ if (!context)
+ return -1;
+
+ l = context->timeouts;
+
+ while (l) {
+ t = l->data;
+ l = l->next;
+
+ if (t->id != id)
+ continue;
+
+ context->timeouts = g_slist_remove(context->timeouts, t);
+ free(t);
+
+ return 0;
+ }
+
+ 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);
+ free(t);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/* 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 = malloc(sizeof(GSList));
+ /* FIXME: this currently just silently fails */
+ if (!entry)
+ return list;
+
+ 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 = malloc(sizeof(GSList));
+ /* FIXME: this currently just silently fails */
+ if (!entry)
+ return list;
+
+ 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 = malloc(sizeof(GSList));
+ if (!entry)
+ return list;
+
+ 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;
+
+ free(match);
+
+ /* If the head was removed, return the next element */
+ if (!prev)
+ return next;
+
+ prev->next = next;
+
+ return list;
+}
+
+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;
+ free(l);
+ }
+}
diff --git a/eglib/gmain.h b/eglib/gmain.h
new file mode 100644
index 00000000..950d4170
--- /dev/null
+++ b/eglib/gmain.h
@@ -0,0 +1,139 @@
+#ifndef __GMAIN_H
+#define __GMAIN_H
+
+#include <stdlib.h>
+#include <sys/poll.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 float gfloat;
+typedef double gdouble;
+
+typedef void * gpointer;
+typedef const void * gconstpointer;
+
+typedef size_t gsize;
+typedef ssize_t gssize;
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX INT_MAX
+#endif
+
+#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;
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+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);
+void g_io_channel_close(GIOChannel *channel);
+
+GIOChannel *g_io_channel_unix_new(int fd);
+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);
+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);
+void g_io_remove_watch(guint id);
+
+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);
+gint g_timeout_remove(const guint id);
+
+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)
+
+/* Begin 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_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);
+
+/* End GSList declarations */
+
+#endif /* __GMAIN_H */