From b8eb516e97042ca9559aaa506becf504180df0a8 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 16 Dec 2011 04:59:14 +0000 Subject: Fix lilv_world_find_nodes to work with wildcard subjects. Add lilv_plugin_get_related to get resources related to plugins that are not directly rdfs:seeAlso linked (e.g. presets). Add lilv_world_load_resource for related resources (e.g. presets). Print presets in lv2info. git-svn-id: http://svn.drobilla.net/lad/trunk/lilv@3877 a436a847-0d15-0410-975c-d299462d15a1 --- src/collections.c | 8 ++++++ src/lilv_internal.h | 8 +++++- src/plugin.c | 29 ++++++++++++++++++++ src/port.c | 2 +- src/query.c | 22 +++++++++------ src/world.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 129 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/collections.c b/src/collections.c index e057c6f..77917f6 100644 --- a/src/collections.c +++ b/src/collections.c @@ -22,6 +22,14 @@ lilv_ptr_cmp(const void* a, const void* b, void* user_data) return (intptr_t)a - (intptr_t)b; } +int +lilv_resource_node_cmp(const void* a, const void* b, void* user_data) +{ + const SordNode* an = ((LilvNode*)a)->val.uri_val; + const SordNode* bn = ((LilvNode*)a)->val.uri_val; + return (intptr_t)an - (intptr_t)bn; +} + /* Generic collection functions */ static inline LilvCollection* diff --git a/src/lilv_internal.h b/src/lilv_internal.h index 710d00f..a700d6f 100644 --- a/src/lilv_internal.h +++ b/src/lilv_internal.h @@ -129,6 +129,7 @@ struct LilvWorldImpl { LilvPluginClasses* plugin_classes; LilvSpec* specs; LilvPlugins* plugins; + LilvNodes* loaded_files; SordNode* dc_replaces_node; SordNode* dyn_manifest_node; SordNode* lv2_binary_node; @@ -153,6 +154,7 @@ struct LilvWorldImpl { SordNode* xsd_double_node; SordNode* xsd_integer_node; LilvNode* doap_name_val; + LilvNode* lv2_applies_to_val; LilvNode* lv2_extensionData_val; LilvNode* lv2_name_val; LilvNode* lv2_optionalFeature_val; @@ -256,6 +258,9 @@ int lilv_header_compare_by_uri(const void* a, const void* b, void* user_data); int lilv_ptr_cmp(const void* a, const void* b, void* user_data); +int +lilv_resource_node_cmp(const void* a, const void* b, void* user_data); + struct LilvHeader* lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri); @@ -306,7 +311,8 @@ static inline bool lilv_matches_end(SordIter* matches) { } LilvNodes* lilv_nodes_from_stream_objects(LilvWorld* w, - SordIter* stream); + SordIter* stream, + bool object); char* lilv_strjoin(const char* first, ...); char* lilv_strdup(const char* str); diff --git a/src/plugin.c b/src/plugin.c index f8cf054..b305291 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -828,6 +828,35 @@ lilv_plugin_get_uis(const LilvPlugin* p) } } +LILV_API +LilvNodes* +lilv_plugin_get_related(const LilvPlugin* plugin, const LilvNode* type) +{ + LilvWorld* const world = plugin->world; + LilvNodes* const related = lilv_world_find_nodes( + world, NULL, world->lv2_applies_to_val, lilv_plugin_get_uri(plugin)); + + if (!type) { + return related; + } + + LilvNodes* matches = lilv_nodes_new(); + LILV_FOREACH(nodes, i, related) { + LilvNode* node = lilv_collection_get(related, i); + SordIter* titer = lilv_world_query_internal( + world, node->val.uri_val, world->rdf_a_node, type->val.uri_val); + if (!sord_iter_end(titer)) { + zix_tree_insert(matches, + lilv_node_new_from_node(world, node->val.uri_val), + NULL); + } + sord_iter_free(titer); + } + + lilv_nodes_free(related); + return matches; +} + static size_t file_sink(const void* buf, size_t len, void* stream) { diff --git a/src/port.c b/src/port.c index 1a8ffaf..2c1b5c7 100644 --- a/src/port.c +++ b/src/port.c @@ -109,7 +109,7 @@ lilv_port_get_value_by_node(const LilvPlugin* p, predicate, NULL); - return lilv_nodes_from_stream_objects(p->world, results); + return lilv_nodes_from_stream_objects(p->world, results, true); } LILV_API diff --git a/src/query.c b/src/query.c index e465a67..40387ef 100644 --- a/src/query.c +++ b/src/query.c @@ -53,14 +53,17 @@ lilv_lang_matches(const char* a, const char* b) LilvNodes* lilv_nodes_from_stream_objects_i18n(LilvWorld* world, - SordIter* stream) + SordIter* stream, + bool object) { LilvNodes* values = lilv_nodes_new(); const SordNode* nolang = NULL; // Untranslated value const SordNode* partial = NULL; // Partial language match char* syslang = lilv_get_lang(); FOREACH_MATCH(stream) { - const SordNode* value = lilv_match_object(stream); + const SordNode* value = object + ? lilv_match_object(stream) + : lilv_match_subject(stream); if (sord_node_get_type(value) == SORD_LITERAL) { const char* lang = sord_node_get_language(value); LilvLangMatch lm = LILV_LANG_MATCH_NONE; @@ -117,20 +120,23 @@ lilv_nodes_from_stream_objects_i18n(LilvWorld* world, LilvNodes* lilv_nodes_from_stream_objects(LilvWorld* world, - SordIter* stream) + SordIter* stream, + bool object) { if (lilv_matches_end(stream)) { lilv_match_end(stream); return NULL; } else if (world->opt.filter_language) { - return lilv_nodes_from_stream_objects_i18n(world, stream); + return lilv_nodes_from_stream_objects_i18n(world, stream, object); } else { LilvNodes* values = lilv_nodes_new(); FOREACH_MATCH(stream) { - LilvNode* value = lilv_node_new_from_node( - world, lilv_match_object(stream)); - if (value) { - zix_tree_insert(values, value, NULL); + const SordNode* value = object + ? lilv_match_object(stream) + : lilv_match_subject(stream); + LilvNode* node = lilv_node_new_from_node(world, value); + if (node) { + zix_tree_insert(values, node, NULL); } } lilv_match_end(stream); diff --git a/src/world.c b/src/world.c index 7a51a3b..d5af0fe 100644 --- a/src/world.c +++ b/src/world.c @@ -45,6 +45,9 @@ lilv_world_new(void) world->specs = NULL; world->plugin_classes = lilv_plugin_classes_new(); world->plugins = lilv_plugins_new(); + world->loaded_files = zix_tree_new( + false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free); + #define NS_DYNMAN "http://lv2plug.in/ns/ext/dynmanifest#" #define NS_DCTERMS "http://purl.org/dc/terms/" @@ -77,6 +80,7 @@ lilv_world_new(void) world->xsd_integer_node = NEW_URI(LILV_NS_XSD "integer"); world->doap_name_val = NEW_URI_VAL(LILV_NS_DOAP "name"); + world->lv2_applies_to_val = NEW_URI_VAL(LILV_NS_LV2 "appliesTo"); world->lv2_extensionData_val = NEW_URI_VAL(LILV_NS_LV2 "extensionData"); world->lv2_name_val = NEW_URI_VAL(LILV_NS_LV2 "name"); world->lv2_optionalFeature_val = NEW_URI_VAL(LILV_NS_LV2 "optionalFeature"); @@ -132,6 +136,7 @@ lilv_world_free(LilvWorld* world) sord_node_free(world->world, world->xsd_double_node); sord_node_free(world->world, world->xsd_integer_node); lilv_node_free(world->doap_name_val); + lilv_node_free(world->lv2_applies_to_val); lilv_node_free(world->lv2_extensionData_val); lilv_node_free(world->lv2_name_val); lilv_node_free(world->lv2_optionalFeature_val); @@ -154,6 +159,9 @@ lilv_world_free(LilvWorld* world) zix_tree_free(world->plugins); world->plugins = NULL; + zix_tree_free(world->loaded_files); + world->loaded_files = NULL; + zix_tree_free(world->plugin_classes); world->plugin_classes = NULL; @@ -205,7 +213,7 @@ lilv_world_find_nodes(LilvWorld* world, const LilvNode* predicate, const LilvNode* object) { - if (!lilv_node_is_uri(subject) && !lilv_node_is_blank(subject)) { + if (subject && !lilv_node_is_uri(subject) && !lilv_node_is_blank(subject)) { LILV_ERRORF("Subject `%s' is not a resource\n", subject->str_val); return NULL; } @@ -213,18 +221,24 @@ lilv_world_find_nodes(LilvWorld* world, LILV_ERRORF("Predicate `%s' is not a URI\n", predicate->str_val); return NULL; } + if (!subject && !object) { + LILV_ERROR("Both subject and object are NULL\n"); + return NULL; + } - SordNode* subject_node = (lilv_node_is_uri(subject)) + SordNode* const subject_node = subject ? sord_node_copy(subject->val.uri_val) - : sord_new_blank(world->world, - (const uint8_t*)lilv_node_as_blank(subject)); + : NULL; + + SordNode* const object_node = object + ? sord_node_copy(object->val.uri_val) + : NULL; - LilvNodes* ret = lilv_world_query_values_internal(world, - subject_node, - predicate->val.uri_val, - NULL); + LilvNodes* ret = lilv_world_query_values_internal( + world, subject_node, predicate->val.uri_val, object_node); sord_node_free(world->world, subject_node); + sord_node_free(world->world, object_node); return ret; } @@ -246,7 +260,8 @@ lilv_world_query_values_internal(LilvWorld* world, { return lilv_nodes_from_stream_objects( world, - lilv_world_query_internal(world, subject, predicate, object)); + lilv_world_query_internal(world, subject, predicate, object), + (object == NULL)); } static SerdNode @@ -804,6 +819,52 @@ lilv_world_load_all(LilvWorld* world) lilv_world_load_plugin_classes(world); } +LILV_API +int +lilv_world_load_resource(LilvWorld* world, + const LilvNode* resource) +{ + if (!lilv_node_is_uri(resource) && !lilv_node_is_blank(resource)) { + LILV_ERRORF("Node `%s' is not a resource\n", resource->str_val); + return -1; + } + + int n_read = 0; + SordIter* files = lilv_world_find_statements(world, world->model, + resource->val.uri_val, + world->rdfs_seealso_node, + NULL, NULL); + FOREACH_MATCH(files) { + const SordNode* file = lilv_match_object(files); + const uint8_t* str = sord_node_get_string(file); + LilvNode* file_node = lilv_node_new_from_node(world, file); + ZixTreeIter* iter; + if (zix_tree_find(world->loaded_files, file, &iter)) { + if (sord_node_get_type(file) == SORD_URI) { + const SerdNode* base = sord_node_to_serd_node(file); + SerdEnv* env = serd_env_new(base); + SerdReader* reader = sord_new_reader( + world->model, env, SERD_TURTLE, (SordNode*)file); + if (!serd_reader_read_file(reader, str)) { + ++n_read; + zix_tree_insert(world->loaded_files, file_node, NULL); + file_node = NULL; // prevent deletion... + } else { + LILV_ERRORF("Error loading resource `%s'\n", str); + } + serd_reader_free(reader); + serd_env_free(env); + } else { + LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", str); + } + } + lilv_node_free(file_node); // ...here + } + lilv_match_end(files); + + return n_read; +} + LILV_API const LilvPluginClass* lilv_world_get_plugin_class(const LilvWorld* world) -- cgit v1.2.1