]> git.draconx.ca Git - upkg.git/commitdiff
package: Get rid of separate mechanisms for opening packages.
authorNick Bowler <nbowler@draconx.ca>
Mon, 7 Dec 2009 08:01:06 +0000 (03:01 -0500)
committerNick Bowler <nbowler@draconx.ca>
Mon, 7 Dec 2009 08:01:06 +0000 (03:01 -0500)
Remove u_pkg_new_by_name and u_pkg_new_by_file, replacing them with
one function, u_pkg_open, that takes just a package name.  Named files
can now be part of the package search just like any other package.  This
should allow cool things like listing dependency packages on the upkg
command line.

m4/.gitignore
m4/gnulib-cache.m4
src/uobject/Makefile.inc
src/uobject/module.c
src/uobject/package.c
src/uobject/package.h
src/uobject/vfs.c [new file with mode: 0644]
src/uobject/vfs.h [new file with mode: 0644]
src/upkg.c

index 222b4c65997acacd14e66e9271f759151e6e352b..e413b24a1cfcdc853929adf0e0d005c9bcc4f7c6 100644 (file)
@@ -13,5 +13,7 @@ gnulib-comp.m4
 gnulib-tool.m4
 include_next.m4
 stddef_h.m4
+strcase.m4
+strings_h.m4
 unistd_h.m4
 wchar_t.m4
index 0f97c570e8a82daa2d00e83a12c585a198f6fa55..7cb7a29e975138de7c32e8f4e4d0990a167610a3 100644 (file)
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --libtool --macro-prefix=gl --no-vc-files getopt-gnu
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --libtool --macro-prefix=gl --no-vc-files getopt-gnu strcase
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([])
 gl_MODULES([
   getopt-gnu
+  strcase
 ])
 gl_AVOID([])
 gl_SOURCE_BASE([lib])
index 7c42e97ce045309066f50ca01d968f0654cb46ba..2009d09f28293950c73b7c60eb445233c25d4c92 100644 (file)
@@ -12,8 +12,9 @@ uobject_HEADERS = uobject/uobject.h uobject/exportable.h uobject/loadable.h \
 noinst_HEADERS += uobject/avl.h
 
 libuobject_la_SOURCES  = uobject/uobject.c uobject/module.c uobject/avl.c \
-       uobject/package.c uobject/loadable.c uobject/exportable.c
+       uobject/package.c uobject/loadable.c uobject/exportable.c \
+       uobject/vfs.c
 libuobject_la_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(LTDLINCL) \
        -DPKGLIBDIR=\"$(pkglibdir)\" -DPKGDATADIR=\"$(pkgdatadir)\"
 libuobject_la_LDFLAGS  = $(AM_LDFLAGS) -export-symbols-regex '^u_'
-libuobject_la_LIBADD   = $(LIBLTDL) $(GLIB_LIBS)
+libuobject_la_LIBADD   = $(LIBLTDL) $(GLIB_LIBS) -lgnu
index 1872a8debdd799b37bb0d62a8e3dd0c95923ba13..2fa44023b9f6db8ffa14b7a7cf552f89eb5e1080 100644 (file)
@@ -84,7 +84,7 @@ GType u_object_module_get_class(const char *package, const char *class)
        if (!mod) {
                void **p;
 
-               mod = u_pkg_new_by_name(package);
+               mod = u_pkg_open(package);
                if (!mod) {
                        return 0;
                }
index bd9713500392cb504ac5d3d19f250f75e37051ef..af4ebb3f929cd82c7f6441f9bc8f8d78029fcd06 100644 (file)
@@ -25,6 +25,7 @@
 #include <ltdl.h>
 
 #include <uobject/package.h>
+#include <uobject/vfs.h>
 #include "upkg.h"
 
 #define U_PKG_GET_PRIV(o) \
@@ -82,74 +83,31 @@ 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 class member
- * will be filled in.
- */
-static int find_package_by_name(const char *filename, void *data)
-{
-       GTypeModule *m = G_TYPE_MODULE(data);
-       UPkg *upkg = U_PKG(data);
-
-       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]);
-               upkg->pkg = upkg_fopen(buf);
-               if (!upkg->pkg) {
-                       free(buf);
-                       return 1;
-               }
-       }
-
-       free(buf);
-       return 0;
-}
-
 static gboolean u_pkg_load(GTypeModule *m)
 {
        struct upkg_priv *priv = U_PKG_GET_PRIV(m);
        int (*init_func)(GTypeModule *);
+       const char *file;
 
-       if (m->name) {
-               priv->native = lt_dlopenext(m->name);
-               if (!priv->native) {
-                       dl_print_errors(m->name);
+       file = u_pkg_vfs_lookup(m->name);
+       if (file) {
+               U_PKG(m)->pkg = upkg_fopen(file);
+               if (!U_PKG(m)->pkg) {
                        return FALSE;
                }
+       }
 
+       priv->native = lt_dlopenext(m->name);
+       if (priv->native) {
                init_func = lt_dlsym(priv->native, "init");
                if (!init_func || init_func(m) != 0) {
                        dl_print_errors(__func__);
                        lt_dlclose(priv->native);
+                       upkg_close(U_PKG(m)->pkg);
                        return FALSE;
                }
        }
 
-       if (!U_PKG(m)->pkg) {
-               lt_dlforeachfile(u_pkg_get_search_path(), find_package_by_name, m);
-       }
-
        return TRUE;
 }
 
@@ -168,6 +126,8 @@ static void u_pkg_unload(GTypeModule *m)
                if (lt_dlclose(priv->native) != 0) {
                        dl_print_errors(__func__);
                }
+
+               priv->native = NULL;
        }
 
        if (upkg->pkg) {
@@ -183,11 +143,7 @@ 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);
-       }
+       u_pkg_unload(G_TYPE_MODULE(o));
 }
 
 static void u_pkg_class_init(UPkgClass *class)
@@ -264,7 +220,7 @@ int u_pkg_add_search_dir(const char *path)
        return 0;
 }
 
-GTypeModule *u_pkg_new_by_name(const char *name)
+GTypeModule *u_pkg_open(const char *name)
 {
        g_return_val_if_fail(name != NULL, NULL);
 
@@ -282,21 +238,3 @@ GTypeModule *u_pkg_new_by_name(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;
-}
index 5e60a18d3467fc0bdb68d46b9ce60f194ba6cd03..03d9b01c78ef0a81bba0e5867890f1febf82f75a 100644 (file)
@@ -46,8 +46,7 @@ struct UPkgClass {
 };
 
 GType u_pkg_get_type(void);
-GTypeModule *u_pkg_new_by_name(const char *name);
-GTypeModule *u_pkg_new_by_file(const char *filename);
+GTypeModule *u_pkg_open(const char *name);
 
 const char *u_pkg_get_search_path(void);
 int u_pkg_set_search_path(const char *path);
diff --git a/src/uobject/vfs.c b/src/uobject/vfs.c
new file mode 100644 (file)
index 0000000..5465144
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *  Functions for handling UObject package search paths.
+ *  Copyright (C) 2009 Nick Bowler
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include <uobject/vfs.h>
+#include <ltdl.h>
+
+#include "avl.h"
+
+/* Check if a character is a directory separator. */
+#ifdef LT_DIRSEP_CHAR
+#      define IS_DIRSEP(x) ((x) == '/' || (x) == LT_DIRSEP_CHAR)
+#else
+#      define IS_DIRSEP(x) ((x) == '/')
+#endif
+
+struct local_pkg {
+       char *file, *name;
+};
+
+static struct avl_table *local_tree;
+static int initialized;
+
+static int localcmp(const void *_a, const void *_b, void *_data)
+{
+       const struct local_pkg *a = _a, *b = _b;
+       return strcasecmp(a->name, b->name);
+}
+
+static const char *pkgname_base(const char *file)
+{
+       const char *base = NULL;
+       int slash = 1;
+
+       for (size_t i = 0; file[i]; i++) {
+               if (IS_DIRSEP(file[i])) {
+                       slash = 1;
+               } else if (slash == 1) {
+                       base = file+i;
+                       slash = 0;
+               }
+       }
+
+       return base;
+}
+
+static size_t pkgname_len(const char *base)
+{
+       size_t i;
+
+       for (i = 0; base[i]; i++) {
+               if (IS_DIRSEP(base[i]) || base[i] == '.')
+                       break;
+       }
+
+       return i;
+}
+
+const char *u_pkg_vfs_add_local(const char *name, const char *file)
+{
+       size_t filelen = strlen(file)+1, namelen;
+       struct local_pkg *spec;
+
+       if (!name)
+               name = pkgname_base(file);
+       if (!name)
+               return NULL;
+       namelen = pkgname_len(name);
+
+       /* For simplicity, stuff everything in a single allocation. */
+       spec = malloc(sizeof *spec + filelen + namelen + 1);
+       if (!spec) {
+               return NULL;
+       }
+
+       spec->file = (char *)spec + sizeof *spec;
+       memcpy(spec->file, file, filelen);
+
+       spec->name = (char *)spec + sizeof *spec + filelen;
+       memcpy(spec->name, name, namelen);
+       spec->name[namelen] = 0;
+
+       if (avl_find(local_tree, spec)) {
+               fprintf(stderr, "%s: attempted to add duplicate local package.\n", __func__);
+               name = spec->name;
+               free(spec);
+               return name; /* "Success"-ish. */
+       }
+
+       if (avl_probe(local_tree, spec) == NULL) {
+               free(spec);
+               return NULL;
+       }
+
+       return spec->name;
+}
+
+void u_pkg_vfs_del_local(const char *name)
+{
+       struct local_pkg spec = { .name = (char *)name }, *item;
+
+       item = avl_find(local_tree, &spec);
+       free(item);
+}
+
+const char *u_pkg_vfs_lookup(const char *name)
+{
+       struct local_pkg spec = { .name = (char *)name }, *item;
+
+       if (!local_tree)
+               return NULL;
+
+       item = avl_find(local_tree, &spec);
+       if (!item)
+               return NULL;
+       return item->file;
+}
+
+int u_pkg_vfs_init(void)
+{
+       if (!initialized) {
+               local_tree = avl_create(localcmp, NULL, NULL);
+               if (!local_tree) {
+                       fprintf(stderr, "%s: failed to create local module tree.\n", __func__);
+                       return -1;
+               }
+       }
+
+       initialized++;
+       return 0;
+}
+
+static void local_destroy(void *item, void *data)
+{
+       free(item);
+}
+
+void u_pkg_vfs_exit(void)
+{
+       if (--initialized == 0)
+               avl_destroy(local_tree, local_destroy);
+}
diff --git a/src/uobject/vfs.h b/src/uobject/vfs.h
new file mode 100644 (file)
index 0000000..d986aec
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  Functions for handling UObject package search paths.
+ *  Copyright (C) 2009 Nick Bowler
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef U_OBJECT_VFS_H_
+#define U_OBJECT_VFS_H_
+
+/*
+ * Insert a local package to the VFS.  A "local package" is an explicit
+ * association of a name to a file, and thus can be located outside the normal
+ * search path.  Local packages are searched before any other location.
+ *
+ * Returns a pointer to an internal copy of name on success, or NULL on
+ * failure.  The returned name must not be modified or freed.  If name is
+ * NULL, it is determined automatically from the filename.
+ */
+const char *u_pkg_vfs_add_local(const char *name, const char *file);
+
+/*
+ * Remove a local package from the VFS by name.
+ */
+void u_pkg_vfs_del_local(const char *name);
+
+/*
+ * Find a package by name in the VFS.  Names are case-insensitive.
+ */
+const char *u_pkg_vfs_lookup(const char *name);
+
+/*
+ * Initialize the UObject VFS system.  Returns 0 on success, -1 otherwise.
+ * The VFS system can be safely initialized multiple times.
+ */
+int u_pkg_vfs_init(void);
+
+/*
+ * Shutdown the UObject VFS system.
+ * The VFS system is only shut down when this function has been called as
+ * many times as u_pkg_vfs_init.
+ */
+void u_pkg_vfs_exit(void);
+
+#endif
index 2c268b4c5cdafb97fcc6894b5539f9fbcc1d6ef9..d3a946b2fada97e2f3f649c25a89f5af0bbdcfa5 100644 (file)
@@ -29,6 +29,7 @@
 #include <uobject/loadable.h>
 #include <uobject/module.h>
 #include <uobject/package.h>
+#include <uobject/vfs.h>
 
 enum {
        MODE_INFO,
@@ -286,7 +287,8 @@ int package_export(struct upkg *pkg)
 
 int main(int argc, char **argv)
 {
-       UPkg *upkg;
+       GTypeModule *pkg;
+       const char *pkgname;
        unsigned mode = MODE_INFO;
        int opt, rc = EXIT_FAILURE;
 
@@ -320,25 +322,39 @@ int main(int argc, char **argv)
                return EXIT_FAILURE;
        }
 
+       if (u_pkg_vfs_init() != 0)
+               return EXIT_FAILURE;
        if (u_object_module_init() != 0)
                return EXIT_FAILURE;
 
-       upkg = U_PKG(u_pkg_new_by_file(argv[optind]));
-       if (!upkg) {
+       pkgname = u_pkg_vfs_add_local(NULL, argv[optind]);
+       if (!pkgname) {
+               fprintf(stderr, "failed to add package `%s'.\n", argv[optind]);
+               return EXIT_FAILURE;
+       }
+
+       pkg = u_pkg_open(pkgname);
+       if (!pkg) {
                fprintf(stderr, "failed to open package!\n");
                return EXIT_FAILURE;
        }
 
+       if (!g_type_module_use(pkg)) {
+               fprintf(stderr, "failed to load package: %s\n", pkg->name);
+               return EXIT_FAILURE;
+       }
+
        switch (mode) {
        case MODE_INFO:
-               rc = package_info(upkg->pkg);
+               rc = package_info(U_PKG(pkg)->pkg);
                break;
        case MODE_EXPORT:
-               rc = package_export(upkg->pkg);
+               rc = package_export(U_PKG(pkg)->pkg);
                break;
        }
 
-       g_object_unref(upkg);
+       g_object_unref(pkg);
        u_object_module_exit();
+       u_pkg_vfs_exit();
        return rc;
 }