]> git.draconx.ca Git - upkg.git/blobdiff - src/uobject/module.c
uobject: Make module loader understand exports/imports.
[upkg.git] / src / uobject / module.c
index 88748a02f20f0e24eb440519a522fbb9fb8f35e3..057d1d0080ee23d685baf05113862208a8cace3d 100644 (file)
@@ -24,7 +24,9 @@
 #include <ltdl.h>
 
 #include <uobject/module.h>
+#include <uobject/uobject.h>
 #include <uobject/package.h>
+#include <upkg.h>
 #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);
 }