traverso-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Traverso-commit] traverso/src/3rdparty/slv2 slv2/lv2.h slv2/plug...


From: Remon Sijrier
Subject: [Traverso-commit] traverso/src/3rdparty/slv2 slv2/lv2.h slv2/plug...
Date: Mon, 23 Apr 2007 11:59:22 +0000

CVSROOT:        /sources/traverso
Module name:    traverso
Changes by:     Remon Sijrier <r_sijrier>       07/04/23 11:59:22

Added files:
        src/3rdparty/slv2/slv2: lv2.h plugin.h plugininstance.h 
                                pluginlist.h port.h slv2.h stringlist.h 
                                types.h util.h world.h 
        src/3rdparty/slv2/src: plugin.c plugininstance.c pluginlist.c 
                               port.c private_types.h query.c 
                               stringlist.c util.c world.c 

Log message:
        * imported slv2 source

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/lv2.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/plugin.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/plugininstance.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/pluginlist.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/port.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/slv2.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/stringlist.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/types.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/util.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/slv2/world.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/plugin.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/plugininstance.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/pluginlist.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/port.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/private_types.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/query.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/stringlist.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/util.c?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/3rdparty/slv2/src/world.c?cvsroot=traverso&rev=1.1

Patches:
Index: slv2/lv2.h
===================================================================
RCS file: slv2/lv2.h
diff -N slv2/lv2.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/lv2.h  23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,389 @@
+/* LV2 - LADSPA (Linux Audio Developer's Simple Plugin API) Version 2.0
+ * *** PROVISIONAL ***
+ *
+ * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis,
+ *                         Stefan Westerfeld
+ * Copyright (C) 2006-2007 Steve Harris, Dave Robillard.
+ *
+ * This header is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License,
+ * or (at your option) any later version.
+ *
+ * This header 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifndef LV2_H_INCLUDED
+#define LV2_H_INCLUDED
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* ************************************************************************* */
+
+
+/** @file lv2.h
+ *
+ * Revision: 1.0beta1
+ *
+ * == Overview ==
+ *
+ * There are a large number of open source and free software synthesis
+ * packages in use or development at this time. This API ('LV2')
+ * attempts to give programmers the ability to write simple 'plugin'
+ * audio processors in C/C++ and link them dynamically ('plug') into
+ * a range of these packages ('hosts').  It should be possible for any
+ * host and any plugin to communicate completely through this interface.
+ *
+ * This API is deliberately as short and simple as possible.
+ * The information required to use a plugin is in a companion data
+ * (RDF) file.  The shared library portion of the API (defined in this
+ * header) does not contain enough information to make use of the plugin
+ * possible - the data file is mandatory.
+ *
+ * Plugins are expected to distinguish between control rate and audio
+ * rate data. Plugins have 'ports' that are inputs or outputs for audio
+ * or control data and each plugin is 'run' for a 'block' corresponding
+ * to a short time interval measured in samples. Audio rate data is
+ * communicated using arrays with one element per sample processed,
+ * allowing a block of audio to be processed by the plugin in a single
+ * pass. Control rate data is communicated using single values. Control
+ * rate data has a single value at the start of a call to the 'run()'
+ * function, and may be considered to remain this value for its duration.
+ * Thus the 'control rate' is determined by the block size, controlled
+ * by the host.  The plugin may assume that all its input and output
+ * ports have been connected to the relevant data location (see the
+ * 'connect_port()' function below) before it is asked to run.
+ *
+ * Plugins will reside in shared object files suitable for dynamic linking
+ * by dlopen() and family. The file will provide a number of 'plugin
+ * types' that can be used to instantiate actual plugins (sometimes known
+ * as 'plugin instances') that can be connected together to perform tasks.
+ * The host can access these plugin types using the lv2_descriptor() 
+ * function.
+ *
+ * This API contains very limited error-handling.
+ *
+ * == Threading rules ==
+ *
+ * Certain hosts may need to call the functions provided by a plugin from
+ * multiple threads. For this to be safe, the plugin must be written so that
+ * those functions can be executed simultaneously without problems.
+ * To facilitate this, the functions provided by a plugin are divided into
+ * classes:
+ *
+ *  - Audio class:           run(), connect_port()
+ *  - Instantiation class:   instantiate(), cleanup(), 
+ *                           activate(), deactivate()
+ *
+ * Extensions to this specification which add new functions MUST declare in
+ * which of these classes the functions belong, or define new classes for them.
+ * The rules that hosts must follow are these:
+ * 
+ *  - When a function from the Instantiation class is running for a plugin 
+ *    instance, no other functions for that instance may run.
+ *  - When a function is running for a plugin instance, no other 
+ *    function in the same class may run for that instance.
+ *
+ * Any simultaneous calls that are not explicitly forbidden by these rules
+ * are allowed. For example, a host may call run() for two different plugin 
+ * instances simultaneously.
+ *
+ * The extension_data() function and the lv2_descriptor() function are never 
+ * associated with any plugin instances and may be called at any time.
+ */
+
+
+/* ************************************************************************* */
+
+    
+/** Plugin Handle.
+ *
+ * This plugin handle indicates a particular instance of the plugin
+ * concerned. It is valid to compare this to NULL (0 for C++) but
+ * otherwise the host MUST NOT attempt to interpret it. The plugin
+ * may use it to reference internal instance data. */
+typedef void * LV2_Handle;
+
+
+/* ************************************************************************* */
+
+
+/** Host feature.
+ * 
+ * These are passed to a plugin's instantiate method to represent a special
+ * feature the host has which the plugin may depend on.  This is to allow
+ * extensions to the LV2 specification without causing any breakage.  The base
+ * LV2 specification does not define any host features; hosts are not required
+ * to use this facility.
+ */
+typedef struct _LV2_Host_Feature {
+       /** A globally unique, case-sensitive identifier for this feature.
+        *
+        * This MUST be defined in the specification of any LV2 extension which
+        * defines a host feature.
+        */
+       const char * URI;
+
+       /** Pointer to arbitrary data.
+        *
+        * This is to allow hosts to pass data to a plugin (simple values, data
+        * structures, function pointers, etc) as part of a 'feature'.  The LV2
+        * specification makes no restrictions on the contents of this data.
+        * The data here MUST be cleary defined by the LV2 extension which 
defines
+        * this feature.
+        * If no data is required, this may be set to NULL.
+        */
+       void * data;
+} LV2_Host_Feature;
+
+
+/* ************************************************************************* */
+
+
+/** Descriptor for a Type of Plugin.
+ * 
+ * This structure is used to describe a plugin type. It provides a number
+ * of functions to instantiate it, link it to buffers and run it. */
+typedef struct _LV2_Descriptor { 
+
+  /** A globally unique, case-sensitive identifier for this plugin type.
+   *
+   * All plugins with the same URI MUST be compatible in terms of 'port
+   * signature', meaning they have the same number of ports, same port
+   * shortnames, and roughly the same functionality.  URIs should
+   * probably contain a version number (or similar) for this reason.
+   *
+   * Rationale:  When serializing session/patch/etc files, hosts MUST
+   * refer to a loaded plugin by the plugin URI only.  In the future
+   * loading a plugin with this URI MUST yield a plugin with the
+   * same ports (etc) which is 100% compatible. */
+  const char * URI;
+
+  /** Function pointer that instantiates a plugin.
+   *
+   * A handle is returned indicating the new plugin instance. The
+   * instantiation function accepts a sample rate as a parameter as well
+   * as the plugin descriptor from which this instantiate function was
+   * found. This function must return NULL if instantiation fails.
+   *
+   * BundlePath is a string of the path to the LV2 bundle which contains
+   * this plugin binary.  It MUST include the trailing directory separator
+   * (e.g. '/') so that BundlePath + filename gives the path to a file
+   * in the bundle.
+   *
+   * HostFeatures is a NULL terminated array of the URIs of the LV2
+   * features that the host supports. Plugins may refuse to instantiate
+   * if required features are not found here (however hosts SHOULD NOT use
+   * this as a discovery mechanism, instead reading the data file before
+   * attempting to instantiate the plugin).  This array must always exist;
+   * if a host has no features, it MUST pass a single element array
+   * containing NULL (to simplify plugins).
+   *
+   * Note that instance initialisation should generally occur in
+   * activate() rather than here.  If a host calls instantiate, it MUST
+   * call cleanup() at some point in the future. */
+  LV2_Handle (*instantiate)(const struct _LV2_Descriptor *  Descriptor,
+                            uint32_t                        SampleRate,
+                            const char *                    BundlePath,
+                            const LV2_Host_Feature *const * HostFeatures);
+
+  /** Function pointer that connects a port on a plugin instance to a memory
+   * location where the block of data for the port will be read/written.
+   *
+   * The data location is expected to be of the type defined in the
+   * plugin's data file (e.g. an array of float for an lv2:AudioPort).
+   * Memory issues are managed by the host. The plugin must read/write
+   * the data at these locations every time run() is called, data
+   * present at the time of this connection call MUST NOT be
+   * considered meaningful.
+   *
+   * connect_port() may be called more than once for a plugin instance
+   * to allow the host to change the buffers that the plugin is reading
+   * or writing. These calls may be made before or after activate()
+   * or deactivate() calls.  Note that there may be realtime constraints
+   * on connect_port (see lv2:hardRTCapable in lv2.ttl).
+   *
+   * connect_port() MUST be called at least once for each port before
+   * run() is called.  The plugin must pay careful attention to the block
+   * size passed to the run function as the block allocated may only just
+   * be large enough to contain the block of data (typically samples), and
+   * is not guaranteed to be constant.
+   *
+   * Plugin writers should be aware that the host may elect to use the
+   * same buffer for more than one port and even use the same buffer for
+   * both input and output (see lv2:inPlaceBroken in lv2.ttl).
+   * However, overlapped buffers or use of a single buffer for both
+   * audio and control data may result in unexpected behaviour.
+   *
+   * If the plugin has the property lv2:hardRTCapable then there are 
+   * various things that the plugin MUST NOT do within the connect_port()
+   * function (see lv2.ttl). */
+  void (*connect_port)(LV2_Handle Instance,
+                       uint32_t   Port,
+                       void *     DataLocation);
+
+  /** Function pointer that initialises a plugin instance and activates
+   * it for use.
+   * 
+   * This is separated from instantiate() to aid real-time support and so
+   * that hosts can reinitialise a plugin instance by calling deactivate()
+   * and then activate(). In this case the plugin instance must reset all
+   * state information dependent on the history of the plugin instance
+   * except for any data locations provided by connect_port(). If there
+   * is nothing for activate() to do then the plugin writer may provide
+   * a NULL rather than an empty function.
+   *
+   * When present, hosts MUST call this function once before run()
+   * is called for the first time. This call SHOULD be made as close
+   * to the run() call as possible and indicates to real-time plugins
+   * that they are now live, however plugins MUST NOT rely on a prompt
+   * call to run() after activate().  activate() may not be called again
+   * unless deactivate() is called first (after which activate() may be
+   * called again, followed by deactivate, etc. etc.).  If a host calls
+   * activate, it MUST call deactivate at some point in the future.
+   *
+   * Note that connect_port() may be called before or after a call to
+   * activate(). */
+  void (*activate)(LV2_Handle Instance);
+
+  /** Function pointer that runs a plugin instance for a block.
+   *
+   * Two parameters are required: the first is a handle to the particular
+   * instance to be run and the second indicates the block size (in
+   * samples) for which the plugin instance may run.
+   *
+   * Note that if an activate() function exists then it must be called
+   * before run(). If deactivate() is called for a plugin instance then
+   * the plugin instance may not be reused until activate() has been
+   * called again.
+   *
+   * If the plugin has the property lv2:hardRTCapable then there are 
+   * various things that the plugin MUST NOT do within the run()
+   * function (see lv2.ttl). */
+  void (*run)(LV2_Handle Instance,
+              uint32_t   SampleCount);
+
+  /** This is the counterpart to activate() (see above). If there is
+   * nothing for deactivate() to do then the plugin writer may provide
+   * a NULL rather than an empty function.
+   *
+   * Hosts must deactivate all activated units after they have been run()
+   * for the last time. This call SHOULD be made as close to the last
+   * run() call as possible and indicates to real-time plugins that
+   * they are no longer live, however plugins MUST NOT rely on prompt
+   * deactivation. Note that connect_port() may be called before or
+   * after a call to deactivate().
+   *
+   * Note that deactivation is not similar to pausing as the plugin
+   * instance will be reinitialised when activate() is called to reuse it.
+   * Hosts MUST NOT call deactivate() unless activate() was previously
+   * called. */
+  void (*deactivate)(LV2_Handle Instance);
+
+  /** This is the counterpart to instantiate() (see above).  Once an instance
+   * of a plugin has been finished with it can be deleted using this
+   * function. The instance handle passed ceases to be valid after
+   * this call.
+   * 
+   * If activate() was called for a plugin instance then a corresponding
+   * call to deactivate() MUST be made before cleanup() is called.
+   * Hosts MUST NOT call cleanup() unless instantiate() was previously
+   * called. */
+  void (*cleanup)(LV2_Handle Instance);
+    
+  /** Function pointer that can be used to return additional instance data for
+   * a plugin defined by some extenion (e.g. a struct containing additional
+   * function pointers).
+   *
+   * The actual type and meaning of the returned object MUST be specified 
+   * precisely by the extension if it defines any extra data.  If a particular
+   * extension does not define extra instance data, this function MUST return
+   * NULL for that extension's URI.  If a plugin does not support any
+   * extensions that define extra instance data, this function pointer may be
+   * set to NULL rather than providing an empty function.
+   * 
+   * The only parameter is the URI of the extension. The plugin MUST return
+   * NULL if it does not support the extension, but hosts SHOULD NOT use this
+   * as a discovery method (e.g. hosts should only call this function for
+   * extensions known to be supported by the plugin from the data file).
+   * 
+   * NOTE: It is highly recommended that this function returns a struct, and
+   * NOT a direct function pointer.  Standard C++ (for real reasons) does not
+   * allow type casts from void* to a function pointer type.  To provide
+   * additional functions a struct should be returned containing the extra
+   * function pointers (which is valid standard C++, and a much better idea
+   * for extensibility anyway).
+   */
+  void* (*extension_data)(const char * URI); 
+
+} LV2_Descriptor;
+
+
+/* ****************************************************************** */
+
+
+/** Accessing Plugin Types.
+ *
+ * The exact mechanism by which plugins are loaded is host-dependent,
+ * however all most hosts will need to know is the URI of the plugin they
+ * wish to load.  The environment variable LV2_PATH, if present, should
+ * contain a colon-separated path indicating directories (containing
+ * plugin bundle subdirectories) that should be searched (in order)
+ * for plugins.  It is expected that hosts will use a library to provide
+ * this functionality.
+ * 
+ * A plugin programmer must include a function called "lv2_descriptor"
+ * with the following function prototype within the shared object
+ * file. This function will have C-style linkage (if you are using
+ * C++ this is taken care of by the 'extern "C"' clause at the top of
+ * the file).
+ *
+ * A host will find the plugin shared object file by one means or another,
+ * find the lv2_descriptor() function, call it, and proceed from there.
+ *
+ * Plugin types are accessed by index (not ID) using values from 0
+ * upwards. Out of range indexes must result in this function returning
+ * NULL, so the plugin count can be determined by checking for the least
+ * index that results in NULL being returned.  Index has no meaning,
+ * hosts MUST NOT depend on it remaining constant (ie when serialising)
+ * in any way. */
+const LV2_Descriptor * lv2_descriptor(uint32_t Index);
+
+
+/** Datatype corresponding to the lv2_descriptor() function. */
+typedef const LV2_Descriptor * 
+(*LV2_Descriptor_Function)(uint32_t Index);
+
+
+/* ******************************************************************** */
+
+
+/* Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded
+ * by the host as a symbol from the dynamic library.
+ */
+#ifdef WIN32
+#define LV2_SYMBOL_EXPORT __declspec(dllexport)
+#else
+#define LV2_SYMBOL_EXPORT
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LV2_H_INCLUDED */
+

Index: slv2/plugin.h
===================================================================
RCS file: slv2/plugin.h
diff -N slv2/plugin.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/plugin.h       23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,330 @@
+/* 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_PLUGIN_H__
+#define __SLV2_PLUGIN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <slv2/types.h>
+#include <slv2/port.h>
+#include <slv2/stringlist.h>
+
+/** \defgroup data Plugin data access
+ *
+ * These functions work exclusively with the plugin's RDF data.
+ * They do not load or access the plugin dynamic library in any way.
+ *
+ * An SLV2Plugin contains an in-memory cache of the plugin data, loaded
+ * on demand.  Duplicating plugins should be avoided when possible for
+ * performance reasons.
+ *
+ * @{
+ */
+
+
+/** Check if this plugin is valid.
+ *
+ * This is used by plugin lists to avoid loading plugins that are not valid
+ * and will not work with libslv2 (eg plugins missing required fields, or
+ * having multiple values for mandatory single-valued fields, etc.
+ * 
+ * Note that normal hosts do NOT need to use this - slv2 does not
+ * load invalid plugins into plugin lists.  This is included for plugin
+ * testing utilities, etc.
+ *
+ * \return true if \a plugin is valid.
+ *
+ * Time = Query
+ */
+bool
+slv2_plugin_verify(SLV2Plugin plugin);
+
+
+#if 0
+/** Duplicate a plugin.
+ *
+ * Use this if you want to keep an SLV2Plugin around but free the list it came
+ * from.  Freeing the returned plugin with slv2_plugin_free is the caller's
+ * responsibility.
+ *
+ * \return a newly allocated deep copy of \a plugin.
+ */
+SLV2Plugin
+slv2_plugin_duplicate(SLV2Plugin plugin);
+#endif
+
+
+/** Get the URI of \a plugin.
+ *
+ * Any serialization that refers to plugins should refer to them by this.
+ * Hosts SHOULD NOT save any filesystem paths, plugin indexes, etc. in saved
+ * files; save only the URI.
+ *
+ * The URI is a globally unique identifier for one specific plugin.  Two
+ * plugins with the same URI are compatible in port signature, and should
+ * be guaranteed to work in a compatible and consistent way.  If a plugin
+ * is upgraded in an incompatible way (eg if it has different ports), it
+ * MUST have a different URI than it's predecessor.
+ *
+ * \return a shared string which must not be modified or free()'d.
+ *
+ * Time = O(1)
+ */
+const char*
+slv2_plugin_get_uri(SLV2Plugin plugin);
+
+
+/** Get the (resolvable) URIs of the RDF data files that define a plugin.
+ *
+ * Note this always returns fully qualified URIs.  If you want local
+ * filesystem paths, use slv2_uri_to_path.
+ *
+ * \return a list of complete URLs eg. "file:///foo/ABundle.lv2/aplug.ttl",
+ * which is shared and must not be modified or freed.
+ *
+ * Time = O(1)
+ */
+SLV2Strings
+slv2_plugin_get_data_uris(SLV2Plugin plugin);
+
+
+/** Get the (resolvable) URI of the shared library for \a plugin.
+ *
+ * Note this always returns a fully qualified URI.  If you want a local
+ * filesystem path, use slv2_uri_to_path.
+ * 
+ * \return a shared string which must not be modified or freed.
+ *
+ * Time = O(1)
+ */
+const char*
+slv2_plugin_get_library_uri(SLV2Plugin plugin);
+
+
+
+/** Get the name of \a plugin.
+ *
+ * This is guaranteed to return the untranslated name (the doap:name in the
+ * data file without a language tag).  Returned value must be freed by
+ * the caller.
+ *
+ * Time = Query
+ */
+char*
+slv2_plugin_get_name(SLV2Plugin plugin);
+
+
+/** Get a value associated with the plugin in a plugin's data files.
+ *
+ * Returns the ?object of all triples found of the form:
+ *
+ * <code>&lt;plugin-uri&gt; predicate ?object</code>
+ * 
+ * May return NULL if the property was not found, or if object is not
+ * sensibly represented as an SLV2Strings (e.g. blank nodes).
+ *
+ * Return value must be freed by caller with slv2_strings_free.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_value(SLV2Plugin  p,
+                      const char* predicate);
+
+
+/** Get a value associated with some subject in a plugin's data files.
+ *
+ * Returns the ?object of all triples found of the form:
+ *
+ * <code>subject predicate ?object</code>
+ *
+ * This can be used to investigate URIs returned by slv2_plugin_get_value
+ * (if information about it is contained in the plugin's data files).
+ *
+ * May return NULL if the property was not found, or if object is not
+ * sensibly represented as an SLV2Strings (e.g. blank nodes).
+ *
+ * Return value must be freed by caller with slv2_strings_free.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_value_for_subject(SLV2Plugin  p,
+                                  const char* subject,
+                                  const char* predicate);
+
+
+/** Get the LV2 Properties of a plugin.
+ *
+ * LV2 Properties are mandatory.  Hosts MUST NOT use a plugin if they do not
+ * understand all the LV2 Properties associated with that plugin (if this is
+ * not what you want, see slv2_plugin_get_hints).
+ *
+ * Return value must be freed by caller with slv2_value_free.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_properties(SLV2Plugin p);
+
+
+/** Get the LV2 Hints of a plugin.
+ *
+ * LV2 Hints are suggestions that may be useful for a host.  LV2 Hints may be
+ * ignored and the plugin will still function correctly.
+ *
+ * Return value must be freed by caller with slv2_value_free.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_hints(SLV2Plugin p);
+
+
+/** Get the number of ports on this plugin.
+ *
+ * Time = O(1)
+ */
+uint32_t
+slv2_plugin_get_num_ports(SLV2Plugin p);
+
+
+/** Return whether or not the plugin introduces (and reports) latency.
+ *
+ * The index of the latency port can be found with slv2_plugin_get_latency_port
+ * ONLY if this function returns true.
+ *
+ * Time = Query
+ */
+bool
+slv2_plugin_has_latency(SLV2Plugin p);
+
+
+/** Return the index of the plugin's latency port, or the empty string if the
+ * plugin has no latency.
+ *
+ * It is a fatal error to call this on a plugin without checking if the port
+ * exists by first calling slv2_plugin_has_latency.
+ *
+ * Any plugin that introduces unwanted latency that should be compensated for
+ * (by hosts with the ability/need) MUST provide this port, which is a control
+ * rate output port that reports the latency for each cycle in frames.
+ *
+ * Time = Query
+ */
+uint32_t
+slv2_plugin_get_latency_port(SLV2Plugin p);
+
+
+/** Get a plugin's supported host features / extensions.
+ *
+ * This returns a list of all supported features (both required and optional).
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_supported_features(SLV2Plugin p);
+
+
+/** Get a plugin's requires host features / extensions.
+ *
+ * All feature URI's returned by this call MUST be passed to the plugin's
+ * instantiate method for the plugin to instantiate successfully.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_required_features(SLV2Plugin p);
+
+
+/** Get a plugin's optional host features / extensions.
+ *
+ * If the feature URI's returned by this method are passed to the plugin's
+ * instantiate method, those features will be used by the function, otherwise
+ * the plugin will act as it would if it did not support that feature at all.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_get_optional_features(SLV2Plugin p);
+
+
+/** Query a plugin for a single variable.
+ *
+ * \param plugin The plugin to query.
+ * \param sparql_str A SPARQL SELECT query.
+ * \param variable The variable to return results for.
+ * \return All matches for \a variable.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_plugin_simple_query(SLV2Plugin  plugin,
+                         const char* sparql_str,
+                         const char* variable);
+
+
+/** Query a plugin and return the number of results found.
+ *
+ * \param plugin The plugin to query.
+ * \param sparql_str A SPARQL SELECT query.
+ *
+ * Time = Query
+ */
+unsigned
+slv2_plugin_query_count(SLV2Plugin  plugin,
+                        const char* sparql_str);
+
+
+/** Get a port on this plugin by \a index.
+ *
+ * To perform multiple calls on a port, the returned value should
+ * be cached and used repeatedly.
+ *
+ * Time = O(1)
+ */
+SLV2Port
+slv2_plugin_get_port_by_index(SLV2Plugin plugin,
+                              uint32_t   index);
+
+
+/** Get a port on this plugin by \a symbol.
+ *
+ * To perform multiple calls on a port, the returned value should
+ * be cached and used repeatedly.
+ *
+ * Time = O(n)
+ */
+SLV2Port
+slv2_plugin_get_port_by_symbol(SLV2Plugin  plugin,
+                               const char* symbol);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_PLUGIN_H__ */
+

Index: slv2/plugininstance.h
===================================================================
RCS file: slv2/plugininstance.h
diff -N slv2/plugininstance.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/plugininstance.h       23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,218 @@
+/* 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_PLUGININSTANCE_H__
+#define __SLV2_PLUGININSTANCE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <assert.h>
+#include <slv2/lv2.h>
+#include <slv2/plugin.h>
+#include <slv2/port.h>
+
+typedef struct _InstanceImpl* SLV2InstanceImpl;
+
+/** \defgroup lib Shared library access
+ *
+ * An SLV2Instance is an instantiated SLV2Plugin (eg a loaded dynamic
+ * library).  These functions interact with the binary library code only,
+ * they do not read data files in any way.
+ * 
+ * @{
+ */
+
+
+/** Instance of a plugin.
+ *
+ * The LV2 descriptor and handle of this are exposed to allow inlining of
+ * performance critical functions like slv2_instance_run (hiding things in
+ * lv2.h is pointless anyway).  The remaining implementation details are
+ * in the opaque pimpl member.
+ */
+typedef struct _Instance {
+       const LV2_Descriptor* lv2_descriptor;
+       LV2_Handle            lv2_handle;
+       SLV2InstanceImpl      pimpl; ///< Move along now, nothing to see here
+}* SLV2Instance;
+
+
+
+/** Instantiate a plugin.
+ *
+ * The returned object represents shared library objects loaded into memory,
+ * it must be cleaned up with slv2_instance_free when no longer
+ * needed.
+ * 
+ * \a plugin is not modified or directly referenced by the returned object
+ * (instances store only a copy of the plugin's URI).
+ * 
+ * \a host_features NULL-terminated array of features the host supports.
+ * NULL may be passed if the host supports no additional features (unlike
+ * the LV2 specification - SLV2 takes care of it).
+ *
+ * \return NULL if instantiation failed.
+ */
+SLV2Instance
+slv2_plugin_instantiate(SLV2Plugin               plugin,
+                        uint32_t                 sample_rate,
+                        const LV2_Host_Feature** host_features);
+
+
+/** Free a plugin instance.
+ *
+ * \a instance is invalid after this call.
+ */
+void
+slv2_instance_free(SLV2Instance instance);
+
+
+#ifndef LIBSLV2_SOURCE
+
+
+/** Get the URI of the plugin which \a instance is an instance of.
+ *
+ * Returned string is shared and must not be modified or deleted.
+ */
+static inline const char*
+slv2_instance_get_uri(SLV2Instance instance)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       
+       return instance->lv2_descriptor->URI;
+}
+
+
+/** Connect a port to a data location.
+ *
+ * This may be called regardless of whether the plugin is activated,
+ * activation and deactivation does not destroy port connections.
+ */
+static inline void
+slv2_instance_connect_port(SLV2Instance instance,
+                           uint32_t     port_index,
+                           void*        data_location)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       assert(instance->lv2_descriptor->connect_port);
+       
+       instance->lv2_descriptor->connect_port
+               (instance->lv2_handle, port_index, data_location);
+}
+
+
+/** Activate a plugin instance.
+ *
+ * This resets all state information in the plugin, except for port data
+ * locations (as set by slv2_instance_connect_port).  This MUST be called
+ * before calling slv2_instance_run.
+ */
+static inline void
+slv2_instance_activate(SLV2Instance instance)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       
+       if (instance->lv2_descriptor->activate)
+               instance->lv2_descriptor->activate(instance->lv2_handle);
+}
+
+
+/** Run \a instance for \a sample_count frames.
+ *
+ * If the hint lv2:hardRtCapable is set for this plugin, this function is
+ * guaranteed not to block.
+ */
+static inline void
+slv2_instance_run(SLV2Instance instance,
+                  uint32_t     sample_count)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       assert(instance->lv2_handle),
+       assert(instance->lv2_descriptor->run);
+       
+       instance->lv2_descriptor->run(instance->lv2_handle, sample_count);
+}
+
+
+/** Deactivate a plugin instance.
+ *
+ * Note that to run the plugin after this you must activate it, which will
+ * reset all state information (except port connections).
+ */
+static inline void
+slv2_instance_deactivate(SLV2Instance instance)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       assert(instance->lv2_handle);
+       
+       if (instance->lv2_descriptor->deactivate)
+               instance->lv2_descriptor->deactivate(instance->lv2_handle);
+}
+
+
+/** Get the LV2_Descriptor of the plugin instance.
+ *
+ * Normally hosts should not need to access the LV2_Descriptor directly,
+ * use the slv2_instance_* functions.
+ *
+ * The returned descriptor is shared and must not be deleted.
+ */
+static inline const LV2_Descriptor*
+slv2_instance_get_descriptor(SLV2Instance instance)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       
+       return instance->lv2_descriptor;
+}
+
+
+/** Get the LV2_Handle of the plugin instance.
+ *
+ * Normally hosts should not need to access the LV2_Handle directly,
+ * use the slv2_instance_* functions.
+ * 
+ * The returned handle is shared and must not be deleted.
+ */
+static inline LV2_Handle
+slv2_instance_get_handle(SLV2Instance instance)
+{
+       assert(instance);
+       assert(instance->lv2_descriptor);
+       
+       return instance->lv2_handle;
+}
+
+#endif /* LIBSLV2_SOURCE */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __SLV2_PLUGININSTANCE_H__ */
+

Index: slv2/pluginlist.h
===================================================================
RCS file: slv2/pluginlist.h
diff -N slv2/pluginlist.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/pluginlist.h   23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,95 @@
+/* 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_PLUGINLIST_H__
+#define __SLV2_PLUGINLIST_H__
+
+#include <slv2/plugin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef void* SLV2Plugins;
+
+
+/** \defgroup plugins Plugin lists
+ * 
+ * These functions work with lists of plugins which come from an
+ * SLV2World.  These lists contain only a weak reference to an LV2 plugin
+ * in the Model.
+ *
+ * @{
+ */
+
+
+/** Free a plugin list.
+ *
+ * Freeing a plugin list does not destroy the plugins it contains (plugins
+ * are owned by the world).  \a list is invalid after this call.
+ */
+void
+slv2_plugins_free(SLV2World   world,
+                  SLV2Plugins list);
+
+
+/** Get the number of plugins in the list.
+ */
+unsigned
+slv2_plugins_size(SLV2Plugins list);
+
+
+/** Get a plugin from the list by URI.
+ *
+ * Return value is shared (stored in \a list) and must not be freed or
+ * modified by the caller in any way.
+ *
+ * Time = O(log2(n))
+ * 
+ * \return NULL if plugin with \a url not found in \a list.
+ */
+SLV2Plugin
+slv2_plugins_get_by_uri(SLV2Plugins list,
+                        const char* uri);
+
+
+/** Get a plugin from the list by index.
+ *
+ * \a index has no significance other than as an index into this list.
+ * Any \a index not less than slv2_list_get_length(list) will return NULL,
+ * so all plugins in a list can be enumerated by repeated calls
+ * to this function starting with \a index = 0.
+ *
+ * Time = O(1)
+ *
+ * \return NULL if \a index out of range.
+ */
+SLV2Plugin
+slv2_plugins_get_at(SLV2Plugins list,
+                    unsigned    index);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_PLUGINLIST_H__ */
+

Index: slv2/port.h
===================================================================
RCS file: slv2/port.h
diff -N slv2/port.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/port.h 23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,138 @@
+/* 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_PORT_H__
+#define __SLV2_PORT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <slv2/types.h>
+#include <slv2/plugin.h>
+#include <slv2/port.h>
+#include <slv2/stringlist.h>
+
+/** \addtogroup data
+ * @{
+ */
+
+
+/** Port equivalent to slv2_plugin_get_value.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_port_get_value(SLV2Plugin  plugin,
+                    SLV2Port    port,
+                    const char* property);
+
+
+/** Port equivalent to slv2_plugin_get_properties.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_port_get_properties(SLV2Plugin plugin,
+                         SLV2Port   port);
+
+
+/** Port equivalent to slv2_plugin_get_hints.
+ *
+ * Time = Query
+ */
+SLV2Strings
+slv2_port_get_hints(SLV2Plugin plugin,
+                    SLV2Port   port);
+
+
+/** Get the symbol of a port given the index.
+ *
+ * The 'symbol' is a short string, a valid C identifier.
+ * Returned string must be free()'d by caller.
+ *
+ * \return NULL when index is out of range
+ *
+ * Time = Query
+ */
+char*
+slv2_port_get_symbol(SLV2Plugin plugin,
+                     SLV2Port   port);
+
+/** Get the name of a port.
+ *
+ * This is guaranteed to return the untranslated name (the doap:name in the
+ * data file without a language tag).  Returned value must be free()'d by
+ * the caller.
+ *
+ * Time = Query
+ */
+char*
+slv2_port_get_name(SLV2Plugin plugin,
+                   SLV2Port   port);
+
+
+/** Get the class (input/output, data type, rate...) of a port.
+ *
+ * Time = Query
+ */
+SLV2PortClass
+slv2_port_get_class(SLV2Plugin plugin,
+                    SLV2Port   port);
+
+
+/** Get the default value of a port.
+ *
+ * Only valid for ports with a data type of lv2:float.
+ *
+ * Time = Query
+ */
+float
+slv2_port_get_default_value(SLV2Plugin plugin, 
+                            SLV2Port   port);
+
+
+/** Get the minimum value of a port.
+ *
+ * Only valid for ports with a data type of lv2:float.
+ *
+ * Time = Query
+ */
+float
+slv2_port_get_minimum_value(SLV2Plugin plugin, 
+                            SLV2Port   port);
+
+
+/** Get the maximum value of a port.
+ *
+ * Only valid for ports with a data type of lv2:float.
+ *
+ * Time = Query
+ */
+float
+slv2_port_get_maximum_value(SLV2Plugin plugin, 
+                            SLV2Port   port);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_PORT_H__ */

Index: slv2/slv2.h
===================================================================
RCS file: slv2/slv2.h
diff -N slv2/slv2.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/slv2.h 23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,39 @@
+/* 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_H
+#define __SLV2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <slv2/types.h>
+#include <slv2/world.h>
+#include <slv2/plugin.h>
+#include <slv2/port.h>
+#include <slv2/pluginlist.h>
+#include <slv2/plugininstance.h>
+#include <slv2/stringlist.h>
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_H */

Index: slv2/stringlist.h
===================================================================
RCS file: slv2/stringlist.h
diff -N slv2/stringlist.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/stringlist.h   23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,84 @@
+/* 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_STRINGLIST_H__
+#define __SLV2_STRINGLIST_H__
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup strings Collections of strings
+ *
+ * SLV2Strings is an ordered collection of strings which is fast for random
+ * access by index (i.e. a fancy array).
+ *
+ * @{
+ */
+
+
+typedef void* SLV2Strings;
+
+
+/** Allocate a new, empty SLV2Strings
+ */
+SLV2Strings
+slv2_strings_new();
+
+
+/** Get the number of elements in a string list.
+ */
+unsigned
+slv2_strings_size(SLV2Strings list);
+
+
+/** Get a string from a string list at the given index.
+ *
+ * @return the element at \a index, or NULL if index is out of range.
+ *
+ * Time = O(1)
+ */
+const char*
+slv2_strings_get_at(SLV2Strings list, unsigned index);
+
+
+/** Return whether \a list contains \a string.
+ *
+ * Time = O(n)
+ */
+bool
+slv2_strings_contains(SLV2Strings list, const char* string);
+
+
+/** Free a string list.
+ */
+void
+slv2_strings_free(SLV2Strings);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_STRINGLIST_H__ */
+

Index: slv2/types.h
===================================================================
RCS file: slv2/types.h
diff -N slv2/types.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/types.h        23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,65 @@
+/* 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_TYPES_H__
+#define __SLV2_TYPES_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Class (direction and type) of a port
+ *
+ * Note that ports may be of other classes not listed here, this is just
+ * to make the most common case simple.  Use slv2_port_get_value(p, "rdf:type")
+ * if you need further class information.
+ */
+typedef enum _PortClass {
+       SLV2_UNKNOWN_PORT_CLASS,
+       SLV2_CONTROL_INPUT,  /**< One input float per block */
+       SLV2_CONTROL_OUTPUT, /**< One output float per block */
+       SLV2_AUDIO_INPUT,    /**< One input float per frame */
+       SLV2_AUDIO_OUTPUT,   /**< One output float per frame */
+       SLV2_MIDI_INPUT,     /**< MIDI input (LL extension) */
+       SLV2_MIDI_OUTPUT     /**< MIDI output (LL extension) */
+} SLV2PortClass;
+
+
+/** A port on a plugin.  Opaque, but valid to compare to NULL. */
+typedef struct _Port* SLV2Port;
+
+
+/** A plugin.  Opaque, but valid to compare to NULL. */
+typedef struct _Plugin* SLV2Plugin;
+
+
+/** The world.  Opaque, but valid to compare to NULL. */
+typedef struct _World* SLV2World;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __SLV2_TYPES_H__ */
+

Index: slv2/util.h
===================================================================
RCS file: slv2/util.h
diff -N slv2/util.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/util.h 23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,71 @@
+/* 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_UTIL_H__
+#define __SLV2_UTIL_H__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup util Utility functions
+ *
+ * @{
+ */
+
+
+/** Convert a full URI (eg file://foo/bar/baz.ttl) to a local path (e.g. 
/foo/bar/baz.ttl).
+ *
+ * Return value is shared and must not be deleted by caller.
+ * \return \a uri converted to a path, or NULL on failure (URI is not local).
+ */
+const char* slv2_uri_to_path(const char* uri);
+
+
+/** 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
+slv2_strappend(char** dst, const char* suffix);
+
+
+/** Join all arguments into one string.
+ *
+ * Arguments are not modified, return value must be free()'d.
+ */
+char*
+slv2_strjoin(const char* first, ...);
+
+
+char*
+slv2_vstrjoin(const char** first, va_list args_list);
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_UTIL_H__ */
+

Index: slv2/world.h
===================================================================
RCS file: slv2/world.h
diff -N slv2/world.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ slv2/world.h        23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,171 @@
+/* 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_WORLD_H__
+#define __SLV2_WORLD_H__
+
+#include <slv2/pluginlist.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup world Library context, data loading, etc.
+ * 
+ * The "world" represents all library state, and the data found in bundles'
+ * manifest.ttl (ie it is an in-memory index of all things LV2 found).
+ * Plugins (and plugin extensions) and the LV2 specification (and LV2
+ * extensions) itself can be queried from the world for use.
+ *
+ * Normal hosts which just want to easily load plugins by URI are strongly
+ * recommended to simply call \ref slv2_world_load_all to find all installed
+ * data in the recommended way.
+ *
+ * Normal hosts should NOT have to refer to bundles directly under normal
+ * circumstances.  However, functions are provided to load individual bundles
+ * explicitly, intended for hosts which depend on a specific bundle
+ * (which is shipped with the application).
+ *
+ * @{
+ */
+
+
+/** Initialize a new, empty world.
+ */
+SLV2World
+slv2_world_new();
+
+
+/** Destroy the world, mwahaha.
+ *
+ * NB: Destroying the world will leave dangling references in any plugin lists,
+ * plugins, etc.  Do not destroy the world until you are finished with all
+ * objects that came from it.
+ */
+void
+slv2_world_free(SLV2World world);
+
+
+/** 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.
+ *
+ * Time = Query
+ */
+void
+slv2_world_load_all(SLV2World world);
+
+
+/** Load a specific bundle.
+ *
+ * \arg bundle_uri 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 \b never attach any long-term significance to bundle paths
+ * as there are no guarantees they will remain consistent whatsoever.
+ * Plugins (and other things) are identified by URIs, \b not bundle or
+ * file names.
+ *
+ * This function should only be used by apps which ship with a special
+ * bundle (which it knows exists at some path because the bundle is
+ * shipped with the application).
+ *
+ * Time = Query
+ */
+void
+slv2_world_load_bundle(SLV2World   world,
+                       const char* bundle_uri);
+
+
+/** Return a list of all found plugins.
+ *
+ * The returned list contains just enough references to query
+ * or instantiate plugins.  The data for a particular plugin will not be
+ * loaded into memory until a call to an slv2_plugin_* function results in
+ * a query (at which time the data is cached with the SLV2Plugin so future
+ * queries are very fast).
+ *
+ * Returned plugins contain a reference to this world, world must not be
+ * destroyed until plugins are finished with.
+ *
+ * Time = O(1)
+ */
+SLV2Plugins
+slv2_world_get_all_plugins(SLV2World world);
+
+
+/** Return a list of found plugins filtered by a user-defined filter function.
+ *
+ * All plugins currently found in \a world that return true when passed to
+ * \a include (a pointer to a function which takes an SLV2Plugin and returns
+ * a bool) will be in the returned list.
+ *
+ * Returned plugins contain a reference to this world, world must not be
+ * destroyed until plugins are finished with.
+ *
+ * Time = O(n * Time(include))
+ */
+SLV2Plugins
+slv2_world_get_plugins_by_filter(SLV2World world,
+                                 bool (*include)(SLV2Plugin));
+
+
+#if 0
+/** Get plugins filtered by a user-defined SPARQL query.
+ *
+ * This is much faster than using slv2_world_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 world, world must not be
+ * destroyed until plugins are finished with.
+ */
+SLV2Plugins
+slv2_world_get_plugins_by_query(SLV2World   world,
+                                const char* query);
+#endif
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_WORLD_H__ */
+

Index: src/plugin.c
===================================================================
RCS file: src/plugin.c
diff -N src/plugin.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/plugin.c        23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,459 @@
+/* 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 <assert.h>
+#include <librdf.h>
+#include <slv2/plugin.h>
+#include <slv2/types.h>
+#include <slv2/util.h>
+#include <slv2/stringlist.h>
+#include "private_types.h"
+
+
+/* private */
+SLV2Plugin
+slv2_plugin_new(SLV2World world, librdf_uri* uri, const char* binary_uri)
+{
+       struct _Plugin* plugin = malloc(sizeof(struct _Plugin));
+       plugin->world = world;
+       plugin->plugin_uri = librdf_new_uri_from_uri(uri);
+       plugin->binary_uri = strdup(binary_uri);
+       plugin->data_uris = slv2_strings_new();
+       plugin->ports = raptor_new_sequence((void (*)(void*))&slv2_port_free, 
NULL);
+       plugin->storage = NULL;
+       plugin->rdf = NULL;
+
+       return plugin;
+}
+
+
+/* private */
+void
+slv2_plugin_free(SLV2Plugin p)
+{
+       librdf_free_uri(p->plugin_uri);
+       p->plugin_uri = NULL;
+       
+       //free(p->bundle_url);
+       free(p->binary_uri);
+       
+       raptor_free_sequence(p->ports);
+       p->ports = NULL;
+
+       if (p->rdf) {
+               librdf_free_model(p->rdf);
+               p->rdf = NULL;
+       }
+       
+       if (p->storage) {
+               librdf_free_storage(p->storage);
+               p->storage = NULL;
+       }
+       
+       slv2_strings_free(p->data_uris);
+
+       free(p);
+}
+
+
+// FIXME: ew
+librdf_query_results*
+slv2_plugin_query(SLV2Plugin plugin,
+                  const char* sparql_str);
+
+
+/*
+SLV2Plugin
+slv2_plugin_duplicate(SLV2Plugin p)
+{
+       assert(p);
+       struct _Plugin* result = malloc(sizeof(struct _Plugin));
+       result->world = p->world;
+       result->plugin_uri = librdf_new_uri_from_uri(p->plugin_uri);
+
+       //result->bundle_url = strdup(p->bundle_url);
+       result->binary_uri = strdup(p->binary_uri);
+       
+       result->data_uris = slv2_strings_new();
+       for (unsigned i=0; i < slv2_strings_size(p->data_uris); ++i)
+               raptor_sequence_push(result->data_uris, 
strdup(slv2_strings_get_at(p->data_uris, i)));
+       
+       result->ports = raptor_new_sequence((void (*)(void*))&slv2_port_free, 
NULL);
+       for (int i=0; i < raptor_sequence_size(p->ports); ++i)
+               raptor_sequence_push(result->ports, 
slv2_port_duplicate(raptor_sequence_get_at(p->ports, i)));
+
+       result->storage = NULL;
+       result->rdf = NULL;
+
+       return result;
+}
+*/
+
+
+/** comparator for sorting */
+int
+slv2_port_compare_by_index(const void* a, const void* b)
+{
+       SLV2Port port_a = *(SLV2Port*)a;
+       SLV2Port port_b = *(SLV2Port*)b;
+
+       if (port_a->index < port_b->index)
+               return -1;
+       else if (port_a->index == port_b->index)
+               return 0;
+       else //if (port_a->index > port_b->index)
+               return 1;
+}
+
+
+void
+slv2_plugin_load(SLV2Plugin p)
+{
+       //printf("Loading cache for %s\n", (const 
char*)librdf_uri_as_string(p->plugin_uri));
+
+       if (!p->storage) {
+               assert(!p->rdf);
+               p->storage = librdf_new_storage(p->world->world, "hashes", NULL,
+                               "hash-type='memory'");
+               p->rdf = librdf_new_model(p->world->world, p->storage, NULL);
+       }
+
+       // Parse all the plugin's data files into RDF model
+       for (unsigned i=0; i < slv2_strings_size(p->data_uris); ++i) {
+               const char* data_uri_str = slv2_strings_get_at(p->data_uris, i);
+               librdf_uri* data_uri = librdf_new_uri(p->world->world, (const 
unsigned char*)data_uri_str);
+               librdf_parser_parse_into_model(p->world->parser, data_uri, 
NULL, p->rdf);
+               librdf_free_uri(data_uri);
+       }
+
+       // Load ports
+       const unsigned char* query = (const unsigned char*)
+               "PREFIX : <http://lv2plug.in/ontology#>\n"
+               "SELECT DISTINCT ?port ?symbol ?index WHERE {\n"
+               "<>    :port   ?port .\n"
+               "?port :symbol ?symbol ;\n"
+               "      :index  ?index .\n"
+               "}";
+       
+       librdf_query* q = librdf_new_query(p->world->world, "sparql",
+               NULL, query, p->plugin_uri);
+       
+       librdf_query_results* results = librdf_query_execute(q, p->rdf);
+
+       while (!librdf_query_results_finished(results)) {
+       
+               //librdf_node* port_node = 
librdf_query_results_get_binding_value(results, 0);
+               librdf_node* symbol_node = 
librdf_query_results_get_binding_value(results, 1);
+               librdf_node* index_node = 
librdf_query_results_get_binding_value(results, 2);
+
+               //assert(librdf_node_is_blank(port_node));
+               assert(librdf_node_is_literal(symbol_node));
+               assert(librdf_node_is_literal(index_node));
+
+               //const char* id = (const 
char*)librdf_node_get_blank_identifier(port_node);
+               const char* symbol = (const 
char*)librdf_node_get_literal_value(symbol_node);
+               const char* index = (const 
char*)librdf_node_get_literal_value(index_node);
+
+               //printf("%s: PORT: %s %s\n", p->plugin_uri, index, symbol);
+               
+               // Create a new SLV2Port
+               SLV2Port port = slv2_port_new((unsigned)atoi(index), symbol);
+               raptor_sequence_push(p->ports, port);
+               
+               librdf_free_node(symbol_node);
+               librdf_free_node(index_node);
+               
+               librdf_query_results_next(results);
+       }
+       
+       raptor_sequence_sort(p->ports, slv2_port_compare_by_index);
+       
+       if (results)
+               librdf_free_query_results(results);
+       
+       librdf_free_query(q);
+
+       //printf("%p %s: NUM PORTS: %d\n", (void*)p, p->plugin_uri, 
slv2_plugin_get_num_ports(p));
+}
+
+
+const char*
+slv2_plugin_get_uri(SLV2Plugin p)
+{
+       return (const char*)librdf_uri_as_string(p->plugin_uri);
+}
+
+
+SLV2Strings
+slv2_plugin_get_data_uris(SLV2Plugin p)
+{
+       return p->data_uris;
+}
+
+
+const char*
+slv2_plugin_get_library_uri(SLV2Plugin p)
+{
+       return p->binary_uri;
+}
+
+
+bool
+slv2_plugin_verify(SLV2Plugin plugin)
+{
+       char* query_str = 
+               "SELECT DISTINCT ?type ?name ?license ?port WHERE {\n"
+               "<> a ?type ;\n"
+               "doap:name    ?name ;\n"
+               "doap:license ?license ;\n"
+               "lv2:port     [ lv2:index ?port ] .\n}";
+
+       librdf_query_results* results = slv2_plugin_query(plugin, query_str);
+
+       bool has_type    = false;
+       bool has_name    = false;
+       bool has_license = false;
+       bool has_port    = false;
+
+       while (!librdf_query_results_finished(results)) {
+               librdf_node* type_node = 
librdf_query_results_get_binding_value(results, 0);
+               const char* const type_str = (const 
char*)librdf_node_get_literal_value(type_node);
+               librdf_node* name_node = 
librdf_query_results_get_binding_value(results, 1);
+               //const char* const name = (const 
char*)librdf_node_get_literal_value(name_node);
+               librdf_node* license_node = 
librdf_query_results_get_binding_value(results, 2);
+               librdf_node* port_node = 
librdf_query_results_get_binding_value(results, 3);
+
+               if (!strcmp(type_str, "http://lv2plug.in/ontology#Plugin";))
+                       has_type = true;
+               
+               if (name_node)
+                       has_name = true;
+               
+               if (license_node)
+                       has_license = true;
+               
+               if (port_node)
+                       has_port = true;
+
+               librdf_free_node(type_node);
+               librdf_free_node(name_node);
+               librdf_free_node(license_node);
+               librdf_free_node(port_node);
+
+               librdf_query_results_next(results);
+       }
+
+       librdf_free_query_results(results);
+
+       if ( ! (has_type && has_name && has_license && has_port) ) {
+               fprintf(stderr, "Invalid LV2 Plugin %s\n", 
slv2_plugin_get_uri(plugin));
+               return false;
+       } else {
+               return true;
+       }
+}
+
+
+char*
+slv2_plugin_get_name(SLV2Plugin plugin)
+{
+       char* result     = NULL;
+       SLV2Strings prop = slv2_plugin_get_value(plugin, "doap:name");
+       
+       // FIXME: guaranteed to be the untagged one?
+       if (prop && slv2_strings_size(prop) >= 1)
+               result = strdup(slv2_strings_get_at(prop, 0));
+
+       if (prop)
+               slv2_strings_free(prop);
+
+       return result;
+}
+
+
+SLV2Strings
+slv2_plugin_get_value(SLV2Plugin  p,
+                      const char* predicate)
+{
+       assert(predicate);
+
+    char* query = slv2_strjoin(
+               "SELECT DISTINCT ?value WHERE {"
+               "<> ", predicate, " ?value .\n"
+               "}\n", NULL);
+
+       SLV2Strings result = slv2_plugin_simple_query(p, query, "value");
+       
+       free(query);
+
+       return result;
+}
+
+       
+SLV2Strings
+slv2_plugin_get_value_for_subject(SLV2Plugin  p,
+                                  const char* subject,
+                                  const char* predicate)
+{
+       assert(predicate);
+
+    char* query = slv2_strjoin(
+               "SELECT DISTINCT ?value WHERE {\n",
+               subject, " ", predicate, " ?value .\n"
+               "}\n", NULL);
+
+       SLV2Strings result = slv2_plugin_simple_query(p, query, "value");
+       
+       free(query);
+
+       return result;
+}
+
+
+SLV2Strings
+slv2_plugin_get_properties(SLV2Plugin p)
+{
+       return slv2_plugin_get_value(p, "lv2:pluginProperty");
+}
+
+
+SLV2Strings
+slv2_plugin_get_hints(SLV2Plugin p)
+{
+       return slv2_plugin_get_value(p, "lv2:pluginHint");
+}
+
+
+uint32_t
+slv2_plugin_get_num_ports(SLV2Plugin p)
+{
+       return raptor_sequence_size(p->ports);
+}
+
+
+bool
+slv2_plugin_has_latency(SLV2Plugin p)
+{
+    const char* const query = 
+               "SELECT DISTINCT ?port WHERE {\n"
+               "       <> lv2:port     ?port .\n"
+               "       ?port   lv2:portHint lv2:reportsLatency .\n"
+               "}\n";
+
+       SLV2Strings results = slv2_plugin_simple_query(p, query, "port");
+       
+       bool exists = (slv2_strings_size(results) > 0);
+       
+       slv2_strings_free(results);
+
+       return exists;
+}
+
+
+uint32_t
+slv2_plugin_get_latency_port(SLV2Plugin p)
+{
+    const char* const query = 
+               "SELECT DISTINCT ?value WHERE {\n"
+               "       <> lv2:port     ?port .\n"
+               "       ?port   lv2:portHint lv2:reportsLatency ;\n"
+               "           lv2:index    ?index .\n"
+               "}\n";
+
+       SLV2Strings result = slv2_plugin_simple_query(p, query, "index");
+       
+       // FIXME: need a sane error handling strategy
+       assert(slv2_strings_size(result) == 1);
+       char* endptr = 0;
+       uint32_t index = strtol(slv2_strings_get_at(result, 0), &endptr, 10);
+       // FIXME: check.. stuff..
+
+       return index;
+}
+
+
+SLV2Strings
+slv2_plugin_get_supported_features(SLV2Plugin p)
+{
+    const char* const query = 
+               "SELECT DISTINCT ?feature WHERE {\n"
+               "       { <>  lv2:optionalHostFeature  ?feature }\n"
+               "               UNION\n"
+               "       { <>  lv2:requiredHostFeature  ?feature }\n"
+               "}\n";
+
+       SLV2Strings result = slv2_plugin_simple_query(p, query, "feature");
+       
+       return result;
+}
+
+
+SLV2Strings
+slv2_plugin_get_optional_features(SLV2Plugin p)
+{
+    const char* const query = 
+               "SELECT DISTINCT ?feature WHERE {\n"
+               "       <>  lv2:optionalHostFeature  ?feature .\n"
+               "}\n";
+
+       SLV2Strings result = slv2_plugin_simple_query(p, query, "feature");
+       
+       return result;
+}
+
+
+SLV2Strings
+slv2_plugin_get_required_features(SLV2Plugin p)
+{
+    const char* const query = 
+               "SELECT DISTINCT ?feature WHERE {\n"
+               "       <>  lv2:requiredHostFeature  ?feature .\n"
+               "}\n";
+
+       SLV2Strings result = slv2_plugin_simple_query(p, query, "feature");
+       
+       return result;
+}
+
+
+SLV2Port
+slv2_plugin_get_port_by_index(SLV2Plugin p,
+                              uint32_t   index)
+{
+       return raptor_sequence_get_at(p->ports, (int)index);
+}
+
+
+SLV2Port
+slv2_plugin_get_port_by_symbol(SLV2Plugin  p,
+                               const char* symbol)
+{
+       // FIXME: sort plugins and do a binary search
+       for (int i=0; i < raptor_sequence_size(p->ports); ++i) {
+               SLV2Port port = raptor_sequence_get_at(p->ports, i);
+               if (!strcmp(port->symbol, symbol))
+                       return port;
+       }
+
+       return NULL;
+}
+

Index: src/plugininstance.c
===================================================================
RCS file: src/plugininstance.c
diff -N src/plugininstance.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/plugininstance.c        23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,141 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <slv2/types.h>
+#include <slv2/plugin.h>
+#include <slv2/plugininstance.h>
+#include <slv2/util.h>
+#include "private_types.h"
+
+
+SLV2Instance
+slv2_plugin_instantiate(SLV2Plugin               plugin,
+                        uint32_t                 sample_rate,
+                        const LV2_Host_Feature** host_features)
+{
+       struct _Instance* result = NULL;
+       
+       bool local_host_features = (host_features == NULL);
+       if (local_host_features) {
+               host_features = malloc(sizeof(LV2_Host_Feature));
+               host_features[0] = NULL;
+       }
+       
+       const char* const lib_uri = slv2_plugin_get_library_uri(plugin);
+       const char* const lib_path = slv2_uri_to_path(lib_uri);
+       
+       if (!lib_path)
+               return NULL;
+       
+       dlerror();
+       void* lib = dlopen(lib_path, RTLD_NOW);
+       if (!lib) {
+               fprintf(stderr, "Unable to open library %s (%s)\n", lib_path, 
dlerror());
+               return NULL;
+       }
+
+       LV2_Descriptor_Function df = dlsym(lib, "lv2_descriptor");
+
+       if (!df) {
+               fprintf(stderr, "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
+               
+               // FIXME: Kluge to get bundle path (containing directory of 
binary)
+               char* bundle_path = strdup(plugin->binary_uri);
+               char* const bundle_path_end = strrchr(bundle_path, '/');
+               if (bundle_path_end)
+               *(bundle_path_end+1) = '\0';
+               printf("Bundle path: %s\n", bundle_path);
+               
+               for (uint32_t i=0; 1; ++i) {
+                       
+                       const LV2_Descriptor* ld = df(i);
+                               
+                       if (!ld) {
+                               fprintf(stderr, "Did not find plugin %s in 
%s\n",
+                                               slv2_plugin_get_uri(plugin), 
lib_path);
+                               dlclose(lib);
+                               break; // return NULL
+                       } else if (!strcmp(ld->URI, 
slv2_plugin_get_uri(plugin))) {
+
+                               printf("Found %s at index %u in:\n\t%s\n\n",
+                                               
librdf_uri_as_string(plugin->plugin_uri), i, lib_path);
+
+                               assert(ld->instantiate);
+
+                               // Create SLV2Instance to return
+                               result = malloc(sizeof(struct _Instance));
+                               result->lv2_descriptor = ld;
+                               result->lv2_handle = ld->instantiate(ld, 
sample_rate, (char*)bundle_path, host_features);
+                               struct _InstanceImpl* impl = 
malloc(sizeof(struct _InstanceImpl));
+                               impl->lib_handle = lib;
+                               result->pimpl = impl;
+
+                               break;
+                       }
+               }
+
+               free(bundle_path);
+       }
+
+       assert(result);
+       assert(slv2_plugin_get_num_ports(plugin) > 0);
+
+       // Failed to instantiate
+       if (result->lv2_handle == NULL) {
+               //printf("Failed to instantiate %s\n", plugin->plugin_uri);
+               free(result);
+               return NULL;
+       }
+
+       // "Connect" all ports to NULL (catches bugs)
+       for (uint32_t i=0; i < slv2_plugin_get_num_ports(plugin); ++i)
+               result->lv2_descriptor->connect_port(result->lv2_handle, i, 
NULL);
+       
+       if (local_host_features)
+               free(host_features);
+
+       return result;
+}
+
+
+void
+slv2_instance_free(SLV2Instance instance)
+{
+       struct _Instance* i = (struct _Instance*)instance;
+       i->lv2_descriptor->cleanup(i->lv2_handle);
+       i->lv2_descriptor = NULL;
+       dlclose(i->pimpl->lib_handle);
+       i->pimpl->lib_handle = NULL;
+       free(i->pimpl);
+       i->pimpl = NULL;
+       free(i);
+}
+
+

Index: src/pluginlist.c
===================================================================
RCS file: src/pluginlist.c
diff -N src/pluginlist.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/pluginlist.c    23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,318 @@
+/* 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 <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <dirent.h>
+#include <librdf.h>
+#include <slv2/types.h>
+#include <slv2/plugin.h>
+#include <slv2/pluginlist.h>
+#include <slv2/stringlist.h>
+#include <slv2/util.h>
+#include "private_types.h"
+
+       
+SLV2Plugins
+slv2_plugins_new()
+{
+       //return raptor_new_sequence((void (*)(void*))&slv2_plugin_free, NULL);
+       return raptor_new_sequence(NULL, NULL);
+}
+
+
+void
+slv2_plugins_free(SLV2World world, SLV2Plugins list)
+{
+       if (list != world->plugins)
+               raptor_free_sequence(list);
+}
+
+#if 0
+void
+slv2_plugins_filter(SLV2Plugins dest, SLV2Plugins source, bool 
(*include)(SLV2Plugin))
+{
+       assert(dest);
+
+       for (int i=0; i < raptor_sequence_size(source); ++i) {
+               SLV2Plugin p = raptor_sequence_get_at(source, i);
+               if (include(p))
+                       raptor_sequence_push(dest, slv2_plugin_duplicate(p));
+       }
+}
+
+
+void
+slv2_plugins_load_all(SLV2Plugins list)
+{
+       /* FIXME: this is much slower than it should be in many ways.. */
+
+       assert(list);
+       
+       char* slv2_path = getenv("LV2_PATH");
+
+       SLV2Plugins load_list = slv2_plugins_new();     
+
+       if (slv2_path) {
+           slv2_plugins_load_path(load_list, slv2_path);
+    } else {
+        const char* const home = getenv("HOME");
+        const char* const suffix = "/.lv2:/usr/local/lib/lv2:usr/lib/lv2";
+        slv2_path = slv2_strjoin(home, suffix, NULL);
+               
+               fprintf(stderr, "$LV2_PATH is unset.  Using default path %s\n", 
slv2_path);
+           
+               /* pass 1: find all plugins */
+               slv2_plugins_load_path(load_list, slv2_path);
+               
+               /* pass 2: find all data files for plugins */
+               slv2_plugins_load_path(load_list, slv2_path);
+
+        free(slv2_path);
+       }
+
+       /* insert only valid plugins into list */
+       slv2_plugins_filter(list, load_list, slv2_plugin_verify);
+       slv2_plugins_free(load_list);
+}
+
+
+/* This is the parser for manifest.ttl
+ * This is called twice on each bundle in the discovery process, which is 
(much) less
+ * efficient than it could be.... */
+void
+slv2_plugins_load_bundle(SLV2Plugins list,
+                         const char* bundle_base_url)
+{
+       assert(list);
+
+       unsigned char* manifest_url = malloc(
+               (strlen((char*)bundle_base_url) + strlen("manifest.ttl") + 2) * 
sizeof(unsigned char));
+       memcpy(manifest_url, bundle_base_url, strlen((char*)bundle_base_url)+1 
* sizeof(unsigned char));
+       if (bundle_base_url[strlen(bundle_base_url)-1] == '/')
+               strcat((char*)manifest_url, "manifest.ttl");
+       else
+               strcat((char*)manifest_url, "/manifest.ttl");
+       
+       librdf_query_results *results;
+       librdf_uri *base_uri = librdf_new_uri(slv2_rdf_world, manifest_url);
+       
+       /* Get all plugins explicitly mentioned in the manifest (discovery pass 
1) */
+       char* query_string =
+       "PREFIX : <http://lv2plug.in/ontology#>\n\n"
+               "SELECT DISTINCT ?plugin_uri FROM <>\n"
+               "WHERE { ?plugin_uri a :Plugin }\n";
+       
+       librdf_query *rq = librdf_new_query(slv2_rdf_world, "sparql", NULL,
+               (unsigned char*)query_string, base_uri);
+
+
+
+       //printf("%s\n\n", query_string);  
+       
+       results = librdf_query_execute(rq, model->model);
+       
+       while (!librdf_query_results_finished(results)) {
+               
+               librdf_node* literal = 
librdf_query_results_get_binding_value(results, 0);
+               assert(literal);
+
+               if (!slv2_plugins_get_by_uri(list, (const 
char*)librdf_node_get_literal_value(literal))) {
+                       /* Create a new plugin */
+                       struct _Plugin* new_plugin = slv2_plugin_new();
+                       new_plugin->plugin_uri = strdup((const 
char*)librdf_node_get_literal_value(literal));
+                       new_plugin->bundle_url = strdup(bundle_base_url);
+                       raptor_sequence_push(new_plugin->data_uris, 
strdup((const char*)manifest_url));
+
+                       raptor_sequence_push(list, new_plugin);
+
+               }
+               
+               librdf_query_results_next(results);
+       }       
+       
+       if (results)
+               librdf_free_query_results(results);
+       
+       librdf_free_query(rq);
+       
+       /* Get all data files linked to plugins (discovery pass 2) */
+       query_string =
+               "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
+       "PREFIX :     <http://lv2plug.in/ontology#>\n\n"
+       "SELECT DISTINCT ?subject ?data_uri ?binary FROM <>\n"
+       "WHERE { ?subject  rdfs:seeAlso  ?data_uri\n"
+               "OPTIONAL { ?subject :binary ?binary } }\n";
+       
+       rq = librdf_new_query(slv2_rdf_world, "sparql", NULL,
+                       (unsigned char*)query_string, base_uri);
+
+       //printf("%s\n\n", query_string);  
+       
+       results = librdf_query_execute(rq, slv2_model);
+
+       while (!librdf_query_results_finished(results)) {
+
+               const char* subject = (const 
char*)librdf_node_get_literal_value(
+                               librdf_query_results_get_binding_value(results, 
0));
+
+               const char* data_uri = (const 
char*)librdf_node_get_literal_value(
+                               librdf_query_results_get_binding_value(results, 
1));
+
+               const char* binary = (const char*)librdf_node_get_literal_value(
+                               librdf_query_results_get_binding_value(results, 
2));
+
+               SLV2Plugin plugin = slv2_plugins_get_by_uri(list, subject);
+
+               if (plugin && data_uri && 
!slv2_strings_contains(plugin->data_uris, data_uri))
+                       raptor_sequence_push(plugin->data_uris, 
strdup(data_uri));
+               
+               if (plugin && binary && !plugin->lib_uri)
+                       ((struct _Plugin*)plugin)->lib_uri = strdup(binary);
+                
+               librdf_query_results_next(results);
+
+       }
+
+       if (results)
+               librdf_free_query_results(results);
+       
+       librdf_free_query(rq);
+
+       librdf_free_uri(base_uri);
+       free(manifest_url);
+}
+
+
+/* Add all the plugins found in dir to list.
+ * (Private helper function, not exposed in public API)
+ */
+void
+slv2_plugins_load_dir(SLV2Plugins list, const char* dir)
+{
+       assert(list);
+
+       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 = slv2_strjoin(dir, "/", pfile->d_name, NULL);
+               char* bundle_url = slv2_strjoin("file://", dir, "/", 
pfile->d_name, NULL);
+               DIR* bundle_dir = opendir(bundle_path);
+
+               if (bundle_dir != NULL) {
+                       closedir(bundle_dir);
+                       
+                       slv2_plugins_load_bundle(list, bundle_url);
+                       //printf("Loaded bundle %s\n", bundle_url);
+               }
+               
+               free(bundle_path);
+               free(bundle_url);
+       }
+
+       closedir(pdir);
+}
+
+
+void
+slv2_plugins_load_path(SLV2Plugins list,
+                       const char* lv2_path)
+{
+       assert(list);
+
+       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_plugins_load_dir(list, dir);
+               
+               *delim = 'X';
+               dir = delim + 1;
+       }
+       
+       //char* slv2_path = strdup(slv2
+
+       free(path);
+}
+#endif
+
+unsigned
+slv2_plugins_size(SLV2Plugins list)
+{
+       return raptor_sequence_size(list);
+}
+
+
+SLV2Plugin
+slv2_plugins_get_by_uri(SLV2Plugins list, const char* uri)
+{
+       // good old fashioned binary search
+       
+       int lower = 0;
+       int upper = raptor_sequence_size(list) - 1;
+       int i;
+       
+       if (upper == 0)
+               return NULL;
+
+       while (upper >= lower) {
+               i = lower + ((upper - lower) / 2);
+
+               SLV2Plugin p = raptor_sequence_get_at(list, i);
+
+               int cmp = strcmp(slv2_plugin_get_uri(p), uri);
+
+               if (cmp == 0)
+                       return p;
+               else if (cmp > 0)
+                       upper = i - 1;
+               else
+                       lower = i + 1;
+       }
+
+       return NULL;
+}
+
+
+SLV2Plugin
+slv2_plugins_get_at(SLV2Plugins list, unsigned index)
+{      
+       assert(list);
+
+       if (index > INT_MAX)
+               return NULL;
+       else
+               return (SLV2Plugin)raptor_sequence_get_at(list, (int)index);
+}
+

Index: src/port.c
===================================================================
RCS file: src/port.c
diff -N src/port.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/port.c  23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,240 @@
+/* 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <slv2/port.h>
+#include <slv2/types.h>
+#include <slv2/util.h>
+#include "private_types.h"
+
+
+/* private */
+SLV2Port
+slv2_port_new(uint32_t index, const char* symbol/*, const char* node_id*/)
+{
+       struct _Port* port = malloc(sizeof(struct _Port));
+       port->index = index;
+       port->symbol = strdup(symbol);
+       //port->node_id = strdup(node_id);
+       return port;
+}
+
+
+/* private */
+void
+slv2_port_free(SLV2Port port)
+{
+       free(port->symbol);
+       //free(port->node_id);
+       free(port);
+}
+
+
+/* private */
+SLV2Port
+slv2_port_duplicate(SLV2Port port)
+{
+       struct _Port* result = malloc(sizeof(struct _Port));
+       result->index = port->index;
+       result->symbol = strdup(port->symbol);
+       //result->node_id = strdup(port->node_id);
+       return result;
+}
+
+
+SLV2PortClass
+slv2_port_get_class(SLV2Plugin p,
+                    SLV2Port   port)
+{
+       SLV2Strings class = slv2_port_get_value(p, port, "rdf:type");
+       assert(class);
+
+       SLV2PortClass ret = SLV2_UNKNOWN_PORT_CLASS;
+
+       int io = -1; // 0 = in, 1 = out
+       enum { UNKNOWN, AUDIO, CONTROL, MIDI } type = UNKNOWN;
+
+       for (unsigned i=0; i < slv2_strings_size(class); ++i) {
+               const char* value = slv2_strings_get_at(class, i);
+               if (!strcmp(value, "http://lv2plug.in/ontology#InputPort";))
+                       io = 0;
+               else if (!strcmp(value, 
"http://lv2plug.in/ontology#OutputPort";))
+                       io = 1;
+               else if (!strcmp(value, 
"http://lv2plug.in/ontology#ControlPort";))
+                       type = CONTROL;
+               else if (!strcmp(value, "http://lv2plug.in/ontology#AudioPort";))
+                       type = AUDIO;
+               else if (!strcmp(value, 
"http://ll-plugins.nongnu.org/lv2/ext/MidiPort";))
+                       type = MIDI;
+       }
+
+       if (io == 0) {
+               if (type == AUDIO)
+                       ret = SLV2_AUDIO_INPUT;
+               else if (type == CONTROL)
+                       ret = SLV2_CONTROL_INPUT;
+               else if (type == MIDI)
+                       ret = SLV2_MIDI_INPUT;
+       } else if (io == 1) {
+               if (type == AUDIO)
+                       ret = SLV2_AUDIO_OUTPUT;
+               else if (type == CONTROL)
+                       ret = SLV2_CONTROL_OUTPUT;
+               else if (type == MIDI)
+                       ret = SLV2_MIDI_OUTPUT;
+       }
+
+       slv2_strings_free(class);
+
+       return ret;
+}
+
+
+SLV2Strings
+slv2_port_get_value(SLV2Plugin  p,
+                    SLV2Port    port,
+                    const char* property)
+{
+       assert(property);
+
+       SLV2Strings result = NULL;
+
+       char* query = slv2_strjoin(
+                       "SELECT DISTINCT ?value WHERE {\n"
+                       "?port lv2:symbol \"", port->symbol, "\";\n\t",
+                              property, " ?value .\n}", 0);
+                       
+       result = slv2_plugin_simple_query(p, query, "value");
+
+       free(query);
+       
+       return result;
+}
+
+
+char*
+slv2_port_get_symbol(SLV2Plugin p,
+                     SLV2Port   port)
+{
+       char* symbol = NULL;
+       
+       SLV2Strings result = slv2_port_get_value(p, port, "lv2:symbol");
+
+       if (result && slv2_strings_size(result) == 1)
+               symbol = strdup(slv2_strings_get_at(result, 0));
+       
+       slv2_strings_free(result);
+
+       return symbol;
+}
+
+       
+char*
+slv2_port_get_name(SLV2Plugin p,
+                   SLV2Port   port)
+{
+       char* name = NULL;
+       
+       SLV2Strings result = slv2_port_get_value(p, port, "lv2:name");
+
+       if (result && slv2_strings_size(result) == 1)
+               name = strdup(slv2_strings_get_at(result, 0));
+       
+       slv2_strings_free(result);
+
+       return name;
+}
+
+
+float
+slv2_port_get_default_value(SLV2Plugin p, 
+                            SLV2Port   port)
+{
+       // FIXME: do casting properly in the SPARQL query
+       
+       float value = 0.0f;
+       
+       SLV2Strings result = slv2_port_get_value(p, port, "lv2:default");
+
+       if (result && slv2_strings_size(result) == 1)
+               value = atof(slv2_strings_get_at(result, 0));
+       
+       slv2_strings_free(result);
+
+       return value;
+}
+
+
+float
+slv2_port_get_minimum_value(SLV2Plugin p, 
+                            SLV2Port   port)
+{
+       // FIXME: need better access to literal types
+       
+       float value = 0.0f;
+       
+       SLV2Strings result = slv2_port_get_value(p, port, "lv2:minimum");
+
+       if (result && slv2_strings_size(result) == 1)
+               value = atof(slv2_strings_get_at(result, 0));
+       
+       slv2_strings_free(result);
+
+       return value;
+}
+
+
+float
+slv2_port_get_maximum_value(SLV2Plugin p, 
+                            SLV2Port   port)
+{
+       // FIXME: need better access to literal types
+       
+       float value = 0.0f;
+       
+       SLV2Strings result = slv2_port_get_value(p, port, "lv2:maximum");
+
+       if (result && slv2_strings_size(result) == 1)
+               value = atof(slv2_strings_get_at(result, 0));
+       
+       slv2_strings_free(result);
+
+       return value;
+}
+
+
+SLV2Strings
+slv2_port_get_properties(SLV2Plugin p,
+                         SLV2Port   port)
+{
+       return slv2_port_get_value(p, port, "lv2:portProperty");
+}
+
+
+SLV2Strings
+slv2_port_get_hints(SLV2Plugin p,
+                    SLV2Port   port)
+{
+       return slv2_port_get_value(p, port, "lv2:portHint");
+}
+

Index: src/private_types.h
===================================================================
RCS file: src/private_types.h
diff -N src/private_types.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/private_types.h 23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,110 @@
+/* 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_PRIVATE_TYPES_H__
+#define __SLV2_PRIVATE_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <librdf.h>
+#include <slv2/pluginlist.h>
+
+
+/** Reference to a port on some plugin.
+ */
+struct _Port {
+       uint32_t index;   ///< LV2 index
+       char*    symbol;  ///< LV2 symbol
+       //char*    node_id; ///< RDF Node ID
+};
+
+
+SLV2Port slv2_port_new(uint32_t index, const char* symbol/*, const char* 
node_id*/);
+SLV2Port slv2_port_duplicate(SLV2Port port);
+void     slv2_port_free(SLV2Port port);
+
+
+/** Record of an installed/available plugin.
+ *
+ * A simple reference to a plugin somewhere on the system. This just holds
+ * paths of relevant files, the actual data therein isn't loaded into memory.
+ */
+struct _Plugin {
+       struct _World*   world;
+       librdf_uri*      plugin_uri;
+//     char*            bundle_url; // Bundle directory plugin was loaded from
+       char*            binary_uri; // lv2:binary
+       raptor_sequence* data_uris;  // rdfs::seeAlso
+       raptor_sequence* ports;
+       librdf_storage*  storage;
+       librdf_model*    rdf;
+};
+
+SLV2Plugin slv2_plugin_new(SLV2World world, librdf_uri* uri, const char* 
binary_uri);
+void       slv2_plugin_load(SLV2Plugin p);
+void       slv2_plugin_free(SLV2Plugin plugin);
+
+
+/** Create a new, empty plugin list.
+ *
+ * Returned object must be freed with slv2_plugins_free.
+ */
+SLV2Plugins
+slv2_plugins_new();
+
+
+/** Pimpl portion of SLV2Instance */
+struct _InstanceImpl {
+       void* lib_handle;
+};
+
+
+/** Model of LV2 (RDF) data loaded from bundles.
+ */
+struct _World {
+       librdf_world*       world;
+       librdf_storage*     storage;
+       librdf_model*       model;
+       librdf_parser*      parser;
+       SLV2Plugins plugins;
+};
+
+/** 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 world will be unmodified.
+ * Use of this function is \b not recommended.  Use \ref slv2_world_load_all.
+ */
+void
+slv2_world_load_path(SLV2World   world,
+                     const char* search_path);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SLV2_PRIVATE_TYPES_H__ */
+

Index: src/query.c
===================================================================
RCS file: src/query.c
diff -N src/query.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/query.c 23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,224 @@
+/* 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 <assert.h>
+#include <librdf.h>
+#include <slv2/plugin.h>
+#include <slv2/util.h>
+#include <slv2/stringlist.h>
+#include "private_types.h"
+
+
+static const char* slv2_query_prefixes =
+       "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";
+
+#if 0
+char*
+slv2_query_lang_filter(const char* variable)
+{
+       char* result = NULL;
+       char* const lang = (char*)getenv("LANG");
+       if (lang) {
+               // FILTER( LANG(?value) = "en" || LANG(?value) = "" )
+               result = slv2_strjoin(
+                       //"FILTER (lang(?value) = \"", lang, "\"\n"), 0);
+                       "FILTER( lang(?", variable, ") = \"", lang, 
+                       "\" || lang(?", variable, ") = \"\" )\n", NULL);
+       }
+
+       return result;
+}
+#endif
+
+SLV2Strings
+slv2_query_get_variable_bindings(librdf_query_results* results,
+                                 const char*           variable)
+{
+       SLV2Strings result = NULL;
+
+    if (librdf_query_results_get_bindings_count(results) > 0)
+               result = slv2_strings_new();
+
+    while (!librdf_query_results_finished(results)) {
+
+        librdf_node* node =
+            librdf_query_results_get_binding_value_by_name(results, variable);
+               
+               char* str = NULL;
+
+               switch (librdf_node_get_type(node)) {
+               case LIBRDF_NODE_TYPE_RESOURCE:
+                       str = strdup((const 
char*)librdf_uri_as_string(librdf_node_get_uri(node)));
+                       break;
+               case LIBRDF_NODE_TYPE_LITERAL:
+                       str = strdup((const 
char*)librdf_node_get_literal_value(node));
+                       break;
+               case LIBRDF_NODE_TYPE_BLANK:
+                       str = strdup((const 
char*)librdf_node_get_blank_identifier(node));
+                       break;
+               case LIBRDF_NODE_TYPE_UNKNOWN:
+               default:
+                       fprintf(stderr, "Unknown variable binding type for 
?%s\n", variable);
+                       break;
+               }
+                       
+               if (str) {
+                       //printf("?%s = %s\n", variable, str);
+                       raptor_sequence_push(result, str);
+               }
+
+               librdf_free_node(node);
+
+        librdf_query_results_next(results);
+    }
+
+    return result;
+}
+
+
+size_t
+slv2_query_count_bindings(librdf_query_results* results)
+{
+       size_t count = 0;
+
+    while (!librdf_query_results_finished(results)) {
+               ++count;
+        librdf_query_results_next(results);
+    }
+
+    return count;
+}
+
+       
+librdf_query_results*
+slv2_plugin_query(SLV2Plugin  plugin,
+                  const char* sparql_str)
+{
+       if (!plugin->rdf)
+               slv2_plugin_load(plugin);
+
+       librdf_uri* base_uri = plugin->plugin_uri;
+
+       char* query_str = slv2_strjoin(slv2_query_prefixes, sparql_str, NULL);
+
+       //printf("******** Query \n%s********\n", query_str);
+       
+       librdf_query *rq = librdf_new_query(plugin->world->world, "sparql", 
NULL,
+                       (const unsigned char*)query_str, base_uri);
+       
+       if (!rq) {
+               fprintf(stderr, "ERROR: Could not create query\n");
+               return NULL;
+       }
+       
+       // Add LV2 ontology to query sources
+       //librdf_query_add_data_graph(rq, slv2_ontology_uri, 
+       //      NULL, RASQAL_DATA_GRAPH_BACKGROUND);
+       
+       // Add all plugin data files to query sources
+       /*for (unsigned i=0; i < slv2_strings_size(plugin->data_uris); ++i) {
+               const char* file_uri_str = 
slv2_strings_get_at(plugin->data_uris, i);
+               raptor_uri* file_uri = raptor_new_uri((const unsigned 
char*)file_uri_str);
+               librdf_query_add_data_graph(rq, file_uri,
+                       NULL, RASQAL_DATA_GRAPH_BACKGROUND);
+               raptor_free_uri(file_uri);
+       }*/
+
+       librdf_query_results* results = librdf_query_execute(rq, plugin->rdf);
+       
+       librdf_free_query(rq);
+
+       free(query_str);
+
+       // FIXME: results leaked internally in places?
+       return results;
+}
+
+
+/** Query a single variable */
+SLV2Strings
+slv2_plugin_simple_query(SLV2Plugin  plugin,
+                         const char* sparql_str,
+                         const char* variable)
+{
+       librdf_query_results* results = slv2_plugin_query(plugin, sparql_str);
+       SLV2Strings ret = slv2_query_get_variable_bindings(results, variable);
+       librdf_free_query_results(results);
+
+       return ret;
+}
+
+
+/** Run a query and count number of matches.
+ *
+ * More efficient than slv2_plugin_simple_query if you're only interested
+ * in the number of results (ie slv2_plugin_num_ports).
+ */
+unsigned
+slv2_plugin_query_count(SLV2Plugin  plugin,
+                        const char* sparql_str)
+{
+       librdf_query_results* results = slv2_plugin_query(plugin, sparql_str);
+
+       if (results) {
+               unsigned ret = slv2_query_count_bindings(results);
+               librdf_free_query_results(results);
+               return ret;
+       } else {
+               return 0;
+       }
+}
+
+
+size_t
+slv2_query_count_results(SLV2Plugin  p,
+                         const char* query)
+{
+       char* query_str = slv2_strjoin(slv2_query_prefixes, query, NULL);
+
+       assert(p);
+       assert(query_str);
+
+       librdf_query *rq = librdf_new_query(p->world->world, "sparql", NULL,
+                       (unsigned char*)query_str, NULL);
+
+       //printf("Query: \n%s\n\n", query_str);
+
+       // Add LV2 ontology to query sources
+       //librdf_query_add_data_graph(rq, slv2_ontology_uri,
+       //      NULL, RASQAL_DATA_GRAPH_BACKGROUND);
+       
+       librdf_query_results* results = librdf_query_execute(rq, 
p->world->model);
+       assert(results);
+       
+       size_t count = slv2_query_count_bindings(results);
+       
+       librdf_free_query_results(results);
+       librdf_free_query(rq);
+       
+       free(query_str);
+
+       return count;
+}
+

Index: src/stringlist.c
===================================================================
RCS file: src/stringlist.c
diff -N src/stringlist.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/stringlist.c    23 Apr 2007 11:59:21 -0000      1.1
@@ -0,0 +1,65 @@
+/* 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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <raptor.h>
+#include <slv2/stringlist.h>
+
+
+SLV2Strings
+slv2_strings_new()
+{
+       return raptor_new_sequence(&free, NULL);
+}
+
+
+void
+slv2_strings_free(SLV2Strings list)
+{
+       raptor_free_sequence(list);
+}
+
+
+unsigned
+slv2_strings_size(SLV2Strings list)
+{
+       return raptor_sequence_size(list);
+}
+
+
+const char*
+slv2_strings_get_at(SLV2Strings list, unsigned index)
+{
+       if (index > INT_MAX)
+               return NULL;
+       else
+               return (const char*)raptor_sequence_get_at(list, (int)index);
+}
+
+
+bool
+slv2_strings_contains(SLV2Strings list, const char* str)
+{
+       for (unsigned i=0; i < slv2_strings_size(list); ++i)
+               if (!strcmp(slv2_strings_get_at(list, i), str))
+                       return true;
+       
+       return false;
+}

Index: src/util.c
===================================================================
RCS file: src/util.c
diff -N src/util.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/util.c  23 Apr 2007 11:59:22 -0000      1.1
@@ -0,0 +1,86 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <slv2/util.h>
+
+
+void
+slv2_strappend(char** dst, const char* 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);
+}
+
+
+char*
+slv2_strjoin(const char* first, ...)
+{
+       size_t  len    = strlen(first);
+       char*   result = NULL;
+       va_list args;
+
+       va_start(args, first);
+       while (1) {
+               const char* const s = va_arg(args, const char *);
+               if (s == NULL)
+                       break;
+               len += strlen(s);
+       }
+       va_end(args);
+
+       result = malloc(len + 1);
+       if (!result)
+               return NULL;
+
+       strcpy(result, first);
+       va_start(args, first);
+       while (1) {
+               const char* const s = va_arg(args, const char *);
+               if (s == NULL)
+                       break;
+               strcat(result, s);
+       }
+       va_end(args);
+
+       return result;
+}
+
+
+const char*
+slv2_uri_to_path(const char* uri)
+{
+       if (!strncmp(uri, "file://", (size_t)7))
+               return (char*)(uri + 7);
+       else
+               return NULL;
+}
+
+
+

Index: src/world.c
===================================================================
RCS file: src/world.c
diff -N src/world.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/world.c 23 Apr 2007 11:59:22 -0000      1.1
@@ -0,0 +1,326 @@
+/* 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/world.h>
+#include <slv2/slv2.h>
+#include <slv2/util.h>
+//#include "config.h"
+#include "private_types.h"
+
+
+SLV2World
+slv2_world_new()
+{
+       struct _World* world = (struct _World*)malloc(sizeof(struct _World));
+
+       world->world = librdf_new_world();
+       librdf_world_open(world->world);
+       
+       world->storage = librdf_new_storage(world->world, "hashes", NULL,
+                       "hash-type='memory'");
+
+       world->model = librdf_new_model(world->world, world->storage, NULL);
+
+       world->parser = librdf_new_parser(world->world, "turtle", NULL, NULL);
+
+       world->plugins = slv2_plugins_new();
+
+       /*slv2_ontology_uri = raptor_new_uri((const unsigned char*)
+               "file://" LV2_TTL_PATH);*/
+
+       return world;
+}
+
+
+void
+slv2_world_free(SLV2World world)
+{
+       /*raptor_free_uri(slv2_ontology_uri);
+       slv2_ontology_uri = NULL;*/
+
+       for (int i=0; i < raptor_sequence_size(world->plugins); ++i)
+               slv2_plugin_free(raptor_sequence_get_at(world->plugins, i));
+       raptor_free_sequence(world->plugins);
+       world->plugins = NULL;
+       
+       librdf_free_parser(world->parser);
+       world->parser = NULL;
+       
+       librdf_free_model(world->model);
+       world->model = NULL;
+       
+       librdf_free_storage(world->storage);
+       world->storage = NULL;
+       
+       librdf_free_world(world->world);
+       world->world = NULL;
+
+       free(world);
+}
+
+
+void
+slv2_world_load_bundle(SLV2World world, const char* bundle_uri_str)
+{
+       librdf_uri* bundle_uri = librdf_new_uri(world->world,
+                       (const unsigned char*)bundle_uri_str);
+
+       librdf_uri* manifest_uri = librdf_new_uri_relative_to_base(
+                       bundle_uri, (const unsigned char*)"manifest.ttl");
+
+       librdf_parser_parse_into_model(world->parser, manifest_uri, NULL, 
world->model);
+
+       librdf_free_uri(manifest_uri);
+       librdf_free_uri(bundle_uri);
+}
+
+
+/** Load all bundles under a directory.
+ * Private.
+ */
+void
+slv2_world_load_directory(SLV2World world, 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* uri = slv2_strjoin("file://", dir, "/", pfile->d_name, 
"/", NULL);
+
+               // FIXME: Probably a better way to check if a dir exists
+               DIR* bundle_dir = opendir(uri + 7);
+
+               if (bundle_dir != NULL) {
+                       closedir(bundle_dir);
+                       slv2_world_load_bundle(world, uri);
+               }
+               
+               free(uri);
+       }
+
+       closedir(pdir);
+}
+
+
+void
+slv2_world_load_path(SLV2World   world,
+                     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_world_load_directory(world, 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_world_load_all(SLV2World world)
+{
+       char* lv2_path = getenv("LV2_PATH");
+
+       /* 1. Read all manifest files into model */
+
+       if (lv2_path) {
+               slv2_world_load_path(world, 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_world_load_path(world, lv2_path);
+
+               free(lv2_path);
+       }
+
+       
+       /* 2. Query out things to cache */
+
+       // 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(world->world, "sparql",
+               NULL, query_string, NULL);
+       
+       librdf_query_results* results = librdf_query_execute(q, world->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(world->plugins,
+                               (const char*)librdf_uri_as_string(plugin_uri));
+               
+               // Create a new SLV2Plugin
+               if (!plugin)
+                       plugin = slv2_plugin_new(world, plugin_uri,
+                                       (const 
char*)librdf_uri_as_string(binary_uri));
+               
+               plugin->world = world;
+
+               // FIXME: check for duplicates
+               raptor_sequence_push(plugin->data_uris,
+                               strdup((const 
char*)librdf_uri_as_string(data_uri)));
+               
+               raptor_sequence_push(world->plugins, plugin);
+               
+               librdf_free_node(plugin_node);
+               librdf_free_node(data_node);
+               librdf_free_node(binary_node);
+
+               librdf_query_results_next(results);
+       }
+
+       // ORDER BY should (and appears to actually) guarantee this
+       //raptor_sequence_sort(world->plugins, slv2_plugin_compare_by_uri);
+
+       if (results)
+               librdf_free_query_results(results);
+       
+       librdf_free_query(q);
+}
+
+
+#if 0
+void
+slv2_world_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_world_to_file(serializer, filename, NULL, 
slv2_model);
+       librdf_free_serializer(serializer);
+}
+#endif
+
+
+SLV2Plugins
+slv2_world_get_all_plugins(SLV2World world)
+{
+       return world->plugins;
+}
+
+
+SLV2Plugins
+slv2_world_get_plugins_by_filter(SLV2World world, bool (*include)(SLV2Plugin))
+{
+       SLV2Plugins result = slv2_plugins_new();
+
+       for (int i=0; i < raptor_sequence_size(world->plugins); ++i) {
+               SLV2Plugin p = raptor_sequence_get_at(world->plugins, i);
+               if (include(p))
+                       raptor_sequence_push(result, p);
+       }
+
+       return result;
+}
+
+
+#if 0
+SLV2Plugins
+slv2_world_get_plugins_by_query(SLV2World world, const char* query)
+{
+       SLV2Plugins list = slv2_plugins_new();  
+
+       librdf_query* rq = librdf_new_query(world->world, "sparql",
+               NULL, (const unsigned char*)query, NULL);
+       
+       librdf_query_results* results = librdf_query_execute(rq, world->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(world, 
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
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]