summaryrefslogtreecommitdiff
path: root/src/libmowgli/object
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmowgli/object')
-rw-r--r--src/libmowgli/object/Makefile21
-rw-r--r--src/libmowgli/object/class.c131
-rw-r--r--src/libmowgli/object/class.h60
-rw-r--r--src/libmowgli/object/message.c142
-rw-r--r--src/libmowgli/object/message.h42
-rw-r--r--src/libmowgli/object/metadata.c104
-rw-r--r--src/libmowgli/object/metadata.h36
-rw-r--r--src/libmowgli/object/object.c164
-rw-r--r--src/libmowgli/object/object.h42
9 files changed, 742 insertions, 0 deletions
diff --git a/src/libmowgli/object/Makefile b/src/libmowgli/object/Makefile
new file mode 100644
index 0000000..1ac3ff3
--- /dev/null
+++ b/src/libmowgli/object/Makefile
@@ -0,0 +1,21 @@
+include ../../../extra.mk
+
+STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_OBJECT}
+STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_OBJECT}
+
+SRCS = object.c \
+ class.c \
+ message.c \
+ metadata.c
+
+INCLUDES = object.h \
+ class.h \
+ message.h \
+ metadata.h
+
+include ../../../buildsys.mk
+
+includesubdir = $(PACKAGE_NAME)/object
+
+CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE
+
diff --git a/src/libmowgli/object/class.c b/src/libmowgli/object/class.c
new file mode 100644
index 0000000..9bddf79
--- /dev/null
+++ b/src/libmowgli/object/class.c
@@ -0,0 +1,131 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * class.c: Object class and type management, cast checking.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mowgli.h"
+
+static mowgli_patricia_t *mowgli_object_class_dict = NULL;
+
+static void _object_key_canon(char *str)
+{
+ while (*str)
+ {
+ *str = toupper(*str);
+ str++;
+ }
+}
+
+void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic)
+{
+ /* if the object_class dictionary has not yet been initialized, we will want to do that. */
+ if (mowgli_object_class_dict == NULL)
+ mowgli_object_class_dict = mowgli_patricia_create(_object_key_canon);
+
+ if (klass == NULL)
+ mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception);
+
+ if (mowgli_object_class_find_by_name(name) != NULL)
+ mowgli_throw_exception_fatal(mowgli.object_class.duplicate_object_class_exception);
+
+ /* initialize object_class::name */
+ klass->name = mowgli_strdup(name);
+
+ /* initialize object_class::derivitives */
+ klass->derivitives.head = NULL;
+ klass->derivitives.tail = NULL;
+ klass->derivitives.count = 0;
+
+ /* initialize object_class::destructor */
+ klass->destructor = des != NULL ? des : mowgli_free;
+
+ /* initialize object_class::dynamic */
+ klass->dynamic = dynamic;
+
+ /* add to the object_class index */
+ mowgli_patricia_add(mowgli_object_class_dict, klass->name, klass);
+}
+
+int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2)
+{
+ mowgli_node_t *n;
+
+ if (klass1 == NULL || klass2 == NULL)
+ mowgli_throw_exception_val(mowgli.object_class.invalid_object_class_exception, 0);
+
+ MOWGLI_LIST_FOREACH(n, klass1->derivitives.head)
+ {
+ mowgli_object_class_t *tklass = (mowgli_object_class_t *) n->data;
+
+ if (tklass == klass2)
+ return 1;
+ }
+
+ return 0;
+}
+
+void mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent)
+{
+ if (klass == NULL || parent == NULL)
+ mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception);
+
+ mowgli_node_add(klass, mowgli_node_create(), &parent->derivitives);
+}
+
+void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *opdata, mowgli_object_class_t *klass)
+{
+ mowgli_object_t *object = mowgli_object(opdata);
+
+ /* this can possibly happen at runtime .. lets not make it a fatal exception. */
+ return_val_if_fail(object != NULL, NULL);
+ return_val_if_fail(klass != NULL, NULL);
+
+ if (mowgli_object_class_check_cast(object->klass, klass))
+ return object;
+
+ mowgli_log("Invalid reinterpreted cast from %s<%p> to %s", object->klass->name, klass->name);
+ return NULL;
+}
+
+mowgli_object_class_t *mowgli_object_class_find_by_name(const char *name)
+{
+ return mowgli_patricia_retrieve(mowgli_object_class_dict, name);
+}
+
+void mowgli_object_class_destroy(mowgli_object_class_t *klass)
+{
+ mowgli_node_t *n, *tn;
+
+ if (klass == NULL)
+ mowgli_throw_exception_fatal(mowgli.object_class.invalid_object_class_exception);
+
+ if (klass->dynamic != TRUE)
+ mowgli_throw_exception_fatal(mowgli.object_class.nondynamic_object_class_exception);
+
+ MOWGLI_LIST_FOREACH_SAFE(n, tn, klass->derivitives.head)
+ {
+ mowgli_node_delete(n, &klass->derivitives);
+ mowgli_node_free(n);
+ }
+
+ mowgli_free(klass->name);
+ mowgli_free(klass);
+}
diff --git a/src/libmowgli/object/class.h b/src/libmowgli/object/class.h
new file mode 100644
index 0000000..9612aa4
--- /dev/null
+++ b/src/libmowgli/object/class.h
@@ -0,0 +1,60 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * class.h: Object class and type management, cast checking.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MOWGLI_OBJECT_CLASS_H__
+#define __MOWGLI_OBJECT_CLASS_H__
+
+typedef void (*mowgli_destructor_t)(void *);
+
+typedef struct {
+ char *name;
+ mowgli_list_t derivitives;
+ mowgli_destructor_t destructor;
+ mowgli_boolean_t dynamic;
+ mowgli_list_t message_handlers;
+} mowgli_object_class_t;
+
+extern void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mowgli_destructor_t des, mowgli_boolean_t dynamic);
+extern int mowgli_object_class_check_cast(mowgli_object_class_t *klass1, mowgli_object_class_t *klass2);
+extern void mowgli_object_class_set_derivitive(mowgli_object_class_t *klass, mowgli_object_class_t *parent);
+extern void *mowgli_object_class_reinterpret_impl(/* mowgli_object_t */ void *object, mowgli_object_class_t *klass);
+extern mowgli_object_class_t *mowgli_object_class_find_by_name(const char *name);
+extern void mowgli_object_class_destroy(mowgli_object_class_t *klass);
+
+#define MOWGLI_REINTERPRET_CAST(object, klass) (klass *) mowgli_object_class_reinterpret_impl(object, mowgli_object_class_find_by_name( # klass ));
+
+#define mowgli_forced_cast(from_type, to_type, from, to)\
+do { \
+ union cast_union \
+ { \
+ to_type out; \
+ from_type in; \
+ } u; \
+ typedef int cant_use_union_cast[ \
+ sizeof (from_type) == sizeof (u) \
+ && sizeof (from_type) == sizeof (to_type) ? 1 : -1];\
+ u.in = from; \
+ to = u.out; \
+} while (0)
+
+#endif
diff --git a/src/libmowgli/object/message.c b/src/libmowgli/object/message.c
new file mode 100644
index 0000000..e4328c8
--- /dev/null
+++ b/src/libmowgli/object/message.c
@@ -0,0 +1,142 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * messaging.c: Object event notification and message passing.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mowgli.h"
+
+void mowgli_object_class_message_handler_attach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig)
+{
+ if (klass == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_object_class_exception);
+
+ if (sig == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception);
+
+ mowgli_node_add(sig, mowgli_node_create(), &klass->message_handlers);
+}
+
+void mowgli_object_class_message_handler_detach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig)
+{
+ mowgli_node_t *n;
+
+ if (klass == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_object_class_exception);
+
+ if (sig == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception);
+
+ n = mowgli_node_find(sig, &klass->message_handlers);
+ mowgli_node_delete(n, &klass->message_handlers);
+ mowgli_node_free(n);
+}
+
+void mowgli_object_message_handler_attach(mowgli_object_t *self, mowgli_object_message_handler_t *sig)
+{
+ if (self == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception);
+
+ if (sig == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception);
+
+ mowgli_node_add(sig, mowgli_node_create(), &self->message_handlers);
+}
+
+void mowgli_object_message_handler_detach(mowgli_object_t *self, mowgli_object_message_handler_t *sig)
+{
+ mowgli_node_t *n;
+
+ if (self == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception);
+
+ if (sig == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_signal_exception);
+
+ n = mowgli_node_find(sig, &self->message_handlers);
+ mowgli_node_delete(n, &self->message_handlers);
+ mowgli_node_free(n);
+}
+
+void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, ...)
+{
+ mowgli_argstack_t *stack;
+ mowgli_object_message_handler_t *sig = NULL;
+ mowgli_node_t *n;
+ va_list va;
+
+ if (self == NULL)
+ mowgli_throw_exception(mowgli.object_messaging.invalid_object_exception);
+
+ if (name == NULL)
+ mowgli_throw_exception(mowgli.null_pointer_exception);
+
+ /* try to find a signal to compile the argument stack from, we start with self::klass first. */
+ MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head)
+ {
+ mowgli_object_message_handler_t *sig2 = (mowgli_object_message_handler_t *) n->data;
+
+ if (!strcasecmp(sig2->name, name))
+ {
+ sig = sig2;
+ break;
+ }
+ }
+
+ if (sig == NULL)
+ {
+ MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head)
+ {
+ mowgli_object_message_handler_t *sig2 = (mowgli_object_message_handler_t *) n->data;
+
+ if (!strcasecmp(sig2->name, name))
+ {
+ sig = sig2;
+ break;
+ }
+ }
+ }
+
+ /* return if no signals found, else compile the argstack */
+ if (sig == NULL)
+ return;
+
+ va_start(va, name);
+ stack = mowgli_argstack_create_from_va_list(sig->descstr, va);
+ va_end(va);
+
+ MOWGLI_LIST_FOREACH(n, self->klass->message_handlers.head)
+ {
+ sig = (mowgli_object_message_handler_t *) n->data;
+
+ if (!strcasecmp(sig->name, name) && sig->handler != NULL)
+ sig->handler(self, sig, stack);
+ }
+
+ MOWGLI_LIST_FOREACH(n, self->message_handlers.head)
+ {
+ sig = (mowgli_object_message_handler_t *) n->data;
+
+ if (!strcasecmp(sig->name, name) && sig->handler != NULL)
+ sig->handler(self, sig, stack);
+ }
+
+ mowgli_object_unref(stack);
+}
diff --git a/src/libmowgli/object/message.h b/src/libmowgli/object/message.h
new file mode 100644
index 0000000..4a49d00
--- /dev/null
+++ b/src/libmowgli/object/message.h
@@ -0,0 +1,42 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * message.h: Object event notification and message passing.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MOWGLI_OBJECT_MESSAGING_H__
+#define __MOWGLI_OBJECT_MESSAGING_H__
+
+typedef struct mowgli_object_message_handler_ mowgli_object_message_handler_t;
+typedef void (*mowgli_object_messaging_func_t)(mowgli_object_t *self, mowgli_object_message_handler_t *sig, mowgli_argstack_t *argstack);
+
+struct mowgli_object_message_handler_ {
+ char *name;
+ char *descstr;
+ mowgli_object_messaging_func_t handler;
+};
+
+extern void mowgli_object_class_message_handler_attach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig);
+extern void mowgli_object_class_message_handler_detach(mowgli_object_class_t *klass, mowgli_object_message_handler_t *sig);
+extern void mowgli_object_message_handler_attach(mowgli_object_t *self, mowgli_object_message_handler_t *sig);
+extern void mowgli_object_message_handler_detach(mowgli_object_t *self, mowgli_object_message_handler_t *sig);
+extern void mowgli_object_message_broadcast(mowgli_object_t *self, const char *name, ...);
+
+#endif
diff --git a/src/libmowgli/object/metadata.c b/src/libmowgli/object/metadata.c
new file mode 100644
index 0000000..742e0dc
--- /dev/null
+++ b/src/libmowgli/object/metadata.c
@@ -0,0 +1,104 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * metadata.c: Object metadata.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mowgli.h"
+
+void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, void *value)
+{
+ mowgli_object_metadata_entry_t *e = NULL;
+ mowgli_node_t *n;
+
+ if (self == NULL)
+ mowgli_throw_exception(mowgli.object_metadata.invalid_object_exception);
+
+ if (key == NULL)
+ mowgli_throw_exception(mowgli.null_pointer_exception);
+
+ MOWGLI_LIST_FOREACH(n, self->metadata.head)
+ {
+ e = (mowgli_object_metadata_entry_t *) n->data;
+
+ if (!strcasecmp(e->name, key))
+ break;
+ }
+
+ if (e != NULL)
+ {
+ e->data = value;
+ return;
+ }
+
+ e = mowgli_alloc(sizeof(mowgli_object_metadata_entry_t));
+ e->name = mowgli_strdup(key);
+ e->data = value;
+
+ mowgli_node_add(e, mowgli_node_create(), &self->metadata);
+}
+
+void mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key)
+{
+ mowgli_object_metadata_entry_t *e;
+ mowgli_node_t *n, *tn;
+
+ if (self == NULL)
+ mowgli_throw_exception(mowgli.object_metadata.invalid_object_exception);
+
+ if (key == NULL)
+ mowgli_throw_exception(mowgli.null_pointer_exception);
+
+ MOWGLI_LIST_FOREACH_SAFE(n, tn, self->metadata.head)
+ {
+ e = (mowgli_object_metadata_entry_t *) n->data;
+
+ if (!strcasecmp(e->name, key))
+ {
+ mowgli_node_delete(n, &self->metadata);
+ mowgli_node_free(n);
+
+ mowgli_free(e->name);
+ mowgli_free(e);
+ }
+ }
+}
+
+void *mowgli_object_metadata_retrieve(mowgli_object_t *self, const char *key)
+{
+ mowgli_object_metadata_entry_t *e;
+ mowgli_node_t *n;
+
+ if (self == NULL)
+ mowgli_throw_exception_val(mowgli.object_metadata.invalid_object_exception, NULL);
+
+ if (key == NULL)
+ mowgli_throw_exception_val(mowgli.null_pointer_exception, NULL);
+
+ MOWGLI_LIST_FOREACH(n, self->metadata.head)
+ {
+ e = (mowgli_object_metadata_entry_t *) n->data;
+
+ if (!strcasecmp(e->name, key))
+ return e->data;
+ }
+
+ return NULL;
+}
diff --git a/src/libmowgli/object/metadata.h b/src/libmowgli/object/metadata.h
new file mode 100644
index 0000000..0cdda69
--- /dev/null
+++ b/src/libmowgli/object/metadata.h
@@ -0,0 +1,36 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * metadata.h: Object metadata.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MOWGLI_OBJECT_METADATA_H__
+#define __MOWGLI_OBJECT_METADATA_H__
+
+typedef struct {
+ char *name;
+ void *data;
+} mowgli_object_metadata_entry_t;
+
+extern void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, void *value);
+extern void mowgli_object_metadata_dissociate(mowgli_object_t *self, const char *key);
+extern void *mowgli_object_metadata_retrieve(mowgli_object_t *self, const char *key);
+
+#endif
diff --git a/src/libmowgli/object/object.c b/src/libmowgli/object/object.c
new file mode 100644
index 0000000..7b24ea7
--- /dev/null
+++ b/src/libmowgli/object/object.c
@@ -0,0 +1,164 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * object.c: Object management.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mowgli.h"
+
+/*
+ * mowgli_object_init
+ *
+ * Populates the object manager part of an object.
+ *
+ * Inputs:
+ * - pointer to object manager area
+ * - (optional) name of object
+ * - (optional) class of object
+ * - (optional) custom destructor
+ *
+ * Outputs:
+ * - none
+ *
+ * Side Effects:
+ * - none
+ */
+void mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_class_t *klass, mowgli_destructor_t des)
+{
+ return_if_fail(obj != NULL);
+
+ if (name != NULL)
+ obj->name = mowgli_strdup(name);
+
+ if (klass != NULL)
+ obj->klass = klass;
+ else
+ {
+ mowgli_object_class_t *tmp = mowgli_alloc(sizeof(mowgli_object_class_t));
+ mowgli_object_class_init(tmp, name, des, TRUE);
+ obj->klass = tmp;
+ }
+
+ obj->refcount = 1;
+
+ obj->message_handlers.head = NULL;
+ obj->message_handlers.tail = NULL;
+ obj->message_handlers.count = 0;
+
+ obj->metadata.head = NULL;
+ obj->metadata.tail = NULL;
+ obj->metadata.count = 0;
+
+ mowgli_object_message_broadcast(obj, "create");
+}
+
+/*
+ * mowgli_object_init_from_class
+ *
+ * Populates the object manager part of an object from an object class.
+ *
+ * Inputs:
+ * - pointer to object manager area
+ * - class of object
+ *
+ * Outputs:
+ * - none
+ *
+ * Side Effects:
+ * - none
+ */
+void
+mowgli_object_init_from_class(mowgli_object_t *obj, const char *name,
+ mowgli_object_class_t *klass)
+{
+ return_if_fail(obj != NULL);
+ return_if_fail(klass != NULL);
+
+ mowgli_object_init(obj, name, klass, NULL);
+}
+
+/*
+ * mowgli_object_ref
+ *
+ * Increment the reference counter on an object.
+ *
+ * Inputs:
+ * - the object to refcount
+ *
+ * Outputs:
+ * - none
+ *
+ * Side Effects:
+ * - none
+ */
+void * mowgli_object_ref(void *object)
+{
+ return_val_if_fail(object != NULL, NULL);
+
+ mowgli_object(object)->refcount++;
+
+ return object;
+}
+
+/*
+ * mowgli_object_unref
+ *
+ * Decrement the reference counter on an object.
+ *
+ * Inputs:
+ * - the object to refcount
+ *
+ * Outputs:
+ * - none
+ *
+ * Side Effects:
+ * - if the refcount is 0, the object is destroyed.
+ */
+void mowgli_object_unref(void *object)
+{
+ mowgli_object_t *obj = mowgli_object(object);
+
+ return_if_fail(object != NULL);
+
+ obj->refcount--;
+
+ if (obj->refcount <= 0)
+ {
+ mowgli_object_message_broadcast(obj, "destroy");
+
+ if (obj->name != NULL)
+ free(obj->name);
+
+ if (obj->klass != NULL)
+ {
+ mowgli_destructor_t destructor = obj->klass->destructor;
+
+ if (obj->klass->dynamic == TRUE)
+ mowgli_object_class_destroy(obj->klass);
+
+ if (destructor != NULL)
+ destructor(obj);
+ else
+ free(obj);
+ }
+ else
+ mowgli_throw_exception(mowgli.object.invalid_object_class_exception);
+ }
+}
diff --git a/src/libmowgli/object/object.h b/src/libmowgli/object/object.h
new file mode 100644
index 0000000..0f13ce1
--- /dev/null
+++ b/src/libmowgli/object/object.h
@@ -0,0 +1,42 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * object.h: Object management.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MOWGLI_OBJECT_H__
+#define __MOWGLI_OBJECT_H__
+
+typedef struct {
+ char *name;
+ int refcount;
+ mowgli_object_class_t *klass;
+ mowgli_list_t message_handlers;
+ mowgli_list_t metadata;
+} mowgli_object_t;
+
+extern void mowgli_object_init(mowgli_object_t *, const char *name, mowgli_object_class_t *klass, mowgli_destructor_t destructor);
+extern void mowgli_object_init_from_class(mowgli_object_t *, const char *, mowgli_object_class_t *klass);
+extern void *mowgli_object_ref(void *);
+extern void mowgli_object_unref(void *);
+
+#define mowgli_object(x) ((mowgli_object_t *) x)
+
+#endif