diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | lilv/lilv.h | 10 | ||||
-rw-r--r-- | src/world.c | 48 | ||||
-rw-r--r-- | test/lilv_test.c | 48 |
4 files changed, 107 insertions, 0 deletions
@@ -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 } }; |