diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | src/util.c | 95 | ||||
-rw-r--r-- | test/lilv_test.c | 48 | ||||
-rw-r--r-- | wscript | 6 |
4 files changed, 111 insertions, 40 deletions
@@ -7,7 +7,6 @@ lilv (UNRELEASED) unstable; urgency=low * Use correct URI for dcterms:replaces (for hiding old plugins): "http://purl.org/dc/terms/replaces" * Fix compilation on BSD - * Fix crash in wordexp when LV2_PATH is corrupt * Only load dynmanifest libraries once per bundle, not once per plugin * Fix lilv_world_find_nodes to work with wildcard subjects * Add lilv_plugin_get_related to get resources related to plugins that @@ -22,6 +21,7 @@ lilv (UNRELEASED) unstable; urgency=low to the LV2 presets format. * Update old references to lv2_list (now lv2ls) * Support compilation as C++ under MSVC++. + * Remove use of wordexp. -- David Robillard <d@drobilla.net> (UNRELEASED) @@ -14,7 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define _POSIX_C_SOURCE 1 /* for wordexp, fileno */ +#define _POSIX_C_SOURCE 1 /* for fileno */ #define _BSD_SOURCE 1 /* for realpath, symlink */ #ifdef __APPLE__ @@ -47,10 +47,6 @@ # include <sys/file.h> #endif -#ifdef HAVE_WORDEXP -# include <wordexp.h> -#endif - char* lilv_strjoin(const char* first, ...) { @@ -81,6 +77,10 @@ lilv_strjoin(const char* first, ...) char* lilv_strdup(const char* str) { + if (!str) { + return NULL; + } + const size_t len = strlen(str); char* dup = (char*)malloc(len + 1); memcpy(dup, str, len + 1); @@ -130,36 +130,77 @@ lilv_get_lang(void) return lang; } +/** Append suffix to dst, update dst_len, and return the realloc'd result. */ +char* +strappend(char* dst, size_t* dst_len, const char* suffix, size_t suffix_len) +{ + dst = (char*)realloc(dst, *dst_len + suffix_len + 1); + memcpy(dst + *dst_len, suffix, suffix_len); + dst[(*dst_len += suffix_len)] = '\0'; + return dst; +} + +/** Append the value of the environment variable var to dst. */ +char* +append_var(char* dst, size_t* dst_len, const char* var) +{ + // Get value from environment + const char* val = getenv(var); + if (val) { // Value found, append it + return strappend(dst, dst_len, val, strlen(val)); + } else { // No value found, append variable reference as-is + return strappend(strappend(dst, dst_len, "$", 1), + dst_len, var, strlen(var)); + } +} + /** Expand variables (e.g. POSIX ~ or $FOO, Windows %FOO%) in @a path. */ char* lilv_expand(const char* path) { -#ifdef HAVE_WORDEXP - char* ret = NULL; - wordexp_t p; - if (wordexp(path, &p, 0)) { - LILV_ERRORF("Error expanding path `%s'\n", path); - return lilv_strdup(path); - } - if (p.we_wordc == 0) { - /* Literal directory path (e.g. no variables or ~) */ - ret = lilv_strdup(path); - } else if (p.we_wordc == 1) { - /* Directory path expands (e.g. contains ~ or $FOO) */ - ret = lilv_strdup(p.we_wordv[0]); - } else { - /* Multiple expansions in a single directory path? */ - LILV_ERRORF("Malformed path `%s'\n", path); - ret = lilv_strdup(path); - } - wordfree(&p); -#elif defined(_WIN32) +#ifdef _WIN32 char* ret = (char*)malloc(MAX_PATH); ExpandEnvironmentStrings(path, ret, MAX_PATH); #else - char* ret = lilv_strdup(path); + char* out = NULL; + size_t len = 0; + + const char* start = path; // Start of current chunk to copy + for (const char* s = path; *s;) { + if (*s == '$') { + // Hit $ (variable reference, e.g. $VAR_NAME) + for (const char* t = s + 1; ; ++t) { + if (*t == '\0' || !(isupper(*t) || *t == '_')) { + // Append preceding chunk + out = strappend(out, &len, start, s - start); + + // Append variable value (or $VAR_NAME if not found) + char* var = (char*)calloc(t - s, 1); + memcpy(var, s + 1, t - s - 1); + append_var(out, &len, var); + free(var); + + // Continue after variable reference + start = s = t; + break; + } + } + } else if (*s == '~' && (*(s + 1) == '/' || (*(s + 1) == '\0'))) { + // Hit ~ before slash or end of string (home directory reference) + out = strappend(out, &len, start, s - start); + append_var(out, &len, "HOME"); + start = ++s; + } else { + ++s; + } + } + + if (*start) { + out = strappend(out, &len, start, strlen(start)); + } + + return out; #endif - return ret; } char* diff --git a/test/lilv_test.c b/test/lilv_test.c index c5f2b93..c8c565a 100644 --- a/test/lilv_test.c +++ b/test/lilv_test.c @@ -17,15 +17,16 @@ #define _POSIX_C_SOURCE 200112L /* for setenv */ -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> #include <assert.h> -#include <sys/stat.h> -#include <limits.h> +#include <ctype.h> #include <float.h> +#include <limits.h> #include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> #include "lilv/lilv.h" #include "../src/lilv_internal.h" @@ -382,6 +383,40 @@ test_discovery(void) /*****************************************************************************/ int +test_lv2_path(void) +{ + char* orig_lv2_path = lilv_strdup(getenv("LV2_PATH")); + + setenv("LV2_PATH", "~/.lv2:/usr/local/lib/lv2:/usr/lib/lv2", 1); + + LilvWorld* world = lilv_world_new(); + lilv_world_load_all(world); + + const LilvPlugins* plugins = lilv_world_get_all_plugins(world); + const size_t n_plugins = lilv_plugins_size(plugins); + + lilv_world_free(world); + + setenv("LV2_PATH", "$HOME/.lv2:/usr/local/lib/lv2:/usr/lib/lv2", 1); + world = lilv_world_new(); + lilv_world_load_all(world); + plugins = lilv_world_get_all_plugins(world); + TEST_ASSERT(lilv_plugins_size(plugins) == n_plugins); + lilv_world_free(world); + + if (orig_lv2_path) { + setenv("LV2_PATH", orig_lv2_path, 1); + } else { + unsetenv("LV2_PATH"); + } + free(orig_lv2_path); + + return 1; +} + +/*****************************************************************************/ + +int test_verify(void) { if (!start_bundle(MANIFEST_PREFIXES @@ -1398,6 +1433,7 @@ static struct TestCase tests[] = { TEST_CASE(verify), TEST_CASE(no_verify), TEST_CASE(discovery), + TEST_CASE(lv2_path), TEST_CASE(classes), TEST_CASE(plugin), TEST_CASE(port), @@ -88,12 +88,6 @@ def configure(conf): if Options.platform == 'darwin': defines += ['_DARWIN_C_SOURCE'] - conf.check_cc(function_name='wordexp', - header_name='wordexp.h', - defines=defines, - define_name='HAVE_WORDEXP', - mandatory=False) - conf.check_cc(function_name='flock', header_name='sys/file.h', defines=defines, |