summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-07-15 19:48:59 +0000
committerDavid Robillard <d@drobilla.net>2014-07-15 19:48:59 +0000
commit45f02a1390bbea3f7acbef5fdb4807a9f9331f3d (patch)
treec0a04698cdc1d392b5671ebe3c20d302acae61bf
parentc067725cf5c187bca3c7b9a41c8b90a8ce50d95d (diff)
downloadlilv-45f02a1390bbea3f7acbef5fdb4807a9f9331f3d.tar.gz
lilv-45f02a1390bbea3f7acbef5fdb4807a9f9331f3d.tar.bz2
lilv-45f02a1390bbea3f7acbef5fdb4807a9f9331f3d.zip
Add lilv_world_unload_bundle() and lilv_world_unload_resource().
git-svn-id: http://svn.drobilla.net/lad/trunk/lilv@5413 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--NEWS5
-rw-r--r--lilv/lilv.h26
-rw-r--r--src/state.c8
-rw-r--r--src/world.c126
-rw-r--r--test/lilv_test.c16
-rw-r--r--wscript2
6 files changed, 155 insertions, 28 deletions
diff --git a/NEWS b/NEWS
index 792c1dd..927ad2f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-lilv (0.19.0) unstable;
+lilv (0.19.2) unstable;
* Don't load files multiple times if they are listed as rdfs:seeAlso for
several plugins
@@ -12,10 +12,11 @@ lilv (0.19.0) unstable;
(thanks Filipe Coelho)
* Improved/working lv2_apply.py to apply plugin to a .wav
(thanks Joe Button)
+ * Add lilv_world_unload_bundle() and lilv_world_unload_resource()
* Fix several minor memory leaks
* Improve test coverage
- -- David Robillard <d@drobilla.net> Sat, 12 Jul 2014 22:42:56 -0400
+ -- David Robillard <d@drobilla.net> Tue, 15 Jul 2014 15:14:36 -0400
lilv (0.18.0) stable;
diff --git a/lilv/lilv.h b/lilv/lilv.h
index 8c60132..7de90d4 100644
--- a/lilv/lilv.h
+++ b/lilv/lilv.h
@@ -608,6 +608,18 @@ lilv_world_load_bundle(LilvWorld* world,
LilvNode* bundle_uri);
/**
+ Unload a specific bundle.
+
+ This unloads statements loaded by lilv_world_load_bundle(). Note that this
+ is not necessarily all information loaded from the bundle. If any resources
+ have been separately loaded with liv_world_load_resource(), they must be
+ separately unloaded with lilv_world_unload_resource().
+*/
+LILV_API
+int
+lilv_world_unload_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
@@ -621,6 +633,18 @@ lilv_world_load_resource(LilvWorld* world,
const LilvNode* resource);
/**
+ Unload all the data associated with the given @c resource.
+ @param resource Must be a subject (i.e. a URI or a blank node).
+
+ This unloads all data loaded by a previous call to
+ lilv_world_load_resource() with the given @c resource.
+*/
+LILV_API
+int
+lilv_world_unload_resource(LilvWorld* world,
+ const LilvNode* resource);
+
+/**
Get the parent of all other plugin classes, lv2:Plugin.
*/
LILV_API
@@ -1236,7 +1260,7 @@ lilv_port_get_scale_points(const LilvPlugin* plugin,
This function can be used to load the default state of a plugin by passing
the plugin URI as the @p subject parameter.
@param subject The subject of the state description (e.g. a preset URI).
- @return A new LilvState which must be freed with lilv_state_free().
+ @return A new LilvState which must be freed with lilv_state_free(), or NULL.
*/
LILV_API
LilvState*
diff --git a/src/state.c b/src/state.c
index 79b55ec..0a775c9 100644
--- a/src/state.c
+++ b/src/state.c
@@ -1,5 +1,5 @@
/*
- Copyright 2007-2012 David Robillard <http://drobilla.net>
+ Copyright 2007-2014 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -439,6 +439,12 @@ new_state_from_model(LilvWorld* world,
const SordNode* node,
const char* dir)
{
+ // Check that we know at least something about this state subject
+ if (!sord_ask(model, node, 0, 0, 0)) {
+ return NULL;
+ }
+
+ // Allocate state
LilvState* const state = (LilvState*)malloc(sizeof(LilvState));
memset(state, '\0', sizeof(LilvState));
state->dir = lilv_strdup(dir);
diff --git a/src/world.c b/src/world.c
index 228db8a..48bf401 100644
--- a/src/world.c
+++ b/src/world.c
@@ -1,5 +1,5 @@
/*
- Copyright 2007-2011 David Robillard <http://drobilla.net>
+ Copyright 2007-2014 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -362,7 +362,7 @@ lilv_world_add_spec(LilvWorld* world,
static void
lilv_world_add_plugin(LilvWorld* world,
const SordNode* plugin_node,
- SerdNode* manifest_uri,
+ const LilvNode* manifest_uri,
void* dynmanifest,
const SordNode* bundle_node)
{
@@ -385,7 +385,7 @@ lilv_world_add_plugin(LilvWorld* world,
// Add manifest as plugin data file (as if it were rdfs:seeAlso)
zix_tree_insert((ZixTree*)plugin->data_uris,
- lilv_new_uri(world, (const char*)manifest_uri->buf),
+ lilv_node_duplicate(manifest_uri),
NULL);
#ifdef LILV_DYN_MANIFEST
@@ -431,9 +431,9 @@ lilv_world_load_graph(LilvWorld* world, SordNode* graph, const LilvNode* uri)
}
static void
-lilv_world_load_dyn_manifest(LilvWorld* world,
- SordNode* bundle_node,
- SerdNode manifest_uri)
+lilv_world_load_dyn_manifest(LilvWorld* world,
+ SordNode* bundle_node,
+ const LilvNode* manifest)
{
#ifdef LILV_DYN_MANIFEST
if (!world->opt.dyn_manifest) {
@@ -542,9 +542,8 @@ lilv_world_load_dyn_manifest(LilvWorld* world,
world->uris.lv2_Plugin,
dmanifest);
FOREACH_MATCH(plug_results) {
- const SordNode* plugin_node = sord_iter_get_node(plug_results, SORD_SUBJECT);
- lilv_world_add_plugin(world, plugin_node,
- &manifest_uri, desc, bundle_node);
+ const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT);
+ lilv_world_add_plugin(world, plug, manifest, desc, bundle_node);
}
sord_iter_free(plug_results);
@@ -554,6 +553,18 @@ lilv_world_load_dyn_manifest(LilvWorld* world,
#endif // LILV_DYN_MANIFEST
}
+static
+LilvNode*
+lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri)
+{
+ SerdNode manifest_uri = lilv_new_uri_relative_to_base(
+ (const uint8_t*)"manifest.ttl",
+ (const uint8_t*)sord_node_get_string(bundle_uri->node));
+ LilvNode* manifest = lilv_new_uri(world, (const char*)manifest_uri.buf);
+ serd_node_free(&manifest_uri);
+ return manifest;
+}
+
LILV_API
void
lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri)
@@ -564,17 +575,14 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri)
return;
}
- SordNode* bundle_node = bundle_uri->node;
- SerdNode manifest_uri = lilv_new_uri_relative_to_base(
- (const uint8_t*)"manifest.ttl",
- (const uint8_t*)sord_node_get_string(bundle_node));
- LilvNode* manifest = lilv_new_uri(world, (const char*)manifest_uri.buf);
+ SordNode* bundle_node = bundle_uri->node;
+ LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri);
// Read manifest into model with graph = bundle_node
SerdStatus st = lilv_world_load_graph(world, bundle_node, manifest);
- lilv_node_free(manifest);
if (st > SERD_FAILURE) {
- LILV_ERRORF("Error reading %s\n", manifest_uri.buf);
+ LILV_ERRORF("Error reading %s\n", lilv_node_as_string(manifest));
+ lilv_node_free(manifest);
return;
}
@@ -586,13 +594,12 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri)
world->uris.lv2_Plugin,
bundle_node);
FOREACH_MATCH(plug_results) {
- const SordNode* plugin_node = sord_iter_get_node(plug_results, SORD_SUBJECT);
- lilv_world_add_plugin(world, plugin_node,
- &manifest_uri, NULL, bundle_node);
+ const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT);
+ lilv_world_add_plugin(world, plug, manifest, NULL, bundle_node);
}
sord_iter_free(plug_results);
- lilv_world_load_dyn_manifest(world, bundle_node, manifest_uri);
+ lilv_world_load_dyn_manifest(world, bundle_node, manifest);
// ?specification a lv2:Specification
SordIter* spec_results = sord_search(
@@ -607,7 +614,51 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri)
}
sord_iter_free(spec_results);
- serd_node_free(&manifest_uri);
+ lilv_node_free(manifest);
+}
+
+static int
+lilv_world_drop_graph(LilvWorld* world, LilvNode* graph)
+{
+ SordIter* i = sord_search(world->model, NULL, NULL, NULL, graph->node);
+
+ while (!sord_iter_end(i)) {
+ // Get quad and increment iter so sord_remove doesn't invalidate it
+ SordQuad quad;
+ sord_iter_get(i, quad);
+ sord_iter_next(i);
+
+ // Remove quad (nodes may now be deleted, quad is invalid)
+ sord_remove(world->model, quad);
+ }
+ sord_iter_free(i);
+
+ return 0;
+}
+
+/** Remove loaded_files entry so file will be reloaded if requested. */
+static int
+lilv_world_unload_file(LilvWorld* world, LilvNode* file)
+{
+ ZixTreeIter* iter;
+ if (!zix_tree_find((ZixTree*)world->loaded_files, file, &iter)) {
+ zix_tree_remove(world->loaded_files, iter);
+ return 0;
+ }
+ return 1;
+}
+
+LILV_API
+int
+lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri)
+{
+ // Remove loaded_files entry for manifest.ttl
+ LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri);
+ lilv_world_unload_file(world, manifest);
+ lilv_node_free(manifest);
+
+ // Drop everything in bundle graph
+ return lilv_world_drop_graph(world, bundle_uri);
}
static void
@@ -824,6 +875,39 @@ lilv_world_load_resource(LilvWorld* world,
}
LILV_API
+int
+lilv_world_unload_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",
+ sord_node_get_string(resource->node));
+ return -1;
+ }
+
+ int n_dropped = 0;
+ SordIter* files = sord_search(world->model,
+ resource->node,
+ world->uris.rdfs_seeAlso,
+ NULL, NULL);
+ FOREACH_MATCH(files) {
+ const SordNode* file = sord_iter_get_node(files, SORD_OBJECT);
+ const uint8_t* file_str = sord_node_get_string(file);
+ LilvNode* file_node = lilv_node_new_from_node(world, file);
+ if (sord_node_get_type(file) != SORD_URI) {
+ LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", file_str);
+ } else if (!lilv_world_drop_graph(world, file_node)) {
+ lilv_world_unload_file(world, file_node);
+ ++n_dropped;
+ }
+ lilv_node_free(file_node);
+ }
+ sord_iter_free(files);
+
+ return n_dropped;
+}
+
+LILV_API
const LilvPluginClass*
lilv_world_get_plugin_class(const LilvWorld* world)
{
diff --git a/test/lilv_test.c b/test/lilv_test.c
index ea12013..52d4113 100644
--- a/test/lilv_test.c
+++ b/test/lilv_test.c
@@ -969,10 +969,9 @@ test_prototype(void)
{
if (!start_bundle(MANIFEST_PREFIXES
":prot a lv2:PluginBase ; rdfs:seeAlso <plugin.ttl> .\n"
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; lv2:prototype :prot .\n",
+ ":plug a lv2:Plugin ; lv2:binary <inst" SHLIB_EXT "> ; lv2:prototype :prot .\n",
BUNDLE_PREFIXES
":prot a lv2:Plugin ; a lv2:CompressorPlugin ; "
- PLUGIN_NAME("Test plugin with project") " ; "
LICENSE_GPL " ; "
"lv2:project [ "
" doap:name \"Fake project\" ;"
@@ -999,10 +998,15 @@ test_prototype(void)
const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value);
TEST_ASSERT(plug);
+ // Test non-inherited property
LilvNode* name = lilv_plugin_get_name(plug);
TEST_ASSERT(!strcmp(lilv_node_as_string(name), "Instance"));
lilv_node_free(name);
+ // Test inherited property
+ const LilvNode* binary = lilv_plugin_get_library_uri(plug);
+ TEST_ASSERT(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
+
cleanup_uris();
return 1;
}
@@ -1608,6 +1612,14 @@ test_state(void)
LilvState* state6 = lilv_state_new_from_world(world, &map, test_state_node);
TEST_ASSERT(lilv_state_equals(state, state6)); // Round trip accuracy
+
+ lilv_world_unload_resource(world, test_state_node);
+ lilv_world_unload_bundle(world, test_state_bundle);
+
+ LilvState* state6_2 = lilv_state_new_from_world(world, &map, test_state_node);
+ TEST_ASSERT(!state6_2); // No longer present
+ lilv_state_free(state6_2);
+
lilv_node_free(test_state_bundle);
lilv_node_free(test_state_node);
diff --git a/wscript b/wscript
index 5af7efb..609e72e 100644
--- a/wscript
+++ b/wscript
@@ -12,7 +12,7 @@ import waflib.Logs as Logs
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
-LILV_VERSION = '0.19.0'
+LILV_VERSION = '0.19.2'
LILV_MAJOR_VERSION = '0'
# Mandatory waf variables