summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--slv2/model.h166
-rw-r--r--src/model.c321
3 files changed, 488 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 04f6dcc..0b058a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,7 @@ AM_INIT_AUTOMAKE
# Checks for compiler
AC_PROG_CC
+AM_PROG_CC_C_O
# Check pedantic other stuff autoscan says we should :)
AC_C_CONST
diff --git a/slv2/model.h b/slv2/model.h
new file mode 100644
index 0000000..4db1b2f
--- /dev/null
+++ b/slv2/model.h
@@ -0,0 +1,166 @@
+/* SLV2
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __SLV2_MODEL_H__
+#define __SLV2_MODEL_H__
+
+#include <slv2/pluginlist.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup model Data model loading
+ *
+ * These functions deal with the data model which other SLV2 methods
+ * operate with. The data model is LV2 data loaded from bundles, from
+ * which you can query plugins, etc.
+ *
+ * Normal hosts which just want to easily load plugins by URI are strongly
+ * recommended to simply find all installed data in the recommended way with
+ * \ref slv2_model_load_all rather than find and load bundles manually.
+ *
+ * Functions are provided for hosts that wish to access bundles explicitly and
+ * individually for some reason, this is intended for hosts which are tied to
+ * a specific bundle (shipped with the application).
+ *
+ * @{
+ */
+
+
+/** Create a new, empty model.
+ */
+SLV2Model
+slv2_model_new();
+
+
+/** Destroy a model.
+ *
+ * NB: Destroying a model will leave dangling references in any plugin lists,
+ * plugins, etc. Do not destroy a model until you are finished with all
+ * objects that came from it.
+ */
+void
+slv2_model_free(SLV2Model model);
+
+
+/** Load all installed LV2 bundles on the system
+ *
+ * This is the recommended way for hosts to load LV2 data. It does the most
+ * reasonable thing to find all installed plugins, extensions, etc. on the
+ * system. The environment variable LV2_PATH may be used to set the
+ * directories inside which this function will look for bundles. Otherwise
+ * a sensible, standard default will be used.
+ *
+ * Use of other functions for loading bundles is \em highly discouraged
+ * without a special reason to do so - use this one.
+ */
+void
+slv2_model_load_all(SLV2Model model);
+
+
+/** Load all bundles found in \a search_path.
+ *
+ * \param search_path A colon-delimited list of directories. These directories
+ * should contain LV2 bundle directories (ie the search path is a list of
+ * parent directories of bundles, not a list of bundle directories).
+ *
+ * If \a search_path is NULL, \a model will be unmodified.
+ * Use of this function is \b not recommended. Use \ref slv2_model_load_all.
+ */
+void
+slv2_model_load_path(SLV2Model model,
+ const char* search_path);
+
+
+/** Load a specific bundle into \a model.
+ *
+ * \arg bundle_base_uri is a fully qualified URI to the bundle directory,
+ * with the trailing slash, eg. file:///usr/lib/lv2/someBundle/
+ *
+ * Normal hosts should not use this function.
+ *
+ * Hosts should not attach \em any long-term significance to bundle paths
+ * as there are no guarantees they will remain consistent whatsoever.
+ * This function should only be used by apps which ship with a special
+ * bundle (which it knows exists at some path because they are part of
+ * the same package).
+ */
+void
+slv2_model_load_bundle(SLV2Model model,
+ const char* bundle_base_uri);
+
+
+/** Add all plugins present in \a model to \a list.
+ *
+ * Returned plugins contain a reference to this model, model must not be
+ * destroyed until plugins are finished with.
+ */
+SLV2Plugins
+slv2_model_get_all_plugins(SLV2Model model);
+
+
+/** Get plugins filtered by a user-defined filter function.
+ *
+ * All plugins in \a model that return true when passed to \a include
+ * (a pointer to a function that takes an SLV2Plugin and returns a bool)
+ * will be added to \a list.
+ *
+ * Returned plugins contain a reference to this model, model must not be
+ * destroyed until plugins are finished with.
+ */
+SLV2Plugins
+slv2_model_get_plugins_by_filter(SLV2Model model,
+ bool (*include)(SLV2Plugin));
+
+
+#if 0
+/** Get plugins filtered by a user-defined SPARQL query.
+ *
+ * This is much faster than using slv2_model_get_plugins_by_filter with a
+ * filter function which calls the various slv2_plugin_* functions.
+ *
+ * \param query A valid SPARQL query which SELECTs a single variable, which
+ * should match the URI of plugins to be loaded.
+ *
+ * \b Example: Get all plugins with at least 1 audio input and output:
+<tt> \verbatim
+PREFIX : <http://lv2plug.in/ontology#>
+SELECT DISTINCT ?plugin WHERE {
+ ?plugin :port [ a :AudioPort; a :InputPort ] ;
+ :port [ a :AudioPort; a :OutputPort ] .
+}
+\endverbatim </tt>
+ *
+ * Returned plugins contain a reference to this model, model must not be
+ * destroyed until plugins are finished with.
+ */
+SLV2Plugins
+slv2_model_get_plugins_by_query(SLV2Model model,
+ const char* query);
+#endif
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_MODEL_H__ */
+
diff --git a/src/model.c b/src/model.c
new file mode 100644
index 0000000..16a1962
--- /dev/null
+++ b/src/model.c
@@ -0,0 +1,321 @@
+/* SLV2
+ * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <librdf.h>
+#include <slv2/model.h>
+#include <slv2/slv2.h>
+#include <slv2/util.h>
+#include "config.h"
+#include "private_types.h"
+
+
+SLV2Model
+slv2_model_new()
+{
+ struct _Model* model = (struct _Model*)malloc(sizeof(struct _Model));
+
+ model->world = librdf_new_world();
+ librdf_world_open(model->world);
+
+ model->storage = librdf_new_storage(model->world, "hashes", NULL,
+ "hash-type='memory'");
+
+ model->model = librdf_new_model(model->world, model->storage, NULL);
+
+ model->parser = librdf_new_parser(model->world, "turtle", NULL, NULL);
+
+ model->plugins = slv2_plugins_new();
+
+ /*slv2_ontology_uri = raptor_new_uri((const unsigned char*)
+ "file://" LV2_TTL_PATH);*/
+
+ return model;
+}
+
+
+void
+slv2_model_free(SLV2Model model)
+{
+ /*raptor_free_uri(slv2_ontology_uri);
+ slv2_ontology_uri = NULL;*/
+
+ slv2_plugins_free(model->plugins);
+ model->plugins = NULL;
+
+ librdf_free_parser(model->parser);
+ model->parser = NULL;
+
+ librdf_free_model(model->model);
+ model->model = NULL;
+
+ librdf_free_storage(model->storage);
+ model->storage = NULL;
+
+ librdf_free_world(model->world);
+ model->world = NULL;
+
+ free(model);
+}
+
+
+/* private */
+void
+slv2_model_load_directory(SLV2Model model, const char* dir)
+{
+ DIR* pdir = opendir(dir);
+ if (!pdir)
+ return;
+
+ struct dirent* pfile;
+ while ((pfile = readdir(pdir))) {
+ if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, ".."))
+ continue;
+
+ char* bundle_uri_str = slv2_strjoin("file://", dir, "/", pfile->d_name, "/", NULL);
+ librdf_uri* bundle_uri = librdf_new_uri(model->world, (unsigned char*)bundle_uri_str);
+
+ DIR* bundle_dir = opendir(bundle_uri_str + 7);
+
+ if (bundle_dir != NULL) {
+ closedir(bundle_dir);
+
+ librdf_uri* manifest_uri = librdf_new_uri_relative_to_base(
+ bundle_uri, (const unsigned char*)"manifest.ttl");
+
+ librdf_parser_parse_into_model(model->parser, manifest_uri, NULL, model->model);
+
+ librdf_free_uri(manifest_uri);
+ }
+
+ free(bundle_uri_str);
+ librdf_free_uri(bundle_uri);
+ }
+
+ closedir(pdir);
+}
+
+
+void
+slv2_model_load_path(SLV2Model model,
+ const char* lv2_path)
+{
+ char* path = slv2_strjoin(lv2_path, ":", NULL);
+ char* dir = path; // Pointer into path
+
+ // Go through string replacing ':' with '\0', using the substring,
+ // then replacing it with 'X' and moving on. i.e. strtok on crack.
+ while (strchr(path, ':') != NULL) {
+ char* delim = strchr(path, ':');
+ *delim = '\0';
+
+ slv2_model_load_directory(model, dir);
+
+ *delim = 'X';
+ dir = delim + 1;
+ }
+
+ free(path);
+}
+
+
+/** comparator for sorting */
+/*int
+slv2_plugin_compare_by_uri(const void* a, const void* b)
+{
+ SLV2Plugin plugin_a = *(SLV2Plugin*)a;
+ SLV2Plugin plugin_b = *(SLV2Plugin*)b;
+
+ return strcmp((const char*)librdf_uri_as_string(plugin_a->plugin_uri),
+ (const char*)librdf_uri_as_string(plugin_b->plugin_uri));
+}
+*/
+
+void
+slv2_model_load_all(SLV2Model model)
+{
+ char* lv2_path = getenv("LV2_PATH");
+
+ // Read all manifest files
+ if (lv2_path) {
+ slv2_model_load_path(model, lv2_path);
+ } else {
+ const char* const home = getenv("HOME");
+ const char* const suffix = "/.lv2:/usr/local/lib/lv2:usr/lib/lv2";
+ lv2_path = slv2_strjoin(home, suffix, NULL);
+
+ //fprintf(stderr, "$LV2_PATH is unset. Using default path %s\n", lv2_path);
+
+ slv2_model_load_path(model, lv2_path);
+
+ free(lv2_path);
+ }
+
+
+ // Find all plugins and associated data files
+ unsigned char* query_string = (unsigned char*)
+ "PREFIX : <http://lv2plug.in/ontology#>\n"
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
+ "SELECT DISTINCT ?plugin ?data ?binary\n"
+ "WHERE { ?plugin a :Plugin; rdfs:seeAlso ?data\n"
+ "OPTIONAL { ?plugin :binary ?binary } }\n"
+ "ORDER BY ?plugin\n";
+
+ librdf_query* q = librdf_new_query(model->world, "sparql",
+ NULL, query_string, NULL);
+
+ librdf_query_results* results = librdf_query_execute(q, model->model);
+
+ while (!librdf_query_results_finished(results)) {
+
+ librdf_node* plugin_node = librdf_query_results_get_binding_value(results, 0);
+ librdf_uri* plugin_uri = librdf_node_get_uri(plugin_node);
+ librdf_node* data_node = librdf_query_results_get_binding_value(results, 1);
+ librdf_uri* data_uri = librdf_node_get_uri(data_node);
+ librdf_node* binary_node = librdf_query_results_get_binding_value(results, 2);
+ librdf_uri* binary_uri = librdf_node_get_uri(binary_node);
+
+ SLV2Plugin plugin = slv2_plugins_get_by_uri(model->plugins,
+ (const char*)librdf_uri_as_string(plugin_uri));
+
+ // Create a new SLV2Plugin
+ if (!plugin)
+ plugin = slv2_plugin_new(model, plugin_uri,
+ (const char*)librdf_uri_as_string(binary_uri));
+
+ plugin->model = model;
+
+ // FIXME: check for duplicates
+ raptor_sequence_push(plugin->data_uris, librdf_new_uri_from_uri(data_uri));
+
+ raptor_sequence_push(model->plugins, plugin);
+
+ librdf_free_node(plugin_node);
+ librdf_free_node(data_node);
+
+ librdf_query_results_next(results);
+ }
+
+ // ORDER BY should (and appears to actually) guarantee this
+ //raptor_sequence_sort(model->plugins, slv2_plugin_compare_by_uri);
+
+ if (results)
+ librdf_free_query_results(results);
+
+ librdf_free_query(q);
+}
+
+
+#if 0
+void
+slv2_model_serialize(const char* filename)
+{
+ librdf_uri* lv2_uri = librdf_new_uri(slv2_rdf_world,
+ (unsigned char*)"http://lv2plug.in/ontology#");
+
+ librdf_uri* rdfs_uri = librdf_new_uri(slv2_rdf_world,
+ (unsigned char*)"http://www.w3.org/2000/01/rdf-schema#");
+
+ // Write out test file
+ librdf_serializer* serializer = librdf_new_serializer(slv2_rdf_world,
+ "turtle", NULL, NULL);
+ librdf_serializer_set_namespace(serializer, lv2_uri, "");
+ librdf_serializer_set_namespace(serializer, rdfs_uri, "rdfs");
+ librdf_serializer_serialize_model_to_file(serializer, filename, NULL, slv2_model);
+ librdf_free_serializer(serializer);
+}
+#endif
+
+
+SLV2Plugins
+slv2_model_get_all_plugins(SLV2Model model)
+{
+ // FIXME: Slow..
+
+ // NULL deleter so user can free returned sequence without nuking
+ // our locally stored plugins
+ raptor_sequence* result = raptor_new_sequence(NULL, NULL);
+
+ for (int i=0; i < raptor_sequence_size(model->plugins); ++i)
+ raptor_sequence_push(result, raptor_sequence_get_at(model->plugins, i));
+
+ // sorted?
+
+ return result;
+}
+
+
+SLV2Plugins
+slv2_model_get_plugins_by_filter(SLV2Model model, bool (*include)(SLV2Plugin))
+{
+ SLV2Plugins all = slv2_model_get_all_plugins(model);
+ SLV2Plugins result = slv2_plugins_new();
+
+ for (int i=0; i < raptor_sequence_size(all); ++i) {
+ SLV2Plugin p = raptor_sequence_get_at(all, i);
+ if (include(p))
+ raptor_sequence_push(result, slv2_plugin_duplicate(p));
+ }
+
+ slv2_plugins_free(all);
+ return result;
+}
+
+
+#if 0
+SLV2Plugins
+slv2_model_get_plugins_by_query(SLV2Model model, const char* query)
+{
+ SLV2Plugins list = slv2_plugins_new();
+
+ librdf_query* rq = librdf_new_query(model->world, "sparql",
+ NULL, (const unsigned char*)query, NULL);
+
+ librdf_query_results* results = librdf_query_execute(rq, model->model);
+
+ while (!librdf_query_results_finished(results)) {
+ librdf_node* plugin_node = librdf_query_results_get_binding_value(results, 0);
+ librdf_uri* plugin_uri = librdf_node_get_uri(plugin_node);
+
+ SLV2Plugin plugin = slv2_plugins_get_by_uri(list,
+ (const char*)librdf_uri_as_string(plugin_uri));
+
+ /* Create a new SLV2Plugin */
+ if (!plugin) {
+ SLV2Plugin new_plugin = slv2_plugin_new(model, plugin_uri);
+ raptor_sequence_push(list, new_plugin);
+ }
+
+ librdf_free_node(plugin_node);
+
+ librdf_query_results_next(results);
+ }
+
+ if (results)
+ librdf_free_query_results(results);
+
+ librdf_free_query(rq);
+
+ return list;
+}
+#endif
+