From: Nick Bowler Date: Tue, 8 Dec 2009 05:58:38 +0000 (-0500) Subject: package: Move package search code to the VFS. X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/commitdiff_plain/b228d2b354248b62d70a582a37693cff829fe0c6 package: Move package search code to the VFS. --- diff --git a/src/uobject/package.c b/src/uobject/package.c index 2da23b3..397d263 100644 --- a/src/uobject/package.c +++ b/src/uobject/package.c @@ -37,13 +37,6 @@ struct upkg_priv { 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; @@ -55,25 +48,6 @@ 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; @@ -165,55 +139,6 @@ static void u_pkg_class_init(UPkgClass *class) objclass->finalize = u_pkg_finalize; } -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_open(const char *name) { g_return_val_if_fail(name != NULL, NULL); diff --git a/src/uobject/package.h b/src/uobject/package.h index 03d9b01..32f76b8 100644 --- a/src/uobject/package.h +++ b/src/uobject/package.h @@ -48,8 +48,4 @@ struct UPkgClass { GType u_pkg_get_type(void); GTypeModule *u_pkg_open(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 diff --git a/src/uobject/vfs.c b/src/uobject/vfs.c index fcbb3e5..8afb49b 100644 --- a/src/uobject/vfs.c +++ b/src/uobject/vfs.c @@ -35,12 +35,21 @@ # define IS_DIRSEP(x) ((x) == '/') #endif +/* Number of times the library has been initialized. */ +static int initialized; + +/* Local package definitions. */ struct local_pkg { char *file, *name; }; - static struct avl_table *local_tree; -static int initialized; + +/* Global package search path. */ +static char *search_path; +static size_t search_path_sz; + +/* Package file extensions, in decreasing order of precedence. */ +static const char u_pkg_exts[][5] = { ".u", ".utx", ".uax", ".umx", ".unr" }; static int localcmp(const void *_a, const void *_b, void *_data) { @@ -116,6 +125,56 @@ const char *u_pkg_vfs_add_local(const char *name, const char *file) return spec->name; } +/* Enlarge the search path buffer so that it can store at least need bytes. */ +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_vfs_get_search_path(void) +{ + return search_path ? search_path : ""; +} + +int u_pkg_vfs_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_vfs_add_search_dir(const char *path) +{ + size_t end = search_path ? strlen(search_path) : 0; + + if (end == 0) { + return u_pkg_vfs_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; +} + void u_pkg_vfs_del_local(const char *name) { struct local_pkg spec = { .name = (char *)name }, *item; @@ -124,9 +183,52 @@ void u_pkg_vfs_del_local(const char *name) free(item); } +struct foreach_state { + const char *name; + struct upkg *f; + size_t sz; + char buf[]; +}; + +static int foreachfile(const char *filename, void *_st) +{ + struct foreach_state **st = _st, *tmp; + size_t need, len; + const char *base; + + /* Check if the filename matches the package name. */ + base = pkgname_base(filename); + if (!base || strcasecmp(base, (*st)->name) != 0) + return 0; + + /* Enlarge the state buffer, if necessary. */ + need = strlen(filename) + sizeof **u_pkg_exts; + if ((*st)->sz < need) { + tmp = realloc(*st, sizeof **st + need); + if (!tmp) + return -1; + *st = tmp; + (*st)->sz = need; + } + + /* Try each file extension, in order. */ + len = sprintf((*st)->buf, "%s", filename); + for (unsigned i = 0; i < sizeof u_pkg_exts / sizeof *u_pkg_exts; i++) { + strcpy((*st)->buf+len, u_pkg_exts[i]); + + (*st)->f = upkg_fopen((*st)->buf); + if ((*st)->f != NULL) + return 1; + } + + return 0; +} + struct upkg *u_pkg_vfs_open_by_name(const char *name) { struct local_pkg spec = { .name = (char *)name }, *item; + struct foreach_state *st; + struct upkg *f = NULL; if (!initialized) return NULL; @@ -134,7 +236,17 @@ struct upkg *u_pkg_vfs_open_by_name(const char *name) item = avl_find(local_tree, &spec); if (item) return upkg_fopen(item->file); - return NULL; + + st = malloc(sizeof *st + 256); + if (!st) + return NULL; + *st = (struct foreach_state) { .sz = 256, .name = name }; + + if (lt_dlforeachfile(u_pkg_vfs_get_search_path(), foreachfile, &st) > 0) + f = st->f; + + free(st); + return f; } int u_pkg_vfs_init(void) diff --git a/src/uobject/vfs.h b/src/uobject/vfs.h index bc835a7..c0bdc4f 100644 --- a/src/uobject/vfs.h +++ b/src/uobject/vfs.h @@ -36,6 +36,27 @@ const char *u_pkg_vfs_add_local(const char *name, const char *file); */ void u_pkg_vfs_del_local(const char *name); +/* + * Set the global VFS search path - a LT_PATHSEP-delimited sequence of + * directories to be searched for packages after local packages. + * + * Returns 0 on success, or -1 on failure. + */ +int u_pkg_vfs_set_search_path(const char *path); + +/* + * Appends a directory to the global VFS search path. This directory will + * be searched after any directories already in the path. + * + * Returns 0 on success, or -1 on failure. + */ +int u_pkg_vfs_add_search_dir(const char *path); + +/* + * Get the global VFS search path. + */ +const char *u_pkg_vfs_get_search_path(void); + /* * Opens a package file by name. First, local packages are searched for a * match. If a local match is found, the global search path is never