From 557eccb32013460418b72bb20acd79c018a5e95a Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Fri, 18 Sep 2009 10:40:22 -0400 Subject: [PATCH 01/16] uobject: Move source files into the uobject directory. --- src/Makefile.am | 10 ++-------- src/uobject/Makefile.inc | 9 +++++++++ src/{ => uobject}/avl.c | 0 src/{ => uobject}/avl.h | 0 src/{ => uobject}/exportable.c | 0 src/{ => uobject}/loadable.c | 0 src/{ => uobject}/module.c | 0 src/{ => uobject}/package.c | 0 src/{ => uobject}/uobject.c | 0 9 files changed, 11 insertions(+), 8 deletions(-) rename src/{ => uobject}/avl.c (100%) rename src/{ => uobject}/avl.h (100%) rename src/{ => uobject}/exportable.c (100%) rename src/{ => uobject}/loadable.c (100%) rename src/{ => uobject}/module.c (100%) rename src/{ => uobject}/package.c (100%) rename src/{ => uobject}/uobject.c (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 719a952..f9224c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,21 +6,15 @@ AM_CPPFLAGS = -DPKGLIBDIR=\"$(pkglibdir)\" -DPKGDATADIR=\"$(pkgdatadir)\" -lib_LTLIBRARIES = libuobject.la libupkg.la +lib_LTLIBRARIES = libupkg.la pkglib_LTLIBRARIES = include_HEADERS = upkg.h -noinst_HEADERS = pack.h avl.h +noinst_HEADERS = pack.h include uobject/Makefile.inc include engine/Makefile.inc -libuobject_la_SOURCES = uobject.c module.c avl.c package.c \ - loadable.c exportable.c -libuobject_la_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(LTDLINCL) -libuobject_la_LIBADD = $(LIBLTDL) $(GLIB_LIBS) -libuobject_la_LDFLAGS = -export-symbols-regex '^u_' - libupkg_la_SOURCES = libupkg.c pack.c bin_PROGRAMS = upkg diff --git a/src/uobject/Makefile.inc b/src/uobject/Makefile.inc index c5cae96..7d4761a 100644 --- a/src/uobject/Makefile.inc +++ b/src/uobject/Makefile.inc @@ -4,6 +4,15 @@ # notice and this notice are preserved. This file is offered as-is, # without any warranty. +lib_LTLIBRARIES += libuobject.la + uobjectdir = $(includedir)/uobject uobject_HEADERS = uobject/uobject.h uobject/exportable.h uobject/loadable.h \ uobject/module.h uobject/package.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 +libuobject_la_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(LTDLINCL) +libuobject_la_LIBADD = $(LIBLTDL) $(GLIB_LIBS) +libuobject_la_LDFLAGS = -export-symbols-regex '^u_' diff --git a/src/avl.c b/src/uobject/avl.c similarity index 100% rename from src/avl.c rename to src/uobject/avl.c diff --git a/src/avl.h b/src/uobject/avl.h similarity index 100% rename from src/avl.h rename to src/uobject/avl.h diff --git a/src/exportable.c b/src/uobject/exportable.c similarity index 100% rename from src/exportable.c rename to src/uobject/exportable.c diff --git a/src/loadable.c b/src/uobject/loadable.c similarity index 100% rename from src/loadable.c rename to src/uobject/loadable.c diff --git a/src/module.c b/src/uobject/module.c similarity index 100% rename from src/module.c rename to src/uobject/module.c diff --git a/src/package.c b/src/uobject/package.c similarity index 100% rename from src/package.c rename to src/uobject/package.c diff --git a/src/uobject.c b/src/uobject/uobject.c similarity index 100% rename from src/uobject.c rename to src/uobject/uobject.c -- 2.43.2 From 8f527347207fa9177c3cf624f73fe33f9aad7f3d Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Fri, 18 Sep 2009 10:43:10 -0400 Subject: [PATCH 02/16] libupkg: Remove checks for an unsigned quantity being less than 0. --- src/libupkg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libupkg.c b/src/libupkg.c index 004cb46..2c0cf07 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -357,12 +357,12 @@ static int pkg_init_imports(struct upkg *pkg) len = 0; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); - if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; + if (rc == 0 || len >= pkg->name_count) goto err; import->class_package = pkg->priv->names[tmp].name; len += rc; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); - if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; + if (rc == 0 || len >= pkg->name_count) goto err; import->class_name = pkg->priv->names[tmp].name; len += rc; @@ -371,7 +371,7 @@ static int pkg_init_imports(struct upkg *pkg) len += 4; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); - if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; + if (rc == 0 || len >= pkg->name_count) goto err; import->object_name = pkg->priv->names[tmp].name; len += rc; -- 2.43.2 From 79c3e2f505f985dba6755b2a1d6b8ca8299bdc6b Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Fri, 18 Sep 2009 11:05:29 -0400 Subject: [PATCH 03/16] pack: Use a user-configurable macro to select 64 bit packing. --- src/pack.c | 15 ++++++--------- src/pack.h | 15 +++++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/pack.c b/src/pack.c index 4490701..1128a19 100644 --- a/src/pack.c +++ b/src/pack.c @@ -8,9 +8,6 @@ * without any warranty. */ -#include -#include - #include "pack.h" /* Unsigned integer packing. */ @@ -36,13 +33,13 @@ DEFPACK_BE(16, unsigned short) DEFPACK_BE(32, unsigned long) -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT DEFPACK_BE(64, unsigned long long) #endif DEFPACK_LE(16, unsigned short) DEFPACK_LE(32, unsigned long) -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT DEFPACK_LE(64, unsigned long long) #endif @@ -72,13 +69,13 @@ DEFPACK_LE(64, unsigned long long) DEFUNPACK_BE(16, unsigned short) DEFUNPACK_BE(32, unsigned long) -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT DEFUNPACK_BE(64, unsigned long long) #endif DEFUNPACK_LE(16, unsigned short) DEFUNPACK_LE(32, unsigned long) -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT DEFUNPACK_LE(64, unsigned long long) #endif @@ -115,12 +112,12 @@ DEFUNPACK_LE(64, unsigned long long) DEFUNPACK_SBE(16, 32767, short) DEFUNPACK_SBE(32, 2147483647l, long) -#ifdef LLONG_MAX +#if PACK_HAVE_64BIT DEFUNPACK_SBE(64, 9223372036854775807ll, long long) #endif DEFUNPACK_SLE(16, 32767, short) DEFUNPACK_SLE(32, 2147483647l, long) -#ifdef LLONG_MAX +#if PACK_HAVE_64BIT DEFUNPACK_SLE(64, 9223372036854775807ll, long long) #endif diff --git a/src/pack.h b/src/pack.h index 8413fdb..d47ddc4 100644 --- a/src/pack.h +++ b/src/pack.h @@ -12,40 +12,43 @@ #define PACK_H_ #include +#if !defined(PACK_HAVE_64BIT) && defined(ULLONG_MAX) && defined(LLONG_MAX) +# define PACK_HAVE_64BIT 1 +#endif void pack_16_be(unsigned char *, unsigned short); void pack_32_be(unsigned char *, unsigned long); -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT void pack_64_be(unsigned char *, unsigned long long); #endif void pack_16_le(unsigned char *, unsigned short); void pack_32_le(unsigned char *, unsigned long); -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT void pack_64_le(unsigned char *, unsigned long long); #endif unsigned short unpack_16_be(const unsigned char *); unsigned long unpack_32_be(const unsigned char *); -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT unsigned long long unpack_64_be(const unsigned char *); #endif unsigned short unpack_16_le(const unsigned char *); unsigned long unpack_32_le(const unsigned char *); -#ifdef ULLONG_MAX +#if PACK_HAVE_64BIT unsigned long long unpack_64_le(const unsigned char *); #endif short unpack_s16_be(const unsigned char *); long unpack_s32_be(const unsigned char *); -#ifdef LLONG_MAX +#if PACK_HAVE_64BIT long long unpack_s64_be(const unsigned char *); #endif short unpack_s16_le(const unsigned char *); long unpack_s32_le(const unsigned char *); -#ifdef LLONG_MAX +#if PACK_HAVE_64BIT long long unpack_s64_le(const unsigned char *); #endif -- 2.43.2 From 51f81705f05a627c71dc96567a26837514ad48f0 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sun, 6 Dec 2009 23:26:09 -0500 Subject: [PATCH 04/16] gnulib: Update to latest version. --- gnulib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnulib b/gnulib index c5c46dc..68145a0 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit c5c46dcc8e875485a2c5d27cce106491fb41400e +Subproject commit 68145a074c0cdc9eff8364a62530da01a5f39bcd -- 2.43.2 From 95cd2b3a5599955317d1f80d515c0d5d5c568c7d Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 7 Dec 2009 02:57:27 -0500 Subject: [PATCH 05/16] build: Re-arrange CFLAGS/LDFLAGS a bit. --- src/Makefile.am | 7 ++++--- src/uobject/Makefile.inc | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index f9224c3..c2019c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,8 @@ # notice and this notice are preserved. This file is offered as-is, # without any warranty. -AM_CPPFLAGS = -DPKGLIBDIR=\"$(pkglibdir)\" -DPKGDATADIR=\"$(pkgdatadir)\" +AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib +AM_LDFLAGS = -L$(top_builddir)/lib lib_LTLIBRARIES = libupkg.la pkglib_LTLIBRARIES = @@ -19,6 +20,6 @@ libupkg_la_SOURCES = libupkg.c pack.c bin_PROGRAMS = upkg upkg_SOURCES = upkg.c -upkg_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib $(GLIB_CFLAGS) -upkg_LDFLAGS = -L$(top_builddir)/lib -export-dynamic +upkg_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) +upkg_LDFLAGS = $(AM_LDFLAGS) -export-dynamic upkg_LDADD = libuobject.la libupkg.la $(GLIB_LIBS) -lgnu diff --git a/src/uobject/Makefile.inc b/src/uobject/Makefile.inc index 7d4761a..7c42e97 100644 --- a/src/uobject/Makefile.inc +++ b/src/uobject/Makefile.inc @@ -13,6 +13,7 @@ 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 -libuobject_la_CPPFLAGS = $(AM_CPPFLAGS) $(GLIB_CFLAGS) $(LTDLINCL) +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_LDFLAGS = -export-symbols-regex '^u_' -- 2.43.2 From 0a55ae84545c5e5a45e2240c06bd77a1917f7d3e Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 7 Dec 2009 03:01:06 -0500 Subject: [PATCH 06/16] package: Get rid of separate mechanisms for opening packages. 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 | 2 + m4/gnulib-cache.m4 | 3 +- src/uobject/Makefile.inc | 5 +- src/uobject/module.c | 2 +- src/uobject/package.c | 90 ++++------------------ src/uobject/package.h | 3 +- src/uobject/vfs.c | 162 +++++++++++++++++++++++++++++++++++++++ src/uobject/vfs.h | 55 +++++++++++++ src/upkg.c | 28 +++++-- 9 files changed, 262 insertions(+), 88 deletions(-) create mode 100644 src/uobject/vfs.c create mode 100644 src/uobject/vfs.h diff --git a/m4/.gitignore b/m4/.gitignore index 222b4c6..e413b24 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -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 diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index 0f97c57..7cb7a29 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -15,12 +15,13 @@ # 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]) diff --git a/src/uobject/Makefile.inc b/src/uobject/Makefile.inc index 7c42e97..2009d09 100644 --- a/src/uobject/Makefile.inc +++ b/src/uobject/Makefile.inc @@ -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 diff --git a/src/uobject/module.c b/src/uobject/module.c index 1872a8d..2fa4402 100644 --- a/src/uobject/module.c +++ b/src/uobject/module.c @@ -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; } diff --git a/src/uobject/package.c b/src/uobject/package.c index bd97135..af4ebb3 100644 --- a/src/uobject/package.c +++ b/src/uobject/package.c @@ -25,6 +25,7 @@ #include #include +#include #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; -} diff --git a/src/uobject/package.h b/src/uobject/package.h index 5e60a18..03d9b01 100644 --- a/src/uobject/package.h +++ b/src/uobject/package.h @@ -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 index 0000000..5465144 --- /dev/null +++ b/src/uobject/vfs.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +#include +#include + +#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 index 0000000..d986aec --- /dev/null +++ b/src/uobject/vfs.h @@ -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 . + */ +#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 diff --git a/src/upkg.c b/src/upkg.c index 2c268b4..d3a946b 100644 --- a/src/upkg.c +++ b/src/upkg.c @@ -29,6 +29,7 @@ #include #include #include +#include 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; } -- 2.43.2 From aa3d8014ba02b49656689d1b4951ea79de76a414 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 8 Dec 2009 00:54:58 -0500 Subject: [PATCH 07/16] package: Make the VFS directly open the package file. This is in preparation for moving the package search mechanism to the VFS, as it nicely allows us to ensure that candidate packages actually open successfully. --- src/uobject/package.c | 10 ++-------- src/uobject/vfs.c | 11 ++++++----- src/uobject/vfs.h | 20 ++++++++++++++++++-- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/uobject/package.c b/src/uobject/package.c index af4ebb3..2da23b3 100644 --- a/src/uobject/package.c +++ b/src/uobject/package.c @@ -87,15 +87,9 @@ static gboolean u_pkg_load(GTypeModule *m) { struct upkg_priv *priv = U_PKG_GET_PRIV(m); int (*init_func)(GTypeModule *); - const char *file; - file = u_pkg_vfs_lookup(m->name); - if (file) { - U_PKG(m)->pkg = upkg_fopen(file); - if (!U_PKG(m)->pkg) { - return FALSE; - } - } + /* Ignore failure here until we get rid of native-only packages. */ + U_PKG(m)->pkg = u_pkg_vfs_open_by_name(m->name); priv->native = lt_dlopenext(m->name); if (priv->native) { diff --git a/src/uobject/vfs.c b/src/uobject/vfs.c index 5465144..fcbb3e5 100644 --- a/src/uobject/vfs.c +++ b/src/uobject/vfs.c @@ -23,6 +23,7 @@ #include #include +#include #include #include "avl.h" @@ -123,17 +124,17 @@ void u_pkg_vfs_del_local(const char *name) free(item); } -const char *u_pkg_vfs_lookup(const char *name) +struct upkg *u_pkg_vfs_open_by_name(const char *name) { struct local_pkg spec = { .name = (char *)name }, *item; - if (!local_tree) + if (!initialized) return NULL; item = avl_find(local_tree, &spec); - if (!item) - return NULL; - return item->file; + if (item) + return upkg_fopen(item->file); + return NULL; } int u_pkg_vfs_init(void) diff --git a/src/uobject/vfs.h b/src/uobject/vfs.h index d986aec..bc835a7 100644 --- a/src/uobject/vfs.h +++ b/src/uobject/vfs.h @@ -18,6 +18,8 @@ #ifndef U_OBJECT_VFS_H_ #define U_OBJECT_VFS_H_ +#include + /* * 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 @@ -35,9 +37,23 @@ const char *u_pkg_vfs_add_local(const char *name, const char *file); void u_pkg_vfs_del_local(const char *name); /* - * Find a package by name in the VFS. Names are case-insensitive. + * 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 + * consulted. If no local match is found, the directories in the global search + * path are examined, in order. + * + * When searching the global search path, the first file found which both + * matches the given name and can be opened successfully is used. A file + * foo.EXT matches the name if foo is equal to name (without regard to case) + * and EXT is one of u, utx, uax, umx or unr. If multiple extensions + * are valid, they are tried in this order. + * + * Note that the particular file extension used does not make any difference + * as to what sort of objects can be contained in a package. + * + * Returns the opened package on success, or NULL on failure. */ -const char *u_pkg_vfs_lookup(const char *name); +struct upkg *u_pkg_vfs_open_by_name(const char *name); /* * Initialize the UObject VFS system. Returns 0 on success, -1 otherwise. -- 2.43.2 From b228d2b354248b62d70a582a37693cff829fe0c6 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 8 Dec 2009 00:58:38 -0500 Subject: [PATCH 08/16] package: Move package search code to the VFS. --- src/uobject/package.c | 75 --------------------------- src/uobject/package.h | 4 -- src/uobject/vfs.c | 118 ++++++++++++++++++++++++++++++++++++++++-- src/uobject/vfs.h | 21 ++++++++ 4 files changed, 136 insertions(+), 82 deletions(-) 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 -- 2.43.2 From 0d572b509281eb39bd418cb7a87ecfd9e101cb8a Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sun, 31 Jan 2010 16:52:05 -0500 Subject: [PATCH 09/16] build: Don't use a semicolon after sed's 't' command. Some (namely, FreeBSD's) sed implementations fail when a semicolon is used after a 't' command. This behaviour appears to be acceptable according to POSIX, so appease these implementations by passing extra -e options to sed. --- m4/glib.m4 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/m4/glib.m4 b/m4/glib.m4 index 9d90f6f..a3253ff 100644 --- a/m4/glib.m4 +++ b/m4/glib.m4 @@ -6,11 +6,12 @@ dnl without any warranty. dnl _GLIB_TRY_VERSION(min-version) AC_DEFUN([_GLIB_TRY_VERSION], [dnl -sedhead='s/@<:@0-9@:>@@<:@0-9@:>@*/<<<&>>>/' -sedtail='s/.*<<<\(.*\)>>>.*/\1/;t;s/.*/0/' -glib_min_major=`printf '%s' '$1' | sed -e "$sedhead"1 -e "$sedtail"` -glib_min_minor=`printf '%s' '$1' | sed -e "$sedhead"2 -e "$sedtail"` -glib_min_release=`printf '%s' '$1' | sed -e "$sedhead"3 -e "$sedtail"` +shead='s/@<:@0-9@:>@@<:@0-9@:>@*/<<<&>>>/' +sbody='s/.*<<<\(.*\)>>>.*/\1/;t' +stail='s/.*/0/' +glib_min_major=`printf '%s' '$1' | sed -e "$shead"1 -e "$sbody" -e "$stail"` +glib_min_minor=`printf '%s' '$1' | sed -e "$shead"2 -e "$sbody" -e "$stail"` +glib_min_release=`printf '%s' '$1' | sed -e "$shead"3 -e "$sbody" -e "$stail"` AC_CACHE_CHECK([for glib version at least $1], [glib_cv_sufficient_ver], -- 2.43.2 From 6fed51f830b164db3ffaeb42604bb5d6a8a05138 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Sun, 31 Jan 2010 16:53:13 -0500 Subject: [PATCH 10/16] libupkg: Add explicit conversions to stdio wrappers. Some C libraries provide a macro version of feof which does not convert the provided pointer to FILE * before dereferencing it. Ordinarily, this conversion would occur automatically since feof's prototype specifies FILE *, but this is suppressed in the macro case. It is not clear to me whether this behaviour is consistent with the requirements of the C standard. However, after encountering at least two implementations which do this, explicit conversions seem simple enough. --- src/libupkg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libupkg.c b/src/libupkg.c index 2c0cf07..40b3913 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -61,27 +61,27 @@ struct upkg_private { /* Default I/O operations for ordinary files. */ static size_t file_read(void *buf, size_t size, void *handle) { - return fread(buf, 1, size, handle); + return fread(buf, 1, size, (FILE *)handle); } static int file_seek(void *handle, long offset, int whence) { - return fseek(handle, offset, whence); + return fseek((FILE *)handle, offset, whence); } static long file_tell(void *handle) { - return ftell(handle); + return ftell((FILE *)handle); } static int file_eof(void *handle) { - return feof(handle); + return feof((FILE *)handle); } static int file_close(void *handle) { - return fclose(handle); + return fclose((FILE *)handle); } const struct upkg_file_ops upkg_default_fops = { -- 2.43.2 From 6476fbdc9473dbb317d2775d487c8b5fd771995a Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 9 Dec 2009 23:32:07 -0500 Subject: [PATCH 11/16] upkg: Don't unref packages, since gobject does not allow this. --- src/upkg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upkg.c b/src/upkg.c index d3a946b..f7ace2a 100644 --- a/src/upkg.c +++ b/src/upkg.c @@ -353,7 +353,7 @@ int main(int argc, char **argv) break; } - g_object_unref(pkg); + g_type_module_unuse(pkg); u_object_module_exit(); u_pkg_vfs_exit(); return rc; -- 2.43.2 From 7df6d63d11473ca5adb5e29abed1aaa2a5196b48 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 9 Dec 2009 23:34:13 -0500 Subject: [PATCH 12/16] upkg: Specify package files as options. Now, one must run "upkg -f foo.u" where previously one would run "upkg foo.u". This new syntax allows multiple packages to be specified on the command line for purposes of dependency resolution and (soon) extraction of specific objects. The package operated upon is the last one specified in this manner. --- src/upkg.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/upkg.c b/src/upkg.c index f7ace2a..191444e 100644 --- a/src/upkg.c +++ b/src/upkg.c @@ -40,10 +40,11 @@ enum { int verbose = 0; static const char *progname = "upkg"; -static const char *sopts = "ixvVH"; +static const char *sopts = "ixvf:VH"; static const struct option lopts[] = { { "info", 0, NULL, 'i' }, { "export", 0, NULL, 'x' }, + { "file", 1, NULL, 'f' }, { "verbose", 0, NULL, 'v' }, { "version", 0, NULL, 'V' }, { "help", 0, NULL, 'H' }, @@ -63,7 +64,7 @@ There is NO WARRANTY, to the extent permitted by law." void print_usage(FILE *f) { - fprintf(f, "Usage: %s [options] package\n", progname); + fprintf(f, "Usage: %s [options]\n", progname); } void print_help(void) @@ -288,14 +289,26 @@ int package_export(struct upkg *pkg) int main(int argc, char **argv) { GTypeModule *pkg; - const char *pkgname; + const char *pkgname = NULL; unsigned mode = MODE_INFO; int opt, rc = EXIT_FAILURE; if (argc > 0) progname = argv[0]; + if (u_pkg_vfs_init() != 0) + return EXIT_FAILURE; + if (u_object_module_init() != 0) + return EXIT_FAILURE; + while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { switch (opt) { + case 'f': + pkgname = u_pkg_vfs_add_local(NULL, optarg); + if (!pkgname) { + fprintf(stderr, "failed to add package `%s'.\n", optarg); + return EXIT_FAILURE; + } + break; case 'i': mode = MODE_INFO; break; @@ -317,19 +330,8 @@ int main(int argc, char **argv) } } - if (argv[optind] == NULL) { - print_usage(stderr); - return EXIT_FAILURE; - } - - if (u_pkg_vfs_init() != 0) - return EXIT_FAILURE; - if (u_object_module_init() != 0) - return EXIT_FAILURE; - - pkgname = u_pkg_vfs_add_local(NULL, argv[optind]); if (!pkgname) { - fprintf(stderr, "failed to add package `%s'.\n", argv[optind]); + print_usage(stderr); return EXIT_FAILURE; } -- 2.43.2 From 152bab24521ea7cefd9e5d8cd1460c5871bff34c Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 1 Feb 2010 18:30:04 -0500 Subject: [PATCH 13/16] music: Add simple file type detection to the dummy module. The dummy module can be a bit smarter so that the file extension of exported data is correct. Add support for xm, it and s3m. --- src/engine/music-dummymod.c | 55 +++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/engine/music-dummymod.c b/src/engine/music-dummymod.c index db18fa4..a4c8666 100644 --- a/src/engine/music-dummymod.c +++ b/src/engine/music-dummymod.c @@ -18,12 +18,16 @@ #include #include +#include #include "music-module.h" #include "upkg.h" struct music_mod { struct upkg_file *f; + + unsigned char header[64]; + unsigned long hdrlen; }; int music_mod_init(void) @@ -37,12 +41,15 @@ void music_mod_exit(void) struct music_mod *music_mod_open(struct upkg_file *f) { - struct music_mod *m = malloc(sizeof *m); + struct music_mod *m; - if (m) { - m->f = f; + m = malloc(sizeof *m); + if (!m) { + return NULL; } + m->f = f; + m->hdrlen = upkg_export_read(f, m->header, sizeof m->header); return m; } @@ -85,7 +92,49 @@ int music_mod_dump(struct music_mod *m, FILE *of) } } +int is_xm(unsigned char *buf, unsigned long len) +{ + static const char head[15] = + /* ASCII encoding of "Extended Module" */ + "\x45\x78\x74\x65\x6e\x64\x65\x64\x20\x4d\x6f\x64\x75\x6c\x65"; + + if (len >= sizeof head && memcmp(head, buf, sizeof head) == 0) + return 1; + return 0; +} + +int is_it(unsigned char *buf, unsigned long len) +{ + static const char head[4] = + /* ASCII encoding of "IMPM" */ + "\x49\x4d\x50\x4d"; + + if (len >= sizeof head && memcmp(head, buf, sizeof head) == 0) + return 1; + return 0; +} + +int is_s3m(unsigned char *buf, unsigned long len) +{ + static const char head[4] = + /* ASCII encoding of "SCRM" */ + "\x53\x43\x52\x4d"; + + if (len < 0x2c + sizeof head) + return 0; + if (memcmp(head, buf+0x2c, sizeof head) == 0) + return 1; + return 0; +} + const char *music_mod_type(struct music_mod *mod) { + if (is_xm(mod->header, mod->hdrlen)) + return "xm"; + if (is_it(mod->header, mod->hdrlen)) + return "it"; + if (is_s3m(mod->header, mod->hdrlen)) + return "s3m"; + return "unknown"; } -- 2.43.2 From c4d3d44d8e7fe87e6c889c116c267954fca9ac1e Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 2 Feb 2010 21:50:39 -0500 Subject: [PATCH 14/16] upkg: Don't crash if the specified package does not exist. Currently, g_type_module_use(pkg) will succeed even if the package does not exist, due to the existence of shared-object-only packages. So the caller must look inside the UPkg structure to see if anything was actually opened. In the future, pending tools to create the things, such packages probably won't exist and this hack can be removed. --- src/upkg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upkg.c b/src/upkg.c index 191444e..1e2c662 100644 --- a/src/upkg.c +++ b/src/upkg.c @@ -341,7 +341,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - if (!g_type_module_use(pkg)) { + if (!g_type_module_use(pkg) || !U_PKG(pkg)->pkg) { fprintf(stderr, "failed to load package: %s\n", pkg->name); return EXIT_FAILURE; } -- 2.43.2 From b6681480afd85ed3914902a96b4d7bc4185e3391 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 3 Feb 2010 14:40:20 -0500 Subject: [PATCH 15/16] build: Abort configure if specified module library is not found. If the user specifies, say, --with-modlib=modplug, it is not right to use any other module library. We also avoid checking for unrequested module libraries. --- configure.ac | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 8844115..6dfc336 100644 --- a/configure.ac +++ b/configure.ac @@ -33,23 +33,16 @@ AC_ARG_WITH([modlib], [with_modlib=$withval], [with_modlib=auto]) -CHECK_LIBMODPLUG([have_libmodplug=yes], [have_libmodplug=no]) -AC_MSG_CHECKING([which module library to use]) case $with_modlib in -none) - use_modlib=none -;; -no) +no|none) use_modlib=none ;; modplug) - if test x$have_libmodplug = xyes; then - use_modlib=modplug - else - use_modlib=none - fi + CHECK_LIBMODPLUG([use_modlib=modplug], []) ;; auto) + CHECK_LIBMODPLUG([have_libmodplug=yes], [have_libmodplug=no]) + if test x$have_libmodplug = xyes; then use_modlib=modplug else @@ -60,6 +53,7 @@ auto) AC_MSG_ERROR([Invalid argument to --with-modlib: $with_modlib]) ;; esac +AC_MSG_CHECKING([which module library to use]) AC_MSG_RESULT([$use_modlib]) AM_CONDITIONAL([USE_LIBMODPLUG], [test x$use_modlib = xmodplug]) -- 2.43.2 From d414b6caf298b8cd6044330678ac5a54a7d10398 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 27 Apr 2010 10:58:47 -0400 Subject: [PATCH 16/16] gnulib: Remove link-warning.h from repository. This was committed by accident earlier. --- .gitignore | 1 + link-warning.h | 28 ---------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 link-warning.h diff --git a/.gitignore b/.gitignore index e3d08f9..9b37668 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ stamp-h1 compile upkg libuobject.pc +link-warning.h lib diff --git a/link-warning.h b/link-warning.h deleted file mode 100644 index fda0194..0000000 --- a/link-warning.h +++ /dev/null @@ -1,28 +0,0 @@ -/* GL_LINK_WARNING("literal string") arranges to emit the literal string as - a linker warning on most glibc systems. - We use a linker warning rather than a preprocessor warning, because - #warning cannot be used inside macros. */ -#ifndef GL_LINK_WARNING - /* This works on platforms with GNU ld and ELF object format. - Testing __GLIBC__ is sufficient for asserting that GNU ld is in use. - Testing __ELF__ guarantees the ELF object format. - Testing __GNUC__ is necessary for the compound expression syntax. */ -# if defined __GLIBC__ && defined __ELF__ && defined __GNUC__ -# define GL_LINK_WARNING(message) \ - GL_LINK_WARNING1 (__FILE__, __LINE__, message) -# define GL_LINK_WARNING1(file, line, message) \ - GL_LINK_WARNING2 (file, line, message) /* macroexpand file and line */ -# define GL_LINK_WARNING2(file, line, message) \ - GL_LINK_WARNING3 (file ":" #line ": warning: " message) -# define GL_LINK_WARNING3(message) \ - ({ static const char warning[sizeof (message)] \ - __attribute__ ((__unused__, \ - __section__ (".gnu.warning"), \ - __aligned__ (1))) \ - = message "\n"; \ - (void)0; \ - }) -# else -# define GL_LINK_WARNING(message) ((void) 0) -# endif -#endif -- 2.43.2