summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--src/util.c95
-rw-r--r--test/lilv_test.c48
-rw-r--r--wscript6
4 files changed, 111 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index e2bbec4..f1d1ff0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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)
diff --git a/src/util.c b/src/util.c
index 564b286..e0cd027 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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),
diff --git a/wscript b/wscript
index 775e0e3..cdbe24c 100644
--- a/wscript
+++ b/wscript
@@ -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,