From: Nick Bowler Date: Mon, 21 May 2012 01:34:42 +0000 (-0400) Subject: uobject: Make module loader understand exports/imports. X-Git-Url: http://git.draconx.ca/gitweb/upkg.git/commitdiff_plain/d78fbc3a4f4bdef475f85b0c1ebeaddd74cce141 uobject: Make module loader understand exports/imports. It's possible for a package to have an instance of a class defined in that same package; therefore the module loader needs to know about this. Bring the export class index up to the public struct so that it's possible to tell the difference. This makes it possible to export the textures defined in Engine.u. There's still a few vestigial bugs left over here, but we can fix those later. --- diff --git a/src/libupkg.c b/src/libupkg.c index f1424e8..d4978a3 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -46,7 +46,7 @@ struct upkg_name { struct upkg_export_priv { struct upkg_export pub; - long class, super; + long super; unsigned long size, offset; }; @@ -282,7 +282,7 @@ static int pkg_init_exports(struct upkg_priv *pkg) } len = 0; - rc = upkg_decode_index(&export->class, buf+len, nbuf-len); + rc = upkg_decode_index(&export->pub.class, buf+len, nbuf-len); if (rc == 0) goto err; len += rc; @@ -556,15 +556,15 @@ const char *upkg_export_class(struct upkg *pub, unsigned long idx, export = &pkg->exports[idx]; /* Assumption: class references are always imports. */ - format_assert(export->class <= 0, return NULL); + format_assert(export->pub.class <= 0, return NULL); /* Get the class. */ - if (export->class == 0) { + if (export->pub.class == 0) { if (package) *package = "Core"; return "Class"; } - pkg_idx = -(export->class + 1); + pkg_idx = -(export->pub.class + 1); if (pkg_idx >= pkg->pub.import_count) return NULL; iclass = &pkg->imports[pkg_idx]; diff --git a/src/uobject/module.c b/src/uobject/module.c index 88748a0..057d1d0 100644 --- a/src/uobject/module.c +++ b/src/uobject/module.c @@ -24,7 +24,9 @@ #include #include +#include #include +#include #include "avl.h" static unsigned initialized; @@ -75,32 +77,109 @@ int u_object_module_exit(void) return 0; } -GType u_object_module_get_class(const char *package, const char *class) +static int lookup_module(GTypeModule **out, const char *name) { - char buf[strlen(package) + strlen(class) + 1]; - GTypeModule search = { .name = str_cpy_lower(buf, package) }; + struct { GTypeModule pkg; char buf[]; } *search_key; + GTypeModule *result; - GTypeModule *mod = avl_find(package_tree, &search); - if (!mod) { + search_key = malloc(sizeof *search_key + strlen(name) + 1); + if (!search_key) + return -1; + + search_key->pkg = (GTypeModule) { + .name = str_cpy_lower(search_key->buf, name), + }; + + result = avl_find(package_tree, search_key); + free(search_key); + + *out = result; + return 0; +} + +GTypeModule * +u_module_get_from_import(GTypeModule *pkg, const struct upkg_import *i) +{ + GTypeModule *result; + + while (i->parent != NULL) + i = i->parent; + + if (strcmp(i->class_package, "Core") != 0 + || strcmp(i->class_name, "Package") != 0) { + u_err(pkg, "import root must be an instance of Core.Package"); + return NULL; + } + + if (lookup_module(&result, i->name) != 0) { + u_err(pkg, "fatal error performing package lookup"); + return NULL; + } + + if (!result) { void **p; - mod = u_pkg_open(package); - if (!mod) { - return 0; + result = u_pkg_open(i->name); + if (!result) { + u_warn(pkg, "failed to open package: %s", i->name); + return NULL; } - p = avl_probe(package_tree, mod); + p = avl_probe(package_tree, result); if (!p) { - g_object_unref(mod); + u_err(pkg, "fatal error inserting package"); + g_object_unref(result); + return NULL; + } + } + + return result; +} + +GType u_object_module_get_class(GTypeModule *pkg, long class) +{ + GTypeModule *mod; + const char *classname; + + if (class == 0) { + u_warn(pkg, "class implementations not supported yet"); + return 0; + } else if (class < 0) { + const struct upkg_import *import; + + import = upkg_get_import(U_PKG(pkg)->pkg, -(class+1)); + if (!import) { + u_err(pkg, "invalid package import: %ld", -(class+1)); return 0; } + + mod = u_module_get_from_import(pkg, import); + if (!mod) + return 0; + + classname = import->name; + } else if (class > 0) { + const struct upkg_export *export; + + export = upkg_get_export(U_PKG(pkg)->pkg, class-1); + if (!export) { + u_err(pkg, "invalid package export: %ld", class-1); + return 0; + } + + mod = pkg; + classname = export->name; } if (!g_type_module_use(mod)) return 0; - str_cpy_lower(buf+strlen(package), class); - buf[0] = toupper(buf[0]); - buf[strlen(package)] = toupper(buf[strlen(package)]); - return g_type_from_name(buf); + /* XXX: Do this better. */ + char typename[strlen(mod->name) + strlen(classname) + 1]; + str_cpy_lower(typename, mod->name); + str_cpy_lower(typename+strlen(mod->name), classname); + typename[0] = toupper(typename[0]); + typename[strlen(mod->name)] = toupper(typename[strlen(mod->name)]); + + return g_type_from_name(typename); } diff --git a/src/uobject/module.h b/src/uobject/module.h index 2803526..e4fd5a6 100644 --- a/src/uobject/module.h +++ b/src/uobject/module.h @@ -35,12 +35,13 @@ int u_object_module_init(void); int u_object_module_exit(void); /* - * Get a class handle from the UObject module system. This will load the - * appropriate shared object if necessary. The resulting handle can then be - * used to create instances of the class with g_object_new. + * Get a class handle from the UObject module system, where class is an + * object reference for the class within the provided package. This will load + * the appropriate shared object if necessary. The resulting handle can then + * be used to create instances of the class with g_object_new. * * Returns 0 on failure. */ -GType u_object_module_get_class(const char *package, const char *class); +GType u_object_module_get_class(GTypeModule *pkg, long class); #endif diff --git a/src/uobject/uobject.c b/src/uobject/uobject.c index 360dd31..9c5bfa1 100644 --- a/src/uobject/uobject.c +++ b/src/uobject/uobject.c @@ -524,15 +524,17 @@ GObject *u_object_new_from_package(GTypeModule *pkg, unsigned long idx) { g_return_val_if_fail(IS_U_PKG(pkg), NULL); - const char *class, *package; + const struct upkg_export *export; GObject *obj = NULL; GType type; - class = upkg_export_class(U_PKG(pkg)->pkg, idx, &package); - if (!class) + export = upkg_get_export(U_PKG(pkg)->pkg, idx); + if (!export) { + u_err(pkg, "invalid package export: %lu", idx); return NULL; + } - type = u_object_module_get_class(package, class); + type = u_object_module_get_class(pkg, export->class); if (type) { obj = g_object_new(type, NULL); if (u_object_deserialize(obj, pkg, idx) != 0) { diff --git a/src/upkg.h b/src/upkg.h index e4e5dcd..d236714 100644 --- a/src/upkg.h +++ b/src/upkg.h @@ -82,6 +82,7 @@ struct upkg_export { const char *name; unsigned long flags; + long class; }; struct upkg_import {