]> git.draconx.ca Git - upkg.git/blobdiff - src/package.c
package: Allow opening by filename in addition to package name.
[upkg.git] / src / package.c
index cbbaf09dd71efbcd6e0fb247cb78001e49e508c9..bd9713500392cb504ac5d3d19f250f75e37051ef 100644 (file)
 #include <ltdl.h>
 
 #include <uobject/package.h>
+#include "upkg.h"
 
 #define U_PKG_GET_PRIV(o) \
        G_TYPE_INSTANCE_GET_PRIVATE(o, U_PKG_TYPE, struct upkg_priv)
 
 struct upkg_priv {
        lt_dlhandle native;
-       FILE *pkg_file;
 };
 
 G_DEFINE_TYPE(UPkg, u_pkg, G_TYPE_TYPE_MODULE);
@@ -85,13 +85,13 @@ static void dl_print_errors(const char *prefix)
 /*
  * Function for use with lt_dlforeachfile.  The user data must point to
  * a UPkg with the GTypeModule name field initialized.  If a suitable file
- * is found and could be successfully opened for reading, the pkg_file member
- * of struct upkg_priv will be filled in.
+ * is found and could be successfully opened for reading, the pkg class member
+ * will be filled in.
  */
-static int find_package_by_name(const char *filename, void *_pkg)
+static int find_package_by_name(const char *filename, void *data)
 {
-       struct upkg_priv *priv = U_PKG_GET_PRIV(_pkg);
-       GTypeModule *m = _pkg;
+       GTypeModule *m = G_TYPE_MODULE(data);
+       UPkg *upkg = U_PKG(data);
 
        const char *base;
        size_t len;
@@ -115,8 +115,8 @@ static int find_package_by_name(const char *filename, void *_pkg)
 
        for (unsigned i = 0; i < sizeof u_pkg_exts / sizeof *u_pkg_exts; i++) {
                strcpy(buf+len, u_pkg_exts[i]);
-               priv->pkg_file = fopen(buf, "rb");
-               if (priv->pkg_file) {
+               upkg->pkg = upkg_fopen(buf);
+               if (!upkg->pkg) {
                        free(buf);
                        return 1;
                }
@@ -131,20 +131,24 @@ static gboolean u_pkg_load(GTypeModule *m)
        struct upkg_priv *priv = U_PKG_GET_PRIV(m);
        int (*init_func)(GTypeModule *);
 
-       priv->native = lt_dlopenext(m->name);
-       if (!priv->native) {
-               dl_print_errors(m->name);
-               return FALSE;
-       }
+       if (m->name) {
+               priv->native = lt_dlopenext(m->name);
+               if (!priv->native) {
+                       dl_print_errors(m->name);
+                       return FALSE;
+               }
 
-       init_func = lt_dlsym(priv->native, "init");
-       if (!init_func || init_func(m) != 0) {
-               dl_print_errors(__func__);
-               lt_dlclose(priv->native);
-               return FALSE;
+               init_func = lt_dlsym(priv->native, "init");
+               if (!init_func || init_func(m) != 0) {
+                       dl_print_errors(__func__);
+                       lt_dlclose(priv->native);
+                       return FALSE;
+               }
        }
 
-       lt_dlforeachfile(u_pkg_get_search_path(), find_package_by_name, m);
+       if (!U_PKG(m)->pkg) {
+               lt_dlforeachfile(u_pkg_get_search_path(), find_package_by_name, m);
+       }
 
        return TRUE;
 }
@@ -153,6 +157,7 @@ static void u_pkg_unload(GTypeModule *m)
 {
        struct upkg_priv *priv = U_PKG_GET_PRIV(m);
        void (*exit_func)(GTypeModule *);
+       UPkg *upkg = U_PKG(m);
 
        if (priv->native) {
                exit_func = lt_dlsym(priv->native, "exit");
@@ -165,8 +170,9 @@ static void u_pkg_unload(GTypeModule *m)
                }
        }
 
-       if (priv->pkg_file) {
-               fclose(priv->pkg_file);
+       if (upkg->pkg) {
+               upkg_close(upkg->pkg);
+               upkg->pkg = NULL;
        }
 }
 
@@ -175,9 +181,20 @@ static void u_pkg_init(UPkg *pkg)
 
 }
 
+static void u_pkg_finalize(GObject *o)
+{
+       UPkg *upkg = U_PKG(o);
+
+       if (upkg->pkg) {
+               upkg_close(upkg->pkg);
+       }
+}
+
 static void u_pkg_class_init(UPkgClass *class)
 {
        GTypeModuleClass *modclass = G_TYPE_MODULE_CLASS(class);
+       GObjectClass *objclass = G_OBJECT_CLASS(class);
+
        const char *modpath = getenv("UOBJECT_MODULE_PATH");
 
        g_type_class_add_private(class, sizeof (struct upkg_priv));
@@ -193,8 +210,9 @@ static void u_pkg_class_init(UPkgClass *class)
                dl_print_errors(__func__);
        }
 
-       modclass->load   = u_pkg_load;
-       modclass->unload = u_pkg_unload;
+       modclass->load     = u_pkg_load;
+       modclass->unload   = u_pkg_unload;
+       objclass->finalize = u_pkg_finalize;
 }
 
 static int expand_search_path(size_t need)
@@ -246,7 +264,7 @@ int u_pkg_add_search_dir(const char *path)
        return 0;
 }
 
-GTypeModule *u_pkg_new(const char *name)
+GTypeModule *u_pkg_new_by_name(const char *name)
 {
        g_return_val_if_fail(name != NULL, NULL);
 
@@ -264,3 +282,21 @@ GTypeModule *u_pkg_new(const char *name)
        mod->name = str_cpy_lower(pkgname, name);
        return mod;
 }
+
+GTypeModule *u_pkg_new_by_file(const char *filename)
+{
+       struct upkg *pkg = upkg_fopen(filename);
+       if (!pkg) {
+               return NULL;
+       }
+
+       GTypeModule *mod = g_object_new(U_PKG_TYPE, NULL);
+       if (!mod) {
+               upkg_close(pkg);
+               return NULL;
+       }
+
+       mod->name = NULL;
+       U_PKG(mod)->pkg = pkg;
+       return mod;
+}