diff options
Diffstat (limited to 'eglib')
| -rw-r--r-- | eglib/Makefile.am | 8 | ||||
| -rw-r--r-- | eglib/glib.h | 1 | ||||
| -rw-r--r-- | eglib/gmain.c | 1977 | ||||
| -rw-r--r-- | eglib/gmain.h | 404 | ||||
| -rw-r--r-- | eglib/gmodule.c | 88 | ||||
| -rw-r--r-- | eglib/gmodule.h | 21 | 
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 */  | 
