summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--lilv/lilv.h10
-rw-r--r--src/world.c48
-rw-r--r--test/lilv_test.c48
4 files changed, 107 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 9fc97f9..b620a48 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ lilv (0.22.1) unstable;
* Add new hand-crafted Pythonic bindings with full test coverage
* Add lv2apply utility for applying plugins to audio files
+ * Add lilv_world_get_symbol()
* Add lilv_state_set_metadata() for adding state banks/comments/etc
(based on patch from Hanspeter Portner)
* Fix crash when state contains non-POD properties
diff --git a/lilv/lilv.h b/lilv/lilv.h
index 1808194..bb2f127 100644
--- a/lilv/lilv.h
+++ b/lilv/lilv.h
@@ -708,6 +708,16 @@ lilv_world_ask(LilvWorld* world,
const LilvNode* object);
/**
+ Get an LV2 symbol for some subject.
+
+ This will return the lv2:symbol property of the subject if it is given
+ explicitly, and otherwise will attempt to derive a symbol from the URI.
+ @return A string node that is a valid LV2 symbol, or NULL on error.
+*/
+LILV_API LilvNode*
+lilv_world_get_symbol(LilvWorld* world, const LilvNode* subject);
+
+/**
@}
@name Plugin
@{
diff --git a/src/world.c b/src/world.c
index 8760604..01f4ebe 100644
--- a/src/world.c
+++ b/src/world.c
@@ -1148,3 +1148,51 @@ lilv_world_get_all_plugins(const LilvWorld* world)
{
return world->plugins;
}
+
+LILV_API LilvNode*
+lilv_world_get_symbol(LilvWorld* world, const LilvNode* subject)
+{
+ // Check for explicitly given symbol
+ SordNode* snode = sord_get(
+ world->model, subject->node, world->uris.lv2_symbol, NULL, NULL);
+
+ if (snode) {
+ LilvNode* ret = lilv_node_new_from_node(world, snode);
+ sord_node_free(world->world, snode);
+ return ret;
+ }
+
+ if (!lilv_node_is_uri(subject)) {
+ return NULL;
+ }
+
+ // Find rightmost segment of URI
+ SerdURI uri;
+ serd_uri_parse((const uint8_t*)lilv_node_as_uri(subject), &uri);
+ const char* str = "_";
+ if (uri.fragment.buf) {
+ str = (const char*)uri.fragment.buf + 1;
+ } else if (uri.query.buf) {
+ str = (const char*)uri.query.buf;
+ } else if (uri.path.buf) {
+ const char* last_slash = strrchr((const char*)uri.path.buf, '/');
+ str = last_slash ? (last_slash + 1) : (const char*)uri.path.buf;
+ }
+
+ // Replace invalid characters
+ const size_t len = strlen(str);
+ char* const sym = (char*)calloc(1, len);
+ for (size_t i = 0; i < len; ++i) {
+ const char c = str[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c == '_') || (i > 0 && c >= '0' && c <= '9'))) {
+ sym[i] = '_';
+ } else {
+ sym[i] = str[i];
+ }
+ }
+
+ LilvNode* ret = lilv_new_string(world, sym);
+ free(sym);
+ return ret;
+}
diff --git a/test/lilv_test.c b/test/lilv_test.c
index fb2b974..7c7e06d 100644
--- a/test/lilv_test.c
+++ b/test/lilv_test.c
@@ -2163,6 +2163,53 @@ test_replace_version(void)
/*****************************************************************************/
+static int
+test_get_symbol(void)
+{
+ if (!start_bundle(
+ MANIFEST_PREFIXES
+ ":plug a lv2:Plugin ; lv2:symbol \"plugsym\" ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ BUNDLE_PREFIXES PREFIX_LV2EV
+ ":plug a lv2:Plugin ; "
+ PLUGIN_NAME("Test plugin") " ; "
+ "lv2:symbol \"plugsym\" .")) {
+ return 0;
+ }
+
+ init_uris();
+
+ LilvNode* plug_sym = lilv_world_get_symbol(world, plugin_uri_value);
+ LilvNode* path = lilv_new_uri(world, "http://example.org/foo");
+ LilvNode* path_sym = lilv_world_get_symbol(world, path);
+ LilvNode* query = lilv_new_uri(world, "http://example.org/foo?bar=baz");
+ LilvNode* query_sym = lilv_world_get_symbol(world, query);
+ LilvNode* frag = lilv_new_uri(world, "http://example.org/foo#bar");
+ LilvNode* frag_sym = lilv_world_get_symbol(world, frag);
+ LilvNode* queryfrag = lilv_new_uri(world, "http://example.org/foo?bar=baz#quux");
+ LilvNode* queryfrag_sym = lilv_world_get_symbol(world, queryfrag);
+ LilvNode* nonuri = lilv_new_int(world, 42);
+
+ TEST_ASSERT(lilv_world_get_symbol(world, nonuri) == NULL);
+ TEST_ASSERT(!strcmp(lilv_node_as_string(plug_sym), "plugsym"));
+ TEST_ASSERT(!strcmp(lilv_node_as_string(path_sym), "foo"));
+ TEST_ASSERT(!strcmp(lilv_node_as_string(query_sym), "bar_baz"));
+ TEST_ASSERT(!strcmp(lilv_node_as_string(frag_sym), "bar"));
+ TEST_ASSERT(!strcmp(lilv_node_as_string(queryfrag_sym), "quux"));
+
+ lilv_node_free(nonuri);
+ lilv_node_free(queryfrag_sym);
+ lilv_node_free(queryfrag);
+ lilv_node_free(frag_sym);
+ lilv_node_free(frag);
+ lilv_node_free(query_sym);
+ lilv_node_free(query);
+ lilv_node_free(plug_sym);
+
+ return 1;
+}
+
+/*****************************************************************************/
+
/* add tests here */
static struct TestCase tests[] = {
TEST_CASE(util),
@@ -2188,6 +2235,7 @@ static struct TestCase tests[] = {
TEST_CASE(state),
TEST_CASE(reload_bundle),
TEST_CASE(replace_version),
+ TEST_CASE(get_symbol),
{ NULL, NULL }
};