summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/plugin.c190
-rw-r--r--src/plugininstance.c100
-rw-r--r--src/pluginlist.c243
-rw-r--r--src/port.c163
-rw-r--r--src/query.c123
-rw-r--r--src/util.c121
-rw-r--r--src/util.h53
8 files changed, 1007 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..5f6cea2
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,14 @@
+AM_CFLAGS = -std=c99 -I$(top_srcdir)/include -I$(top_srcdir) @RASQAL_CFLAGS@ -DLIBSLV2_SOURCE
+AM_LDFLAGS = `pkg-config --libs rasqal`
+
+lib_LTLIBRARIES = libslv2.la
+libslv2_la_LIBADD = @RASQAL_LIBS@
+
+libslv2_la_SOURCES = \
+ util.h \
+ plugin.c \
+ query.c \
+ port.c \
+ pluginlist.c \
+ util.c \
+ plugininstance.c
diff --git a/src/plugin.c b/src/plugin.c
new file mode 100644
index 0000000..27fb481
--- /dev/null
+++ b/src/plugin.c
@@ -0,0 +1,190 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rasqal.h>
+#include <slv2/private_types.h>
+#include <slv2/plugin.h>
+#include <slv2/types.h>
+#include <slv2/query.h>
+#include "util.h"
+
+
+SLV2Plugin*
+slv2_plugin_duplicate(const SLV2Plugin* p)
+{
+ assert(p);
+ struct _Plugin* result = malloc(sizeof(struct _Plugin));
+ result->plugin_uri = p->plugin_uri;
+ result->bundle_url = p->bundle_url;
+ result->data_url = p->data_url;
+ result->lib_url = p->lib_url;
+ return result;
+}
+
+
+const unsigned char*
+slv2_plugin_get_uri(const SLV2Plugin* p)
+{
+ assert(p);
+ return p->plugin_uri;
+}
+
+
+const unsigned char*
+slv2_plugin_get_data_url(const SLV2Plugin* p)
+{
+ assert(p);
+ return p->data_url;
+}
+
+
+const unsigned char*
+slv2_plugin_get_data_path(const SLV2Plugin* p)
+{
+ assert(p);
+ if (!strncmp((char*)p->data_url, "file://", 7))
+ return (p->data_url) + 7;
+ else
+ return NULL;
+}
+
+
+const unsigned char*
+slv2_plugin_get_library_url(const SLV2Plugin* p)
+{
+ assert(p);
+ return p->lib_url;
+}
+
+
+const unsigned char*
+slv2_plugin_get_library_path(const SLV2Plugin* p)
+{
+ assert(p);
+ if (!strncmp((char*)p->lib_url, "file://", 7))
+ return (p->lib_url) + 7;
+ else
+ return NULL;
+}
+
+
+bool
+slv2_plugin_verify(const SLV2Plugin* plugin)
+{
+ // FIXME: finish this (properly)
+ /*
+ size_t num_values = 0;
+
+ struct SLV2Property* prop = slv2_plugin_get_property(plugin, "doap:name");
+ if (prop) {
+ num_values = prop->num_values;
+ free(prop);
+ }
+ if (num_values < 1)
+ return false;
+
+ prop = slv2_plugin_get_property(plugin, "doap:license");
+ num_values = prop->num_values;
+ free(prop);
+ if (num_values < 1)
+ return false;
+*/
+ return true;
+}
+
+
+unsigned char*
+slv2_plugin_get_name(const SLV2Plugin* plugin)
+{
+// FIXME: leak
+ unsigned char* result = NULL;
+ struct _Property* prop = slv2_plugin_get_property(plugin, "doap:name");
+
+ // FIXME: guaranteed to be the untagged one?
+ if (prop && prop->num_values >= 1)
+ result = prop->values[0];
+
+ return result;
+}
+
+
+SLV2Property
+slv2_plugin_get_property(const SLV2Plugin* p,
+ const char* property)
+{
+ assert(p);
+ assert(property);
+
+ /*
+ uchar* header = slv2_query_header(p);
+ uchar* lang_filter = slv2_query_lang_filter(U("?value"));
+
+ uchar* query_string = ustrjoin(
+ header,
+ U("SELECT DISTINCT ?value FROM data: WHERE { \n"),
+ U("plugin: "), property, U(" ?value . \n"),
+ ((lang_filter != NULL) ? lang_filter : U("")),
+ "}", 0);
+
+ free(header);
+ free(lang_filter);*/
+
+ rasqal_init();
+
+ rasqal_query_results* results = slv2_plugin_run_query(p,
+ U("SELECT DISTINCT ?value FROM data: WHERE { \n"
+ "plugin: "), property, U(" ?value . \n"
+ "} \n"), 0);
+
+ struct _Property* result = slv2_query_get_results(results);
+
+ //free(query_string);
+ rasqal_free_query_results(results);
+ rasqal_finish();
+
+ return result;
+}
+
+
+unsigned long
+slv2_plugin_get_num_ports(const SLV2Plugin* p)
+{
+ unsigned long result = 0;
+
+ rasqal_init();
+
+
+ rasqal_query_results* results = slv2_plugin_run_query(p,
+ U("SELECT DISTINCT ?value FROM data: WHERE { \n"
+ "plugin: lv2:port ?value . \n"
+ "} \n"), 0);
+
+ while (!rasqal_query_results_finished(results)) {
+ ++result;
+ rasqal_query_results_next(results);
+ }
+
+ rasqal_free_query_results(results);
+ rasqal_finish();
+
+ return result;
+}
+
diff --git a/src/plugininstance.c b/src/plugininstance.c
new file mode 100644
index 0000000..40de08c
--- /dev/null
+++ b/src/plugininstance.c
@@ -0,0 +1,100 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <slv2/private_types.h>
+#include <slv2/types.h>
+#include <slv2/plugin.h>
+#include <slv2/plugininstance.h>
+#include "util.h"
+
+
+SLV2Instance*
+slv2_plugin_instantiate(const SLV2Plugin* plugin,
+ unsigned long sample_rate,
+ const LV2_Host_Feature** host_features)
+{
+ struct _Instance* result = NULL;
+
+ const unsigned char* const lib_path = slv2_plugin_get_library_path(plugin);
+ if (!lib_path)
+ return NULL;
+
+ void* lib = dlopen((char*)lib_path, RTLD_NOW);
+ if (!lib) {
+ printf("Unable to open library %s\n", lib_path);
+ return NULL;
+ }
+
+ LV2_Descriptor_Function df = dlsym(lib, "lv2_descriptor");
+
+ if (!df) {
+ printf("Could not find symbol 'lv2_descriptor', "
+ "%s is not a LV2 plugin.\n", lib_path);
+ dlclose(lib);
+ return NULL;
+ } else {
+ // Search for plugin by URI
+
+ const char* const bundle_path = url2path(plugin->bundle_url);
+
+ for (unsigned long i=0; 1; ++i) {
+ const LV2_Descriptor* ld = df(i);
+
+ if (!ld) {
+ printf("Did not find plugin %s in %s\n",
+ plugin->plugin_uri, plugin->lib_url);
+ dlclose(lib);
+ break; // return NULL
+ } else if (!strcmp(ld->URI, (char*)plugin->plugin_uri)) {
+ //printf("Found %s at index %ld in:\n\t%s\n\n", plugin->plugin_uri, i, lib_path);
+
+ assert(ld->instantiate);
+
+ // Create SLV2Instance to return
+ result = malloc(sizeof(struct _Instance));
+ /*result->plugin = malloc(sizeof(struct _Plugin));
+ memcpy(result->plugin, plugin, sizeof(struct _Plugin));*/
+ result->descriptor = ld;
+ result->lib_handle = lib;
+ result->lv2_handle = ld->instantiate(ld, sample_rate, (char*)bundle_path, host_features);
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+void
+slv2_instance_free(SLV2Instance* instance)
+{
+ struct _Instance* i = (struct _Instance*)instance;
+ i->descriptor->cleanup(i->lv2_handle);
+ i->descriptor = NULL;
+ dlclose(i->lib_handle);
+ i->lib_handle = NULL;
+ free(i);
+}
+
+
diff --git a/src/pluginlist.c b/src/pluginlist.c
new file mode 100644
index 0000000..61e4c4b
--- /dev/null
+++ b/src/pluginlist.c
@@ -0,0 +1,243 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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 <rasqal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <dirent.h>
+#include <slv2/private_types.h>
+#include <slv2/types.h>
+#include <slv2/plugin.h>
+#include <slv2/pluginlist.h>
+#include "util.h"
+
+
+struct _PluginList*
+slv2_list_new()
+{
+ struct _PluginList* result = malloc(sizeof(struct _PluginList));
+ result->num_plugins = 0;
+ result->plugins = NULL;
+ return result;
+}
+
+
+void
+slv2_list_free(SLV2List list)
+{
+ list->num_plugins = 0;
+ free(list->plugins);
+ free(list);
+}
+
+
+void
+slv2_list_load_all(SLV2List list)
+{
+ assert(list != NULL);
+
+ char* slv2_path = getenv("LV2_PATH");
+
+ if (!slv2_path) {
+ slv2_path = "~/.lv2:/usr/local/lib/lv2:usr/lib/lv2";
+
+ printf("$LV2_PATH is unset. Using default path %s\n",
+ slv2_path);
+ }
+
+ slv2_list_load_path(list, slv2_path);
+}
+
+
+/* This is the parser for manifest.ttl */
+void
+slv2_list_load_bundle(SLV2List list,
+ const unsigned char* bundle_base_uri)
+{
+ // FIXME: ew
+ unsigned char* manifest_uri = malloc(
+ (strlen((char*)bundle_base_uri) + strlen("manifest.ttl") + 2) * sizeof(unsigned char));
+ memcpy(manifest_uri, bundle_base_uri, strlen((char*)bundle_base_uri)+1 * sizeof(unsigned char));
+ if (bundle_base_uri[strlen((char*)bundle_base_uri)-1] == '/')
+ strcat((char*)manifest_uri, (char*)"manifest.ttl");
+ else
+ strcat((char*)manifest_uri, (char*)"/manifest.ttl");
+
+ rasqal_init();
+ rasqal_query_results *results;
+ raptor_uri *base_uri = raptor_new_uri(manifest_uri);
+ rasqal_query *rq = rasqal_new_query((const char*)"sparql", (const uchar*)base_uri);
+
+ unsigned char* query_string =
+ U("PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "PREFIX : <http://lv2plug.in/ontology#> \n\n"
+
+ "SELECT DISTINCT $plugin_uri $data_url $lib_url FROM <> WHERE { \n"
+ "$plugin_uri :binary $lib_url ; \n"
+ " rdfs:seeAlso $data_url . \n"
+ "} \n");
+
+ //printf("%s\n\n", query_string);
+
+ rasqal_query_prepare(rq, (const uchar*)query_string, base_uri);
+ results = rasqal_query_execute(rq);
+
+ while (!rasqal_query_results_finished(results)) {
+
+ // Create a new plugin
+ struct _Plugin* new_plugin = malloc(sizeof(struct _Plugin));
+ new_plugin->bundle_url = ustrdup(bundle_base_uri);
+
+ rasqal_literal* literal = NULL;
+
+ literal = rasqal_query_results_get_binding_value_by_name(results,
+ U("plugin_uri"));
+ if (literal)
+ new_plugin->plugin_uri = ustrdup(rasqal_literal_as_string(literal));
+
+ literal = rasqal_query_results_get_binding_value_by_name(results,
+ U("data_url"));
+ if (literal)
+ new_plugin->data_url = ustrdup(rasqal_literal_as_string(literal));
+
+ literal = rasqal_query_results_get_binding_value_by_name(results,
+ U("lib_url"));
+ if (literal)
+ new_plugin->lib_url = ustrdup(rasqal_literal_as_string(literal));
+
+ /* Add the plugin if it's valid */
+ if (new_plugin->lib_url && new_plugin->data_url && new_plugin->plugin_uri
+ && slv2_plugin_verify(new_plugin)) {
+ /* Yes, this is disgusting, but it doesn't seem there's a way to know
+ * how many matches there are before iterating over them */
+ list->num_plugins++;
+ list->plugins = realloc(list->plugins,
+ list->num_plugins * sizeof(struct _Plugin*));
+ list->plugins[list->num_plugins-1] = new_plugin;
+ }
+
+ rasqal_query_results_next(results);
+ }
+
+ rasqal_free_query_results(results);
+ rasqal_free_query(rq);
+ raptor_free_uri(base_uri);
+ rasqal_finish();
+
+ free(manifest_uri);
+}
+
+
+/* Add all the plugins found in dir to list.
+ * (Private helper function, not exposed in public API)
+ */
+void
+add_plugins_from_dir(SLV2List list, 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_path = (char*)ustrjoin(U(dir), U("/"), U(pfile->d_name), 0);
+ char* bundle_url = (char*)ustrjoin(U("file://"), U(dir), U("/"), U(pfile->d_name), 0);
+ DIR* bundle_dir = opendir(bundle_path);
+
+ if (bundle_dir != NULL) {
+ closedir(bundle_dir);
+
+ slv2_list_load_bundle(list, U(bundle_url));
+ //printf("Loaded bundle %s\n", bundle_url);
+ }
+
+ free(bundle_path);
+ }
+
+ closedir(pdir);
+}
+
+
+void
+slv2_list_load_path(SLV2List list,
+ const char* slv2_path)
+{
+
+ char* path = (char*)ustrjoin(U(slv2_path), U(":"), 0);
+
+ char* dir = path; // Pointer into path
+
+ // Go through string replacing ':' with '\0', using the substring,
+ // then replacing it with 'X' and moving on. eg strtok on crack.
+ while (strchr(path, ':') != NULL) {
+ char* delim = strchr(path, ':');
+ *delim = '\0';
+
+ add_plugins_from_dir(list, dir);
+
+ *delim = 'X';
+ dir = delim + 1;
+ }
+
+ //char* slv2_path = strdup(slv2
+
+ free(path);
+}
+
+
+unsigned long
+slv2_list_get_length(const SLV2List list)
+{
+ assert(list != NULL);
+ return list->num_plugins;
+}
+
+
+SLV2Plugin*
+slv2_list_get_plugin_by_uri(const SLV2List list, const unsigned char* uri)
+{
+ if (list->num_plugins > 0) {
+ assert(list->plugins != NULL);
+
+ for (unsigned long i=0; i < list->num_plugins; ++i)
+ if (!strcmp((char*)list->plugins[i]->plugin_uri, (char*)uri))
+ return list->plugins[i];
+ }
+
+ return NULL;
+}
+
+
+SLV2Plugin*
+slv2_list_get_plugin_by_index(const SLV2List list, unsigned long index)
+{
+ if (list->num_plugins == 0)
+ return NULL;
+
+ assert(list->plugins != NULL);
+
+ return (index < list->num_plugins) ? list->plugins[index] : NULL;
+}
+
diff --git a/src/port.c b/src/port.c
new file mode 100644
index 0000000..e25eb2f
--- /dev/null
+++ b/src/port.c
@@ -0,0 +1,163 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <slv2/port.h>
+#include <slv2/types.h>
+#include <slv2/query.h>
+#include "util.h"
+
+enum SLV2PortClass
+slv2_port_get_class(SLV2Plugin* p,
+ unsigned long index)
+{
+ struct _Property* class = slv2_port_get_property(p, index, U("rdf:type"));
+ assert(class);
+ assert(class->num_values == 1);
+ assert(class->values);
+
+ if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#InputControlRatePort"))
+ return SLV2_CONTROL_RATE_INPUT;
+ else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#OutputControlRatePort"))
+ return SLV2_CONTROL_RATE_OUTPUT;
+ else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#InputAudioRatePort"))
+ return SLV2_AUDIO_RATE_INPUT;
+ else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#OutputAudioRatePort"))
+ return SLV2_AUDIO_RATE_OUTPUT;
+ else
+ return SLV2_UNKNOWN_PORT_CLASS;
+}
+
+
+enum SLV2DataType
+slv2_port_get_data_type(SLV2Plugin* p,
+ unsigned long index)
+{
+ SLV2Property type = slv2_port_get_property(p, index, U("lv2:datatype"));
+ assert(type);
+ assert(type->num_values == 1);
+ assert(type->values);
+
+ if (!strcmp((char*)type->values[0], "http://lv2plug.in/ontology#float"))
+ return SLV2_DATA_TYPE_FLOAT;
+ else
+ return SLV2_UNKNOWN_DATA_TYPE;
+}
+
+
+SLV2Property
+slv2_port_get_property(SLV2Plugin* p,
+ unsigned long index,
+ const uchar* property)
+{
+ assert(p);
+ assert(property);
+
+ char index_str[4];
+ snprintf(index_str, 4, "%ld", index);
+
+ rasqal_init();
+
+ rasqal_query_results* results = slv2_plugin_run_query(p,
+ U("SELECT DISTINCT ?value FROM data: WHERE { \n"
+ "plugin: lv2:port ?port \n"
+ "?port lv2:index "), index_str, U(" \n"
+ "?port "), property, U(" ?value . \n}\n"), 0);
+
+ SLV2Property result = slv2_query_get_results(results);
+
+ rasqal_free_query_results(results);
+ rasqal_finish();
+
+ return result;
+}
+
+
+uchar*
+slv2_port_get_symbol(SLV2Plugin* p, unsigned long index)
+{
+ // FIXME: leaks
+ uchar* result = NULL;
+
+ SLV2Property prop
+ = slv2_port_get_property(p, index, U("lv2:symbol"));
+
+ if (prop && prop->num_values == 1)
+ result = (uchar*)strdup((char*)prop->values[0]);
+ free(prop);
+
+ return result;
+}
+
+
+float
+slv2_port_get_default_value(SLV2Plugin* p,
+ unsigned long index)
+{
+ // FIXME: do casting properly in the SPARQL query
+
+ float result = 0.0f;
+
+ SLV2Property prop
+ = slv2_port_get_property(p, index, U("lv2:default"));
+
+ if (prop && prop->num_values == 1)
+ result = atof((char*)prop->values[0]);
+
+ return result;
+}
+
+
+float
+slv2_port_get_minimum_value(SLV2Plugin* p,
+ unsigned long index)
+{
+ // FIXME: do casting properly in the SPARQL query
+
+ float result = 0.0f;
+
+ SLV2Property prop
+ = slv2_port_get_property(p, index, U("lv2:minimum"));
+
+ if (prop && prop->num_values == 1)
+ result = atof((char*)prop->values[0]);
+
+ return result;
+}
+
+
+float
+slv2_port_get_maximum_value(SLV2Plugin* p,
+ unsigned long index)
+{
+ // FIXME: do casting properly in the SPARQL query
+
+ float result = 0.0f;
+
+ SLV2Property prop
+ = slv2_port_get_property(p, index, U("lv2:maximum"));
+
+ if (prop && prop->num_values == 1)
+ result = atof((char*)prop->values[0]);
+
+ return result;
+}
+
diff --git a/src/query.c b/src/query.c
new file mode 100644
index 0000000..2030735
--- /dev/null
+++ b/src/query.c
@@ -0,0 +1,123 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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.
+ */
+
+#include <util.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <slv2/plugin.h>
+#include <slv2/query.h>
+
+
+unsigned char*
+slv2_query_header(const SLV2Plugin* p)
+{
+ const unsigned char* plugin_uri = slv2_plugin_get_uri(p);
+ const unsigned char* data_file_url = slv2_plugin_get_data_url(p);
+
+ unsigned char* query_string = ustrjoin(U(
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "PREFIX doap: <http://usefulinc.com/ns/doap#> \n"
+ "PREFIX lv2: <http://lv2plug.in/ontology#> \n"
+ "PREFIX plugin: <"), plugin_uri, U("> \n"),
+ U("PREFIX data: <"), data_file_url, U("> \n\n"), 0);
+
+ return query_string;
+}
+
+
+unsigned char*
+slv2_query_lang_filter(const uchar* variable)
+{
+ uchar* result = NULL;
+ uchar* const lang = (uchar*)getenv("LANG");
+ if (lang) {
+ // FILTER( LANG(?value) = "en" || LANG(?value) = "" )
+ result = ustrjoin(
+ //U("FILTER (lang(?value) = \""), lang, U("\")\n"), 0);
+ U("FILTER( lang(?value) = \""), lang,
+ U("\" || lang(?value) = \"\" )\n"), 0);
+ }
+
+ return result;
+}
+
+
+rasqal_query_results*
+slv2_plugin_run_query(const SLV2Plugin* p,
+ const uchar* first, ...)
+{
+ va_list args_list;
+ va_start(args_list, first);
+ va_list args_copy;
+ va_copy(args_copy, args_list);
+
+ /* FIXME: Too much unecessary allocation */
+ uchar* header = slv2_query_header(p);
+ uchar* args_str = vstrjoin(first, args_copy);
+ uchar* query_str = ustrjoin(header, args_str, 0);
+
+ assert(p);
+ assert(query_str);
+
+ rasqal_query *rq = rasqal_new_query("sparql", NULL);
+
+ //printf("Query: \n%s\n\n", query_str);
+
+ rasqal_query_prepare(rq, query_str, NULL);
+ rasqal_query_results* results = rasqal_query_execute(rq);
+
+ rasqal_free_query(rq);
+
+ free(query_str);
+ free(args_str);
+ free(header);
+
+ return results;
+}
+
+
+SLV2Property
+slv2_query_get_results(rasqal_query_results* results)
+{
+ struct _Property* result = NULL;
+
+ if (rasqal_query_results_get_count(results) > 0) {
+ result = malloc(sizeof(struct _Property));
+ result->num_values = 0;
+ result->values = NULL;
+ }
+
+ while (!rasqal_query_results_finished(results)) {
+
+ rasqal_literal* literal =
+ rasqal_query_results_get_binding_value_by_name(results, U("value"));
+ assert(literal != NULL);
+
+ // Add value on to the array. Yes, this is disgusting.
+ result->num_values++;
+ // FIXME LEAK:
+ result->values = realloc(result->values, result->num_values * sizeof(char*));
+ result->values[result->num_values-1] = ustrdup(rasqal_literal_as_string(literal));
+
+ rasqal_query_results_next(results);
+ }
+
+ return result;
+}
+
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..55953b8
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,121 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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 <util.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+
+void
+ustrappend(uchar** dst, const uchar* suffix)
+{
+ assert(dst);
+ assert(*dst);
+ assert(suffix);
+
+ const size_t new_length = strlen((char*)*dst) + strlen((char*)suffix) + 1;
+ *dst = realloc(*dst, (new_length * sizeof(char)));
+ assert(dst);
+ strcat((char*)*dst, (char*)suffix);
+}
+
+
+uchar*
+ustrdup(const uchar* src)
+{
+ assert(src);
+ return (uchar*)strdup((char*)src);
+}
+
+
+uchar*
+ustrjoin(const uchar* first, ...)
+{
+ // FIXME: this is horribly, awfully, disgracefully slow
+
+ va_list args_list;
+ va_start(args_list, first);
+
+ va_list args_copy;
+ va_copy(args_copy, args_list);
+
+ uchar* result = vstrjoin(first, args_copy);
+
+ //va_end(args_copy);
+ va_end(args_list);
+
+ return result;
+
+ /*
+ va_list args_list;
+ uchar* arg = NULL;
+ uchar* result = ustrdup(first);
+
+ va_start(args_list, first);
+
+ while ((arg = va_arg(args_list, uchar*)) != (uchar*)0)
+ ustrappend(&result, arg);
+
+ va_end(args_list);
+
+ return result;*/
+}
+
+
+uchar*
+vstrjoin(const uchar* first, va_list args_list)
+{
+ // FIXME: this is horribly, awfully, disgracefully slow
+
+ uchar* arg = NULL;
+ uchar* result = ustrdup(first);
+
+ while ((arg = va_arg(args_list, uchar*)) != NULL)
+ ustrappend(&result, arg);
+
+ va_end(args_list);
+
+ return result;
+}
+
+
+
+/** Convert a URL to a local filesystem path (ie by chopping off the
+ * leading "file://".
+ *
+ * Returns NULL if URL is not a valid URL on the local filesystem.
+ * Result is simply a pointer in to \a url and must not be free()'d.
+ */
+const char*
+url2path(const uchar* const url)
+{
+ /*assert(strlen((char*)url) > 8);
+ char* result = calloc(strlen((char*)url)-7+1, sizeof(char));
+ strcpy(result, (char*)url+7);
+ return result;*/
+ if (!strncmp((char*)url, "file://", 7))
+ return (char*)url + 7;
+ else
+ return NULL;
+}
+
+
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..dbb7801
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,53 @@
+/* LibSLV2
+ * Copyright (C) 2006 Dave Robillard <drobilla@connect.carleton.ca>
+ *
+ * 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 __UTIL_H
+#define __UTIL_H
+
+#include <stdarg.h>
+#include <slv2/types.h>
+
+/* Cast a char* to an unsigned char* (Used for string literals) */
+#define U(x) (unsigned char*)(x)
+
+/** Append \a suffix to \a *dst, reallocating \a dst as necessary.
+ *
+ * \a dst will (possibly) be freed, it must be dynamically allocated with malloc
+ * or NULL.
+ */
+void
+ustrappend(uchar** dst, const uchar* suffix);
+
+uchar*
+ustrdup(const uchar* src);
+
+/** Join all arguments into one string.
+ *
+ * Arguments are not modified, return value must be free()'d.
+ */
+uchar*
+ustrjoin(const uchar* first, ...);
+
+uchar*
+vstrjoin(const uchar* first, va_list args_list);
+
+const char*
+url2path(const uchar* const url);
+
+
+#endif