X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/blobdiff_plain/90b53df329f9a114770dccab6b7e41f9094dfac9..e4d0c035db32adb640129d8b4897bd95789318c7:/src/module.c diff --git a/src/module.c b/src/module.c index f97bc65..025d600 100644 --- a/src/module.c +++ b/src/module.c @@ -6,10 +6,23 @@ #include #include "module.h" - -G_DEFINE_TYPE(UPkgModule, upkg_module, G_TYPE_TYPE_MODULE); +#include "avl.h" static unsigned initialized; +static struct avl_table *package_tree; + +static char *str_cpy_lower(char *dst, const char *src) +{ + size_t i; + + for (i = 0; src[i]; i++) + dst[i] = tolower(src[i]); + dst[i] = 0; + + return dst; +} + +G_DEFINE_TYPE(UPkgModule, upkg_module, G_TYPE_TYPE_MODULE); static void dl_print_errors(const char *prefix) { @@ -65,14 +78,12 @@ static void upkg_module_class_init(UPkgModuleClass *class) UPkgModule *upkg_module_new(const char *name) { char *name2; - size_t len; if (!name) { return NULL; } - len = strlen(name); - name2 = malloc(len+1); + name2 = malloc(strlen(name)+1); if (!name2) { return NULL; } @@ -83,19 +94,29 @@ UPkgModule *upkg_module_new(const char *name) return NULL; } - G_TYPE_MODULE(mod)->name = name2; - for (size_t i = 0; i < len; i++) { - name2[i] = tolower(name[i]); - } - name2[len] = 0; - + G_TYPE_MODULE(mod)->name = str_cpy_lower(name2, name); return mod; } +static int modcmp(const void *a, const void *b, void *_data) +{ + GTypeModule *ma = G_TYPE_MODULE(a); + GTypeModule *mb = G_TYPE_MODULE(b); + + return strcmp(ma->name, mb->name); +} + int module_init(void) { if (!initialized) { + package_tree = avl_create(modcmp, 0, &avl_allocator_default); + if (!package_tree) { + fprintf(stderr, "%s: failed to create package tree.\n", __func__); + return -1; + } + if (lt_dlinit() != 0) { + avl_destroy(package_tree, NULL); dl_print_errors(__func__); return -1; } @@ -117,3 +138,33 @@ int module_exit(void) return -1; } } + +GType module_get_class(const char *package, const char *class) +{ + char buf[strlen(package) + strlen(class) + 1]; + GTypeModule search = { .name = str_cpy_lower(buf, package) }; + + GTypeModule *mod = avl_find(package_tree, &search); + if (!mod) { + void **p; + + mod = G_TYPE_MODULE(upkg_module_new(package)); + if (!mod) { + return 0; + } + + p = avl_probe(package_tree, mod); + if (!p) { + g_object_unref(mod); + return 0; + } + } + + 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); +}