summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--lilv/lilv.h38
-rw-r--r--src/collections.c8
-rw-r--r--src/lilv_internal.h8
-rw-r--r--src/plugin.c29
-rw-r--r--src/port.c2
-rw-r--r--src/query.c22
-rw-r--r--src/world.c79
-rw-r--r--utils/lv2info.c55
-rw-r--r--wscript2
10 files changed, 205 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index ff4eabd..3f8e5e2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,11 @@ lilv (UNRELEASED) unstable; urgency=low
* 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
+ are not directly rdfs:seeAlso linked (e.g. presets)
+ * Add lilv_world_load_resource for related resources (e.g. presets)
+ * Print presets in lv2info
-- David Robillard <d@drobilla.net> (UNRELEASED)
diff --git a/lilv/lilv.h b/lilv/lilv.h
index 649d341..ca3809d 100644
--- a/lilv/lilv.h
+++ b/lilv/lilv.h
@@ -583,6 +583,19 @@ lilv_world_load_bundle(LilvWorld* world,
LilvNode* bundle_uri);
/**
+ Load all the data associated with the given @c resource.
+ @param resource Must be a subject (i.e. a URI or a blank node).
+ @return The number of files parsed, or -1 on error
+
+ All accessible data files linked to @c resource with rdfs:seeAlso will be
+ loaded into the world model.
+*/
+LILV_API
+int
+lilv_world_load_resource(LilvWorld* world,
+ const LilvNode* resource);
+
+/**
Get the parent of all other plugin classes, lv2:Plugin.
*/
LILV_API
@@ -919,7 +932,7 @@ bool
lilv_plugin_is_replaced(const LilvPlugin* plugin);
/**
- Write the Turtle description of @c plugin to @c file.
+ Write the Turtle description of @c plugin to @c plugin_file.
This function is particularly useful for porting plugins in conjunction with
an LV2 bridge such as NASPRO.
@@ -931,6 +944,12 @@ lilv_plugin_write_description(LilvWorld* world,
const LilvNode* base_uri,
FILE* plugin_file);
+/**
+ Write a manifest entry for @c plugin to @c manifest_file.
+
+ This function is intended for use with lilv_plugin_write_description to
+ write a complete description of a plugin to a bundle.
+*/
LILV_API
void
lilv_plugin_write_manifest_entry(LilvWorld* world,
@@ -940,6 +959,23 @@ lilv_plugin_write_manifest_entry(LilvWorld* world,
const char* plugin_file_path);
/**
+ Get the resources related to @c plugin with lv2:appliesTo.
+
+ Some plugin-related resources are not linked directly to the plugin with
+ rdfs:seeAlso and thus will not be automatically loaded along with the plugin
+ data (usually for performance reasons). All such resources of the given @c
+ type related to @c plugin can be accessed with this function.
+
+ If @c type is NULL, all such resources will be returned, regardless of type.
+
+ To actually load the data for each returned resource, use
+ lilv_world_load_resource.
+*/
+LILV_API
+LilvNodes*
+lilv_plugin_get_related(const LilvPlugin* plugin, const LilvNode* type);
+
+/**
@}
@name Port
@{
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
@@ -805,6 +820,52 @@ lilv_world_load_all(LilvWorld* 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)
{
diff --git a/utils/lv2info.c b/utils/lv2info.c
index d55b9cd..7f231f3 100644
--- a/utils/lv2info.c
+++ b/utils/lv2info.c
@@ -24,19 +24,20 @@
#include "lilv-config.h"
-LilvNode* event_class = NULL;
+LilvNode* applies_to_pred = NULL;
LilvNode* control_class = NULL;
+LilvNode* event_class = NULL;
LilvNode* in_group_pred = NULL;
-LilvNode* role_pred = NULL;
-LilvNode* preset_pred = NULL;
LilvNode* label_pred = NULL;
+LilvNode* preset_class = NULL;
+LilvNode* role_pred = NULL;
LilvNode* supports_event_pred = NULL;
void
print_group(const LilvPlugin* p,
- const LilvNode* group,
- LilvNode* type,
- LilvNode* symbol)
+ const LilvNode* group,
+ LilvNode* type,
+ LilvNode* symbol)
{
printf("\n\tGroup %s:\n", lilv_node_as_string(group));
printf("\t\tType: %s\n", lilv_node_as_string(type));
@@ -198,23 +199,23 @@ print_plugin(LilvWorld* world,
LilvUIs* uis = lilv_plugin_get_uis(p);
if (lilv_nodes_size(uis) > 0) {
- printf("\tUI: ");
+ printf("\tUIs:\n");
LILV_FOREACH(uis, i, uis) {
const LilvUI* ui = lilv_uis_get(uis, i);
- printf("%s\n", lilv_node_as_uri(lilv_ui_get_uri(ui)));
+ printf("\t\t%s\n", lilv_node_as_uri(lilv_ui_get_uri(ui)));
const char* binary = lilv_node_as_uri(lilv_ui_get_binary_uri(ui));
const LilvNodes* types = lilv_ui_get_classes(ui);
LILV_FOREACH(nodes, i, types) {
- printf("\t Class: %s\n",
+ printf("\t\t\tClass: %s\n",
lilv_node_as_uri(lilv_nodes_get(types, i)));
}
if (binary)
- printf("\t Binary: %s\n", binary);
+ printf("\t\t\tBinary: %s\n", binary);
- printf("\t Bundle: %s\n",
+ printf("\t\t\tBundle: %s\n",
lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)));
}
}
@@ -267,6 +268,7 @@ print_plugin(LilvWorld* world,
lilv_nodes_free(features);
/* Extension Data */
+
LilvNodes* data = lilv_plugin_get_extension_data(p);
if (data)
printf("\tExtension Data: ");
@@ -278,25 +280,30 @@ print_plugin(LilvWorld* world,
printf("%s", lilv_node_as_uri(lilv_nodes_get(data, i)));
first = false;
}
- if (features)
+ if (data)
printf("\n");
lilv_nodes_free(data);
/* Presets */
- LilvNodes* presets = lilv_plugin_get_value(p, preset_pred);
+ LilvNodes* presets = lilv_plugin_get_related(p, preset_class);
if (presets)
printf("\tPresets: \n");
LILV_FOREACH(nodes, i, presets) {
- LilvNodes* titles = lilv_world_find_nodes(world,
- lilv_nodes_get(presets, i),
- label_pred,
- NULL);
+ const LilvNode* preset = lilv_nodes_get(presets, i);
+ lilv_world_load_resource(world, preset);
+ LilvNodes* titles = lilv_world_find_nodes(
+ world, preset, label_pred, NULL);
if (titles) {
- const LilvNode* title = lilv_nodes_get(titles, lilv_nodes_begin(titles));
+ const LilvNode* title = lilv_nodes_get_first(titles);
printf("\t %s\n", lilv_node_as_string(title));
+ lilv_nodes_free(titles);
+ } else {
+ fprintf(stderr, "Preset <%s> has no rdfs:label\n",
+ lilv_node_as_string(lilv_nodes_get(presets, i)));
}
}
+ lilv_nodes_free(presets);
/* Ports */
@@ -380,12 +387,13 @@ main(int argc, char** argv)
#define NS_PSET "http://lv2plug.in/ns/ext/presets#"
#define NS_EV "http://lv2plug.in/ns/ext/event#"
+ applies_to_pred = lilv_new_uri(world, LILV_NS_LV2 "appliesTo");
control_class = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
event_class = lilv_new_uri(world, LILV_URI_EVENT_PORT);
in_group_pred = lilv_new_uri(world, NS_PG "inGroup");
- preset_pred = lilv_new_uri(world, NS_PSET "hasPreset");
- role_pred = lilv_new_uri(world, NS_PG "role");
label_pred = lilv_new_uri(world, LILV_NS_RDFS "label");
+ preset_class = lilv_new_uri(world, NS_PSET "Preset");
+ role_pred = lilv_new_uri(world, NS_PG "role");
supports_event_pred = lilv_new_uri(world, NS_EV "supportsEvent");
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
@@ -416,12 +424,15 @@ main(int argc, char** argv)
lilv_node_free(uri);
- lilv_node_free(label_pred);
+ lilv_node_free(supports_event_pred);
lilv_node_free(role_pred);
- lilv_node_free(preset_pred);
+ lilv_node_free(preset_class);
+ lilv_node_free(label_pred);
lilv_node_free(in_group_pred);
lilv_node_free(event_class);
lilv_node_free(control_class);
+ lilv_node_free(applies_to_pred);
+
lilv_world_free(world);
return ret;
}
diff --git a/wscript b/wscript
index 3dee8e0..8a3b9be 100644
--- a/wscript
+++ b/wscript
@@ -8,7 +8,7 @@ import waflib.Options as Options
import waflib.Logs as Logs
# Version of this package (even if built as a child)
-LILV_VERSION = '0.7.0'
+LILV_VERSION = '0.8.0'
LILV_MAJOR_VERSION = '0'
# Library version (UNIX style major, minor, micro)