]> git.draconx.ca Git - upkg.git/commitdiff
package: Add initial support for package search.
authorNick Bowler <nbowler@draconx.ca>
Tue, 15 Sep 2009 02:43:49 +0000 (22:43 -0400)
committerNick Bowler <nbowler@draconx.ca>
Tue, 15 Sep 2009 02:43:49 +0000 (22:43 -0400)
src/package.c
src/uobject/package.h

index afa1272416f6d564d62e46d82a049bc4ef7cd37b..cbbaf09dd71efbcd6e0fb247cb78001e49e508c9 100644 (file)
 
 struct upkg_priv {
        lt_dlhandle native;
+       FILE *pkg_file;
 };
 
 G_DEFINE_TYPE(UPkg, u_pkg, G_TYPE_TYPE_MODULE);
 
+/* Package search path. */
+static char  *search_path;
+static size_t search_path_sz;
+
+/* List of package file extensions, in descending order of precedence. */
+static const char u_pkg_exts[][5] = { ".u", ".utx", ".umx", ".uax", ".unr" };
+
 static char *str_cpy_lower(char *dst, const char *src)
 {
        size_t i;
@@ -46,6 +54,25 @@ static char *str_cpy_lower(char *dst, const char *src)
        return dst;
 }
 
+static int str_cmp_lower(const char *s1, const char *s2)
+{
+       size_t i;
+
+       for (i = 0; s1[i] && s2[i]; i++) {
+               int c1 = tolower(s1[i]), c2 = tolower(s2[i]);
+               if (c1 < c2)
+                       return -1;
+               if (c1 > c2)
+                       return 1;
+       }
+
+       if (s1[i])
+               return 1;
+       if (s2[i])
+               return -1;
+       return 0;
+}
+
 static void dl_print_errors(const char *prefix)
 {
        const char *err;
@@ -55,6 +82,50 @@ 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.
+ */
+static int find_package_by_name(const char *filename, void *_pkg)
+{
+       struct upkg_priv *priv = U_PKG_GET_PRIV(_pkg);
+       GTypeModule *m = _pkg;
+
+       const char *base;
+       size_t len;
+       char *buf;
+
+       base = strrchr(filename, '/');
+       if (base) {
+               base++;
+       } else {
+               base = filename;
+       }
+
+       if (str_cmp_lower(base, m->name) != 0)
+               return 0;
+
+       len = strlen(filename);
+       buf = malloc(len + sizeof **u_pkg_exts);
+       if (!buf)
+               return 0;
+       strcpy(buf, filename);
+
+       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) {
+                       free(buf);
+                       return 1;
+               }
+       }
+
+       free(buf);
+       return 0;
+}
+
 static gboolean u_pkg_load(GTypeModule *m)
 {
        struct upkg_priv *priv = U_PKG_GET_PRIV(m);
@@ -73,6 +144,8 @@ static gboolean u_pkg_load(GTypeModule *m)
                return FALSE;
        }
 
+       lt_dlforeachfile(u_pkg_get_search_path(), find_package_by_name, m);
+
        return TRUE;
 }
 
@@ -91,6 +164,10 @@ static void u_pkg_unload(GTypeModule *m)
                        dl_print_errors(__func__);
                }
        }
+
+       if (priv->pkg_file) {
+               fclose(priv->pkg_file);
+       }
 }
 
 static void u_pkg_init(UPkg *pkg)
@@ -120,6 +197,55 @@ static void u_pkg_class_init(UPkgClass *class)
        modclass->unload = u_pkg_unload;
 }
 
+static int expand_search_path(size_t need)
+{
+       size_t want = search_path_sz;
+       if (want == 0) want = 1;
+
+       while (want < need)
+               want *= 2;
+
+       if (want > search_path_sz) {
+               char *new = realloc(search_path, want);
+               if (!new) {
+                       return -1;
+               }
+
+               search_path    = new;
+               search_path_sz = want;
+       }
+
+       return 0;
+}
+
+const char *u_pkg_get_search_path(void)
+{
+       return search_path ? search_path : "";
+}
+
+int u_pkg_set_search_path(const char *path)
+{
+       if (expand_search_path(strlen(path)+1) != 0)
+               return -1;
+       strcpy(search_path, path);
+       return 0;
+}
+
+int u_pkg_add_search_dir(const char *path)
+{
+       size_t end = search_path ? strlen(search_path) : 0;
+
+       if (end == 0) {
+               return u_pkg_set_search_path(path);
+       }
+
+       if (expand_search_path(end + strlen(path) + 2) != 0)
+               return -1;
+       search_path[end] = LT_PATHSEP_CHAR;
+       strcpy(search_path+end+1, path);
+       return 0;
+}
+
 GTypeModule *u_pkg_new(const char *name)
 {
        g_return_val_if_fail(name != NULL, NULL);
index e8cb4a8c2b951201e88e5dc9751c2bf59e4e5ae1..697abd24fcdcafbacdcd1a34fc3bcf81a858171d 100644 (file)
@@ -47,4 +47,8 @@ struct UPkgClass {
 GType u_pkg_get_type(void);
 GTypeModule *u_pkg_new(const char *name);
 
+const char *u_pkg_get_search_path(void);
+int u_pkg_set_search_path(const char *path);
+int u_pkg_add_search_dir(const char *path);
+
 #endif