From: Nick Bowler Date: Tue, 15 Sep 2009 02:43:49 +0000 (-0400) Subject: package: Add initial support for package search. X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/commitdiff_plain/5a1bc015e48db57deda5a7069c26ebcd6b255441 package: Add initial support for package search. --- diff --git a/src/package.c b/src/package.c index afa1272..cbbaf09 100644 --- a/src/package.c +++ b/src/package.c @@ -31,10 +31,18 @@ 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); diff --git a/src/uobject/package.h b/src/uobject/package.h index e8cb4a8..697abd2 100644 --- a/src/uobject/package.h +++ b/src/uobject/package.h @@ -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