@@ -1 +1 @@ | |||
../modules/lilv/lilv-0.22.1/lilv | |||
../modules/lilv/lilv-0.24.0/lilv |
@@ -1 +1 @@ | |||
../modules/lilv/serd-0.22.0/serd/ | |||
../modules/lilv/serd-0.24.0/serd/ |
@@ -1 +1 @@ | |||
../modules/lilv/sord-0.14.0/sord/ | |||
../modules/lilv/sord-0.16.0/sord/ |
@@ -1 +1 @@ | |||
../modules/lilv/sratom-0.4.7/sratom/ | |||
../modules/lilv/sratom-0.6.0/sratom/ |
@@ -10,10 +10,10 @@ include ../Makefile.mk | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
SERD_VERSION = 0.22.0 | |||
SORD_VERSION = 0.14.0 | |||
SRATOM_VERSION = 0.4.7 | |||
LILV_VERSION = 0.22.1 | |||
SERD_VERSION = 0.24.0 | |||
SORD_VERSION = 0.16.0 | |||
SRATOM_VERSION = 0.6.0 | |||
LILV_VERSION = 0.24.0 | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
@@ -1,11 +0,0 @@ | |||
Lilv | |||
---- | |||
Lilv is a library for LV2 hosts intended to make using LV2 Plugins as simple | |||
as possible (without sacrificing capabilities). | |||
More information about LV2 plugins can be found at <http://lv2plug.in>. | |||
More information about Lilv can be found at <http://drobilla.net/software/lilv>. | |||
-- David Robillard <d@drobilla.net> |
@@ -1,84 +0,0 @@ | |||
# Copyright 2013 Kaspar Emanuel <kaspar.emanuel@gmail.com> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
from lilv import * | |||
import unittest | |||
import os | |||
class UriTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv_world_new() | |||
lilv_world_load_all(self.world) | |||
def testInvalidURI(self): | |||
self.uri = lilv_new_uri(self.world, "invalid_uri") | |||
self.assertIsNone(self.uri) | |||
def testInvalidURI2(self): | |||
self.uri = lilv_new_uri(self.world, "invalid_uri") | |||
self.assertFalse( lilv_node_is_uri(self.uri) ) | |||
def testNonExistentURI(self): | |||
self.uri = lilv_new_uri(self.world, "exist:does_not") | |||
plugins = lilv_world_get_all_plugins(self.world) | |||
self.plugin = lilv_plugins_get_by_uri(plugins, self.uri) | |||
self.assertIsNone(self.plugin) | |||
def testPortTypes(self): | |||
self.uri = lilv_new_uri(self.world, LILV_URI_INPUT_PORT) | |||
self.assertIsNotNone(self.uri) | |||
def testPortTypes2(self): | |||
self.uri = lilv_new_uri(self.world, LILV_URI_OUTPUT_PORT) | |||
self.assertIsNotNone(self.uri) | |||
def testPortTypes3(self): | |||
self.uri = lilv_new_uri(self.world, LILV_URI_AUDIO_PORT) | |||
self.assertIsNotNone(self.uri) | |||
def testPortTypes4(self): | |||
self.uri = lilv_new_uri(self.world, LILV_URI_CONTROL_PORT) | |||
self.assertIsNotNone(self.uri) | |||
def tearDown(self): | |||
lilv_node_free(self.uri) | |||
lilv_world_free(self.world) | |||
class PluginTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv_world_new() | |||
location = "file://" + os.getcwd() + "/bindings/bindings_test_plugin.lv2/" | |||
self.plugin_uri = lilv_new_uri(self.world, location) | |||
self.assertIsNotNone(self.plugin_uri, "Invalid URI: '" + location + "'") | |||
lilv_world_load_bundle(self.world, self.plugin_uri) | |||
self.plugins = lilv_world_get_all_plugins(self.world) | |||
self.plugin = lilv_plugins_get(self.plugins, lilv_plugins_begin(self.plugins)) | |||
self.assertIsNotNone(self.plugin, msg="Test plugin not found at location: '" + location + "'") | |||
self.assertEqual(location, lilv_node_as_string(lilv_plugin_get_bundle_uri(self.plugin))) | |||
self.instance = lilv_plugin_instantiate(self.plugin, 48000, None) | |||
self.assertIsNotNone(self.instance) | |||
self.lv2_InputPort = lilv_new_uri(self.world, LILV_URI_INPUT_PORT) | |||
self.lv2_OutputPort = lilv_new_uri(self.world, LILV_URI_OUTPUT_PORT) | |||
self.lv2_AudioPort = lilv_new_uri(self.world, LILV_URI_AUDIO_PORT) | |||
self.lv2_ControlPort = lilv_new_uri(self.world, LILV_URI_CONTROL_PORT) | |||
def testPorts(self): | |||
n = lilv_plugin_get_num_ports_of_class(self.plugin, self.lv2_InputPort, self.lv2_AudioPort) | |||
self.assertEqual(n, 1) | |||
def testPorts2(self): | |||
n = lilv_plugin_get_num_ports_of_class(self.plugin, self.lv2_OutputPort, self.lv2_AudioPort) | |||
self.assertEqual(n, 1) | |||
def testPorts3(self): | |||
n = lilv_plugin_get_num_ports_of_class(self.plugin, self.lv2_OutputPort, self.lv2_ControlPort) | |||
self.assertEqual(n, 1) | |||
def testPorts4(self): | |||
n = lilv_plugin_get_num_ports_of_class(self.plugin, self.lv2_InputPort, self.lv2_ControlPort) | |||
self.assertEqual(n, 1) | |||
def tearDown(self): | |||
lilv_node_free(self.lv2_InputPort) | |||
lilv_node_free(self.lv2_OutputPort) | |||
lilv_node_free(self.lv2_AudioPort) | |||
lilv_node_free(self.plugin_uri) | |||
lilv_world_free(self.world) |
@@ -1,70 +0,0 @@ | |||
# Copyright 2013 Kaspar Emanuel <kaspar.emanuel@gmail.com> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
import lilv | |||
import unittest | |||
import os | |||
class UriTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.world.load_all(); | |||
def testInvalidURI(self): | |||
self.plugin_uri = self.world.new_uri("invalid_uri") | |||
self.assertEqual(self.plugin_uri, None) | |||
def testInvalidURI2(self): | |||
self.plugin_uri = self.world.new_uri("invalid_uri") | |||
self.assertFalse( lilv.lilv_node_is_uri(self.plugin_uri) ) | |||
def testNonExistentURI(self): | |||
self.plugin_uri = self.world.new_uri("exist:does_not") | |||
self.plugin = self.world.get_all_plugins().get_by_uri(self.plugin_uri) | |||
self.assertEqual(self.plugin, None) | |||
def testPortTypes(self): | |||
self.assertIsNotNone( self.world.new_uri(lilv.LILV_URI_INPUT_PORT) ) | |||
def testPortTypes2(self): | |||
self.assertIsNotNone( self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT) ) | |||
def testPortTypes3(self): | |||
self.assertIsNotNone( self.world.new_uri(lilv.LILV_URI_AUDIO_PORT) ) | |||
def testPortTypes4(self): | |||
self.assertIsNotNone( self.world.new_uri(lilv.LILV_URI_CONTROL_PORT) ) | |||
class PluginTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
location = "file://" + os.getcwd() + "/bindings/bindings_test_plugin.lv2/" | |||
self.plugin_uri = self.world.new_uri(location) | |||
self.assertIsNotNone(self.plugin_uri, "Invalid URI: '" + location + "'") | |||
self.world.load_bundle(self.plugin_uri) | |||
self.plugins = self.world.get_all_plugins() | |||
self.plugin = self.plugins.get(self.plugins.begin()) | |||
self.assertIsNotNone(self.plugin, msg="Test plugin not found at location: '" + location + "'") | |||
self.assertEqual(location, self.plugin.get_bundle_uri().as_string()) | |||
self.instance = lilv.Instance(self.plugin, 48000, None) | |||
self.assertIsNotNone(self.instance) | |||
self.lv2_InputPort = self.world.new_uri(lilv.LILV_URI_INPUT_PORT) | |||
self.lv2_OutputPort = self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT) | |||
self.lv2_AudioPort = self.world.new_uri(lilv.LILV_URI_AUDIO_PORT) | |||
self.lv2_ControlPort = self.world.new_uri(lilv.LILV_URI_CONTROL_PORT) | |||
def testPorts(self): | |||
n = self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_AudioPort) | |||
self.assertEqual(n, 1) | |||
def testPorts2(self): | |||
n = self.plugin.get_num_ports_of_class(self.lv2_OutputPort, self.lv2_AudioPort) | |||
self.assertEqual(n, 1) | |||
def testPorts3(self): | |||
n = self.plugin.get_num_ports_of_class(self.lv2_OutputPort, self.lv2_ControlPort) | |||
self.assertEqual(n, 1) | |||
def testPorts4(self): | |||
n = self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_ControlPort) | |||
self.assertEqual(n, 1) |
@@ -1,4 +1,4 @@ | |||
Copyright 2011-2015 David Robillard <http://drobilla.net> | |||
Copyright 2011-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above |
@@ -1,8 +1,31 @@ | |||
lilv (0.22.1) unstable; | |||
* Fix Python bindings | |||
-- David Robillard <d@drobilla.net> Fri, 09 Oct 2015 13:01:14 -0400 | |||
lilv (0.24.1) unstable; | |||
* Fix comparison of restored states with paths | |||
-- David Robillard <d@drobilla.net> Mon, 26 Sep 2016 12:51:37 -0400 | |||
lilv (0.24.0) stable; | |||
* Add new hand-crafted Pythonic bindings with full test coverage | |||
* Add lv2apply utility for applying plugins to audio files | |||
* Add lilv_world_get_symbol() | |||
* Add lilv_state_set_metadata() for adding state banks/comments/etc | |||
(based on patch from Hanspeter Portner) | |||
* Fix crash when state contains non-POD properties | |||
* Fix crash when NULL predicate is passed to lilv_world_find_nodes() | |||
* Fix state file versioning | |||
* Unload contained resources when bundle is unloaded | |||
* Do not instantiate plugin when data fails to parse | |||
* Support re-loading plugins | |||
* Replace bundles if bundle with newer plugin version is loaded | |||
(based on patch from Robin Gareus) | |||
* Fix loading dyn-manifest from bundles with spaces in their path | |||
* Check lv2:binary predicate for UIs | |||
* Add LILV_URI_ATOM_PORT and LILV_URI_CV_PORT defines | |||
* Fix documentation installation | |||
* Fix outdated comment references to lilv_uri_to_path() | |||
-- David Robillard <d@drobilla.net> Mon, 19 Sep 2016 22:24:57 -0400 | |||
lilv (0.22.0) stable; | |||
@@ -0,0 +1,8 @@ | |||
Lilv | |||
==== | |||
Lilv is a C library to make the use of LV2 plugins as simple as possible for | |||
applications. | |||
For more information, see <http://drobilla.net/software/lilv>. | |||
-- David Robillard <d@drobilla.net> |
@@ -0,0 +1,186 @@ | |||
# Makefile for Sphinx documentation | |||
# | |||
# You can set these variables from the command line. | |||
SPHINXOPTS = | |||
SPHINXBUILD = sphinx-build | |||
PAPER = | |||
BUILDDIR = _build | |||
# User-friendly check for sphinx-build | |||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) | |||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) | |||
endif | |||
# Internal variables. | |||
PAPEROPT_a4 = -D latex_paper_size=a4 | |||
PAPEROPT_letter = -D latex_paper_size=letter | |||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | |||
# the i18n builder cannot share the environment and doctrees with the others | |||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | |||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext | |||
help: | |||
@echo "Please use \`make <target>' where <target> is one of" | |||
@echo " html to make standalone HTML files" | |||
@echo " dirhtml to make HTML files named index.html in directories" | |||
@echo " singlehtml to make a single large HTML file" | |||
@echo " pickle to make pickle files" | |||
@echo " json to make JSON files" | |||
@echo " htmlhelp to make HTML files and a HTML help project" | |||
@echo " qthelp to make HTML files and a qthelp project" | |||
@echo " devhelp to make HTML files and a Devhelp project" | |||
@echo " epub to make an epub" | |||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" | |||
@echo " latexpdf to make LaTeX files and run them through pdflatex" | |||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" | |||
@echo " text to make text files" | |||
@echo " man to make manual pages" | |||
@echo " texinfo to make Texinfo files" | |||
@echo " info to make Texinfo files and run them through makeinfo" | |||
@echo " gettext to make PO message catalogs" | |||
@echo " changes to make an overview of all changed/added/deprecated items" | |||
@echo " xml to make Docutils-native XML files" | |||
@echo " pseudoxml to make pseudoxml-XML files for display purposes" | |||
@echo " linkcheck to check all external links for integrity" | |||
@echo " doctest to run all doctests embedded in the documentation (if enabled)" | |||
modules.rst lilv.rst: | |||
mkdir -p lilv | |||
ln -s -t lilv ../lilv.py | |||
sphinx-apidoc -o . lilv | |||
clean: | |||
rm -rf $(BUILDDIR)/* | |||
rm -f lilv/lilv.py | |||
rm -rf lilv | |||
rm -f lilv.rst | |||
rm -f modules.rst | |||
html: | |||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html | |||
@echo | |||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html." | |||
dirhtml: | |||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml | |||
@echo | |||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." | |||
singlehtml: modules.rst lilv.rst | |||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml | |||
@echo | |||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." | |||
pickle: | |||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle | |||
@echo | |||
@echo "Build finished; now you can process the pickle files." | |||
json: | |||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json | |||
@echo | |||
@echo "Build finished; now you can process the JSON files." | |||
htmlhelp: | |||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp | |||
@echo | |||
@echo "Build finished; now you can run HTML Help Workshop with the" \ | |||
".hhp project file in $(BUILDDIR)/htmlhelp." | |||
qthelp: | |||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp | |||
@echo | |||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \ | |||
".qhcp project file in $(BUILDDIR)/qthelp, like this:" | |||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Lilv.qhcp" | |||
@echo "To view the help file:" | |||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Lilv.qhc" | |||
devhelp: | |||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | |||
@echo | |||
@echo "Build finished." | |||
@echo "To view the help file:" | |||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Lilv" | |||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Lilv" | |||
@echo "# devhelp" | |||
epub: | |||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub | |||
@echo | |||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub." | |||
latex: | |||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |||
@echo | |||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." | |||
@echo "Run \`make' in that directory to run these through (pdf)latex" \ | |||
"(use \`make latexpdf' here to do that automatically)." | |||
latexpdf: | |||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |||
@echo "Running LaTeX files through pdflatex..." | |||
$(MAKE) -C $(BUILDDIR)/latex all-pdf | |||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | |||
latexpdfja: | |||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |||
@echo "Running LaTeX files through platex and dvipdfmx..." | |||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja | |||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | |||
text: | |||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text | |||
@echo | |||
@echo "Build finished. The text files are in $(BUILDDIR)/text." | |||
man: | |||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man | |||
@echo | |||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man." | |||
texinfo: | |||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | |||
@echo | |||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." | |||
@echo "Run \`make' in that directory to run these through makeinfo" \ | |||
"(use \`make info' here to do that automatically)." | |||
info: | |||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | |||
@echo "Running Texinfo files through makeinfo..." | |||
make -C $(BUILDDIR)/texinfo info | |||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." | |||
gettext: | |||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale | |||
@echo | |||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." | |||
changes: | |||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes | |||
@echo | |||
@echo "The overview file is in $(BUILDDIR)/changes." | |||
linkcheck: | |||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | |||
@echo | |||
@echo "Link check complete; look for any errors in the above output " \ | |||
"or in $(BUILDDIR)/linkcheck/output.txt." | |||
doctest: | |||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest | |||
@echo "Testing of doctests in the sources finished, look at the " \ | |||
"results in $(BUILDDIR)/doctest/output.txt." | |||
xml: | |||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml | |||
@echo | |||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml." | |||
pseudoxml: | |||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml | |||
@echo | |||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." |
@@ -0,0 +1,263 @@ | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Lilv documentation build configuration file, created by | |||
# sphinx-quickstart on Sun Sep 4 18:25:58 2016. | |||
# | |||
# This file is execfile()d with the current directory set to its | |||
# containing dir. | |||
# | |||
# Note that not all possible configuration values are present in this | |||
# autogenerated file. | |||
# | |||
# All configuration values have a default; values that are commented out | |||
# serve to show the default. | |||
import sys | |||
import os | |||
# If extensions (or modules to document with autodoc) are in another directory, | |||
# add these directories to sys.path here. If the directory is relative to the | |||
# documentation root, use os.path.abspath to make it absolute, like shown here. | |||
#sys.path.insert(0, os.path.abspath('.')) | |||
sys.path.insert(0, os.path.abspath('.')) | |||
# -- General configuration ------------------------------------------------ | |||
# If your documentation needs a minimal Sphinx version, state it here. | |||
#needs_sphinx = '1.0' | |||
# Add any Sphinx extension module names here, as strings. They can be | |||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | |||
# ones. | |||
extensions = [ | |||
'sphinx.ext.autodoc', | |||
'sphinx.ext.ifconfig', | |||
] | |||
# Add any paths that contain templates here, relative to this directory. | |||
templates_path = ['_templates'] | |||
# The suffix of source filenames. | |||
source_suffix = '.rst' | |||
# The encoding of source files. | |||
#source_encoding = 'utf-8-sig' | |||
# The master toctree document. | |||
master_doc = 'index' | |||
# General information about the project. | |||
project = u'Lilv' | |||
copyright = u'2016, David Robillard' | |||
# The version info for the project you're documenting, acts as replacement for | |||
# |version| and |release|, also used in various other places throughout the | |||
# built documents. | |||
# | |||
# The short X.Y version. | |||
version = '0.24.0' | |||
# The full version, including alpha/beta/rc tags. | |||
release = '0.24.0' | |||
# The language for content autogenerated by Sphinx. Refer to documentation | |||
# for a list of supported languages. | |||
#language = None | |||
# There are two options for replacing |today|: either, you set today to some | |||
# non-false value, then it is used: | |||
#today = '' | |||
# Else, today_fmt is used as the format for a strftime call. | |||
#today_fmt = '%B %d, %Y' | |||
# List of patterns, relative to source directory, that match files and | |||
# directories to ignore when looking for source files. | |||
exclude_patterns = ['_build'] | |||
# The reST default role (used for this markup: `text`) to use for all | |||
# documents. | |||
#default_role = None | |||
# If true, '()' will be appended to :func: etc. cross-reference text. | |||
#add_function_parentheses = True | |||
# If true, the current module name will be prepended to all description | |||
# unit titles (such as .. function::). | |||
#add_module_names = True | |||
# If true, sectionauthor and moduleauthor directives will be shown in the | |||
# output. They are ignored by default. | |||
#show_authors = False | |||
# The name of the Pygments (syntax highlighting) style to use. | |||
pygments_style = 'sphinx' | |||
# A list of ignored prefixes for module index sorting. | |||
#modindex_common_prefix = [] | |||
# If true, keep warnings as "system message" paragraphs in the built documents. | |||
#keep_warnings = False | |||
# -- Options for HTML output ---------------------------------------------- | |||
# The theme to use for HTML and HTML Help pages. See the documentation for | |||
# a list of builtin themes. | |||
#html_theme = '' | |||
# Theme options are theme-specific and customize the look and feel of a theme | |||
# further. For a list of options available for each theme, see the | |||
# documentation. | |||
html_theme_options = { 'nosidebar': True } | |||
# Add any paths that contain custom themes here, relative to this directory. | |||
#html_theme_path = [] | |||
# The name for this set of Sphinx documents. If None, it defaults to | |||
# "<project> v<release> documentation". | |||
#html_title = None | |||
# A shorter title for the navigation bar. Default is the same as html_title. | |||
#html_short_title = None | |||
# The name of an image file (relative to this directory) to place at the top | |||
# of the sidebar. | |||
#html_logo = None | |||
# The name of an image file (within the static path) to use as favicon of the | |||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 | |||
# pixels large. | |||
#html_favicon = None | |||
# Add any paths that contain custom static files (such as style sheets) here, | |||
# relative to this directory. They are copied after the builtin static files, | |||
# so a file named "default.css" will overwrite the builtin "default.css". | |||
html_static_path = ['_static'] | |||
# Add any extra paths that contain custom files (such as robots.txt or | |||
# .htaccess) here, relative to this directory. These files are copied | |||
# directly to the root of the documentation. | |||
#html_extra_path = [] | |||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | |||
# using the given strftime format. | |||
#html_last_updated_fmt = '%b %d, %Y' | |||
# If true, SmartyPants will be used to convert quotes and dashes to | |||
# typographically correct entities. | |||
#html_use_smartypants = True | |||
# Custom sidebar templates, maps document names to template names. | |||
#html_sidebars = {} | |||
# Additional templates that should be rendered to pages, maps page names to | |||
# template names. | |||
#html_additional_pages = {} | |||
# If false, no module index is generated. | |||
#html_domain_indices = True | |||
# If false, no index is generated. | |||
#html_use_index = True | |||
# If true, the index is split into individual pages for each letter. | |||
#html_split_index = False | |||
# If true, links to the reST sources are added to the pages. | |||
#html_show_sourcelink = True | |||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | |||
#html_show_sphinx = True | |||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | |||
#html_show_copyright = True | |||
# If true, an OpenSearch description file will be output, and all pages will | |||
# contain a <link> tag referring to it. The value of this option must be the | |||
# base URL from which the finished HTML is served. | |||
#html_use_opensearch = '' | |||
# This is the file name suffix for HTML files (e.g. ".xhtml"). | |||
#html_file_suffix = None | |||
# Output file base name for HTML help builder. | |||
htmlhelp_basename = 'Lilvdoc' | |||
# -- Options for LaTeX output --------------------------------------------- | |||
latex_elements = { | |||
# The paper size ('letterpaper' or 'a4paper'). | |||
#'papersize': 'letterpaper', | |||
# The font size ('10pt', '11pt' or '12pt'). | |||
#'pointsize': '10pt', | |||
# Additional stuff for the LaTeX preamble. | |||
#'preamble': '', | |||
} | |||
# Grouping the document tree into LaTeX files. List of tuples | |||
# (source start file, target name, title, | |||
# author, documentclass [howto, manual, or own class]). | |||
latex_documents = [ | |||
('index', 'Lilv.tex', u'Lilv Documentation', | |||
u'David Robillard', 'manual'), | |||
] | |||
# The name of an image file (relative to this directory) to place at the top of | |||
# the title page. | |||
#latex_logo = None | |||
# For "manual" documents, if this is true, then toplevel headings are parts, | |||
# not chapters. | |||
#latex_use_parts = False | |||
# If true, show page references after internal links. | |||
#latex_show_pagerefs = False | |||
# If true, show URL addresses after external links. | |||
#latex_show_urls = False | |||
# Documents to append as an appendix to all manuals. | |||
#latex_appendices = [] | |||
# If false, no module index is generated. | |||
#latex_domain_indices = True | |||
# -- Options for manual page output --------------------------------------- | |||
# One entry per manual page. List of tuples | |||
# (source start file, name, description, authors, manual section). | |||
man_pages = [ | |||
('index', 'lilv', u'Lilv Documentation', | |||
[u'David Robillard'], 1) | |||
] | |||
# If true, show URL addresses after external links. | |||
#man_show_urls = False | |||
# -- Options for Texinfo output ------------------------------------------- | |||
# Grouping the document tree into Texinfo files. List of tuples | |||
# (source start file, target name, title, author, | |||
# dir menu entry, description, category) | |||
texinfo_documents = [ | |||
('index', 'Lilv', u'Lilv Documentation', | |||
u'David Robillard', 'Lilv', 'One line description of project.', | |||
'Miscellaneous'), | |||
] | |||
# Documents to append as an appendix to all manuals. | |||
#texinfo_appendices = [] | |||
# If false, no module index is generated. | |||
#texinfo_domain_indices = True | |||
# How to display URL addresses: 'footnote', 'no', or 'inline'. | |||
#texinfo_show_urls = 'footnote' | |||
# If true, do not generate a @detailmenu in the "Top" node's menu. | |||
#texinfo_no_detailmenu = False |
@@ -0,0 +1,9 @@ | |||
Lilv Python Documentation | |||
========================= | |||
.. toctree:: | |||
.. automodule:: lilv | |||
:noindex: | |||
:members: |
@@ -41,8 +41,8 @@ class WavFile(object): | |||
data = [(i - float(range/2)) / float(range/2) for i in data] | |||
channels = [] | |||
for i in xrange(self.nchannels): | |||
channels.append([data[j] for j in xrange(0, len(data), self.nchannels) ]) | |||
for i in range(self.nchannels): | |||
channels.append([data[j] for j in range(0, len(data), self.nchannels) ]) | |||
return channels | |||
@@ -57,6 +57,7 @@ def main(): | |||
# Initialise Lilv | |||
world = lilv.World() | |||
ns = world.ns | |||
world.load_all() | |||
plugin_uri = sys.argv[1] | |||
@@ -65,19 +66,14 @@ def main(): | |||
# Find plugin | |||
plugin_uri_node = world.new_uri(plugin_uri) | |||
plugin = world.get_all_plugins().get_by_uri(plugin_uri_node) | |||
if not plugin: | |||
print("Unknown plugin `%s'\n" % plugin_uri) | |||
plugins = world.get_all_plugins() | |||
if plugin_uri_node not in plugins: | |||
print("Unknown plugin `%s'" % plugin_uri) | |||
sys.exit(1) | |||
lv2_InputPort = world.new_uri(lilv.LILV_URI_INPUT_PORT) | |||
lv2_OutputPort = world.new_uri(lilv.LILV_URI_OUTPUT_PORT) | |||
lv2_AudioPort = world.new_uri(lilv.LILV_URI_AUDIO_PORT) | |||
lv2_ControlPort = world.new_uri(lilv.LILV_URI_CONTROL_PORT) | |||
lv2_default = world.new_uri("http://lv2plug.in/ns/lv2core#default") | |||
n_audio_in = plugin.get_num_ports_of_class(lv2_InputPort, lv2_AudioPort) | |||
n_audio_out = plugin.get_num_ports_of_class(lv2_OutputPort, lv2_AudioPort) | |||
plugin = plugins[plugin_uri_node] | |||
n_audio_in = plugin.get_num_ports_of_class(ns.lv2.InputPort, ns.lv2.AudioPort) | |||
n_audio_out = plugin.get_num_ports_of_class(ns.lv2.OutputPort, ns.lv2.AudioPort) | |||
if n_audio_out == 0: | |||
print("Plugin has no audio outputs\n") | |||
sys.exit(1) | |||
@@ -120,22 +116,21 @@ def main(): | |||
control_output_buffers = [] | |||
for index in range(plugin.get_num_ports()): | |||
port = plugin.get_port_by_index(index) | |||
if port.is_a(lv2_InputPort): | |||
if port.is_a(lv2_AudioPort): | |||
if port.is_a(ns.lv2.InputPort): | |||
if port.is_a(ns.lv2.AudioPort): | |||
audio_input_buffers.append(numpy.array(channels[len(audio_input_buffers)], numpy.float32)) | |||
instance.connect_port(index, audio_input_buffers[-1]) | |||
elif port.is_a(lv2_ControlPort): | |||
#if port.has_property(lv2_default): # Doesn't seem to work | |||
default = lilv.lilv_node_as_float(lilv.lilv_nodes_get_first(port.get_value(lv2_default))) | |||
elif port.is_a(ns.lv2.ControlPort): | |||
default = float(port.get(ns.lv2.default)) | |||
control_input_buffers.append(numpy.array([default], numpy.float32)) | |||
instance.connect_port(index, control_input_buffers[-1]) | |||
else: | |||
raise ValueError("Unhandled port type") | |||
elif port.is_a(lv2_OutputPort): | |||
if port.is_a(lv2_AudioPort): | |||
elif port.is_a(ns.lv2.OutputPort): | |||
if port.is_a(ns.lv2.AudioPort): | |||
audio_output_buffers.append(numpy.array([0] * wav_in.nframes, numpy.float32)) | |||
instance.connect_port(index, audio_output_buffers[-1]) | |||
elif port.is_a(lv2_ControlPort): | |||
elif port.is_a(ns.lv2.ControlPort): | |||
control_output_buffers.append(numpy.array([0], numpy.float32)) | |||
instance.connect_port(index, control_output_buffers[-1]) | |||
else: | |||
@@ -156,7 +151,7 @@ def main(): | |||
# Write output file in chunks to stop memory usage getting out of hand: | |||
CHUNK_SIZE = 8192 | |||
for chunk in numpy.array_split(data, CHUNK_SIZE): | |||
wav_out.writeframes(wave.struct.pack("%u%s" % (len(chunk), wav_in.struct_fmt_code), *chunk)) | |||
wav_out.writeframes(wave.struct.pack("%u%s" % (len(chunk), wav_in.struct_fmt_code), *chunk.astype(int))) | |||
wav_out.close() | |||
@@ -54,7 +54,7 @@ typedef enum { | |||
every instance method. In this simple plugin, only port buffers need to be | |||
stored, since there is no additional instance data. */ | |||
typedef struct { | |||
// Port buffers | |||
float* buf; | |||
} Test; | |||
/** | |||
@@ -179,7 +179,7 @@ static const LV2_Descriptor descriptor = { | |||
indices to find all the plugins defined in the library. The index is not an | |||
indentifier, the URI of the returned descriptor is used to determine the | |||
identify of the plugin. | |||
This method is in the ``discovery'' threading class, so no other functions | |||
or methods in this plugin library will be called concurrently with it. | |||
*/ |
@@ -16,18 +16,27 @@ | |||
@prefix doap: <http://usefulinc.com/ns/doap#> . | |||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . | |||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |||
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . | |||
<http://example.org/lilv-bindings-test-plugin> | |||
a lv2:Plugin ; | |||
doap:name "Lilv Bindings Test" ; | |||
doap:license <http://opensource.org/licenses/isc> ; | |||
lv2:optionalFeature lv2:hardRTCapable ; | |||
ui:ui <http://example.org/lilv-bindings-test-plugin-ui> ; | |||
lv2:port [ | |||
a lv2:InputPort , | |||
lv2:ControlPort ; | |||
lv2:index 0 ; | |||
lv2:symbol "input" ; | |||
lv2:name "Input" | |||
lv2:name "Input" ; | |||
lv2:default 0.5 ; | |||
lv2:minimum 0.0 ; | |||
lv2:maximum 1.0 ; | |||
lv2:scalePoint [ rdfs:label "off" ; rdf:value 0.0 ] ; | |||
lv2:scalePoint [ rdfs:label "on" ; rdf:value 1.0 ] ; | |||
] , [ | |||
a lv2:OutputPort , | |||
lv2:ControlPort ; | |||
@@ -47,3 +56,7 @@ | |||
lv2:symbol "audio_output" ; | |||
lv2:name "Audio Output" ; | |||
] . | |||
<http://example.org/lilv-bindings-test-plugin-ui> | |||
a ui:GtkUI ; | |||
ui:binary <TODO> . |
@@ -0,0 +1,290 @@ | |||
# Copyright 2016 David Robillard <d@drobilla.net> | |||
# Copyright 2013 Kaspar Emanuel <kaspar.emanuel@gmail.com> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
import lilv | |||
import unittest | |||
import os | |||
location = "file://" + os.getcwd() + "/bindings/bindings_test_plugin.lv2/" | |||
class NodeTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
def testNodes(self): | |||
aint = self.world.new_int(1) | |||
aint2 = self.world.new_int(1) | |||
aint3 = self.world.new_int(3) | |||
afloat = self.world.new_float(2.0) | |||
atrue = self.world.new_bool(True) | |||
afalse = self.world.new_bool(False) | |||
auri = self.world.new_uri("http://example.org") | |||
afile = self.world.new_file_uri(None, "/foo/bar") | |||
astring = self.world.new_string("hello") | |||
self.assertEqual(auri.get_turtle_token(), '<http://example.org>') | |||
self.assertTrue(aint.is_int()) | |||
self.assertTrue(afloat.is_float()) | |||
self.assertTrue(auri.is_uri()) | |||
self.assertTrue(astring.is_string()) | |||
self.assertTrue(astring.is_literal()) | |||
self.assertFalse(auri.is_blank()) | |||
self.assertTrue(int(aint) == 1) | |||
self.assertTrue(float(afloat) == 2.0) | |||
self.assertTrue(bool(atrue)) | |||
self.assertFalse(bool(afalse)) | |||
self.assertEqual(afile.get_path(), "/foo/bar") | |||
self.assertTrue(aint == aint2) | |||
self.assertTrue(aint != aint3) | |||
self.assertTrue(aint != afloat) | |||
with self.assertRaises(ValueError): | |||
int(atrue) | |||
with self.assertRaises(ValueError): | |||
float(aint) | |||
with self.assertRaises(ValueError): | |||
bool(astring) | |||
class UriTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.world.load_all(); | |||
def testInvalidURI(self): | |||
self.plugin_uri = self.world.new_uri("invalid_uri") | |||
self.assertIsNone(self.plugin_uri) | |||
def testNonExistentURI(self): | |||
self.plugin_uri = self.world.new_uri("exist:does_not") | |||
self.plugin = self.world.get_all_plugins().get_by_uri(self.plugin_uri) | |||
self.assertEqual(self.plugin, None) | |||
def testPortTypes(self): | |||
self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_INPUT_PORT)) | |||
def testPortTypes2(self): | |||
self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT)) | |||
def testPortTypes3(self): | |||
self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_AUDIO_PORT)) | |||
def testPortTypes4(self): | |||
self.assertIsNotNone(self.world.new_uri(lilv.LILV_URI_CONTROL_PORT)) | |||
class PluginClassTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
def testPluginClasses(self): | |||
pclass = self.world.get_plugin_class() | |||
self.assertIsNotNone(pclass) | |||
self.assertIsNone(pclass.get_parent_uri()) | |||
self.assertIsNotNone(pclass.get_uri()) | |||
self.assertIsNotNone(pclass.get_label()) | |||
self.assertEqual(str(pclass.get_uri()), str(pclass)) | |||
for i in pclass.get_children(): | |||
self.assertIsNotNone(i) | |||
self.assertIsNotNone(i.get_uri()) | |||
self.assertIsNotNone(i.get_label()) | |||
class PluginClassesTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.world.load_all() | |||
def testPluginClasses(self): | |||
classes = self.world.get_plugin_classes() | |||
pclass = self.world.get_plugin_class() | |||
self.assertIsNotNone(classes) | |||
self.assertIsNotNone(pclass) | |||
self.assertTrue(pclass in classes) | |||
self.assertTrue(pclass.get_uri() in classes) | |||
self.assertGreater(len(classes), 1) | |||
self.assertIsNotNone(classes[0]) | |||
self.assertIsNotNone(classes[pclass.get_uri()]) | |||
class LoadTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.bundle_uri = self.world.new_uri(location) | |||
self.world.load_specifications() | |||
self.world.load_plugin_classes() | |||
def tearDown(self): | |||
del self.world | |||
def testLoadUnload(self): | |||
self.world.load_bundle(self.bundle_uri) | |||
plugins = self.world.get_all_plugins() | |||
plugin = plugins.get(plugins.begin()) | |||
self.world.load_resource(plugin) | |||
self.world.unload_resource(plugin) | |||
self.world.unload_bundle(self.bundle_uri) | |||
class PluginTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.world.set_option(lilv.OPTION_FILTER_LANG, self.world.new_bool(True)) | |||
self.bundle_uri = self.world.new_uri(location) | |||
self.assertIsNotNone(self.bundle_uri, "Invalid URI: '" + location + "'") | |||
self.world.load_bundle(self.bundle_uri) | |||
self.plugins = self.world.get_all_plugins() | |||
self.plugin = self.plugins.get(self.plugins.begin()) | |||
self.assertTrue(self.plugin.verify()) | |||
self.assertTrue(self.plugin in self.plugins) | |||
self.assertTrue(self.plugin.get_uri() in self.plugins) | |||
self.assertEqual(self.plugins[self.plugin.get_uri()], self.plugin) | |||
self.assertIsNotNone(self.plugin, msg="Test plugin not found at location: '" + location + "'") | |||
self.assertEqual(location, str(self.plugin.get_bundle_uri())) | |||
self.plugin_uri = self.plugin.get_uri() | |||
self.assertEqual(self.plugin.get_uri(), self.plugin_uri, "URI equality broken") | |||
self.instance = lilv.Instance(self.plugin, 48000, None) | |||
self.assertIsNotNone(self.instance) | |||
self.lv2_InputPort = self.world.new_uri(lilv.LILV_URI_INPUT_PORT) | |||
self.lv2_OutputPort = self.world.new_uri(lilv.LILV_URI_OUTPUT_PORT) | |||
self.lv2_AudioPort = self.world.new_uri(lilv.LILV_URI_AUDIO_PORT) | |||
self.lv2_ControlPort = self.world.new_uri(lilv.LILV_URI_CONTROL_PORT) | |||
def testGetters(self): | |||
self.assertIsNotNone(self.plugin.get_bundle_uri()) | |||
self.assertGreater(len(self.plugin.get_data_uris()), 0) | |||
self.assertIsNotNone(self.plugin.get_library_uri()) | |||
self.assertTrue(self.plugin.get_name().is_string()) | |||
self.assertTrue(self.plugin.get_class().get_uri().is_uri()) | |||
self.assertEqual(len(self.plugin.get_value(self.world.ns.doap.license)), 1) | |||
licenses = self.plugin.get_value(self.world.ns.doap.license) | |||
features = self.plugin.get_value(self.world.ns.lv2.optionalFeature) | |||
self.assertEqual(len(licenses), 1) | |||
self.assertTrue(licenses[0] in licenses) | |||
with self.assertRaises(IndexError): | |||
self.assertIsNone(licenses[len(licenses)]) | |||
self.assertEqual(len(licenses) + len(features), | |||
len(licenses.merge(features))) | |||
self.assertEqual(licenses.get(licenses.begin()), self.world.new_uri('http://opensource.org/licenses/isc')) | |||
self.assertEqual(licenses[0], licenses.get(licenses.begin())) | |||
self.assertTrue(self.plugin.has_feature(self.world.ns.lv2.hardRTCapable)) | |||
self.assertEqual(len(self.plugin.get_supported_features()), 1) | |||
self.assertEqual(len(self.plugin.get_optional_features()), 1) | |||
self.assertEqual(len(self.plugin.get_required_features()), 0) | |||
self.assertFalse(self.plugin.has_extension_data(self.world.new_uri('http://example.org/nope'))) | |||
self.assertEqual(len(self.plugin.get_extension_data()), 0) | |||
self.assertEqual(len(self.plugin.get_extension_data()), 0) | |||
self.assertFalse(self.plugin.has_latency()) | |||
self.assertIsNone(self.plugin.get_latency_port_index()) | |||
def testPorts(self): | |||
self.assertEqual(self.plugin.get_num_ports(), 4) | |||
self.assertIsNotNone(self.plugin.get_port(0)) | |||
self.assertIsNotNone(self.plugin.get_port(1)) | |||
self.assertIsNotNone(self.plugin.get_port(2)) | |||
self.assertIsNotNone(self.plugin.get_port(3)) | |||
self.assertIsNone(self.plugin.get_port_by_index(4)) | |||
self.assertIsNotNone(self.plugin.get_port("input")) | |||
self.assertIsNotNone(self.plugin.get_port("output")) | |||
self.assertIsNotNone(self.plugin.get_port("audio_input")) | |||
self.assertIsNotNone(self.plugin.get_port("audio_output")) | |||
self.assertIsNone(self.plugin.get_port_by_symbol("nonexistent")) | |||
self.assertIsNone(self.plugin.get_port_by_designation(self.world.ns.lv2.InputPort, self.world.ns.lv2.control)) | |||
self.assertIsNone(self.plugin.get_project()) | |||
self.assertIsNone(self.plugin.get_author_name()) | |||
self.assertIsNone(self.plugin.get_author_email()) | |||
self.assertIsNone(self.plugin.get_author_homepage()) | |||
self.assertFalse(self.plugin.is_replaced()) | |||
self.assertEqual(0, len(self.plugin.get_related(self.world.new_uri("http://example.org/Type")))) | |||
self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_AudioPort)) | |||
port = self.plugin.get_port("input") | |||
self.assertTrue(port.get_node().is_blank()) | |||
self.assertEqual(0, port.get(self.world.ns.lv2.index)) | |||
self.assertEqual(1, len(port.get_value(self.world.ns.lv2.symbol))) | |||
self.assertEqual(port.get_value(self.world.ns.lv2.symbol)[0], "input") | |||
self.assertFalse(port.has_property(self.world.ns.lv2.latency)) | |||
self.assertFalse(port.supports_event(self.world.ns.midi.MidiEvent)) | |||
self.assertEqual(0, port.get_index()) | |||
self.assertEqual("input", port.get_symbol()) | |||
self.assertEqual("Input", port.get_name()) | |||
self.assertEqual([self.world.ns.lv2.ControlPort, self.world.ns.lv2.InputPort], | |||
list(port.get_classes())) | |||
self.assertTrue(port.is_a(self.world.ns.lv2.ControlPort)) | |||
self.assertFalse(port.is_a(self.world.ns.lv2.AudioPort)) | |||
self.assertEquals((0.5, 0.0, 1.0), port.get_range()) | |||
self.assertEquals(0, len(port.get_properties())) | |||
def testScalePoints(self): | |||
port = self.plugin.get_port("input") | |||
points = port.get_scale_points() | |||
self.assertEqual(points[0].get_label(), "off") | |||
self.assertEqual(points[0].get_value(), 0.0) | |||
self.assertEqual(points[1].get_label(), "on") | |||
self.assertEqual(points[1].get_value(), 1.0) | |||
def testPortCount(self): | |||
self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_OutputPort, self.lv2_AudioPort)) | |||
self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_OutputPort, self.lv2_ControlPort)) | |||
self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_AudioPort)) | |||
self.assertEqual(1, self.plugin.get_num_ports_of_class(self.lv2_InputPort, self.lv2_ControlPort)) | |||
class QueryTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.world.load_all() | |||
self.bundle_uri = self.world.new_uri(location) | |||
self.world.load_bundle(self.bundle_uri) | |||
self.plugins = self.world.get_all_plugins() | |||
self.plugin = self.plugins.get(self.plugins.begin()) | |||
def testNamespaces(self): | |||
self.assertEqual(self.world.ns.lv2, "http://lv2plug.in/ns/lv2core#") | |||
self.assertEqual(self.world.ns.lv2.Plugin, "http://lv2plug.in/ns/lv2core#Plugin") | |||
def testQuery(self): | |||
self.assertTrue(self.world.ask(None, | |||
self.world.ns.rdf.type, | |||
self.world.ns.lv2.Plugin)) | |||
self.assertLess(0, len(self.world.find_nodes(None, | |||
self.world.ns.rdf.type, | |||
self.world.ns.lv2.Plugin))) | |||
self.assertEqual(self.plugin.get_uri(), self.world.get(None, | |||
self.world.ns.rdf.type, | |||
self.world.ns.lv2.Plugin)) | |||
class InstanceTests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.bundle_uri = self.world.new_uri(location) | |||
self.world.load_bundle(self.bundle_uri) | |||
self.plugins = self.world.get_all_plugins() | |||
self.plugin = self.plugins[0] | |||
self.instance = lilv.Instance(self.plugin, 48000) | |||
self.assertEqual(self.plugin.get_uri(), self.instance.get_uri()) | |||
self.assertIsNone(self.instance.get_extension_data(self.world.new_uri("http://example.org/ext"))) | |||
self.assertIsNone(self.instance.get_extension_data("http://example.org/ext")) | |||
def testRun(self): | |||
import numpy | |||
n_samples = 100 | |||
buf = numpy.zeros(n_samples) | |||
with self.assertRaises(Exception): | |||
self.instance.connect_port(0, "hello") | |||
self.instance.connect_port(0, None) | |||
self.instance.connect_port(0, None) | |||
self.instance.connect_port(2, buf) | |||
self.instance.connect_port(3, buf) | |||
self.instance.activate() | |||
self.instance.run(n_samples) | |||
self.instance.deactivate() | |||
class UITests(unittest.TestCase): | |||
def setUp(self): | |||
self.world = lilv.World() | |||
self.bundle_uri = self.world.new_uri(location) | |||
self.world.load_bundle(self.bundle_uri) | |||
self.plugins = self.world.get_all_plugins() | |||
self.plugin = self.plugins[0] | |||
def testUI(self): | |||
uis = self.plugin.get_uis() | |||
ui_uri = self.world.new_uri('http://example.org/lilv-bindings-test-plugin-ui') | |||
self.assertEqual(1, len(uis)) | |||
self.assertEqual(str(uis[0]), str(ui_uri)) | |||
self.assertEqual(uis[0], str(ui_uri)) | |||
self.assertEqual(uis[0].get_uri(), ui_uri) | |||
self.assertEqual(uis[0].get_bundle_uri(), self.bundle_uri) | |||
self.assertEqual(uis[0].get_binary_uri(), str(self.bundle_uri) + "TODO") | |||
self.assertEqual(uis[uis[0].get_uri()], uis[0]) | |||
self.assertTrue(uis[0].is_a(self.world.ns.ui.GtkUI)) | |||
self.assertTrue(uis[0] in uis) | |||
self.assertTrue(uis[0].get_uri() in uis) | |||
self.assertEqual([self.world.ns.ui.GtkUI], list(uis[0].get_classes())) | |||
for ui in uis: | |||
print(ui) |
@@ -0,0 +1,34 @@ | |||
.TH LV2APPLY 1 "05 Sep 2016" | |||
.SH NAME | |||
.B lv2apply \- apply an LV2 plugin to an audio file | |||
.SH SYNOPSIS | |||
.B lv2apply [OPTION]... PLUGIN_URI | |||
.SH OPTIONS | |||
.TP | |||
\fB\-i IN_FILE\fR | |||
Input file | |||
.TP | |||
\fB\-o OUT_FILE\fR | |||
Output file | |||
.TP | |||
\fB\-c SYM VAL\fR | |||
Set control port SYM to VAL | |||
.TP | |||
\fB\-\-help\fR | |||
Display help and exit | |||
.TP | |||
\fB\-\-version\fR | |||
Display version information and exit | |||
.SH "SEE ALSO" | |||
.BR lv2ls(1) | |||
.BR lv2info(1) | |||
.SH AUTHOR | |||
lv2apply was written by David Robillard <d@drobilla.net> |
@@ -1,17 +1,17 @@ | |||
.TH LV2INFO 1 "8 Jan 2012" | |||
.TH LV2INFO 1 "05 Sep 2016" | |||
.SH NAME | |||
.B lv2info \- print information about an installed LV2 plugin. | |||
.B lv2info \- print information about an installed LV2 plugin | |||
.SH SYNOPSIS | |||
.B lv2info PLUGIN_URI | |||
.SH OPTIONS | |||
.TP | |||
\fB\-p FILE | |||
\fB\-p FILE\fR | |||
Write Turtle description of plugin to FILE | |||
.TP | |||
\fB\-m FILE | |||
\fB\-m FILE\fR | |||
Add record of plugin to manifest FILE | |||
.TP | |||
@@ -22,7 +22,7 @@ Display help and exit | |||
\fB\-\-version\fR | |||
Display version information and exit | |||
.SH SEE ALSO | |||
.SH "SEE ALSO" | |||
.BR lilv(3), | |||
.BR lv2ls(1) | |||
@@ -1,7 +1,7 @@ | |||
.TH LV2LS 1 "17 Jan 2012" | |||
.TH LV2LS 1 "26 Aug 2016" | |||
.SH NAME | |||
.B lv2ls \- List all installed LV2 plugins. | |||
.B lv2ls \- list all installed LV2 plugins | |||
.SH SYNOPSIS | |||
.B lv2ls [OPTION]... | |||
@@ -19,7 +19,7 @@ Display help and exit | |||
\fB\-\-version\fR | |||
Display version information and exit | |||
.SH SEE ALSO | |||
.SH "SEE ALSO" | |||
.BR lilv(3), | |||
.BR lv2info(1) | |||
@@ -1,4 +1,4 @@ | |||
# Doxyfile 1.8.7 | |||
# Doxyfile 1.8.12 | |||
# This file describes the settings to be used by the documentation system | |||
# doxygen (www.doxygen.org) for a project. | |||
@@ -46,10 +46,10 @@ PROJECT_NUMBER = @LILV_VERSION@ | |||
PROJECT_BRIEF = | |||
# With the PROJECT_LOGO tag one can specify an logo or icon that is included in | |||
# the documentation. The maximum height of the logo should not exceed 55 pixels | |||
# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo | |||
# to the output directory. | |||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included | |||
# in the documentation. The maximum height of the logo should not exceed 55 | |||
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy | |||
# the logo to the output directory. | |||
PROJECT_LOGO = | |||
@@ -60,7 +60,7 @@ PROJECT_LOGO = | |||
OUTPUT_DIRECTORY = . | |||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- | |||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- | |||
# directories (in 2 levels) under the output directory of each output format and | |||
# will distribute the generated files over these directories. Enabling this | |||
# option can be useful when feeding doxygen a huge amount of source files, where | |||
@@ -93,14 +93,14 @@ ALLOW_UNICODE_NAMES = NO | |||
OUTPUT_LANGUAGE = English | |||
# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member | |||
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member | |||
# descriptions after the members that are listed in the file and class | |||
# documentation (similar to Javadoc). Set to NO to disable this. | |||
# The default value is: YES. | |||
BRIEF_MEMBER_DESC = NO | |||
# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief | |||
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief | |||
# description of a member or function before the detailed description | |||
# | |||
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the | |||
@@ -135,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO | |||
INLINE_INHERITED_MEMB = NO | |||
# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path | |||
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path | |||
# before files name in the file list and in the header files. If set to NO the | |||
# shortest path that makes the file name unique will be used | |||
# The default value is: YES. | |||
@@ -205,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO | |||
INHERIT_DOCS = YES | |||
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a | |||
# new page for each member. If set to NO, the documentation of a member will be | |||
# part of the file/class/namespace that contains it. | |||
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new | |||
# page for each member. If set to NO, the documentation of a member will be part | |||
# of the file/class/namespace that contains it. | |||
# The default value is: NO. | |||
SEPARATE_MEMBER_PAGES = NO | |||
@@ -276,7 +276,7 @@ OPTIMIZE_OUTPUT_VHDL = NO | |||
# instance to make doxygen treat .inc files as Fortran files (default is PHP), | |||
# and .f files as C (default is Fortran), use: inc=Fortran f=C. | |||
# | |||
# Note For files without extension you can use no_extension as a placeholder. | |||
# Note: For files without extension you can use no_extension as a placeholder. | |||
# | |||
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise | |||
# the files are not read by doxygen. | |||
@@ -293,10 +293,19 @@ EXTENSION_MAPPING = | |||
MARKDOWN_SUPPORT = YES | |||
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up | |||
# to that level are automatically included in the table of contents, even if | |||
# they do not have an id attribute. | |||
# Note: This feature currently applies only to Markdown headings. | |||
# Minimum value: 0, maximum value: 99, default value: 0. | |||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. | |||
TOC_INCLUDE_HEADINGS = 0 | |||
# When enabled doxygen tries to link words that correspond to documented | |||
# classes, or namespaces to their corresponding documentation. Such a link can | |||
# be prevented in individual cases by by putting a % sign in front of the word | |||
# or globally by setting AUTOLINK_SUPPORT to NO. | |||
# be prevented in individual cases by putting a % sign in front of the word or | |||
# globally by setting AUTOLINK_SUPPORT to NO. | |||
# The default value is: YES. | |||
AUTOLINK_SUPPORT = YES | |||
@@ -336,13 +345,20 @@ SIP_SUPPORT = NO | |||
IDL_PROPERTY_SUPPORT = YES | |||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC | |||
# tag is set to YES, then doxygen will reuse the documentation of the first | |||
# tag is set to YES then doxygen will reuse the documentation of the first | |||
# member in the group (if any) for the other members of the group. By default | |||
# all members of a group must be documented explicitly. | |||
# The default value is: NO. | |||
DISTRIBUTE_GROUP_DOC = NO | |||
# If one adds a struct or class to a group and this option is enabled, then also | |||
# any nested class or struct is added to the same group. By default this option | |||
# is disabled and one has to add nested compounds explicitly via \ingroup. | |||
# The default value is: NO. | |||
GROUP_NESTED_COMPOUNDS = NO | |||
# Set the SUBGROUPING tag to YES to allow class member groups of the same type | |||
# (for instance a group of public functions) to be put as a subgroup of that | |||
# type (e.g. under the Public Functions section). Set it to NO to prevent | |||
@@ -401,7 +417,7 @@ LOOKUP_CACHE_SIZE = 0 | |||
# Build related configuration options | |||
#--------------------------------------------------------------------------- | |||
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in | |||
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in | |||
# documentation are documented, even if no documentation was available. Private | |||
# class members and static file members will be hidden unless the | |||
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. | |||
@@ -411,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 | |||
EXTRACT_ALL = YES | |||
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will | |||
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will | |||
# be included in the documentation. | |||
# The default value is: NO. | |||
EXTRACT_PRIVATE = NO | |||
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal | |||
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal | |||
# scope will be included in the documentation. | |||
# The default value is: NO. | |||
EXTRACT_PACKAGE = NO | |||
# If the EXTRACT_STATIC tag is set to YES all static members of a file will be | |||
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be | |||
# included in the documentation. | |||
# The default value is: NO. | |||
EXTRACT_STATIC = YES | |||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined | |||
# locally in source files will be included in the documentation. If set to NO | |||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined | |||
# locally in source files will be included in the documentation. If set to NO, | |||
# only classes defined in header files are included. Does not have any effect | |||
# for Java sources. | |||
# The default value is: YES. | |||
EXTRACT_LOCAL_CLASSES = NO | |||
# This flag is only useful for Objective-C code. When set to YES local methods, | |||
# This flag is only useful for Objective-C code. If set to YES, local methods, | |||
# which are defined in the implementation section but not in the interface are | |||
# included in the documentation. If set to NO only methods in the interface are | |||
# included in the documentation. If set to NO, only methods in the interface are | |||
# included. | |||
# The default value is: NO. | |||
@@ -464,21 +480,21 @@ HIDE_UNDOC_MEMBERS = YES | |||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all | |||
# undocumented classes that are normally visible in the class hierarchy. If set | |||
# to NO these classes will be included in the various overviews. This option has | |||
# no effect if EXTRACT_ALL is enabled. | |||
# to NO, these classes will be included in the various overviews. This option | |||
# has no effect if EXTRACT_ALL is enabled. | |||
# The default value is: NO. | |||
HIDE_UNDOC_CLASSES = YES | |||
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend | |||
# (class|struct|union) declarations. If set to NO these declarations will be | |||
# (class|struct|union) declarations. If set to NO, these declarations will be | |||
# included in the documentation. | |||
# The default value is: NO. | |||
HIDE_FRIEND_COMPOUNDS = NO | |||
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any | |||
# documentation blocks found inside the body of a function. If set to NO these | |||
# documentation blocks found inside the body of a function. If set to NO, these | |||
# blocks will be appended to the function's detailed documentation block. | |||
# The default value is: NO. | |||
@@ -492,7 +508,7 @@ HIDE_IN_BODY_DOCS = YES | |||
INTERNAL_DOCS = NO | |||
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file | |||
# names in lower-case letters. If set to YES upper-case letters are also | |||
# names in lower-case letters. If set to YES, upper-case letters are also | |||
# allowed. This is useful if you have classes or files whose names only differ | |||
# in case and if your file system supports case sensitive file names. Windows | |||
# and Mac users are advised to set this option to NO. | |||
@@ -501,12 +517,19 @@ INTERNAL_DOCS = NO | |||
CASE_SENSE_NAMES = YES | |||
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with | |||
# their full class and namespace scopes in the documentation. If set to YES the | |||
# their full class and namespace scopes in the documentation. If set to YES, the | |||
# scope will be hidden. | |||
# The default value is: NO. | |||
HIDE_SCOPE_NAMES = NO | |||
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will | |||
# append additional text to a page's title, such as Class Reference. If set to | |||
# YES the compound reference will be hidden. | |||
# The default value is: NO. | |||
HIDE_COMPOUND_REFERENCE= NO | |||
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of | |||
# the files that are included by a file in the documentation of that file. | |||
# The default value is: YES. | |||
@@ -534,14 +557,14 @@ INLINE_INFO = YES | |||
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the | |||
# (detailed) documentation of file and class members alphabetically by member | |||
# name. If set to NO the members will appear in declaration order. | |||
# name. If set to NO, the members will appear in declaration order. | |||
# The default value is: YES. | |||
SORT_MEMBER_DOCS = NO | |||
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief | |||
# descriptions of file, namespace and class members alphabetically by member | |||
# name. If set to NO the members will appear in declaration order. Note that | |||
# name. If set to NO, the members will appear in declaration order. Note that | |||
# this will also influence the order of the classes in the class list. | |||
# The default value is: NO. | |||
@@ -586,27 +609,25 @@ SORT_BY_SCOPE_NAME = YES | |||
STRICT_PROTO_MATCHING = NO | |||
# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the | |||
# todo list. This list is created by putting \todo commands in the | |||
# documentation. | |||
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo | |||
# list. This list is created by putting \todo commands in the documentation. | |||
# The default value is: YES. | |||
GENERATE_TODOLIST = NO | |||
# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the | |||
# test list. This list is created by putting \test commands in the | |||
# documentation. | |||
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test | |||
# list. This list is created by putting \test commands in the documentation. | |||
# The default value is: YES. | |||
GENERATE_TESTLIST = NO | |||
# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug | |||
# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug | |||
# list. This list is created by putting \bug commands in the documentation. | |||
# The default value is: YES. | |||
GENERATE_BUGLIST = NO | |||
# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) | |||
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) | |||
# the deprecated list. This list is created by putting \deprecated commands in | |||
# the documentation. | |||
# The default value is: YES. | |||
@@ -631,8 +652,8 @@ ENABLED_SECTIONS = | |||
MAX_INITIALIZER_LINES = 30 | |||
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at | |||
# the bottom of the documentation of classes and structs. If set to YES the list | |||
# will mention the files that were used to generate the documentation. | |||
# the bottom of the documentation of classes and structs. If set to YES, the | |||
# list will mention the files that were used to generate the documentation. | |||
# The default value is: YES. | |||
SHOW_USED_FILES = YES | |||
@@ -680,8 +701,7 @@ LAYOUT_FILE = @LILV_SRCDIR@/doc/layout.xml | |||
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. | |||
# For LaTeX the style of the bibliography can be controlled using | |||
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the | |||
# search path. Do not use file names with spaces, bibtex cannot handle them. See | |||
# also \cite for info how to create references. | |||
# search path. See also \cite for info how to create references. | |||
CITE_BIB_FILES = | |||
@@ -697,7 +717,7 @@ CITE_BIB_FILES = | |||
QUIET = YES | |||
# The WARNINGS tag can be used to turn on/off the warning messages that are | |||
# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES | |||
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES | |||
# this implies that the warnings are on. | |||
# | |||
# Tip: Turn warnings on while writing the documentation. | |||
@@ -705,7 +725,7 @@ QUIET = YES | |||
WARNINGS = YES | |||
# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate | |||
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate | |||
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag | |||
# will automatically be disabled. | |||
# The default value is: YES. | |||
@@ -722,12 +742,18 @@ WARN_IF_DOC_ERROR = YES | |||
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that | |||
# are documented, but have no documentation for their parameters or return | |||
# value. If set to NO doxygen will only warn about wrong or incomplete parameter | |||
# documentation, but not about the absence of documentation. | |||
# value. If set to NO, doxygen will only warn about wrong or incomplete | |||
# parameter documentation, but not about the absence of documentation. | |||
# The default value is: NO. | |||
WARN_NO_PARAMDOC = YES | |||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when | |||
# a warning is encountered. | |||
# The default value is: NO. | |||
WARN_AS_ERROR = NO | |||
# The WARN_FORMAT tag determines the format of the warning messages that doxygen | |||
# can produce. The string should contain the $file, $line, and $text tags, which | |||
# will be replaced by the file and line number from which the warning originated | |||
@@ -751,7 +777,7 @@ WARN_LOGFILE = | |||
# The INPUT tag is used to specify the files and/or directories that contain | |||
# documented source files. You may enter file names like myfile.cpp or | |||
# directories like /usr/src/myproject. Separate the files or directories with | |||
# spaces. | |||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING | |||
# Note: If this tag is empty the current directory is searched. | |||
INPUT = @LILV_SRCDIR@/lilv/lilv.h | |||
@@ -767,12 +793,17 @@ INPUT_ENCODING = UTF-8 | |||
# If the value of the INPUT tag contains directories, you can use the | |||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and | |||
# *.h) to filter out the source-files in the directories. If left blank the | |||
# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, | |||
# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, | |||
# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, | |||
# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, | |||
# *.qsf, *.as and *.js. | |||
# *.h) to filter out the source-files in the directories. | |||
# | |||
# Note that for custom extensions or not directly supported extensions you also | |||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not | |||
# read by doxygen. | |||
# | |||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, | |||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, | |||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, | |||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, | |||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. | |||
FILE_PATTERNS = | |||
@@ -858,6 +889,10 @@ IMAGE_PATH = | |||
# Note that the filter must not add or remove lines; it is applied before the | |||
# code is scanned, but not when the output code is generated. If lines are added | |||
# or removed, the anchors will not be placed correctly. | |||
# | |||
# Note that for custom extensions or not directly supported extensions you also | |||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not | |||
# properly processed by doxygen. | |||
INPUT_FILTER = | |||
@@ -867,11 +902,15 @@ INPUT_FILTER = | |||
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how | |||
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the | |||
# patterns match the file name, INPUT_FILTER is applied. | |||
# | |||
# Note that for custom extensions or not directly supported extensions you also | |||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not | |||
# properly processed by doxygen. | |||
FILTER_PATTERNS = | |||
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using | |||
# INPUT_FILTER ) will also be used to filter the input files that are used for | |||
# INPUT_FILTER) will also be used to filter the input files that are used for | |||
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). | |||
# The default value is: NO. | |||
@@ -931,7 +970,7 @@ REFERENCED_BY_RELATION = YES | |||
REFERENCES_RELATION = YES | |||
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set | |||
# to YES, then the hyperlinks from functions in REFERENCES_RELATION and | |||
# to YES then the hyperlinks from functions in REFERENCES_RELATION and | |||
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will | |||
# link to the documentation. | |||
# The default value is: YES. | |||
@@ -1008,7 +1047,7 @@ IGNORE_PREFIX = | |||
# Configuration options related to the HTML output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output | |||
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output | |||
# The default value is: YES. | |||
GENERATE_HTML = YES | |||
@@ -1070,13 +1109,15 @@ HTML_FOOTER = | |||
HTML_STYLESHEET = @LILV_SRCDIR@/doc/style.css | |||
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- | |||
# defined cascading style sheet that is included after the standard style sheets | |||
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined | |||
# cascading style sheets that are included after the standard style sheets | |||
# created by doxygen. Using this option one can overrule certain style aspects. | |||
# This is preferred over using HTML_STYLESHEET since it does not replace the | |||
# standard style sheet and is therefor more robust against future updates. | |||
# Doxygen will copy the style sheet file to the output directory. For an example | |||
# see the documentation. | |||
# standard style sheet and is therefore more robust against future updates. | |||
# Doxygen will copy the style sheet files to the output directory. | |||
# Note: The order of the extra style sheet files is of importance (e.g. the last | |||
# style sheet in the list overrules the setting of the previous ones in the | |||
# list). For an example see the documentation. | |||
# This tag requires that the tag GENERATE_HTML is set to YES. | |||
HTML_EXTRA_STYLESHEET = | |||
@@ -1092,7 +1133,7 @@ HTML_EXTRA_STYLESHEET = | |||
HTML_EXTRA_FILES = | |||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen | |||
# will adjust the colors in the stylesheet and background images according to | |||
# will adjust the colors in the style sheet and background images according to | |||
# this color. Hue is specified as an angle on a colorwheel, see | |||
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value | |||
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 | |||
@@ -1123,8 +1164,9 @@ HTML_COLORSTYLE_GAMMA = 80 | |||
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML | |||
# page will contain the date and time when the page was generated. Setting this | |||
# to NO can help when comparing the output of multiple runs. | |||
# The default value is: YES. | |||
# to YES can help to show when doxygen was last run and thus if the | |||
# documentation is up to date. | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_HTML is set to YES. | |||
HTML_TIMESTAMP = NO | |||
@@ -1220,28 +1262,28 @@ GENERATE_HTMLHELP = NO | |||
CHM_FILE = | |||
# The HHC_LOCATION tag can be used to specify the location (absolute path | |||
# including file name) of the HTML help compiler ( hhc.exe). If non-empty | |||
# including file name) of the HTML help compiler (hhc.exe). If non-empty, | |||
# doxygen will try to run the HTML help compiler on the generated index.hhp. | |||
# The file has to be specified with full path. | |||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |||
HHC_LOCATION = | |||
# The GENERATE_CHI flag controls if a separate .chi index file is generated ( | |||
# YES) or that it should be included in the master .chm file ( NO). | |||
# The GENERATE_CHI flag controls if a separate .chi index file is generated | |||
# (YES) or that it should be included in the master .chm file (NO). | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |||
GENERATE_CHI = NO | |||
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) | |||
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) | |||
# and project file content. | |||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |||
CHM_INDEX_ENCODING = | |||
# The BINARY_TOC flag controls whether a binary table of contents is generated ( | |||
# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it | |||
# The BINARY_TOC flag controls whether a binary table of contents is generated | |||
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it | |||
# enables the Previous and Next buttons. | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |||
@@ -1355,7 +1397,7 @@ DISABLE_INDEX = YES | |||
# index structure (just like the one that is generated for HTML Help). For this | |||
# to work a browser that supports JavaScript, DHTML, CSS and frames is required | |||
# (i.e. any modern browser). Windows users are probably better off using the | |||
# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can | |||
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can | |||
# further fine-tune the look of the index. As an example, the default style | |||
# sheet generated by doxygen has an example that shows how to put an image at | |||
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has | |||
@@ -1374,7 +1416,7 @@ GENERATE_TREEVIEW = NO | |||
# Minimum value: 0, maximum value: 20, default value: 4. | |||
# This tag requires that the tag GENERATE_HTML is set to YES. | |||
ENUM_VALUES_PER_LINE = 4 | |||
ENUM_VALUES_PER_LINE = 1 | |||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used | |||
# to set the initial width (in pixels) of the frame in which the tree is shown. | |||
@@ -1383,7 +1425,7 @@ ENUM_VALUES_PER_LINE = 4 | |||
TREEVIEW_WIDTH = 250 | |||
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to | |||
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to | |||
# external symbols imported via tag files in a separate window. | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_HTML is set to YES. | |||
@@ -1412,7 +1454,7 @@ FORMULA_TRANSPARENT = YES | |||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see | |||
# http://www.mathjax.org) which uses client side Javascript for the rendering | |||
# instead of using prerendered bitmaps. Use this if you do not have LaTeX | |||
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX | |||
# installed or if you want to formulas look prettier in the HTML output. When | |||
# enabled you may also need to install MathJax separately and configure the path | |||
# to it using the MATHJAX_RELPATH option. | |||
@@ -1498,7 +1540,7 @@ SERVER_BASED_SEARCH = NO | |||
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the | |||
# search results. | |||
# | |||
# Doxygen ships with an example indexer ( doxyindexer) and search engine | |||
# Doxygen ships with an example indexer (doxyindexer) and search engine | |||
# (doxysearch.cgi) which are based on the open source search engine library | |||
# Xapian (see: http://xapian.org/). | |||
# | |||
@@ -1511,7 +1553,7 @@ EXTERNAL_SEARCH = NO | |||
# The SEARCHENGINE_URL should point to a search engine hosted by a web server | |||
# which will return the search results when EXTERNAL_SEARCH is enabled. | |||
# | |||
# Doxygen ships with an example indexer ( doxyindexer) and search engine | |||
# Doxygen ships with an example indexer (doxyindexer) and search engine | |||
# (doxysearch.cgi) which are based on the open source search engine library | |||
# Xapian (see: http://xapian.org/). See the section "External Indexing and | |||
# Searching" for details. | |||
@@ -1549,7 +1591,7 @@ EXTRA_SEARCH_MAPPINGS = | |||
# Configuration options related to the LaTeX output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. | |||
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. | |||
# The default value is: YES. | |||
GENERATE_LATEX = NO | |||
@@ -1580,7 +1622,7 @@ LATEX_CMD_NAME = latex | |||
MAKEINDEX_CMD_NAME = makeindex | |||
# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX | |||
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX | |||
# documents. This may be useful for small projects and may help to save some | |||
# trees in general. | |||
# The default value is: NO. | |||
@@ -1598,9 +1640,12 @@ COMPACT_LATEX = NO | |||
PAPER_TYPE = a4wide | |||
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names | |||
# that should be included in the LaTeX output. To get the times font for | |||
# instance you can specify | |||
# EXTRA_PACKAGES=times | |||
# that should be included in the LaTeX output. The package can be specified just | |||
# by its name or with the correct syntax as to be used with the LaTeX | |||
# \usepackage command. To get the times font for instance you can specify : | |||
# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} | |||
# To use the option intlimits with the amsmath package you can specify: | |||
# EXTRA_PACKAGES=[intlimits]{amsmath} | |||
# If left blank no extra packages will be included. | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
@@ -1614,23 +1659,36 @@ EXTRA_PACKAGES = | |||
# | |||
# Note: Only use a user-defined header if you know what you are doing! The | |||
# following commands have a special meaning inside the header: $title, | |||
# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will | |||
# replace them by respectively the title of the page, the current date and time, | |||
# only the current date, the version number of doxygen, the project name (see | |||
# PROJECT_NAME), or the project number (see PROJECT_NUMBER). | |||
# $datetime, $date, $doxygenversion, $projectname, $projectnumber, | |||
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty | |||
# string, for the replacement values of the other commands the user is referred | |||
# to HTML_HEADER. | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
LATEX_HEADER = | |||
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the | |||
# generated LaTeX document. The footer should contain everything after the last | |||
# chapter. If it is left blank doxygen will generate a standard footer. | |||
# chapter. If it is left blank doxygen will generate a standard footer. See | |||
# LATEX_HEADER for more information on how to generate a default footer and what | |||
# special commands can be used inside the footer. | |||
# | |||
# Note: Only use a user-defined footer if you know what you are doing! | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
LATEX_FOOTER = | |||
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined | |||
# LaTeX style sheets that are included after the standard style sheets created | |||
# by doxygen. Using this option one can overrule certain style aspects. Doxygen | |||
# will copy the style sheet files to the output directory. | |||
# Note: The order of the extra style sheet files is of importance (e.g. the last | |||
# style sheet in the list overrules the setting of the previous ones in the | |||
# list). | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
LATEX_EXTRA_STYLESHEET = | |||
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or | |||
# other source files which should be copied to the LATEX_OUTPUT output | |||
# directory. Note that the files will be copied as-is; there are no commands or | |||
@@ -1646,15 +1704,15 @@ LATEX_EXTRA_FILES = | |||
# The default value is: YES. | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
PDF_HYPERLINKS = NO | |||
PDF_HYPERLINKS = YES | |||
# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate | |||
# the PDF file directly from the LaTeX files. Set this option to YES to get a | |||
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate | |||
# the PDF file directly from the LaTeX files. Set this option to YES, to get a | |||
# higher quality PDF documentation. | |||
# The default value is: YES. | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
USE_PDFLATEX = NO | |||
USE_PDFLATEX = YES | |||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode | |||
# command to the generated LaTeX files. This will instruct LaTeX to keep running | |||
@@ -1690,11 +1748,19 @@ LATEX_SOURCE_CODE = NO | |||
LATEX_BIB_STYLE = plain | |||
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated | |||
# page will contain the date and time when the page was generated. Setting this | |||
# to NO can help when comparing the output of multiple runs. | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_LATEX is set to YES. | |||
LATEX_TIMESTAMP = NO | |||
#--------------------------------------------------------------------------- | |||
# Configuration options related to the RTF output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The | |||
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The | |||
# RTF output is optimized for Word 97 and may not look too pretty with other RTF | |||
# readers/editors. | |||
# The default value is: NO. | |||
@@ -1709,7 +1775,7 @@ GENERATE_RTF = NO | |||
RTF_OUTPUT = rtf | |||
# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF | |||
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF | |||
# documents. This may be useful for small projects and may help to save some | |||
# trees in general. | |||
# The default value is: NO. | |||
@@ -1746,11 +1812,21 @@ RTF_STYLESHEET_FILE = | |||
RTF_EXTENSIONS_FILE = | |||
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code | |||
# with syntax highlighting in the RTF output. | |||
# | |||
# Note that which sources are shown also depends on other settings such as | |||
# SOURCE_BROWSER. | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_RTF is set to YES. | |||
RTF_SOURCE_CODE = NO | |||
#--------------------------------------------------------------------------- | |||
# Configuration options related to the man page output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for | |||
# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for | |||
# classes and files. | |||
# The default value is: NO. | |||
@@ -1794,7 +1870,7 @@ MAN_LINKS = NO | |||
# Configuration options related to the XML output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that | |||
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that | |||
# captures the structure of the code including all documentation. | |||
# The default value is: NO. | |||
@@ -1808,7 +1884,7 @@ GENERATE_XML = NO | |||
XML_OUTPUT = xml | |||
# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program | |||
# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program | |||
# listings (including syntax highlighting and cross-referencing information) to | |||
# the XML output. Note that enabling this will significantly increase the size | |||
# of the XML output. | |||
@@ -1821,7 +1897,7 @@ XML_PROGRAMLISTING = YES | |||
# Configuration options related to the DOCBOOK output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files | |||
# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files | |||
# that can be used to generate PDF. | |||
# The default value is: NO. | |||
@@ -1835,14 +1911,23 @@ GENERATE_DOCBOOK = NO | |||
DOCBOOK_OUTPUT = docbook | |||
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the | |||
# program listings (including syntax highlighting and cross-referencing | |||
# information) to the DOCBOOK output. Note that enabling this will significantly | |||
# increase the size of the DOCBOOK output. | |||
# The default value is: NO. | |||
# This tag requires that the tag GENERATE_DOCBOOK is set to YES. | |||
DOCBOOK_PROGRAMLISTING = NO | |||
#--------------------------------------------------------------------------- | |||
# Configuration options for the AutoGen Definitions output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen | |||
# Definitions (see http://autogen.sf.net) file that captures the structure of | |||
# the code including all documentation. Note that this feature is still | |||
# experimental and incomplete at the moment. | |||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an | |||
# AutoGen Definitions (see http://autogen.sf.net) file that captures the | |||
# structure of the code including all documentation. Note that this feature is | |||
# still experimental and incomplete at the moment. | |||
# The default value is: NO. | |||
GENERATE_AUTOGEN_DEF = NO | |||
@@ -1851,7 +1936,7 @@ GENERATE_AUTOGEN_DEF = NO | |||
# Configuration options related to the Perl module output | |||
#--------------------------------------------------------------------------- | |||
# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module | |||
# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module | |||
# file that captures the structure of the code including all documentation. | |||
# | |||
# Note that this feature is still experimental and incomplete at the moment. | |||
@@ -1859,7 +1944,7 @@ GENERATE_AUTOGEN_DEF = NO | |||
GENERATE_PERLMOD = NO | |||
# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary | |||
# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary | |||
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI | |||
# output from the Perl module output. | |||
# The default value is: NO. | |||
@@ -1867,9 +1952,9 @@ GENERATE_PERLMOD = NO | |||
PERLMOD_LATEX = NO | |||
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely | |||
# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely | |||
# formatted so it can be parsed by a human reader. This is useful if you want to | |||
# understand what is going on. On the other hand, if this tag is set to NO the | |||
# understand what is going on. On the other hand, if this tag is set to NO, the | |||
# size of the Perl module output will be much smaller and Perl will parse it | |||
# just the same. | |||
# The default value is: YES. | |||
@@ -1889,14 +1974,14 @@ PERLMOD_MAKEVAR_PREFIX = | |||
# Configuration options related to the preprocessor | |||
#--------------------------------------------------------------------------- | |||
# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all | |||
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all | |||
# C-preprocessor directives found in the sources and include files. | |||
# The default value is: YES. | |||
ENABLE_PREPROCESSING = YES | |||
# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names | |||
# in the source code. If set to NO only conditional compilation will be | |||
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names | |||
# in the source code. If set to NO, only conditional compilation will be | |||
# performed. Macro expansion can be done in a controlled way by setting | |||
# EXPAND_ONLY_PREDEF to YES. | |||
# The default value is: NO. | |||
@@ -1912,7 +1997,7 @@ MACRO_EXPANSION = NO | |||
EXPAND_ONLY_PREDEF = NO | |||
# If the SEARCH_INCLUDES tag is set to YES the includes files in the | |||
# If the SEARCH_INCLUDES tag is set to YES, the include files in the | |||
# INCLUDE_PATH will be searched if a #include is found. | |||
# The default value is: YES. | |||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |||
@@ -1988,20 +2073,21 @@ TAGFILES = | |||
GENERATE_TAGFILE = | |||
# If the ALLEXTERNALS tag is set to YES all external class will be listed in the | |||
# class index. If set to NO only the inherited external classes will be listed. | |||
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in | |||
# the class index. If set to NO, only the inherited external classes will be | |||
# listed. | |||
# The default value is: NO. | |||
ALLEXTERNALS = NO | |||
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in | |||
# the modules index. If set to NO, only the current project's groups will be | |||
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed | |||
# in the modules index. If set to NO, only the current project's groups will be | |||
# listed. | |||
# The default value is: YES. | |||
EXTERNAL_GROUPS = YES | |||
# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in | |||
# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in | |||
# the related pages index. If set to NO, only the current project's pages will | |||
# be listed. | |||
# The default value is: YES. | |||
@@ -2018,7 +2104,7 @@ PERL_PATH = /usr/bin/perl | |||
# Configuration options related to the dot tool | |||
#--------------------------------------------------------------------------- | |||
# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram | |||
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram | |||
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to | |||
# NO turns the diagrams off. Note that this option also works with HAVE_DOT | |||
# disabled, but it is recommended to install and use dot, since it yields more | |||
@@ -2043,7 +2129,7 @@ MSCGEN_PATH = | |||
DIA_PATH = | |||
# If set to YES, the inheritance and collaboration graphs will hide inheritance | |||
# If set to YES the inheritance and collaboration graphs will hide inheritance | |||
# and usage relations if the target is undocumented or is not a class. | |||
# The default value is: YES. | |||
@@ -2054,7 +2140,7 @@ HIDE_UNDOC_RELATIONS = YES | |||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent | |||
# Bell Labs. The other options in this section have no effect if this option is | |||
# set to NO | |||
# The default value is: YES. | |||
# The default value is: NO. | |||
HAVE_DOT = NO | |||
@@ -2068,7 +2154,7 @@ HAVE_DOT = NO | |||
DOT_NUM_THREADS = 0 | |||
# When you want a differently looking font n the dot files that doxygen | |||
# When you want a differently looking font in the dot files that doxygen | |||
# generates you can specify the font name using DOT_FONTNAME. You need to make | |||
# sure dot is able to find the font, which can be done by putting it in a | |||
# standard location or by setting the DOTFONTPATH environment variable or by | |||
@@ -2116,7 +2202,7 @@ COLLABORATION_GRAPH = NO | |||
GROUP_GRAPHS = YES | |||
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and | |||
# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and | |||
# collaboration diagrams in a style similar to the OMG's Unified Modeling | |||
# Language. | |||
# The default value is: NO. | |||
@@ -2168,7 +2254,8 @@ INCLUDED_BY_GRAPH = NO | |||
# | |||
# Note that enabling this option will significantly increase the time of a run. | |||
# So in most cases it will be better to enable call graphs for selected | |||
# functions only using the \callgraph command. | |||
# functions only using the \callgraph command. Disabling a call graph can be | |||
# accomplished by means of the command \hidecallgraph. | |||
# The default value is: NO. | |||
# This tag requires that the tag HAVE_DOT is set to YES. | |||
@@ -2179,7 +2266,8 @@ CALL_GRAPH = NO | |||
# | |||
# Note that enabling this option will significantly increase the time of a run. | |||
# So in most cases it will be better to enable caller graphs for selected | |||
# functions only using the \callergraph command. | |||
# functions only using the \callergraph command. Disabling a caller graph can be | |||
# accomplished by means of the command \hidecallergraph. | |||
# The default value is: NO. | |||
# This tag requires that the tag HAVE_DOT is set to YES. | |||
@@ -2202,13 +2290,15 @@ GRAPHICAL_HIERARCHY = NO | |||
DIRECTORY_GRAPH = NO | |||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images | |||
# generated by dot. | |||
# generated by dot. For an explanation of the image formats see the section | |||
# output formats in the documentation of the dot tool (Graphviz (see: | |||
# http://www.graphviz.org/)). | |||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order | |||
# to make the SVG files visible in IE 9+ (other browsers do not have this | |||
# requirement). | |||
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, | |||
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, | |||
# gif:cairo:gd, gif:gd, gif:gd:gd and svg. | |||
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, | |||
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and | |||
# png:gdiplus:gdiplus. | |||
# The default value is: png. | |||
# This tag requires that the tag HAVE_DOT is set to YES. | |||
@@ -2251,6 +2341,19 @@ MSCFILE_DIRS = | |||
DIAFILE_DIRS = | |||
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the | |||
# path where java can find the plantuml.jar file. If left blank, it is assumed | |||
# PlantUML is not used or called during a preprocessing step. Doxygen will | |||
# generate a warning when it encounters a \startuml command in this case and | |||
# will not generate output for the diagram. | |||
PLANTUML_JAR_PATH = | |||
# When using plantuml, the specified paths are searched for files specified by | |||
# the !include statement in a plantuml block. | |||
PLANTUML_INCLUDE_PATH = | |||
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes | |||
# that will be shown in the graph. If the number of nodes in a graph becomes | |||
# larger than this value, doxygen will truncate the graph, which is visualized | |||
@@ -2287,7 +2390,7 @@ MAX_DOT_GRAPH_DEPTH = 0 | |||
DOT_TRANSPARENT = NO | |||
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output | |||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output | |||
# files in one run (i.e. multiple -o and -T options on the command line). This | |||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support | |||
# this, this feature is disabled by default. | |||
@@ -2304,7 +2407,7 @@ DOT_MULTI_TARGETS = NO | |||
GENERATE_LEGEND = NO | |||
# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot | |||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot | |||
# files that are used to generate the various graphs. | |||
# The default value is: YES. | |||
# This tag requires that the tag HAVE_DOT is set to YES. |
@@ -1,69 +1,54 @@ | |||
body { | |||
font-size: medium; | |||
font-family: sans-serif; | |||
} | |||
#top { | |||
background-color: #F3F3F3; | |||
max-width: 80em; | |||
margin: 0; | |||
padding: 0; | |||
border-bottom: 1px solid #DDD; | |||
margin-bottom: 1ex; | |||
font-size: xx-large; | |||
font-weight: bold; | |||
} | |||
div.header { | |||
display: none; | |||
margin-left: auto; | |||
margin-right: auto; | |||
background: #FFF; | |||
color: #000; | |||
} | |||
.tabs { | |||
#titlearea { | |||
display: none; | |||
} | |||
h1 h2 h3 h4 h5 h6 { | |||
font-weight: bold; | |||
} | |||
h1 { | |||
font-size: 164%; | |||
font-size: 180%; | |||
font-weight: 900; | |||
} | |||
h2 { | |||
font-size: 132%; | |||
font-size: 140%; | |||
font-weight: 700; | |||
} | |||
h3 { | |||
font-size: 124%; | |||
font-size: 120%; | |||
font-weight: 700; | |||
} | |||
h4 { | |||
font-size: 116%; | |||
font-size: 110%; | |||
font-weight: 700; | |||
} | |||
h5 { | |||
font-size: 108%; | |||
font-size: 100%; | |||
font-weight: 700; | |||
} | |||
h6 { | |||
font-size: 100%; | |||
font-weight: 600; | |||
} | |||
p { | |||
margin: 0 0 1ex 0; | |||
} | |||
br { | |||
display: none; | |||
margin: 0 0 1em 0; | |||
} | |||
dt { | |||
font-weight: 700; | |||
} | |||
div.multicol { | |||
} | |||
p.startli,p.startdd,p.starttd { | |||
margin-top: 2px; | |||
} | |||
@@ -85,12 +70,12 @@ caption { | |||
} | |||
span.legend { | |||
font-size: 70%; | |||
font-size: small; | |||
text-align: center; | |||
} | |||
h3.version { | |||
font-size: 90%; | |||
font-size: small; | |||
text-align: center; | |||
} | |||
@@ -102,23 +87,18 @@ div.qindex,div.navtab { | |||
padding: 2px; | |||
} | |||
div.qindex,div.navpath { | |||
width: 100%; | |||
line-height: 140%; | |||
} | |||
div.navtab { | |||
margin-right: 15px; | |||
} | |||
/* @group Link Styling */ | |||
a { | |||
color: #3D8C57; | |||
color: #546E00; | |||
text-decoration: none; | |||
} | |||
.contents a:visited { | |||
color: #50755E; | |||
color: #344E00; | |||
} | |||
a:hover { | |||
@@ -131,6 +111,10 @@ a.qindexHL { | |||
border: 1px double #869DCA; | |||
} | |||
code { | |||
color: #444; | |||
} | |||
a.code { | |||
color: #4665A2; | |||
} | |||
@@ -146,7 +130,6 @@ dl.el { | |||
.fragment { | |||
font-family: monospace, fixed; | |||
font-size: 105%; | |||
} | |||
pre.fragment { | |||
@@ -155,7 +138,6 @@ pre.fragment { | |||
padding: 4px 6px; | |||
margin: 4px 8px 4px 2px; | |||
overflow: auto; | |||
font-size: 9pt; | |||
line-height: 125%; | |||
} | |||
@@ -176,17 +158,15 @@ div.groupHeader { | |||
font-weight: 700; | |||
} | |||
a + h2.groupheader { | |||
display: none; | |||
} | |||
div.groupText { | |||
margin-left: 16px; | |||
font-style: italic; | |||
} | |||
body { | |||
background: #FFF; | |||
color: #000; | |||
margin: 0; | |||
} | |||
div.contents { | |||
margin-top: 10px; | |||
margin-left: 10px; | |||
@@ -216,9 +196,6 @@ p.formulaDsp { | |||
text-align: center; | |||
} | |||
img.formulaDsp { | |||
} | |||
img.formulaInl { | |||
vertical-align: middle; | |||
} | |||
@@ -236,7 +213,7 @@ div.center img { | |||
address.footer { | |||
text-align: right; | |||
padding: 0 0.25em 0.25em 0; | |||
padding-right: 12px; | |||
} | |||
img.footer { | |||
@@ -250,7 +227,7 @@ span.keyword { | |||
} | |||
span.keywordtype { | |||
color: #604020; | |||
color: #3E873E; | |||
} | |||
span.keywordflow { | |||
@@ -287,7 +264,7 @@ span.vhdllogic { | |||
/* @end */ | |||
td.tiny { | |||
font-size: 75%; | |||
font-size: x-small; | |||
} | |||
.dirtab { | |||
@@ -314,14 +291,16 @@ hr.footer { | |||
/* @group Member Descriptions */ | |||
table.memberdecls { | |||
border-spacing: 0; | |||
font-size: small; | |||
border-spacing: 0.125em; | |||
} | |||
h2.groupheader { | |||
margin: 0.5em 0 0.25em 0; | |||
} | |||
.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,.memTemplItemLeft,.memTemplItemRight,.memTemplParams { | |||
background-color: #FBFBFB; | |||
margin: 0; | |||
padding: 0.25ex; | |||
padding: 0; | |||
} | |||
.mdescLeft,.mdescRight { | |||
@@ -329,12 +308,18 @@ table.memberdecls { | |||
} | |||
.memItemLeft,.memItemRight,.memTemplParams { | |||
border-top: 1px solid #DDD; | |||
border: 0; | |||
font-family: monospace, fixed; | |||
} | |||
.memItemLeft,.memTemplItemLeft { | |||
white-space: nowrap; | |||
padding-left: 2em; | |||
padding-right: 1em; | |||
} | |||
.memItemLeft a.el { | |||
font-weight: bold; | |||
} | |||
.memTemplParams { | |||
@@ -342,11 +327,24 @@ table.memberdecls { | |||
white-space: nowrap; | |||
} | |||
td.memSeparator { | |||
display: none; | |||
} | |||
td.mlabels-right { | |||
vertical-align: top; | |||
padding-top: 4px; | |||
color: #AA6; | |||
} | |||
.memtitle { | |||
display: none; | |||
} | |||
/* @end */ | |||
/* @group Member Details */ | |||
/* Styles for detailed member documentation */ | |||
.memtemplate { | |||
font-size: 80%; | |||
color: #4665A2; | |||
font-weight: bold; | |||
} | |||
@@ -362,26 +360,22 @@ table.memberdecls { | |||
.memitem { | |||
padding: 0; | |||
margin: 1ex 0 2ex 0; | |||
border: 1px solid #CCC; | |||
margin: 1em 0 1em 0; | |||
} | |||
.memname { | |||
white-space: nowrap; | |||
.memproto { | |||
padding: 0; | |||
font-weight: bold; | |||
color: #000; | |||
} | |||
.memproto { | |||
border-bottom: 1px solid #DDD; | |||
padding: 0.5ex; | |||
font-weight: bold; | |||
background-color: #F3F3F3; | |||
.memproto .paramname { | |||
color: #444; | |||
font-style: normal; | |||
} | |||
.memdoc { | |||
padding: 1ex; | |||
background-color: #FBFBFB; | |||
border-top-width: 0; | |||
padding: 0 0 0.5em 2em; | |||
} | |||
.paramkey { | |||
@@ -389,16 +383,37 @@ table.memberdecls { | |||
} | |||
.paramtype { | |||
color: #3E873E; | |||
white-space: nowrap; | |||
} | |||
.paramname { | |||
color: #602020; | |||
color: #444; | |||
white-space: nowrap; | |||
font-weight: bold; | |||
} | |||
.paramname em { | |||
font-style: normal; | |||
td.paramname { | |||
vertical-align: top; | |||
} | |||
.fieldname { | |||
color: #000; | |||
} | |||
td.fieldname { | |||
padding-right: 1em; | |||
vertical-align: top; | |||
} | |||
td.fieldtype { | |||
vertical-align: top; | |||
color: #444; | |||
padding-right: 0.5em; | |||
} | |||
td.fielddoc p { | |||
margin: 0; | |||
} | |||
/* @end */ | |||
@@ -411,9 +426,8 @@ table.memberdecls { | |||
/* these are for tree view when used as main index */ | |||
.directory { | |||
font-size: 9pt; | |||
font-weight: bold; | |||
margin: 5px; | |||
font-size: small; | |||
margin: 0.5em; | |||
} | |||
.directory h3 { | |||
@@ -482,7 +496,7 @@ address { | |||
table.doxtable { | |||
border-collapse: collapse; | |||
margin: 0.5ex; | |||
margin: 0.5em; | |||
} | |||
table.doxtable td,table.doxtable th { | |||
@@ -508,12 +522,13 @@ table.doxtable th { | |||
font-size: 13px; | |||
} | |||
div.navpath { | |||
padding: 0.25em; | |||
} | |||
.navpath ul { | |||
font-size: 11px; | |||
height: 30px; | |||
line-height: 30px; | |||
font-size: x-small; | |||
color: #8AA0CC; | |||
border: 1px solid #C2CDE4; | |||
overflow: hidden; | |||
margin: 0; | |||
padding: 0; | |||
@@ -528,7 +543,6 @@ table.doxtable th { | |||
} | |||
.navpath a { | |||
height: 32px; | |||
display: block; | |||
text-decoration: none; | |||
outline: none; | |||
@@ -540,8 +554,8 @@ table.doxtable th { | |||
div.summary { | |||
float: right; | |||
font-size: 8pt; | |||
padding-right: 5px; | |||
font-size: x-small; | |||
padding: 0.25em 0.5em 0 0; | |||
width: 50%; | |||
text-align: right; | |||
} | |||
@@ -553,11 +567,125 @@ div.summary a { | |||
div.header { | |||
background-color: #F3F3F3; | |||
margin: 0; | |||
border-bottom: 1px solid #DDD; | |||
border: 0; | |||
} | |||
div.headertitle { | |||
padding: 5px 5px 5px 10px; | |||
font-size: 180%; | |||
font-weight: bold; | |||
color: #FFF; | |||
padding: 0.125em 0.25em 0.125em 0.25em; | |||
background-color: #333; | |||
background: linear-gradient(to bottom, #333 0%, #111 100%); | |||
border: solid 1px #444; | |||
border-top: 0; | |||
border-radius: 0 0 6px 6px; | |||
} | |||
div.line { | |||
font-family: monospace, fixed; | |||
font-size: 13px; | |||
min-height: 13px; | |||
line-height: 1.0; | |||
text-wrap: avoid; | |||
white-space: pre-wrap; | |||
text-indent: -53px; | |||
padding-left: 53px; | |||
padding-bottom: 0; | |||
margin: 0; | |||
} | |||
.glow { | |||
background-color: cyan; | |||
box-shadow: 0 0 10px cyan; | |||
} | |||
span.lineno { | |||
padding-right: 4px; | |||
text-align: right; | |||
border-right: 2px solid #0F0; | |||
background-color: #E8E8E8; | |||
white-space: pre; | |||
} | |||
span.lineno a { | |||
background-color: #D8D8D8; | |||
} | |||
span.lineno a:hover { | |||
background-color: #C8C8C8; | |||
} | |||
.tabs, .tabs2, .navpath { | |||
background-image: none; | |||
background-color: #333; | |||
background: linear-gradient(to bottom, #333 0%, #111 100%); | |||
border: 0; | |||
border-bottom: solid 2px #000; | |||
padding: 0; | |||
padding-top: 2px; | |||
font-size: small; | |||
} | |||
#navrow1 { | |||
border: 0; | |||
} | |||
th { | |||
text-align: left; | |||
} | |||
.mlabel { | |||
padding: 0.125em; | |||
} | |||
/* tabs*/ | |||
.tablist { | |||
margin: 0; | |||
padding: 0; | |||
display: table; | |||
} | |||
.tablist li { | |||
display: table-cell; | |||
line-height: 2em; | |||
list-style: none; | |||
background-color: #333; | |||
background: linear-gradient(to bottom, #444 0%, #222 100%); | |||
border: 1px solid #222; | |||
border-bottom: 0; | |||
border-radius: 6px 6px 0 0; | |||
color: #DDD; | |||
} | |||
.tablist a { | |||
display: block; | |||
padding: 0 20px; | |||
font-weight: bold; | |||
color: #859900; | |||
text-decoration: none; | |||
outline: none; | |||
} | |||
.header a { | |||
color: #859900; | |||
} | |||
.tabs3 .tablist a { | |||
padding: 0 10px; | |||
} | |||
.tablist a:hover { | |||
color: #fff; | |||
text-shadow: 0 1px 1px rgba(0, 0, 0, 1.0); | |||
text-decoration: none; | |||
} | |||
.tablist li.current a { | |||
color: #fff; | |||
text-shadow: 0 1px 1px rgba(0, 0, 0, 1.0); | |||
} | |||
span.icon { | |||
display: none; | |||
} |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2014 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -67,8 +67,10 @@ extern "C" { | |||
#define LILV_NS_RDFS "http://www.w3.org/2000/01/rdf-schema#" | |||
#define LILV_NS_XSD "http://www.w3.org/2001/XMLSchema#" | |||
#define LILV_URI_ATOM_PORT "http://lv2plug.in/ns/ext/atom#AtomPort" | |||
#define LILV_URI_AUDIO_PORT "http://lv2plug.in/ns/lv2core#AudioPort" | |||
#define LILV_URI_CONTROL_PORT "http://lv2plug.in/ns/lv2core#ControlPort" | |||
#define LILV_URI_CV_PORT "http://lv2plug.in/ns/lv2core#CVPort" | |||
#define LILV_URI_EVENT_PORT "http://lv2plug.in/ns/ext/event#EventPort" | |||
#define LILV_URI_INPUT_PORT "http://lv2plug.in/ns/lv2core#InputPort" | |||
#define LILV_URI_MIDI_EVENT "http://lv2plug.in/ns/ext/midi#MidiEvent" | |||
@@ -578,8 +580,8 @@ lilv_world_load_all(LilvWorld* world, const char* lv2_path); | |||
other things) MUST be identified by URIs (not paths) in save files. | |||
*/ | |||
LILV_API void | |||
lilv_world_load_bundle(LilvWorld* world, | |||
LilvNode* bundle_uri); | |||
lilv_world_load_bundle(LilvWorld* world, | |||
const LilvNode* bundle_uri); | |||
/** | |||
Load all specifications from currently loaded bundles. | |||
@@ -606,11 +608,11 @@ lilv_world_load_plugin_classes(LilvWorld* world); | |||
This unloads statements loaded by lilv_world_load_bundle(). Note that this | |||
is not necessarily all information loaded from the bundle. If any resources | |||
have been separately loaded with liv_world_load_resource(), they must be | |||
have been separately loaded with lilv_world_load_resource(), they must be | |||
separately unloaded with lilv_world_unload_resource(). | |||
*/ | |||
LILV_API int | |||
lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri); | |||
lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri); | |||
/** | |||
Load all the data associated with the given `resource`. | |||
@@ -706,6 +708,16 @@ lilv_world_ask(LilvWorld* world, | |||
const LilvNode* predicate, | |||
const LilvNode* object); | |||
/** | |||
Get an LV2 symbol for some subject. | |||
This will return the lv2:symbol property of the subject if it is given | |||
explicitly, and otherwise will attempt to derive a symbol from the URI. | |||
@return A string node that is a valid LV2 symbol, or NULL on error. | |||
*/ | |||
LILV_API LilvNode* | |||
lilv_world_get_symbol(LilvWorld* world, const LilvNode* subject); | |||
/** | |||
@} | |||
@name Plugin | |||
@@ -751,7 +763,7 @@ lilv_plugin_get_uri(const LilvPlugin* plugin); | |||
Typical hosts should not need to use this function. | |||
Note this always returns a fully qualified URI. If you want a local | |||
filesystem path, use lilv_uri_to_path(). | |||
filesystem path, use lilv_file_uri_parse(). | |||
@return a shared string which must not be modified or freed. | |||
*/ | |||
LILV_API const LilvNode* | |||
@@ -761,7 +773,7 @@ lilv_plugin_get_bundle_uri(const LilvPlugin* plugin); | |||
Get the (resolvable) URIs of the RDF data files that define a plugin. | |||
Typical hosts should not need to use this function. | |||
Note this always returns fully qualified URIs. If you want local | |||
filesystem paths, use lilv_uri_to_path(). | |||
filesystem paths, use lilv_file_uri_parse(). | |||
@return a list of complete URLs eg. "file:///foo/ABundle.lv2/aplug.ttl", | |||
which is shared and must not be modified or freed. | |||
*/ | |||
@@ -771,7 +783,7 @@ lilv_plugin_get_data_uris(const LilvPlugin* plugin); | |||
/** | |||
Get the (resolvable) URI of the shared library for `plugin`. | |||
Note this always returns a fully qualified URI. If you want a local | |||
filesystem path, use lilv_uri_to_path(). | |||
filesystem path, use lilv_file_uri_parse(). | |||
@return a shared string which must not be modified or freed. | |||
*/ | |||
LILV_API const LilvNode* | |||
@@ -1381,6 +1393,28 @@ LILV_API void | |||
lilv_state_set_label(LilvState* state, | |||
const char* label); | |||
/** | |||
Set a metadata property on `state`. | |||
@param state The state to set the metadata for. | |||
@param key The key to store `value` under (URID). | |||
@param value Pointer to the value to be stored. | |||
@param size The size of `value` in bytes. | |||
@param type The type of `value` (URID). | |||
@param flags LV2_State_Flags for `value`. | |||
@return 0 on success. | |||
This is a generic version of lilv_state_set_label(), which sets metadata | |||
properties visible to hosts, but not plugins. This allows storing useful | |||
information such as comments or preset banks. | |||
*/ | |||
LILV_API int | |||
lilv_state_set_metadata(LilvState* state, | |||
uint32_t key, | |||
const void* value, | |||
size_t size, | |||
uint32_t type, | |||
uint32_t flags); | |||
/** | |||
Function to set a port value. | |||
@param port_symbol The symbol of the port. |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2015 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -26,14 +26,15 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
const LV2_Feature*const* features) | |||
{ | |||
lilv_plugin_load_if_necessary(plugin); | |||
if (plugin->parse_errors) { | |||
return NULL; | |||
} | |||
LilvInstance* result = NULL; | |||
const LilvNode* const lib_uri = lilv_plugin_get_library_uri(plugin); | |||
const LilvNode* const bundle_uri = lilv_plugin_get_bundle_uri(plugin); | |||
char* const bundle_path = lilv_file_uri_parse( | |||
lilv_node_as_uri(lilv_plugin_get_bundle_uri(plugin)), NULL); | |||
LilvInstance* result = NULL; | |||
const LilvNode* const lib_uri = lilv_plugin_get_library_uri(plugin); | |||
const LilvNode* const bundle_uri = lilv_plugin_get_bundle_uri(plugin); | |||
char* const bundle_path = lilv_file_uri_parse( | |||
lilv_node_as_uri(bundle_uri), NULL); | |||
LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features); | |||
if (!lib) { | |||
@@ -41,15 +42,6 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
return NULL; | |||
} | |||
// Parse bundle URI to use as base URI | |||
const char* bundle_uri_str = lilv_node_as_uri(bundle_uri); | |||
SerdURI base_uri; | |||
if (serd_uri_parse((const uint8_t*)bundle_uri_str, &base_uri)) { | |||
lilv_lib_close(lib); | |||
lilv_free(bundle_path); | |||
return NULL; | |||
} | |||
const LV2_Feature** local_features = NULL; | |||
if (features == NULL) { | |||
local_features = (const LV2_Feature**)malloc(sizeof(LV2_Feature*)); | |||
@@ -67,18 +59,7 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
break; // return NULL | |||
} | |||
// Resolve library plugin URI against base URI | |||
SerdURI abs_uri; | |||
SerdNode abs_uri_node = serd_node_new_uri_from_string( | |||
(const uint8_t*)ld->URI, &base_uri, &abs_uri); | |||
if (!abs_uri_node.buf) { | |||
LILV_ERRORF("Failed to parse plugin URI `%s'\n", ld->URI); | |||
lilv_lib_close(lib); | |||
break; | |||
} | |||
if (!strcmp((const char*)abs_uri_node.buf, | |||
lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) { | |||
if (!strcmp(ld->URI, lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) { | |||
// Create LilvInstance to return | |||
result = (LilvInstance*)malloc(sizeof(LilvInstance)); | |||
result->lv2_descriptor = ld; | |||
@@ -86,10 +67,7 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
ld, sample_rate, bundle_path, | |||
(features) ? features : local_features); | |||
result->pimpl = lib; | |||
serd_node_free(&abs_uri_node); | |||
break; | |||
} else { | |||
serd_node_free(&abs_uri_node); | |||
} | |||
} | |||
@@ -97,15 +75,17 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
lilv_free(bundle_path); | |||
if (result) { | |||
// Failed to instantiate | |||
if (result->lv2_handle == NULL) { | |||
// Failed to instantiate | |||
free(result); | |||
lilv_lib_close(lib); | |||
return NULL; | |||
} | |||
// "Connect" all ports to NULL (catches bugs) | |||
for (uint32_t i = 0; i < lilv_plugin_get_num_ports(plugin); ++i) | |||
for (uint32_t i = 0; i < lilv_plugin_get_num_ports(plugin); ++i) { | |||
result->lv2_descriptor->connect_port(result->lv2_handle, i, NULL); | |||
} | |||
} | |||
return result; |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Copyright 2012-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -56,7 +56,8 @@ lilv_lib_open(LilvWorld* world, | |||
if (ldf) { | |||
desc = ldf(bundle_path, features); | |||
if (!desc) { | |||
LILV_ERRORF("Call to `lv2_lib_descriptor' in %s failed\n", lib_path); | |||
LILV_ERRORF("Call to %s:lv2_lib_descriptor failed\n", lib_path); | |||
dlclose(lib); | |||
lilv_free(lib_path); | |||
return NULL; | |||
} | |||
@@ -87,8 +88,7 @@ lilv_lib_get_plugin(LilvLib* lib, uint32_t index) | |||
{ | |||
if (lib->lv2_descriptor) { | |||
return lib->lv2_descriptor(index); | |||
} | |||
if (lib->desc) { | |||
} else if (lib->desc) { | |||
return lib->desc->get_plugin(lib->desc->handle, index); | |||
} | |||
return NULL; |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2014 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -43,7 +43,7 @@ extern "C" { | |||
#ifndef NAN | |||
# define NAN INFINITY - INFINITY | |||
#endif | |||
static inline char* dlerror(void) { return "Unknown error"; } | |||
static inline const char* dlerror(void) { return "Unknown error"; } | |||
#else | |||
# include <dlfcn.h> | |||
# include <unistd.h> | |||
@@ -127,6 +127,7 @@ struct LilvPluginImpl { | |||
LilvPort** ports; | |||
uint32_t num_ports; | |||
bool loaded; | |||
bool parse_errors; | |||
bool replaced; | |||
}; | |||
@@ -156,6 +157,7 @@ struct LilvWorldImpl { | |||
LilvPluginClasses* plugin_classes; | |||
LilvSpec* specs; | |||
LilvPlugins* plugins; | |||
LilvPlugins* zombies; | |||
LilvNodes* loaded_files; | |||
ZixTree* libs; | |||
struct { | |||
@@ -172,7 +174,9 @@ struct LilvWorldImpl { | |||
SordNode* lv2_index; | |||
SordNode* lv2_latency; | |||
SordNode* lv2_maximum; | |||
SordNode* lv2_microVersion; | |||
SordNode* lv2_minimum; | |||
SordNode* lv2_minorVersion; | |||
SordNode* lv2_name; | |||
SordNode* lv2_optionalFeature; | |||
SordNode* lv2_port; | |||
@@ -181,6 +185,8 @@ struct LilvWorldImpl { | |||
SordNode* lv2_requiredFeature; | |||
SordNode* lv2_symbol; | |||
SordNode* lv2_prototype; | |||
SordNode* mod_builderVersion; | |||
SordNode* mod_releaseNumber; | |||
SordNode* owl_Ontology; | |||
SordNode* pset_value; | |||
SordNode* rdf_a; | |||
@@ -233,6 +239,13 @@ struct LilvUIImpl { | |||
LilvNodes* classes; | |||
}; | |||
typedef struct LilvVersion { | |||
int builder; | |||
int minor; | |||
int micro; | |||
int release; | |||
} LilvVersion; | |||
/* | |||
* | |||
* Functions | |||
@@ -248,6 +261,7 @@ void lilv_port_free(const LilvPlugin* plugin, LilvPort* port); | |||
LilvPlugin* lilv_plugin_new(LilvWorld* world, | |||
LilvNode* uri, | |||
LilvNode* bundle_uri); | |||
void lilv_plugin_clear(LilvPlugin* plugin, LilvNode* bundle_uri); | |||
void lilv_plugin_load_if_necessary(const LilvPlugin* p); | |||
void lilv_plugin_free(LilvPlugin* plugin); | |||
LilvNode* lilv_plugin_get_unique(const LilvPlugin* p, | |||
@@ -282,7 +296,8 @@ LilvScalePoints* lilv_scale_points_new(void); | |||
LilvPluginClasses* lilv_plugin_classes_new(void); | |||
LilvUIs* lilv_uis_new(void); | |||
LilvNode* lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri); | |||
LilvNode* lilv_world_get_manifest_uri(LilvWorld* world, | |||
const LilvNode* bundle_uri); | |||
const uint8_t* lilv_world_blank_node_prefix(LilvWorld* world); | |||
@@ -311,6 +326,55 @@ int lilv_lib_compare(const void* a, const void* b, void* user_data); | |||
int lilv_ptr_cmp(const void* a, const void* b, void* user_data); | |||
int lilv_resource_node_cmp(const void* a, const void* b, void* user_data); | |||
static inline int | |||
lilv_version_cmp(const LilvVersion* a, const LilvVersion* b) | |||
{ | |||
if (a->minor == b->minor && a->micro == b->micro) { | |||
return 0; | |||
} else if ((a->minor < b->minor) | |||
|| (a->minor == b->minor && a->micro < b->micro)) { | |||
return -1; | |||
} else { | |||
return 1; | |||
} | |||
} | |||
static inline int | |||
lilv_version_cmp_mod(const LilvVersion* a, const LilvVersion* b) | |||
{ | |||
// same version | |||
if (a->builder == b->builder && a->minor == b->minor | |||
&& a->micro == b->micro && a->release == b->release) | |||
return 0; | |||
// check builder | |||
if (a->builder < b->builder) | |||
return -1; | |||
if (a->builder > b->builder) | |||
return 1; | |||
// check minor | |||
if (a->minor < b->minor) | |||
return -1; | |||
if (a->minor > b->minor) | |||
return 1; | |||
// check micro | |||
if (a->micro < b->micro) | |||
return -1; | |||
if (a->micro > b->micro) | |||
return 1; | |||
// check release | |||
if (a->release < b->release) | |||
return -1; | |||
if (a->release > b->release) | |||
return 1; | |||
// huh!? | |||
return 0; | |||
} | |||
struct LilvHeader* | |||
lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri); | |||
@@ -405,6 +469,10 @@ static const LV2_Feature* const dman_features = { NULL }; | |||
__func__) | |||
#define LILV_WARNF(fmt, ...) fprintf(stderr, "%s(): warning: " fmt, \ | |||
__func__, __VA_ARGS__) | |||
#define LILV_NOTE(str) fprintf(stderr, "%s(): note: " str, \ | |||
__func__) | |||
#define LILV_NOTEF(fmt, ...) fprintf(stderr, "%s(): note: " fmt, \ | |||
__func__, __VA_ARGS__) | |||
#ifdef __cplusplus | |||
} |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2015 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -15,16 +15,16 @@ | |||
*/ | |||
#include <math.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "lilv_internal.h" | |||
static void | |||
lilv_node_set_numerics_from_string(LilvNode* val, size_t len) | |||
lilv_node_set_numerics_from_string(LilvNode* val) | |||
{ | |||
const char* str = (const char*)sord_node_get_string(val->node); | |||
char* endptr; | |||
switch (val->type) { | |||
case LILV_VALUE_URI: | |||
@@ -33,10 +33,10 @@ lilv_node_set_numerics_from_string(LilvNode* val, size_t len) | |||
case LILV_VALUE_BLOB: | |||
break; | |||
case LILV_VALUE_INT: | |||
val->val.int_val = strtol(str, &endptr, 10); | |||
val->val.int_val = strtol(str, NULL, 10); | |||
break; | |||
case LILV_VALUE_FLOAT: | |||
val->val.float_val = serd_strtod(str, &endptr); | |||
val->val.float_val = serd_strtod(str, NULL); | |||
break; | |||
case LILV_VALUE_BOOL: | |||
val->val.bool_val = !strcmp(str, "true"); | |||
@@ -104,7 +104,6 @@ lilv_node_new_from_node(LilvWorld* world, const SordNode* node) | |||
LilvNode* result = NULL; | |||
SordNode* datatype_uri = NULL; | |||
LilvNodeType type = LILV_VALUE_STRING; | |||
size_t len = 0; | |||
switch (sord_node_get_type(node)) { | |||
case SORD_URI: | |||
@@ -137,8 +136,8 @@ lilv_node_new_from_node(LilvWorld* world, const SordNode* node) | |||
sord_node_get_string(datatype_uri)); | |||
} | |||
result = lilv_node_new( | |||
world, type, (const char*)sord_node_get_string_counted(node, &len)); | |||
lilv_node_set_numerics_from_string(result, len); | |||
world, type, (const char*)sord_node_get_string(node)); | |||
lilv_node_set_numerics_from_string(result); | |||
break; | |||
} | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2014 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -33,14 +33,9 @@ | |||
#define NS_FOAF (const uint8_t*)"http://xmlns.com/foaf/0.1/" | |||
#define NS_MOD (const uint8_t*)"http://moddevices.com/ns/modgui#" | |||
/** Ownership of `uri` is taken */ | |||
LilvPlugin* | |||
lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri) | |||
static void | |||
lilv_plugin_init(LilvPlugin* plugin, LilvNode* bundle_uri) | |||
{ | |||
assert(bundle_uri); | |||
LilvPlugin* plugin = (LilvPlugin*)malloc(sizeof(LilvPlugin)); | |||
plugin->world = world; | |||
plugin->plugin_uri = uri; | |||
plugin->bundle_uri = bundle_uri; | |||
plugin->binary_uri = NULL; | |||
#ifdef LILV_DYN_MANIFEST | |||
@@ -51,11 +46,32 @@ lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri) | |||
plugin->ports = NULL; | |||
plugin->num_ports = 0; | |||
plugin->loaded = false; | |||
plugin->parse_errors = false; | |||
plugin->replaced = false; | |||
} | |||
/** Ownership of `uri` and `bundle` is taken */ | |||
LilvPlugin* | |||
lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri) | |||
{ | |||
LilvPlugin* plugin = (LilvPlugin*)malloc(sizeof(LilvPlugin)); | |||
plugin->world = world; | |||
plugin->plugin_uri = uri; | |||
lilv_plugin_init(plugin, bundle_uri); | |||
return plugin; | |||
} | |||
void | |||
lilv_plugin_clear(LilvPlugin* plugin, LilvNode* bundle_uri) | |||
{ | |||
lilv_node_free(plugin->bundle_uri); | |||
lilv_node_free(plugin->binary_uri); | |||
lilv_nodes_free(plugin->data_uris); | |||
lilv_plugin_init(plugin, bundle_uri); | |||
} | |||
static void | |||
lilv_plugin_free_ports(LilvPlugin* p) | |||
{ | |||
@@ -113,7 +129,8 @@ lilv_plugin_get_one(const LilvPlugin* p, | |||
SordIter* stream = lilv_world_query_internal( | |||
p->world, subject, predicate, NULL); | |||
if (!sord_iter_end(stream)) { | |||
ret = lilv_node_new_from_node(p->world, sord_iter_get_node(stream, SORD_OBJECT)); | |||
ret = lilv_node_new_from_node(p->world, | |||
sord_iter_get_node(stream, SORD_OBJECT)); | |||
} | |||
sord_iter_free(stream); | |||
return ret; | |||
@@ -126,7 +143,7 @@ lilv_plugin_get_unique(const LilvPlugin* p, | |||
{ | |||
LilvNode* ret = lilv_plugin_get_one(p, subject, predicate); | |||
if (!ret) { | |||
LILV_ERRORF("Multiple values found for (%s %s ...) property\n", | |||
LILV_ERRORF("No value found for (%s %s ...) property\n", | |||
sord_node_get_string(subject), | |||
sord_node_get_string(predicate)); | |||
} | |||
@@ -143,13 +160,13 @@ lilv_plugin_load(LilvPlugin* p) | |||
SerdReader* reader = sord_new_reader(p->world->model, env, SERD_TURTLE, | |||
bundle_uri_node); | |||
SordModel* prototypes = lilv_world_filter_model(p->world, | |||
p->world->model, | |||
p->plugin_uri->node, | |||
p->world->uris.lv2_prototype, | |||
NULL, NULL); | |||
SordModel* prots = lilv_world_filter_model(p->world, | |||
p->world->model, | |||
p->plugin_uri->node, | |||
p->world->uris.lv2_prototype, | |||
NULL, NULL); | |||
SordModel* skel = sord_new(p->world->world, SORD_SPO, false); | |||
SordIter* iter = sord_begin(prototypes); | |||
SordIter* iter = sord_begin(prots); | |||
for (; !sord_iter_end(iter); sord_iter_next(iter)) { | |||
const SordNode* t = sord_iter_get_node(iter, SORD_OBJECT); | |||
LilvNode* prototype = lilv_node_new_from_node(p->world, t); | |||
@@ -177,14 +194,26 @@ lilv_plugin_load(LilvPlugin* p) | |||
} | |||
sord_iter_free(iter); | |||
sord_free(skel); | |||
sord_free(prototypes); | |||
sord_free(prots); | |||
// Parse all the plugin's data files into RDF model | |||
SerdStatus st = SERD_SUCCESS; | |||
LILV_FOREACH(nodes, i, p->data_uris) { | |||
const LilvNode* data_uri = lilv_nodes_get(p->data_uris, i); | |||
serd_env_set_base_uri(env, sord_node_to_serd_node(data_uri->node)); | |||
lilv_world_load_file(p->world, reader, data_uri); | |||
st = lilv_world_load_file(p->world, reader, data_uri); | |||
if (st > SERD_FAILURE) { | |||
break; | |||
} | |||
} | |||
if (st > SERD_FAILURE) { | |||
p->loaded = true; | |||
p->parse_errors = true; | |||
serd_reader_free(reader); | |||
serd_env_free(env); | |||
return; | |||
} | |||
#ifdef LILV_DYN_MANIFEST | |||
@@ -235,8 +264,8 @@ static void | |||
lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) | |||
{ | |||
LilvPlugin* p = (LilvPlugin*)const_p; | |||
if (!p->loaded) | |||
lilv_plugin_load(p); | |||
lilv_plugin_load_if_necessary(p); | |||
if (!p->ports) { | |||
p->ports = (LilvPort**)malloc(sizeof(LilvPort*)); | |||
@@ -255,21 +284,24 @@ lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) | |||
LilvNode* symbol = lilv_plugin_get_unique( | |||
p, port, p->world->uris.lv2_symbol); | |||
bool error = false; | |||
if (!lilv_node_is_string(symbol) || | |||
!is_symbol((const char*)sord_node_get_string(symbol->node))) { | |||
LILV_ERRORF("Plugin <%s> port symbol `%s' is invalid\n", | |||
lilv_node_as_uri(p->plugin_uri), | |||
lilv_node_as_string(symbol)); | |||
error = true; | |||
goto done; | |||
lilv_node_free(symbol); | |||
lilv_node_free(index); | |||
lilv_plugin_free_ports(p); | |||
break; | |||
} | |||
if (!lilv_node_is_int(index)) { | |||
LILV_ERRORF("Plugin <%s> port index is not an integer\n", | |||
lilv_node_as_uri(p->plugin_uri)); | |||
error = true; | |||
goto done; | |||
lilv_node_free(symbol); | |||
lilv_node_free(index); | |||
lilv_plugin_free_ports(p); | |||
break; | |||
} | |||
uint32_t this_index = lilv_node_as_int(index); | |||
@@ -308,13 +340,8 @@ lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) | |||
} | |||
sord_iter_free(types); | |||
done: | |||
lilv_node_free(symbol); | |||
lilv_node_free(index); | |||
if (error) { // Invalid plugin | |||
lilv_plugin_free_ports(p); | |||
break; | |||
} | |||
} | |||
sord_iter_free(ports); | |||
@@ -389,12 +416,12 @@ lilv_plugin_get_class(const LilvPlugin* const_p) | |||
lilv_plugin_load_if_necessary(p); | |||
if (!p->plugin_class) { | |||
// <plugin> a ?class | |||
SordIter* results = lilv_world_query_internal(p->world, | |||
p->plugin_uri->node, | |||
p->world->uris.rdf_a, | |||
NULL); | |||
FOREACH_MATCH(results) { | |||
const SordNode* class_node = sord_iter_get_node(results, SORD_OBJECT); | |||
SordIter* c = lilv_world_query_internal(p->world, | |||
p->plugin_uri->node, | |||
p->world->uris.rdf_a, | |||
NULL); | |||
FOREACH_MATCH(c) { | |||
const SordNode* class_node = sord_iter_get_node(c, SORD_OBJECT); | |||
if (sord_node_get_type(class_node) != SORD_URI) { | |||
continue; | |||
} | |||
@@ -413,7 +440,7 @@ lilv_plugin_get_class(const LilvPlugin* const_p) | |||
lilv_node_free(klass); | |||
} | |||
sord_iter_free(results); | |||
sord_iter_free(c); | |||
if (p->plugin_class == NULL) | |||
p->plugin_class = p->world->lv2_plugin_class; | |||
@@ -433,6 +460,11 @@ lilv_plugin_get_value_internal(const LilvPlugin* p, | |||
LILV_API bool | |||
lilv_plugin_verify(const LilvPlugin* plugin) | |||
{ | |||
lilv_plugin_load_if_necessary(plugin); | |||
if (plugin->parse_errors) { | |||
return false; | |||
} | |||
LilvNode* rdf_type = lilv_new_uri(plugin->world, LILV_NS_RDF "type"); | |||
LilvNodes* results = lilv_plugin_get_value(plugin, rdf_type); | |||
lilv_node_free(rdf_type); | |||
@@ -867,46 +899,36 @@ lilv_plugin_get_author(const LilvPlugin* p) | |||
return author; | |||
} | |||
LILV_API LilvNode* | |||
lilv_plugin_get_author_name(const LilvPlugin* plugin) | |||
static LilvNode* | |||
lilv_plugin_get_author_property(const LilvPlugin* plugin, const uint8_t* uri) | |||
{ | |||
const SordNode* author = lilv_plugin_get_author(plugin); | |||
if (author) { | |||
SordWorld* sworld = plugin->world->world; | |||
SordNode* foaf_name = sord_new_uri(sworld, NS_FOAF "name"); | |||
LilvNode* ret = lilv_plugin_get_one(plugin, author, foaf_name); | |||
sord_node_free(sworld, foaf_name); | |||
SordWorld* sworld = plugin->world->world; | |||
SordNode* pred = sord_new_uri(sworld, uri); | |||
LilvNode* ret = lilv_plugin_get_one(plugin, author, pred); | |||
sord_node_free(sworld, pred); | |||
return ret; | |||
} | |||
return NULL; | |||
} | |||
LILV_API LilvNode* | |||
lilv_plugin_get_author_name(const LilvPlugin* plugin) | |||
{ | |||
return lilv_plugin_get_author_property(plugin, NS_FOAF "name"); | |||
} | |||
LILV_API LilvNode* | |||
lilv_plugin_get_author_email(const LilvPlugin* plugin) | |||
{ | |||
const SordNode* author = lilv_plugin_get_author(plugin); | |||
if (author) { | |||
SordWorld* sworld = plugin->world->world; | |||
SordNode* foaf_mbox = sord_new_uri(sworld, NS_FOAF "mbox"); | |||
LilvNode* ret = lilv_plugin_get_one(plugin, author, foaf_mbox); | |||
sord_node_free(sworld, foaf_mbox); | |||
return ret; | |||
} | |||
return NULL; | |||
return lilv_plugin_get_author_property(plugin, NS_FOAF "mbox"); | |||
} | |||
LILV_API LilvNode* | |||
lilv_plugin_get_author_homepage(const LilvPlugin* plugin) | |||
{ | |||
const SordNode* author = lilv_plugin_get_author(plugin); | |||
if (author) { | |||
SordWorld* sworld = plugin->world->world; | |||
SordNode* foaf_homepage = sord_new_uri(sworld, NS_FOAF "homepage"); | |||
LilvNode* ret = lilv_plugin_get_one(plugin, author, foaf_homepage); | |||
sord_node_free(sworld, foaf_homepage); | |||
return ret; | |||
} | |||
return NULL; | |||
return lilv_plugin_get_author_property(plugin, NS_FOAF "homepage"); | |||
} | |||
static const SordNode* | |||
@@ -1060,7 +1082,10 @@ lilv_plugin_get_uis(const LilvPlugin* p) | |||
const SordNode* ui = sord_iter_get_node(uis, SORD_OBJECT); | |||
LilvNode* type = lilv_plugin_get_unique(p, ui, p->world->uris.rdf_a); | |||
LilvNode* binary = lilv_plugin_get_unique(p, ui, ui_binary_node); | |||
LilvNode* binary = lilv_plugin_get_one(p, ui, p->world->uris.lv2_binary); | |||
if (!binary) { | |||
binary = lilv_plugin_get_unique(p, ui, ui_binary_node); | |||
} | |||
if (sord_node_get_type(ui) != SORD_URI | |||
|| !lilv_node_is_uri(type) |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2015 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -49,21 +49,26 @@ typedef struct { | |||
char* rel; ///< Abstract path (relative path in state dir) | |||
} PathMap; | |||
typedef struct { | |||
size_t n; | |||
Property* props; | |||
} PropertyArray; | |||
struct LilvStateImpl { | |||
LilvNode* plugin_uri; ///< Plugin URI | |||
LilvNode* uri; ///< State/preset URI | |||
char* dir; ///< Save directory (if saved) | |||
char* file_dir; ///< Directory for files created by plugin | |||
char* copy_dir; ///< Directory for snapshots of external files | |||
char* link_dir; ///< Directory for links to external files | |||
char* label; ///< State/Preset label | |||
ZixTree* abs2rel; ///< PathMap sorted by abs | |||
ZixTree* rel2abs; ///< PathMap sorted by rel | |||
Property* props; ///< State properties | |||
PortValue* values; ///< Port values | |||
uint32_t atom_Path; ///< atom:Path URID | |||
uint32_t num_props; ///< Number of state properties | |||
uint32_t num_values; ///< Number of port values | |||
LilvNode* plugin_uri; ///< Plugin URI | |||
LilvNode* uri; ///< State/preset URI | |||
char* dir; ///< Save directory (if saved) | |||
char* file_dir; ///< Directory for files created by plugin | |||
char* copy_dir; ///< Directory for snapshots of external files | |||
char* link_dir; ///< Directory for links to external files | |||
char* label; ///< State/Preset label | |||
ZixTree* abs2rel; ///< PathMap sorted by abs | |||
ZixTree* rel2abs; ///< PathMap sorted by rel | |||
PropertyArray props; ///< State properties | |||
PropertyArray metadata; ///< State metadata | |||
PortValue* values; ///< Port values | |||
uint32_t atom_Path; ///< atom:Path URID | |||
uint32_t n_values; ///< Number of port values | |||
}; | |||
static int | |||
@@ -106,18 +111,18 @@ append_port_value(LilvState* state, | |||
uint32_t size, | |||
uint32_t type) | |||
{ | |||
PortValue* pv = NULL; | |||
if (value) { | |||
state->values = (PortValue*)realloc( | |||
state->values, (++state->num_values) * sizeof(PortValue)); | |||
PortValue* pv = &state->values[state->num_values - 1]; | |||
state->values, (++state->n_values) * sizeof(PortValue)); | |||
pv = &state->values[state->n_values - 1]; | |||
pv->symbol = lilv_strdup(port_symbol); | |||
pv->value = malloc(size); | |||
pv->size = size; | |||
pv->type = type; | |||
memcpy(pv->value, value, size); | |||
return pv; | |||
} | |||
return NULL; | |||
return pv; | |||
} | |||
static const char* | |||
@@ -131,24 +136,23 @@ lilv_state_rel2abs(const LilvState* state, const char* path) | |||
return path; | |||
} | |||
static LV2_State_Status | |||
store_callback(LV2_State_Handle handle, | |||
uint32_t key, | |||
const void* value, | |||
size_t size, | |||
uint32_t type, | |||
uint32_t flags) | |||
static void | |||
append_property(LilvState* state, | |||
PropertyArray* array, | |||
uint32_t key, | |||
const void* value, | |||
size_t size, | |||
uint32_t type, | |||
uint32_t flags) | |||
{ | |||
LilvState* const state = (LilvState*)handle; | |||
state->props = (Property*)realloc( | |||
state->props, (++state->num_props) * sizeof(Property)); | |||
Property* const prop = &state->props[state->num_props - 1]; | |||
array->props = (Property*)realloc( | |||
array->props, (++array->n) * sizeof(Property)); | |||
Property* const prop = &array->props[array->n - 1]; | |||
if ((flags & LV2_STATE_IS_POD) || type == state->atom_Path) { | |||
prop->value = malloc(size); | |||
memcpy(prop->value, value, size); | |||
} else { | |||
LILV_WARN("Storing non-POD value\n"); | |||
prop->value = (void*)value; | |||
} | |||
@@ -156,7 +160,18 @@ store_callback(LV2_State_Handle handle, | |||
prop->key = key; | |||
prop->type = type; | |||
prop->flags = flags; | |||
} | |||
static LV2_State_Status | |||
store_callback(LV2_State_Handle handle, | |||
uint32_t key, | |||
const void* value, | |||
size_t size, | |||
uint32_t type, | |||
uint32_t flags) | |||
{ | |||
LilvState* const state = (LilvState*)handle; | |||
append_property(state, &state->props, key, value, size, type, flags); | |||
return LV2_STATE_SUCCESS; | |||
} | |||
@@ -170,7 +185,7 @@ retrieve_callback(LV2_State_Handle handle, | |||
const LilvState* const state = (LilvState*)handle; | |||
const Property search_key = { NULL, 0, key, 0, 0 }; | |||
const Property* const prop = (Property*)bsearch( | |||
&search_key, state->props, state->num_props, | |||
&search_key, state->props.props, state->props.n, | |||
sizeof(Property), property_cmp); | |||
if (prop) { | |||
@@ -230,6 +245,7 @@ abstract_path(LV2_State_Map_Path_Handle handle, | |||
char* copy = lilv_get_latest_copy(real_path, cpath); | |||
if (!copy || !lilv_file_equals(real_path, copy)) { | |||
// No recent enough copy, make a new one | |||
free(copy); | |||
copy = lilv_find_free_path(cpath, lilv_path_exists, NULL); | |||
const int st = lilv_copy_file(real_path, copy); | |||
if (st) { | |||
@@ -388,15 +404,15 @@ lilv_state_new_from_instance(const LilvPlugin* plugin, | |||
instance->lv2_handle, store_callback, state, flags, features); | |||
if (st) { | |||
LILV_ERRORF("Error saving plugin state: %s\n", state_strerror(st)); | |||
free(state->props); | |||
state->props = NULL; | |||
state->num_props = 0; | |||
free(state->props.props); | |||
state->props.props = NULL; | |||
state->props.n = 0; | |||
} else { | |||
qsort(state->props, state->num_props, sizeof(Property), property_cmp); | |||
qsort(state->props.props, state->props.n, sizeof(Property), property_cmp); | |||
} | |||
} | |||
qsort(state->values, state->num_values, sizeof(PortValue), value_cmp); | |||
qsort(state->values, state->n_values, sizeof(PortValue), value_cmp); | |||
free(sfeatures); | |||
return state; | |||
@@ -407,7 +423,7 @@ lilv_state_emit_port_values(const LilvState* state, | |||
LilvSetPortValueFunc set_value, | |||
void* user_data) | |||
{ | |||
for (uint32_t i = 0; i < state->num_values; ++i) { | |||
for (uint32_t i = 0; i < state->n_values; ++i) { | |||
const PortValue* val = &state->values[i]; | |||
set_value(val->symbol, user_data, val->value, val->size, val->type); | |||
} | |||
@@ -422,7 +438,7 @@ lilv_state_restore(const LilvState* state, | |||
uint32_t flags, | |||
const LV2_Feature *const * features) | |||
{ | |||
if (iface) { | |||
if (iface && iface->restore) { | |||
iface->restore(handle, retrieve_callback, | |||
(LV2_State_Handle)state, flags, features); | |||
} | |||
@@ -477,7 +493,7 @@ new_state_from_model(LilvWorld* world, | |||
const SordNode* object = sord_iter_get_node(i, SORD_OBJECT); | |||
const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH); | |||
state->label = lilv_strdup((const char*)sord_node_get_string(object)); | |||
if (!state->dir) { | |||
if (!state->dir && graph) { | |||
state->dir = lilv_strdup((const char*)sord_node_get_string(graph)); | |||
} | |||
sord_iter_free(i); | |||
@@ -531,8 +547,9 @@ new_state_from_model(LilvWorld* world, | |||
if (state_node) { | |||
SordIter* props = sord_search(model, state_node, 0, 0, 0); | |||
FOREACH_MATCH(props) { | |||
const SordNode* p = sord_iter_get_node(props, SORD_PREDICATE); | |||
const SordNode* o = sord_iter_get_node(props, SORD_OBJECT); | |||
const SordNode* p = sord_iter_get_node(props, SORD_PREDICATE); | |||
const SordNode* o = sord_iter_get_node(props, SORD_OBJECT); | |||
const char* key = (const char*)sord_node_get_string(p); | |||
chunk.len = 0; | |||
lv2_atom_forge_set_sink( | |||
@@ -543,19 +560,19 @@ new_state_from_model(LilvWorld* world, | |||
uint32_t flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; | |||
Property prop = { NULL, 0, 0, 0, flags }; | |||
prop.key = map->map(map->handle, (const char*)sord_node_get_string(p)); | |||
prop.key = map->map(map->handle, key); | |||
prop.type = atom->type; | |||
prop.size = atom->size; | |||
prop.value = malloc(atom->size); | |||
memcpy(prop.value, LV2_ATOM_BODY_CONST(atom), atom->size); | |||
if (atom->type == forge.Path) { | |||
prop.flags = LV2_STATE_IS_PORTABLE; | |||
prop.flags = LV2_STATE_IS_POD; | |||
} | |||
if (prop.value) { | |||
state->props = (Property*)realloc( | |||
state->props, (++state->num_props) * sizeof(Property)); | |||
state->props[state->num_props - 1] = prop; | |||
state->props.props = (Property*)realloc( | |||
state->props.props, (++state->props.n) * sizeof(Property)); | |||
state->props.props[state->props.n - 1] = prop; | |||
} | |||
} | |||
sord_iter_free(props); | |||
@@ -566,8 +583,12 @@ new_state_from_model(LilvWorld* world, | |||
free((void*)chunk.buf); | |||
sratom_free(sratom); | |||
qsort(state->props, state->num_props, sizeof(Property), property_cmp); | |||
qsort(state->values, state->num_values, sizeof(PortValue), value_cmp); | |||
if (state->props.props) { | |||
qsort(state->props.props, state->props.n, sizeof(Property), property_cmp); | |||
} | |||
if (state->values) { | |||
qsort(state->values, state->n_values, sizeof(PortValue), value_cmp); | |||
} | |||
return state; | |||
} | |||
@@ -683,7 +704,9 @@ ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env) | |||
SerdWriter* writer = serd_writer_new( | |||
SERD_TURTLE, | |||
(SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED), | |||
(SerdStyle)(SERD_STYLE_RESOLVED | | |||
SERD_STYLE_ABBREVIATED| | |||
SERD_STYLE_CURIED), | |||
env, | |||
&base_uri, | |||
sink, | |||
@@ -839,6 +862,37 @@ link_exists(const char* path, void* data) | |||
return !matches; | |||
} | |||
static void | |||
write_property_array(const LilvState* state, | |||
const PropertyArray* array, | |||
Sratom* sratom, | |||
uint32_t flags, | |||
const SerdNode* subject, | |||
LV2_URID_Unmap* unmap, | |||
const char* dir) | |||
{ | |||
for (uint32_t i = 0; i < array->n; ++i) { | |||
Property* prop = &array->props[i]; | |||
const char* key = unmap->unmap(unmap->handle, prop->key); | |||
const SerdNode p = serd_node_from_string(SERD_URI, USTR(key)); | |||
if (prop->type == state->atom_Path && !dir) { | |||
const char* path = (const char*)prop->value; | |||
const char* abs_path = lilv_state_rel2abs(state, path); | |||
LILV_WARNF("Writing absolute path %s\n", abs_path); | |||
sratom_write(sratom, unmap, flags, | |||
subject, &p, prop->type, | |||
strlen(abs_path) + 1, abs_path); | |||
} else if (prop->flags & LV2_STATE_IS_POD || | |||
prop->type == state->atom_Path) { | |||
sratom_write(sratom, unmap, flags, | |||
subject, &p, prop->type, prop->size, prop->value); | |||
} else { | |||
LILV_WARNF("Lost non-POD property <%s> on save\n", key); | |||
} | |||
} | |||
} | |||
static int | |||
lilv_state_write(LilvWorld* world, | |||
LV2_URID_Map* map, | |||
@@ -885,11 +939,14 @@ lilv_state_write(LilvWorld* world, | |||
(SerdEndSink)serd_writer_end_anon, | |||
writer); | |||
// Write port values as pretty numbers | |||
sratom_set_pretty_numbers(sratom, true); | |||
// Write metadata | |||
sratom_set_pretty_numbers(sratom, false); // Use precise types | |||
write_property_array(state, &state->metadata, sratom, 0, | |||
&subject, unmap, dir); | |||
// Write port values | |||
for (uint32_t i = 0; i < state->num_values; ++i) { | |||
sratom_set_pretty_numbers(sratom, true); // Use pretty numbers | |||
for (uint32_t i = 0; i < state->n_values; ++i) { | |||
PortValue* const value = &state->values[i]; | |||
const SerdNode port = serd_node_from_string( | |||
@@ -914,35 +971,19 @@ lilv_state_write(LilvWorld* world, | |||
serd_writer_end_anon(writer, &port); | |||
} | |||
// Write property values with precise types | |||
sratom_set_pretty_numbers(sratom, false); | |||
// Write properties | |||
const SerdNode state_node = serd_node_from_string(SERD_BLANK, | |||
USTR("2state")); | |||
if (state->num_props > 0) { | |||
const SerdNode body = serd_node_from_string(SERD_BLANK, USTR("body")); | |||
if (state->props.n > 0) { | |||
p = serd_node_from_string(SERD_URI, USTR(LV2_STATE__state)); | |||
serd_writer_write_statement(writer, SERD_ANON_O_BEGIN, NULL, | |||
&subject, &p, &state_node, NULL, NULL); | |||
&subject, &p, &body, NULL, NULL); | |||
} | |||
for (uint32_t i = 0; i < state->num_props; ++i) { | |||
Property* prop = &state->props[i]; | |||
const char* key = unmap->unmap(unmap->handle, prop->key); | |||
sratom_set_pretty_numbers(sratom, false); // Use precise types | |||
write_property_array(state, &state->props, sratom, SERD_ANON_CONT, | |||
&body, unmap, dir); | |||
p = serd_node_from_string(SERD_URI, USTR(key)); | |||
if (prop->type == state->atom_Path && !dir) { | |||
const char* path = (const char*)prop->value; | |||
const char* abs_path = lilv_state_rel2abs(state, path); | |||
sratom_write(sratom, unmap, SERD_ANON_CONT, | |||
&state_node, &p, prop->type, | |||
strlen(abs_path) + 1, abs_path); | |||
} else { | |||
sratom_write(sratom, unmap, SERD_ANON_CONT, | |||
&state_node, &p, prop->type, prop->size, prop->value); | |||
} | |||
} | |||
if (state->num_props > 0) { | |||
serd_writer_end_anon(writer, &state_node); | |||
if (state->props.n > 0) { | |||
serd_writer_end_anon(writer, &body); | |||
} | |||
sratom_free(sratom); | |||
@@ -1099,12 +1140,12 @@ lilv_state_delete(LilvWorld* world, | |||
model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL); | |||
if (file) { | |||
// Remove state file | |||
char* file_path = lilv_file_uri_parse( | |||
char* path = lilv_file_uri_parse( | |||
(const char*)sord_node_get_string(file), NULL); | |||
if (unlink(file_path)) { | |||
LILV_ERRORF("Failed to remove %s (%s)\n", file_path, strerror(errno)); | |||
if (unlink(path)) { | |||
LILV_ERRORF("Failed to remove %s (%s)\n", path, strerror(errno)); | |||
} | |||
lilv_free(file_path); | |||
lilv_free(path); | |||
} | |||
// Remove any existing manifest entries for this state | |||
@@ -1141,14 +1182,26 @@ lilv_state_delete(LilvWorld* world, | |||
return 0; | |||
} | |||
static void | |||
free_property_array(LilvState* state, PropertyArray* array) | |||
{ | |||
for (uint32_t i = 0; i < array->n; ++i) { | |||
Property* prop = &array->props[i]; | |||
if ((prop->flags & LV2_STATE_IS_POD) || | |||
prop->type == state->atom_Path) { | |||
free(prop->value); | |||
} | |||
} | |||
free(array->props); | |||
} | |||
LILV_API void | |||
lilv_state_free(LilvState* state) | |||
{ | |||
if (state) { | |||
for (uint32_t i = 0; i < state->num_props; ++i) { | |||
free(state->props[i].value); | |||
} | |||
for (uint32_t i = 0; i < state->num_values; ++i) { | |||
free_property_array(state, &state->props); | |||
free_property_array(state, &state->metadata); | |||
for (uint32_t i = 0; i < state->n_values; ++i) { | |||
free(state->values[i].value); | |||
free(state->values[i].symbol); | |||
} | |||
@@ -1156,7 +1209,6 @@ lilv_state_free(LilvState* state) | |||
lilv_node_free(state->uri); | |||
zix_tree_free(state->abs2rel); | |||
zix_tree_free(state->rel2abs); | |||
free(state->props); | |||
free(state->values); | |||
free(state->label); | |||
free(state->dir); | |||
@@ -1174,12 +1226,12 @@ lilv_state_equals(const LilvState* a, const LilvState* b) | |||
|| (a->label && !b->label) | |||
|| (b->label && !a->label) | |||
|| (a->label && b->label && strcmp(a->label, b->label)) | |||
|| a->num_props != b->num_props | |||
|| a->num_values != b->num_values) { | |||
|| a->props.n != b->props.n | |||
|| a->n_values != b->n_values) { | |||
return false; | |||
} | |||
for (uint32_t i = 0; i < a->num_values; ++i) { | |||
for (uint32_t i = 0; i < a->n_values; ++i) { | |||
PortValue* const av = &a->values[i]; | |||
PortValue* const bv = &b->values[i]; | |||
if (av->size != bv->size || av->type != bv->type | |||
@@ -1189,9 +1241,9 @@ lilv_state_equals(const LilvState* a, const LilvState* b) | |||
} | |||
} | |||
for (uint32_t i = 0; i < a->num_props; ++i) { | |||
Property* const ap = &a->props[i]; | |||
Property* const bp = &b->props[i]; | |||
for (uint32_t i = 0; i < a->props.n; ++i) { | |||
Property* const ap = &a->props.props[i]; | |||
Property* const bp = &b->props.props[i]; | |||
if (ap->key != bp->key | |||
|| ap->type != bp->type | |||
|| ap->flags != bp->flags) { | |||
@@ -1213,7 +1265,7 @@ lilv_state_equals(const LilvState* a, const LilvState* b) | |||
LILV_API unsigned | |||
lilv_state_get_num_properties(const LilvState* state) | |||
{ | |||
return state->num_props; | |||
return state->props.n; | |||
} | |||
LILV_API const LilvNode* | |||
@@ -1241,3 +1293,15 @@ lilv_state_set_label(LilvState* state, const char* label) | |||
state->label = (char*)realloc(state->label, len + 1); | |||
memcpy(state->label, label, len + 1); | |||
} | |||
LILV_API int | |||
lilv_state_set_metadata(LilvState* state, | |||
uint32_t key, | |||
const void* value, | |||
size_t size, | |||
uint32_t type, | |||
uint32_t flags) | |||
{ | |||
append_property(state, &state->metadata, key, value, size, type, flags); | |||
return LV2_STATE_SUCCESS; | |||
} |
@@ -0,0 +1,42 @@ | |||
--- src/state.c | |||
+++ src/state.c | |||
@@ -415,35 +415,18 @@ | |||
LILV_API void | |||
lilv_state_restore(const LilvState* state, | |||
- LilvInstance* instance, | |||
+ const LV2_State_Interface* iface, | |||
+ LV2_Handle handle, | |||
LilvSetPortValueFunc set_value, | |||
void* user_data, | |||
uint32_t flags, | |||
const LV2_Feature *const * features) | |||
{ | |||
- if (!state) { | |||
- LILV_ERROR("lilv_state_restore() called on NULL state\n"); | |||
- return; | |||
- } | |||
- | |||
- LV2_State_Map_Path map_path = { | |||
- (LilvState*)state, abstract_path, absolute_path }; | |||
- LV2_Feature map_feature = { LV2_STATE__mapPath, &map_path }; | |||
- | |||
- const LV2_Feature** sfeatures = add_features(features, &map_feature, NULL); | |||
- | |||
- const LV2_Descriptor* desc = instance ? instance->lv2_descriptor : NULL; | |||
- const LV2_State_Interface* iface = (desc && desc->extension_data) | |||
- ? (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface) | |||
- : NULL; | |||
- | |||
if (iface) { | |||
- iface->restore(instance->lv2_handle, retrieve_callback, | |||
- (LV2_State_Handle)state, flags, sfeatures); | |||
+ iface->restore(handle, retrieve_callback, | |||
+ (LV2_State_Handle)state, flags, features); | |||
} | |||
- free(sfeatures); | |||
- | |||
if (set_value) { | |||
lilv_state_emit_port_values(state, set_value, user_data); | |||
} |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2015 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -16,6 +16,7 @@ | |||
#define _POSIX_C_SOURCE 200809L /* for fileno */ | |||
#define _BSD_SOURCE 1 /* for realpath, symlink */ | |||
#define _DEFAULT_SOURCE 1 /* for realpath, symlink */ | |||
#ifdef __APPLE__ | |||
# define _DARWIN_C_SOURCE 1 /* for flock */ | |||
@@ -27,24 +28,27 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stddef.h> | |||
#ifdef _WIN32 | |||
#ifndef _WIN32_WINNT | |||
# define _WIN32_WINNT 0x0600 /* for CreateSymbolicLink */ | |||
#endif | |||
# include <windows.h> | |||
# include <direct.h> | |||
# include <io.h> | |||
# define F_OK 0 | |||
# define mkdir(path, flags) _mkdir(path) | |||
# if (defined(_MSC_VER) && (_MSC_VER < 1500)) | |||
/** Implement 'CreateSymbolicLink()' for MSVC 8 or earlier */ | |||
BOOLEAN WINAPI | |||
CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | |||
{ | |||
typedef BOOLEAN (WINAPI* PFUNC)(LPCTSTR, LPCTSTR, DWORD); | |||
PFUNC pfn = (PFUNC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkA"); | |||
PFUNC pfn = (PFUNC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | |||
"CreateSymbolicLinkA"); | |||
return pfn ? pfn(linkpath, targetpath, flags) : 0; | |||
} | |||
# endif /* _MSC_VER < 1500 */ | |||
#else | |||
# include <dirent.h> | |||
# include <limits.h> | |||
@@ -61,7 +65,7 @@ CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | |||
#endif | |||
#ifndef PAGE_SIZE | |||
# define PAGE_SIZE 4096 | |||
# define PAGE_SIZE 4096 | |||
#endif | |||
void | |||
@@ -296,6 +300,7 @@ lilv_copy_file(const char* src, const char* dst) | |||
FILE* out = fopen(dst, "w"); | |||
if (!out) { | |||
fclose(in); | |||
return errno; | |||
} | |||
@@ -370,26 +375,8 @@ lilv_path_join(const char* a, const char* b) | |||
return path; | |||
} | |||
static void | |||
lilv_size_mtime(const char* path, off_t* size, time_t* time) | |||
{ | |||
struct stat buf; | |||
if (stat(path, &buf)) { | |||
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno)); | |||
return; | |||
} | |||
if (size) { | |||
*size = buf.st_size; | |||
} | |||
if (time) { | |||
*time = buf.st_mtime; | |||
} | |||
} | |||
typedef struct { | |||
char* pattern; | |||
off_t orig_size; | |||
time_t time; | |||
char* latest; | |||
} Latest; | |||
@@ -397,16 +384,18 @@ typedef struct { | |||
static void | |||
update_latest(const char* path, const char* name, void* data) | |||
{ | |||
Latest* latest = (Latest*)data; | |||
char* entry_path = lilv_path_join(path, name); | |||
Latest* latest = (Latest*)data; | |||
char* entry_path = lilv_path_join(path, name); | |||
unsigned num; | |||
if (sscanf(entry_path, latest->pattern, &num) == 1) { | |||
off_t entry_size = 0; | |||
time_t entry_time = 0; | |||
lilv_size_mtime(entry_path, &entry_size, &entry_time); | |||
if (entry_size == latest->orig_size && entry_time >= latest->time) { | |||
free(latest->latest); | |||
latest->latest = entry_path; | |||
struct stat st; | |||
if (!stat(entry_path, &st)) { | |||
if (st.st_mtime >= latest->time) { | |||
free(latest->latest); | |||
latest->latest = entry_path; | |||
} | |||
} else { | |||
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno)); | |||
} | |||
} | |||
if (entry_path != latest->latest) { | |||
@@ -419,8 +408,14 @@ char* | |||
lilv_get_latest_copy(const char* path, const char* copy_path) | |||
{ | |||
char* copy_dir = lilv_dirname(copy_path); | |||
Latest latest = { lilv_strjoin(copy_path, "%u", NULL), 0, 0, NULL }; | |||
lilv_size_mtime(path, &latest.orig_size, &latest.time); | |||
Latest latest = { lilv_strjoin(copy_path, ".%u", NULL), 0, NULL }; | |||
struct stat st; | |||
if (!stat(path, &st)) { | |||
latest.time = st.st_mtime; | |||
} else { | |||
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno)); | |||
} | |||
lilv_dir_for_each(copy_dir, &latest, update_latest); | |||
@@ -609,19 +604,16 @@ lilv_file_equals(const char* a_path, const char* b_path) | |||
FILE* b_file = NULL; | |||
char* const a_real = lilv_realpath(a_path); | |||
char* const b_real = lilv_realpath(b_path); | |||
if (!a_real || !b_real) { | |||
match = false; // Missing file matches nothing | |||
} else if (!strcmp(a_real, b_real)) { | |||
if (!strcmp(a_real, b_real)) { | |||
match = true; // Real paths match | |||
} else if (lilv_file_size(a_path) != lilv_file_size(b_path)) { | |||
match = false; // Sizes differ | |||
} else if (!(a_file = fopen(a_real, "rb"))) { | |||
match = false; // Missing file matches nothing | |||
} else if (!(b_file = fopen(b_real, "rb"))) { | |||
} else if (!(a_file = fopen(a_real, "rb")) || | |||
!(b_file = fopen(b_real, "rb"))) { | |||
match = false; // Missing file matches nothing | |||
} else { | |||
match = true; | |||
// TODO: Improve performance by reading chunks | |||
match = true; | |||
while (!feof(a_file) && !feof(b_file)) { | |||
if (fgetc(a_file) != fgetc(b_file)) { | |||
match = false; |
@@ -0,0 +1,637 @@ | |||
/* | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#define _POSIX_C_SOURCE 200809L /* for fileno */ | |||
#define _BSD_SOURCE 1 /* for realpath, symlink */ | |||
#define _DEFAULT_SOURCE 1 /* for realpath, symlink */ | |||
#ifdef __APPLE__ | |||
# define _DARWIN_C_SOURCE 1 /* for flock */ | |||
#endif | |||
#include <ctype.h> | |||
#include <errno.h> | |||
#include <stdarg.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stddef.h> | |||
#ifdef _WIN32 | |||
#ifndef _WIN32_WINNT | |||
# define _WIN32_WINNT 0x0600 /* for CreateSymbolicLink */ | |||
#endif | |||
# include <windows.h> | |||
# include <direct.h> | |||
# include <io.h> | |||
# define F_OK 0 | |||
# define mkdir(path, flags) _mkdir(path) | |||
/** Implement 'CreateSymbolicLink()' for MSVC 8 or earlier */ | |||
BOOLEAN WINAPI | |||
CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | |||
{ | |||
typedef BOOLEAN (WINAPI* PFUNC)(LPCTSTR, LPCTSTR, DWORD); | |||
PFUNC pfn = (PFUNC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | |||
"CreateSymbolicLinkA"); | |||
return pfn ? pfn(linkpath, targetpath, flags) : 0; | |||
} | |||
#else | |||
# include <dirent.h> | |||
# include <limits.h> | |||
# include <unistd.h> | |||
#endif | |||
#include <sys/stat.h> | |||
#include <sys/types.h> | |||
#include "lilv_internal.h" | |||
#if defined(HAVE_FLOCK) && defined(HAVE_FILENO) | |||
# include <sys/file.h> | |||
#endif | |||
#ifndef PAGE_SIZE | |||
# define PAGE_SIZE 4096 | |||
#endif | |||
void | |||
lilv_free(void* ptr) | |||
{ | |||
free(ptr); | |||
} | |||
char* | |||
lilv_strjoin(const char* first, ...) | |||
{ | |||
size_t len = strlen(first); | |||
char* result = (char*)malloc(len + 1); | |||
memcpy(result, first, len); | |||
va_list args; | |||
va_start(args, first); | |||
while (1) { | |||
const char* const s = va_arg(args, const char *); | |||
if (s == NULL) | |||
break; | |||
const size_t this_len = strlen(s); | |||
char* new_result = (char*)realloc(result, len + this_len + 1); | |||
if (!new_result) { | |||
free(result); | |||
return NULL; | |||
} | |||
result = new_result; | |||
memcpy(result + len, s, this_len); | |||
len += this_len; | |||
} | |||
va_end(args); | |||
result[len] = '\0'; | |||
return result; | |||
} | |||
char* | |||
lilv_strdup(const char* str) | |||
{ | |||
if (!str) { | |||
return NULL; | |||
} | |||
const size_t len = strlen(str); | |||
char* copy = (char*)malloc(len + 1); | |||
memcpy(copy, str, len + 1); | |||
return copy; | |||
} | |||
const char* | |||
lilv_uri_to_path(const char* uri) | |||
{ | |||
return (const char*)serd_uri_to_path((const uint8_t*)uri); | |||
} | |||
char* | |||
lilv_file_uri_parse(const char* uri, char** hostname) | |||
{ | |||
return (char*)serd_file_uri_parse((const uint8_t*)uri, (uint8_t**)hostname); | |||
} | |||
/** Return the current LANG converted to Turtle (i.e. RFC3066) style. | |||
* For example, if LANG is set to "en_CA.utf-8", this returns "en-ca". | |||
*/ | |||
char* | |||
lilv_get_lang(void) | |||
{ | |||
const char* const env_lang = getenv("LANG"); | |||
if (!env_lang || !strcmp(env_lang, "") | |||
|| !strcmp(env_lang, "C") || !strcmp(env_lang, "POSIX")) { | |||
return NULL; | |||
} | |||
const size_t env_lang_len = strlen(env_lang); | |||
char* const lang = (char*)malloc(env_lang_len + 1); | |||
for (size_t i = 0; i < env_lang_len + 1; ++i) { | |||
if (env_lang[i] == '_') { | |||
lang[i] = '-'; // Convert _ to - | |||
} else if (env_lang[i] >= 'A' && env_lang[i] <= 'Z') { | |||
lang[i] = env_lang[i] + ('a' - 'A'); // Convert to lowercase | |||
} else if (env_lang[i] >= 'a' && env_lang[i] <= 'z') { | |||
lang[i] = env_lang[i]; // Lowercase letter, copy verbatim | |||
} else if (env_lang[i] >= '0' && env_lang[i] <= '9') { | |||
lang[i] = env_lang[i]; // Digit, copy verbatim | |||
} else if (env_lang[i] == '\0' || env_lang[i] == '.') { | |||
// End, or start of suffix (e.g. en_CA.utf-8), finished | |||
lang[i] = '\0'; | |||
break; | |||
} else { | |||
LILV_ERRORF("Illegal LANG `%s' ignored\n", env_lang); | |||
free(lang); | |||
return NULL; | |||
} | |||
} | |||
return lang; | |||
} | |||
/** Append suffix to dst, update dst_len, and return the realloc'd result. */ | |||
static char* | |||
strappend(char* dst, size_t* dst_len, const char* suffix, size_t suffix_len) | |||
{ | |||
dst = (char*)realloc(dst, *dst_len + suffix_len + 1); | |||
memcpy(dst + *dst_len, suffix, suffix_len); | |||
dst[(*dst_len += suffix_len)] = '\0'; | |||
return dst; | |||
} | |||
/** Append the value of the environment variable var to dst. */ | |||
static char* | |||
append_var(char* dst, size_t* dst_len, const char* var) | |||
{ | |||
// Get value from environment | |||
const char* val = getenv(var); | |||
if (val) { // Value found, append it | |||
return strappend(dst, dst_len, val, strlen(val)); | |||
} else { // No value found, append variable reference as-is | |||
return strappend(strappend(dst, dst_len, "$", 1), | |||
dst_len, var, strlen(var)); | |||
} | |||
} | |||
/** Expand variables (e.g. POSIX ~ or $FOO, Windows %FOO%) in `path`. */ | |||
char* | |||
lilv_expand(const char* path) | |||
{ | |||
#ifdef _WIN32 | |||
char* out = (char*)malloc(MAX_PATH); | |||
ExpandEnvironmentStrings(path, out, MAX_PATH); | |||
#else | |||
char* out = NULL; | |||
size_t len = 0; | |||
const char* start = path; // Start of current chunk to copy | |||
for (const char* s = path; *s;) { | |||
if (*s == '$') { | |||
// Hit $ (variable reference, e.g. $VAR_NAME) | |||
for (const char* t = s + 1; ; ++t) { | |||
if (!*t || (!isupper(*t) && !isdigit(*t) && *t != '_')) { | |||
// Append preceding chunk | |||
out = strappend(out, &len, start, s - start); | |||
// Append variable value (or $VAR_NAME if not found) | |||
char* var = (char*)calloc(t - s, 1); | |||
memcpy(var, s + 1, t - s - 1); | |||
out = append_var(out, &len, var); | |||
free(var); | |||
// Continue after variable reference | |||
start = s = t; | |||
break; | |||
} | |||
} | |||
} else if (*s == '~' && (*(s + 1) == '/' || !*(s + 1))) { | |||
// Hit ~ before slash or end of string (home directory reference) | |||
out = strappend(out, &len, start, s - start); | |||
out = append_var(out, &len, "HOME"); | |||
start = ++s; | |||
} else { | |||
++s; | |||
} | |||
} | |||
if (*start) { | |||
out = strappend(out, &len, start, strlen(start)); | |||
} | |||
#endif | |||
return out; | |||
} | |||
static bool | |||
lilv_is_dir_sep(const char c) | |||
{ | |||
return c == '/' || c == LILV_DIR_SEP[0]; | |||
} | |||
char* | |||
lilv_dirname(const char* path) | |||
{ | |||
const char* s = path + strlen(path) - 1; // Last character | |||
for (; s > path && lilv_is_dir_sep(*s); --s) {} // Last non-slash | |||
for (; s > path && !lilv_is_dir_sep(*s); --s) {} // Last internal slash | |||
for (; s > path && lilv_is_dir_sep(*s); --s) {} // Skip duplicates | |||
if (s == path) { // Hit beginning | |||
return lilv_is_dir_sep(*s) ? lilv_strdup("/") : lilv_strdup("."); | |||
} else { // Pointing to the last character of the result (inclusive) | |||
char* dirname = (char*)malloc(s - path + 2); | |||
memcpy(dirname, path, s - path + 1); | |||
dirname[s - path + 1] = '\0'; | |||
return dirname; | |||
} | |||
} | |||
bool | |||
lilv_path_exists(const char* path, void* ignored) | |||
{ | |||
return !access(path, F_OK); | |||
} | |||
char* | |||
lilv_find_free_path(const char* in_path, | |||
bool (*exists)(const char*, void*), void* user_data) | |||
{ | |||
const size_t in_path_len = strlen(in_path); | |||
char* path = (char*)malloc(in_path_len + 7); | |||
memcpy(path, in_path, in_path_len + 1); | |||
for (int i = 2; i < 1000000; ++i) { | |||
if (!exists(path, user_data)) { | |||
return path; | |||
} | |||
snprintf(path, in_path_len + 7, "%s.%u", in_path, i); | |||
} | |||
return NULL; | |||
} | |||
int | |||
lilv_copy_file(const char* src, const char* dst) | |||
{ | |||
FILE* in = fopen(src, "r"); | |||
if (!in) { | |||
return errno; | |||
} | |||
FILE* out = fopen(dst, "w"); | |||
if (!out) { | |||
fclose(in); | |||
return errno; | |||
} | |||
char* page = (char*)malloc(PAGE_SIZE); | |||
size_t n_read = 0; | |||
int st = 0; | |||
while ((n_read = fread(page, 1, PAGE_SIZE, in)) > 0) { | |||
if (fwrite(page, 1, n_read, out) != n_read) { | |||
st = errno; | |||
break; | |||
} | |||
} | |||
if (!st && (ferror(in) || ferror(out))) { | |||
st = EBADF; | |||
} | |||
free(page); | |||
fclose(in); | |||
fclose(out); | |||
return st; | |||
} | |||
bool | |||
lilv_path_is_absolute(const char* path) | |||
{ | |||
if (lilv_is_dir_sep(path[0])) { | |||
return true; | |||
} | |||
#ifdef _WIN32 | |||
if (isalpha(path[0]) && path[1] == ':' && lilv_is_dir_sep(path[2])) { | |||
return true; | |||
} | |||
#endif | |||
return false; | |||
} | |||
char* | |||
lilv_path_absolute(const char* path) | |||
{ | |||
if (lilv_path_is_absolute(path)) { | |||
return lilv_strdup(path); | |||
} else { | |||
char* cwd = getcwd(NULL, 0); | |||
char* abs_path = lilv_path_join(cwd, path); | |||
free(cwd); | |||
return abs_path; | |||
} | |||
} | |||
char* | |||
lilv_path_join(const char* a, const char* b) | |||
{ | |||
if (!a) { | |||
return lilv_strdup(b); | |||
} | |||
const size_t a_len = strlen(a); | |||
const size_t b_len = b ? strlen(b) : 0; | |||
const size_t pre_len = a_len - (lilv_is_dir_sep(a[a_len - 1]) ? 1 : 0); | |||
char* path = (char*)calloc(1, a_len + b_len + 2); | |||
memcpy(path, a, pre_len); | |||
path[pre_len] = '/'; | |||
if (b) { | |||
memcpy(path + pre_len + 1, | |||
b + (lilv_is_dir_sep(b[0]) ? 1 : 0), | |||
lilv_is_dir_sep(b[0]) ? b_len - 1 : b_len); | |||
} | |||
return path; | |||
} | |||
typedef struct { | |||
char* pattern; | |||
time_t time; | |||
char* latest; | |||
} Latest; | |||
static void | |||
update_latest(const char* path, const char* name, void* data) | |||
{ | |||
Latest* latest = (Latest*)data; | |||
char* entry_path = lilv_path_join(path, name); | |||
unsigned num; | |||
if (sscanf(entry_path, latest->pattern, &num) == 1) { | |||
struct stat st; | |||
if (!stat(entry_path, &st)) { | |||
if (st.st_mtime >= latest->time) { | |||
free(latest->latest); | |||
latest->latest = entry_path; | |||
} | |||
} else { | |||
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno)); | |||
} | |||
} | |||
if (entry_path != latest->latest) { | |||
free(entry_path); | |||
} | |||
} | |||
/** Return the latest copy of the file at `path` that is newer. */ | |||
char* | |||
lilv_get_latest_copy(const char* path, const char* copy_path) | |||
{ | |||
char* copy_dir = lilv_dirname(copy_path); | |||
Latest latest = { lilv_strjoin(copy_path, ".%u", NULL), 0, NULL }; | |||
struct stat st; | |||
if (!stat(path, &st)) { | |||
latest.time = st.st_mtime; | |||
} else { | |||
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno)); | |||
} | |||
lilv_dir_for_each(copy_dir, &latest, update_latest); | |||
free(latest.pattern); | |||
free(copy_dir); | |||
return latest.latest; | |||
} | |||
char* | |||
lilv_realpath(const char* path) | |||
{ | |||
#if defined(_WIN32) | |||
char* out = (char*)malloc(MAX_PATH); | |||
GetFullPathName(path, MAX_PATH, out, NULL); | |||
return out; | |||
#elif _POSIX_VERSION >= 200809L | |||
char* real_path = realpath(path, NULL); | |||
return real_path ? real_path : lilv_strdup(path); | |||
#else | |||
// OSX <= 10.5, if anyone cares. I sure don't. | |||
char* out = (char*)malloc(PATH_MAX); | |||
char* real_path = realpath(path, out); | |||
if (!real_path) { | |||
free(out); | |||
return lilv_strdup(path); | |||
} else { | |||
return real_path; | |||
} | |||
#endif | |||
} | |||
int | |||
lilv_symlink(const char* oldpath, const char* newpath) | |||
{ | |||
int ret = 0; | |||
if (strcmp(oldpath, newpath)) { | |||
#ifdef _WIN32 | |||
ret = !CreateSymbolicLink(newpath, oldpath, 0); | |||
if (ret) { | |||
ret = !CreateHardLink(newpath, oldpath, 0); | |||
} | |||
#else | |||
ret = symlink(oldpath, newpath); | |||
#endif | |||
} | |||
if (ret) { | |||
LILV_ERRORF("Failed to link %s => %s (%s)\n", | |||
newpath, oldpath, strerror(errno)); | |||
} | |||
return ret; | |||
} | |||
char* | |||
lilv_path_relative_to(const char* path, const char* base) | |||
{ | |||
const size_t path_len = strlen(path); | |||
const size_t base_len = strlen(base); | |||
const size_t min_len = (path_len < base_len) ? path_len : base_len; | |||
// Find the last separator common to both paths | |||
size_t last_shared_sep = 0; | |||
for (size_t i = 0; i < min_len && path[i] == base[i]; ++i) { | |||
if (lilv_is_dir_sep(path[i])) { | |||
last_shared_sep = i; | |||
} | |||
} | |||
if (last_shared_sep == 0) { | |||
// No common components, return path | |||
return lilv_strdup(path); | |||
} | |||
// Find the number of up references ("..") required | |||
size_t up = 0; | |||
for (size_t i = last_shared_sep + 1; i < base_len; ++i) { | |||
if (lilv_is_dir_sep(base[i])) { | |||
++up; | |||
} | |||
} | |||
// Write up references | |||
const size_t suffix_len = path_len - last_shared_sep; | |||
char* rel = (char*)calloc(1, suffix_len + (up * 3) + 1); | |||
for (size_t i = 0; i < up; ++i) { | |||
memcpy(rel + (i * 3), "../", 3); | |||
} | |||
// Write suffix | |||
memcpy(rel + (up * 3), path + last_shared_sep + 1, suffix_len); | |||
return rel; | |||
} | |||
bool | |||
lilv_path_is_child(const char* path, const char* dir) | |||
{ | |||
if (path && dir) { | |||
const size_t path_len = strlen(path); | |||
const size_t dir_len = strlen(dir); | |||
return dir && path_len >= dir_len && !strncmp(path, dir, dir_len); | |||
} | |||
return false; | |||
} | |||
int | |||
lilv_flock(FILE* file, bool lock) | |||
{ | |||
#if defined(HAVE_FLOCK) && defined(HAVE_FILENO) | |||
return flock(fileno(file), lock ? LOCK_EX : LOCK_UN); | |||
#else | |||
return 0; | |||
#endif | |||
} | |||
void | |||
lilv_dir_for_each(const char* path, | |||
void* data, | |||
void (*f)(const char* path, const char* name, void* data)) | |||
{ | |||
#ifdef _WIN32 | |||
char* pat = lilv_path_join(path, "*"); | |||
WIN32_FIND_DATA fd; | |||
HANDLE fh = FindFirstFile(pat, &fd); | |||
if (fh != INVALID_HANDLE_VALUE) { | |||
do { | |||
f(path, fd.cFileName, data); | |||
} while (FindNextFile(fh, &fd)); | |||
} | |||
free(pat); | |||
#else | |||
DIR* dir = opendir(path); | |||
if (dir) { | |||
long name_max = pathconf(path, _PC_NAME_MAX); | |||
if (name_max == -1) { | |||
name_max = 255; // Limit not defined, or error | |||
} | |||
const size_t len = offsetof(struct dirent, d_name) + name_max + 1; | |||
struct dirent* entry = (struct dirent*)malloc(len); | |||
struct dirent* result; | |||
while (!readdir_r(dir, entry, &result) && result) { | |||
f(path, entry->d_name, data); | |||
} | |||
free(entry); | |||
closedir(dir); | |||
} | |||
#endif | |||
} | |||
int | |||
lilv_mkdir_p(const char* dir_path) | |||
{ | |||
char* path = lilv_strdup(dir_path); | |||
const size_t path_len = strlen(path); | |||
for (size_t i = 1; i <= path_len; ++i) { | |||
if (path[i] == LILV_DIR_SEP[0] || path[i] == '\0') { | |||
path[i] = '\0'; | |||
if (mkdir(path, 0755) && errno != EEXIST) { | |||
free(path); | |||
return errno; | |||
} | |||
path[i] = LILV_DIR_SEP[0]; | |||
} | |||
} | |||
free(path); | |||
return 0; | |||
} | |||
static off_t | |||
lilv_file_size(const char* path) | |||
{ | |||
struct stat buf; | |||
if (stat(path, &buf)) { | |||
LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno)); | |||
return 0; | |||
} | |||
return buf.st_size; | |||
} | |||
bool | |||
lilv_file_equals(const char* a_path, const char* b_path) | |||
{ | |||
if (!strcmp(a_path, b_path)) { | |||
return true; // Paths match | |||
} | |||
bool match = false; | |||
FILE* a_file = NULL; | |||
FILE* b_file = NULL; | |||
char* const a_real = lilv_realpath(a_path); | |||
char* const b_real = lilv_realpath(b_path); | |||
if (!strcmp(a_real, b_real)) { | |||
match = true; // Real paths match | |||
} else if (lilv_file_size(a_path) != lilv_file_size(b_path)) { | |||
match = false; // Sizes differ | |||
} else if (!(a_file = fopen(a_real, "rb")) || | |||
!(b_file = fopen(b_real, "rb"))) { | |||
match = false; // Missing file matches nothing | |||
} else { | |||
// TODO: Improve performance by reading chunks | |||
match = true; | |||
while (!feof(a_file) && !feof(b_file)) { | |||
if (fgetc(a_file) != fgetc(b_file)) { | |||
match = false; | |||
break; | |||
} | |||
} | |||
} | |||
if (a_file) { | |||
fclose(a_file); | |||
} | |||
if (b_file) { | |||
fclose(b_file); | |||
} | |||
free(a_real); | |||
free(b_real); | |||
return match; | |||
} |
@@ -0,0 +1,10 @@ | |||
--- src/util.c | |||
+++ src/util.c | |||
@@ -29,7 +29,6 @@ | |||
#include <string.h> | |||
#ifdef _WIN32 | |||
-# define _WIN32_WINNT 0x0600 /* for CreateSymbolicLink */ | |||
# include <windows.h> | |||
# include <direct.h> | |||
# include <io.h> |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2014 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -23,6 +23,9 @@ | |||
#include "lilv_internal.h" | |||
static int | |||
lilv_world_drop_graph(LilvWorld* world, const SordNode* graph); | |||
LILV_API LilvWorld* | |||
lilv_world_new(void) | |||
{ | |||
@@ -39,6 +42,7 @@ lilv_world_new(void) | |||
world->specs = NULL; | |||
world->plugin_classes = lilv_plugin_classes_new(); | |||
world->plugins = lilv_plugins_new(); | |||
world->zombies = lilv_plugins_new(); | |||
world->loaded_files = zix_tree_new( | |||
false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free); | |||
@@ -63,7 +67,9 @@ lilv_world_new(void) | |||
world->uris.lv2_index = NEW_URI(LV2_CORE__index); | |||
world->uris.lv2_latency = NEW_URI(LV2_CORE__latency); | |||
world->uris.lv2_maximum = NEW_URI(LV2_CORE__maximum); | |||
world->uris.lv2_microVersion = NEW_URI(LV2_CORE__microVersion); | |||
world->uris.lv2_minimum = NEW_URI(LV2_CORE__minimum); | |||
world->uris.lv2_minorVersion = NEW_URI(LV2_CORE__minorVersion); | |||
world->uris.lv2_name = NEW_URI(LV2_CORE__name); | |||
world->uris.lv2_optionalFeature = NEW_URI(LV2_CORE__optionalFeature); | |||
world->uris.lv2_port = NEW_URI(LV2_CORE__port); | |||
@@ -133,6 +139,13 @@ lilv_world_free(LilvWorld* world) | |||
zix_tree_free((ZixTree*)world->plugins); | |||
world->plugins = NULL; | |||
LILV_FOREACH(plugins, i, world->zombies) { | |||
const LilvPlugin* p = lilv_plugins_get(world->zombies, i); | |||
lilv_plugin_free((LilvPlugin*)p); | |||
} | |||
zix_tree_free((ZixTree*)world->zombies); | |||
world->zombies = NULL; | |||
zix_tree_free((ZixTree*)world->loaded_files); | |||
world->loaded_files = NULL; | |||
@@ -180,6 +193,9 @@ lilv_world_find_nodes(LilvWorld* world, | |||
LILV_ERRORF("Subject `%s' is not a resource\n", | |||
sord_node_get_string(subject->node)); | |||
return NULL; | |||
} else if (!predicate) { | |||
LILV_ERROR("Missing required predicate\n"); | |||
return NULL; | |||
} else if (!lilv_node_is_uri(predicate)) { | |||
LILV_ERRORF("Predicate `%s' is not a URI\n", | |||
sord_node_get_string(predicate->node)); | |||
@@ -278,12 +294,8 @@ lilv_new_uri_relative_to_base(const uint8_t* uri_str, | |||
const uint8_t* base_uri_str) | |||
{ | |||
SerdURI base_uri; | |||
if (serd_uri_parse(base_uri_str, &base_uri)) { | |||
return SERD_NODE_NULL; | |||
} | |||
SerdURI ignored; | |||
return serd_node_new_uri_from_string(uri_str, &base_uri, &ignored); | |||
serd_uri_parse(base_uri_str, &base_uri); | |||
return serd_node_new_uri_from_string(uri_str, &base_uri, NULL); | |||
} | |||
const uint8_t* | |||
@@ -322,23 +334,24 @@ lilv_lib_compare(const void* a, const void* b, void* user_data) | |||
} | |||
/** Get an element of a collection of any object with an LilvHeader by URI. */ | |||
struct LilvHeader* | |||
lilv_collection_get_by_uri(const ZixTree* const_seq, | |||
const LilvNode* uri) | |||
static ZixTreeIter* | |||
lilv_collection_find_by_uri(const ZixTree* seq, const LilvNode* uri) | |||
{ | |||
if (!lilv_node_is_uri(uri)) { | |||
return NULL; | |||
ZixTreeIter* i = NULL; | |||
if (lilv_node_is_uri(uri)) { | |||
struct LilvHeader key = { NULL, (LilvNode*)uri }; | |||
zix_tree_find(seq, &key, &i); | |||
} | |||
return i; | |||
} | |||
ZixTree* seq = (ZixTree*)const_seq; | |||
struct LilvHeader key = { NULL, (LilvNode*)uri }; | |||
ZixTreeIter* i = NULL; | |||
ZixStatus st = zix_tree_find(seq, &key, &i); | |||
if (!st) { | |||
return (struct LilvHeader*)zix_tree_get(i); | |||
} | |||
/** Get an element of a collection of any object with an LilvHeader by URI. */ | |||
struct LilvHeader* | |||
lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri) | |||
{ | |||
ZixTreeIter* const i = lilv_collection_find_by_uri(seq, uri); | |||
return NULL; | |||
return i ? (struct LilvHeader*)zix_tree_get(i) : NULL; | |||
} | |||
static void | |||
@@ -371,33 +384,55 @@ lilv_world_add_spec(LilvWorld* world, | |||
} | |||
static void | |||
lilv_world_add_plugin(LilvWorld* world, | |||
const SordNode* plugin_node, | |||
const LilvNode* manifest_uri, | |||
void* dynmanifest, | |||
const SordNode* bundle_node) | |||
{ | |||
LilvNode* plugin_uri = lilv_node_new_from_node(world, plugin_node); | |||
const LilvPlugin* last = lilv_plugins_get_by_uri(world->plugins, | |||
plugin_uri); | |||
if (last) { | |||
LILV_ERRORF("Duplicate plugin <%s>\n", lilv_node_as_uri(plugin_uri)); | |||
LILV_ERRORF("... found in %s\n", lilv_node_as_string( | |||
lilv_plugin_get_bundle_uri(last))); | |||
LILV_ERRORF("... and %s\n", sord_node_get_string(bundle_node)); | |||
lilv_world_add_plugin(LilvWorld* world, | |||
const SordNode* plugin_node, | |||
const LilvNode* manifest_uri, | |||
void* dynmanifest, | |||
const SordNode* bundle) | |||
{ | |||
LilvNode* plugin_uri = lilv_node_new_from_node(world, plugin_node); | |||
ZixTreeIter* z = NULL; | |||
LilvPlugin* plugin = (LilvPlugin*)lilv_plugins_get_by_uri( | |||
world->plugins, plugin_uri); | |||
if (plugin) { | |||
// Existing plugin, if this is different bundle, ignore it | |||
// (use the first plugin found in LV2_PATH) | |||
const LilvNode* last_bundle = lilv_plugin_get_bundle_uri(plugin); | |||
const char* plugin_uri_str = lilv_node_as_uri(plugin_uri); | |||
if (sord_node_equals(bundle, last_bundle->node)) { | |||
LILV_WARNF("Reloading plugin <%s>\n", plugin_uri_str); | |||
plugin->loaded = false; | |||
lilv_node_free(plugin_uri); | |||
} else { | |||
LILV_WARNF("Duplicate plugin <%s>\n", plugin_uri_str); | |||
LILV_WARNF("... found in %s\n", lilv_node_as_string(last_bundle)); | |||
LILV_WARNF("... and %s (ignored)\n", sord_node_get_string(bundle)); | |||
lilv_node_free(plugin_uri); | |||
return; | |||
} | |||
} else if ((z = lilv_collection_find_by_uri((const ZixTree*)world->zombies, | |||
plugin_uri))) { | |||
// Plugin bundle has been re-loaded, move from zombies to plugins | |||
plugin = (LilvPlugin*)zix_tree_get(z); | |||
zix_tree_remove((ZixTree*)world->zombies, z); | |||
zix_tree_insert((ZixTree*)world->plugins, plugin, NULL); | |||
lilv_node_free(plugin_uri); | |||
return; | |||
} | |||
lilv_plugin_clear(plugin, lilv_node_new_from_node(world, bundle)); | |||
} else { | |||
// Add new plugin to the world | |||
plugin = lilv_plugin_new( | |||
world, plugin_uri, lilv_node_new_from_node(world, bundle)); | |||
// Create LilvPlugin | |||
LilvNode* bundle_uri = lilv_node_new_from_node(world, bundle_node); | |||
LilvPlugin* plugin = lilv_plugin_new(world, plugin_uri, bundle_uri); | |||
// Add manifest as plugin data file (as if it were rdfs:seeAlso) | |||
zix_tree_insert((ZixTree*)plugin->data_uris, | |||
lilv_node_duplicate(manifest_uri), | |||
NULL); | |||
// Add plugin to world plugin sequence | |||
zix_tree_insert((ZixTree*)world->plugins, plugin, NULL); | |||
} | |||
// Add manifest as plugin data file (as if it were rdfs:seeAlso) | |||
zix_tree_insert((ZixTree*)plugin->data_uris, | |||
lilv_node_duplicate(manifest_uri), | |||
NULL); | |||
#ifdef LILV_DYN_MANIFEST | |||
// Set dynamic manifest library URI, if applicable | |||
@@ -420,9 +455,6 @@ lilv_world_add_plugin(LilvWorld* world, | |||
NULL); | |||
} | |||
sord_iter_free(files); | |||
// Add plugin to world plugin sequence | |||
zix_tree_insert((ZixTree*)world->plugins, plugin, NULL); | |||
} | |||
SerdStatus | |||
@@ -480,7 +512,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
// Get binary path | |||
const SordNode* binary = sord_iter_get_node(binaries, SORD_OBJECT); | |||
const uint8_t* lib_uri = sord_node_get_string(binary); | |||
const char* lib_path = lilv_uri_to_path((const char*)lib_uri); | |||
char* lib_path = lilv_file_uri_parse((const char*)lib_uri, 0); | |||
if (!lib_path) { | |||
LILV_ERROR("No dynamic manifest library path\n"); | |||
sord_iter_free(binaries); | |||
@@ -494,6 +526,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
LILV_ERRORF("Failed to open dynmanifest library `%s' (%s)\n", | |||
lib_path, dlerror()); | |||
sord_iter_free(binaries); | |||
lilv_free(lib_path); | |||
continue; | |||
} | |||
@@ -505,6 +538,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
LILV_ERRORF("No `lv2_dyn_manifest_open' in `%s'\n", lib_path); | |||
sord_iter_free(binaries); | |||
dlclose(lib); | |||
lilv_free(lib_path); | |||
continue; | |||
} | |||
@@ -517,6 +551,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
lib_path); | |||
sord_iter_free(binaries); | |||
dlclose(lib); | |||
lilv_free(lib_path); | |||
continue; | |||
} | |||
@@ -563,6 +598,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
} | |||
sord_iter_free(p); | |||
sord_free(plugins); | |||
lilv_free(lib_path); | |||
} | |||
sord_iter_free(iter); | |||
sord_free(model); | |||
@@ -570,7 +606,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
} | |||
LilvNode* | |||
lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri) | |||
lilv_world_get_manifest_uri(LilvWorld* world, const LilvNode* bundle_uri) | |||
{ | |||
SerdNode manifest_uri = lilv_new_uri_relative_to_base( | |||
(const uint8_t*)"manifest.ttl", | |||
@@ -580,8 +616,67 @@ lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri) | |||
return manifest; | |||
} | |||
static SordModel* | |||
load_plugin_model(LilvWorld* world, | |||
const LilvNode* bundle_uri, | |||
const LilvNode* plugin_uri) | |||
{ | |||
// Create model and reader for loading into it | |||
SordNode* bundle_node = bundle_uri->node; | |||
SordModel* model = sord_new(world->world, SORD_SPO|SORD_OPS, false); | |||
SerdEnv* env = serd_env_new(sord_node_to_serd_node(bundle_node)); | |||
SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL); | |||
// Load manifest | |||
LilvNode* manifest_uri = lilv_world_get_manifest_uri(world, bundle_uri); | |||
serd_reader_add_blank_prefix(reader, lilv_world_blank_node_prefix(world)); | |||
serd_reader_read_file( | |||
reader, (const uint8_t*)lilv_node_as_string(manifest_uri)); | |||
// Load any seeAlso files | |||
SordModel* files = lilv_world_filter_model( | |||
world, model, plugin_uri->node, world->uris.rdfs_seeAlso, NULL, NULL); | |||
SordIter* f = sord_begin(files); | |||
FOREACH_MATCH(f) { | |||
const SordNode* file = sord_iter_get_node(f, SORD_OBJECT); | |||
const uint8_t* file_str = sord_node_get_string(file); | |||
if (sord_node_get_type(file) == SORD_URI) { | |||
serd_reader_add_blank_prefix( | |||
reader, lilv_world_blank_node_prefix(world)); | |||
serd_reader_read_file(reader, file_str); | |||
} | |||
} | |||
sord_iter_free(f); | |||
sord_free(files); | |||
serd_reader_free(reader); | |||
serd_env_free(env); | |||
lilv_node_free(manifest_uri); | |||
return model; | |||
} | |||
static LilvVersion | |||
get_version(LilvWorld* world, SordModel* model, const LilvNode* subject) | |||
{ | |||
const SordNode* minor_node = sord_get( | |||
model, subject->node, world->uris.lv2_minorVersion, NULL, NULL); | |||
const SordNode* micro_node = sord_get( | |||
model, subject->node, world->uris.lv2_microVersion, NULL, NULL); | |||
LilvVersion version = { 0, 0 }; | |||
if (minor_node && micro_node) { | |||
version.minor = atoi((const char*)sord_node_get_string(minor_node)); | |||
version.micro = atoi((const char*)sord_node_get_string(micro_node)); | |||
} | |||
return version; | |||
} | |||
LILV_API void | |||
lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
lilv_world_load_bundle(LilvWorld* world, const LilvNode* bundle_uri) | |||
{ | |||
if (!lilv_node_is_uri(bundle_uri)) { | |||
LILV_ERRORF("Bundle URI `%s' is not a URI\n", | |||
@@ -606,6 +701,88 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
world->uris.rdf_a, | |||
world->uris.lv2_Plugin, | |||
bundle_node); | |||
// Find any loaded plugins that will be replaced with a newer version | |||
LilvNodes* unload_uris = lilv_nodes_new(); | |||
FOREACH_MATCH(plug_results) { | |||
const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT); | |||
LilvNode* plugin_uri = lilv_node_new_from_node(world, plug); | |||
const LilvPlugin* plugin = lilv_plugins_get_by_uri(world->plugins, plugin_uri); | |||
const LilvNode* last_bundle = plugin ? lilv_plugin_get_bundle_uri(plugin) : NULL; | |||
if (!plugin || sord_node_equals(bundle_node, last_bundle->node)) { | |||
// No previously loaded version, or it's from the same bundle | |||
lilv_node_free(plugin_uri); | |||
continue; | |||
} | |||
// Compare versions | |||
SordModel* this_model = load_plugin_model(world, bundle_uri, plugin_uri); | |||
LilvVersion this_version = get_version(world, this_model, plugin_uri); | |||
SordModel* last_model = load_plugin_model(world, last_bundle, plugin_uri); | |||
LilvVersion last_version = get_version(world, last_model, plugin_uri); | |||
sord_free(this_model); | |||
sord_free(last_model); | |||
const int cmp = lilv_version_cmp(&this_version, &last_version); | |||
if (cmp > 0) { | |||
zix_tree_insert((ZixTree*)unload_uris, | |||
lilv_node_duplicate(plugin_uri), | |||
NULL); | |||
LILV_WARNF("Replacing version %d.%d of <%s> from <%s>\n", | |||
last_version.minor, last_version.micro, | |||
sord_node_get_string(plug), | |||
sord_node_get_string(last_bundle->node)); | |||
LILV_NOTEF("New version %d.%d found in <%s>\n", | |||
this_version.minor, this_version.micro, | |||
sord_node_get_string(bundle_node)); | |||
} else if (cmp < 0) { | |||
LILV_WARNF("Ignoring bundle <%s>\n", | |||
sord_node_get_string(bundle_node)); | |||
LILV_NOTEF("Newer version of <%s> loaded from <%s>\n", | |||
sord_node_get_string(plug), | |||
sord_node_get_string(last_bundle->node)); | |||
lilv_node_free(plugin_uri); | |||
sord_iter_free(plug_results); | |||
lilv_world_drop_graph(world, bundle_node); | |||
lilv_node_free(manifest); | |||
lilv_nodes_free(unload_uris); | |||
return; | |||
} | |||
lilv_node_free(plugin_uri); | |||
} | |||
sord_iter_free(plug_results); | |||
// Unload any old conflicting plugins | |||
LilvNodes* unload_bundles = lilv_nodes_new(); | |||
LILV_FOREACH(nodes, i, unload_uris) { | |||
const LilvNode* uri = lilv_nodes_get(unload_uris, i); | |||
const LilvPlugin* plugin = lilv_plugins_get_by_uri(world->plugins, uri); | |||
const LilvNode* bundle = lilv_plugin_get_bundle_uri(plugin); | |||
// Unload plugin and record bundle for later unloading | |||
lilv_world_unload_resource(world, uri); | |||
zix_tree_insert((ZixTree*)unload_bundles, | |||
lilv_node_duplicate(bundle), | |||
NULL); | |||
} | |||
lilv_nodes_free(unload_uris); | |||
// Now unload the associated bundles | |||
// This must be done last since several plugins could be in the same bundle | |||
LILV_FOREACH(nodes, i, unload_bundles) { | |||
lilv_world_unload_bundle(world, lilv_nodes_get(unload_bundles, i)); | |||
} | |||
lilv_nodes_free(unload_bundles); | |||
// Re-search for plugin results now that old plugins are gone | |||
plug_results = sord_search(world->model, | |||
NULL, | |||
world->uris.rdf_a, | |||
world->uris.lv2_Plugin, | |||
bundle_node); | |||
FOREACH_MATCH(plug_results) { | |||
const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT); | |||
lilv_world_add_plugin(world, plug, manifest, NULL, bundle_node); | |||
@@ -633,14 +810,14 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
} | |||
static int | |||
lilv_world_drop_graph(LilvWorld* world, LilvNode* graph) | |||
lilv_world_drop_graph(LilvWorld* world, const SordNode* graph) | |||
{ | |||
SordIter* i = sord_search(world->model, NULL, NULL, NULL, graph->node); | |||
SordIter* i = sord_search(world->model, NULL, NULL, NULL, graph); | |||
while (!sord_iter_end(i)) { | |||
const SerdStatus st = sord_erase(world->model, i); | |||
if (st) { | |||
LILV_ERRORF("Error removing statement from <%s> (%s)\n", | |||
lilv_node_as_uri(graph), serd_strerror(st)); | |||
sord_node_get_string(graph), serd_strerror(st)); | |||
return st; | |||
} | |||
} | |||
@@ -651,7 +828,7 @@ lilv_world_drop_graph(LilvWorld* world, LilvNode* graph) | |||
/** Remove loaded_files entry so file will be reloaded if requested. */ | |||
static int | |||
lilv_world_unload_file(LilvWorld* world, LilvNode* file) | |||
lilv_world_unload_file(LilvWorld* world, const LilvNode* file) | |||
{ | |||
ZixTreeIter* iter; | |||
if (!zix_tree_find((ZixTree*)world->loaded_files, file, &iter)) { | |||
@@ -662,19 +839,54 @@ lilv_world_unload_file(LilvWorld* world, LilvNode* file) | |||
} | |||
LILV_API int | |||
lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri) | |||
{ | |||
if (!bundle_uri) { | |||
return 0; | |||
} | |||
// Remove loaded_files entry for manifest.ttl | |||
LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri); | |||
lilv_world_unload_file(world, manifest); | |||
lilv_node_free(manifest); | |||
// Find all loaded files that are inside the bundle | |||
LilvNodes* files = lilv_nodes_new(); | |||
LILV_FOREACH(nodes, i, world->loaded_files) { | |||
const LilvNode* file = lilv_nodes_get(world->loaded_files, i); | |||
if (!strncmp(lilv_node_as_string(file), | |||
lilv_node_as_string(bundle_uri), | |||
strlen(lilv_node_as_string(bundle_uri)))) { | |||
zix_tree_insert((ZixTree*)files, | |||
lilv_node_duplicate(file), | |||
NULL); | |||
} | |||
} | |||
// Unload all loaded files in the bundle | |||
LILV_FOREACH(nodes, i, files) { | |||
const LilvNode* file = lilv_nodes_get(world->plugins, i); | |||
lilv_world_unload_file(world, file); | |||
} | |||
lilv_nodes_free(files); | |||
/* Remove any plugins in the bundle from the plugin list. Since the | |||
application may still have a pointer to the LilvPlugin, it can not be | |||
destroyed here. Instead, we move it to the zombie plugin list, so it | |||
will not be in the list returned by lilv_world_get_all_plugins() but can | |||
still be used. | |||
*/ | |||
ZixTreeIter* i = zix_tree_begin((ZixTree*)world->plugins); | |||
while (i != zix_tree_end((ZixTree*)world->plugins)) { | |||
LilvPlugin* p = (LilvPlugin*)zix_tree_get(i); | |||
ZixTreeIter* next = zix_tree_iter_next(i); | |||
if (lilv_node_equals(lilv_plugin_get_bundle_uri(p), bundle_uri)) { | |||
zix_tree_remove((ZixTree*)world->plugins, i); | |||
zix_tree_insert((ZixTree*)world->zombies, p, NULL); | |||
} | |||
i = next; | |||
} | |||
// Drop everything in bundle graph | |||
return lilv_world_drop_graph(world, bundle_uri); | |||
return lilv_world_drop_graph(world, bundle_uri->node); | |||
} | |||
static void | |||
@@ -903,7 +1115,7 @@ lilv_world_unload_resource(LilvWorld* world, | |||
if (sord_node_get_type(file) != SORD_URI) { | |||
LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", | |||
sord_node_get_string(file)); | |||
} else if (!lilv_world_drop_graph(world, file_node)) { | |||
} else if (!lilv_world_drop_graph(world, file_node->node)) { | |||
lilv_world_unload_file(world, file_node); | |||
++n_dropped; | |||
} | |||
@@ -932,3 +1144,51 @@ lilv_world_get_all_plugins(const LilvWorld* world) | |||
{ | |||
return world->plugins; | |||
} | |||
LILV_API LilvNode* | |||
lilv_world_get_symbol(LilvWorld* world, const LilvNode* subject) | |||
{ | |||
// Check for explicitly given symbol | |||
SordNode* snode = sord_get( | |||
world->model, subject->node, world->uris.lv2_symbol, NULL, NULL); | |||
if (snode) { | |||
LilvNode* ret = lilv_node_new_from_node(world, snode); | |||
sord_node_free(world->world, snode); | |||
return ret; | |||
} | |||
if (!lilv_node_is_uri(subject)) { | |||
return NULL; | |||
} | |||
// Find rightmost segment of URI | |||
SerdURI uri; | |||
serd_uri_parse((const uint8_t*)lilv_node_as_uri(subject), &uri); | |||
const char* str = "_"; | |||
if (uri.fragment.buf) { | |||
str = (const char*)uri.fragment.buf + 1; | |||
} else if (uri.query.buf) { | |||
str = (const char*)uri.query.buf; | |||
} else if (uri.path.buf) { | |||
const char* last_slash = strrchr((const char*)uri.path.buf, '/'); | |||
str = last_slash ? (last_slash + 1) : (const char*)uri.path.buf; | |||
} | |||
// Replace invalid characters | |||
const size_t len = strlen(str); | |||
char* const sym = (char*)calloc(1, len + 1); | |||
for (size_t i = 0; i < len; ++i) { | |||
const char c = str[i]; | |||
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || | |||
(c == '_') || (i > 0 && c >= '0' && c <= '9'))) { | |||
sym[i] = '_'; | |||
} else { | |||
sym[i] = str[i]; | |||
} | |||
} | |||
LilvNode* ret = lilv_new_string(world, sym); | |||
free(sym); | |||
return ret; | |||
} |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2011 David Robillard <http://drobilla.net> | |||
Copyright 2016 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -59,7 +59,7 @@ typedef enum { | |||
ZIX_STATUS_NOT_FOUND, | |||
ZIX_STATUS_EXISTS, | |||
ZIX_STATUS_BAD_ARG, | |||
ZIX_STATUS_BAD_PERMS, | |||
ZIX_STATUS_BAD_PERMS | |||
} ZixStatus; | |||
/** |
@@ -0,0 +1,93 @@ | |||
/* | |||
Lilv Test Plugin - Bad syntax in plugin data file | |||
Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include <stdlib.h> | |||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
#define PLUGIN_URI "http://example.org/bad-syntax" | |||
enum { | |||
TEST_INPUT = 0, | |||
TEST_OUTPUT = 1 | |||
}; | |||
typedef struct { | |||
float* input; | |||
float* output; | |||
} Test; | |||
static void | |||
cleanup(LV2_Handle instance) | |||
{ | |||
free((Test*)instance); | |||
} | |||
static void | |||
connect_port(LV2_Handle instance, uint32_t port, void* data) | |||
{ | |||
Test* test = (Test*)instance; | |||
switch (port) { | |||
case TEST_INPUT: | |||
test->input = (float*)data; | |||
break; | |||
case TEST_OUTPUT: | |||
test->output = (float*)data; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
static LV2_Handle | |||
instantiate(const LV2_Descriptor* descriptor, | |||
double rate, | |||
const char* path, | |||
const LV2_Feature* const* features) | |||
{ | |||
Test* test = (Test*)calloc(1, sizeof(Test)); | |||
if (!test) { | |||
return NULL; | |||
} | |||
return (LV2_Handle)test; | |||
} | |||
static void | |||
run(LV2_Handle instance, uint32_t sample_count) | |||
{ | |||
Test* test = (Test*)instance; | |||
*test->output = *test->input; | |||
} | |||
static const LV2_Descriptor descriptor = { | |||
PLUGIN_URI, | |||
instantiate, | |||
connect_port, | |||
NULL, // activate, | |||
run, | |||
NULL, // deactivate, | |||
cleanup, | |||
NULL // extension_data | |||
}; | |||
LV2_SYMBOL_EXPORT | |||
const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||
{ | |||
return (index == 0) ? &descriptor : NULL; | |||
} |
@@ -0,0 +1,22 @@ | |||
# Lilv Test Plugin - Bad syntax in plugin data file | |||
# Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
@prefix doap: <http://usefulinc.com/ns/doap#> . | |||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . | |||
<http://example.org/bad-syntax> | |||
a plugin with a clearly broken data file |
@@ -0,0 +1,7 @@ | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |||
<http://example.org/bad-syntax> | |||
a lv2:Plugin ; | |||
lv2:binary <bad_syntax@SHLIB_EXT@> ; | |||
rdfs:seeAlso <bad_syntax.ttl> . |
@@ -0,0 +1,45 @@ | |||
#include "lilv/lilv.h" | |||
#include "../src/lilv_internal.h" | |||
#define PLUGIN_URI "http://example.org/bad-syntax" | |||
#define TEST_ASSERT(check) do {\ | |||
if (!(check)) {\ | |||
fprintf(stderr, "%s:%d: failed test: %s\n", __FILE__, __LINE__, #check);\ | |||
return 1;\ | |||
}\ | |||
} while (0) | |||
int | |||
main(int argc, char** argv) | |||
{ | |||
if (argc != 2) { | |||
fprintf(stderr, "USAGE: %s BUNDLE\n", argv[0]); | |||
return 1; | |||
} | |||
const char* bundle_path = argv[1]; | |||
LilvWorld* world = lilv_world_new(); | |||
// Load test plugin bundle | |||
uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(bundle_path); | |||
SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true); | |||
LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf); | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri); | |||
TEST_ASSERT(!lilv_plugin_get_name(plugin)); | |||
TEST_ASSERT(!lilv_plugin_instantiate(plugin, 48000, NULL)); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; | |||
} | |||
@@ -0,0 +1,70 @@ | |||
/* | |||
Lilv Test Plugin - Failed instantiation | |||
Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include <stdlib.h> | |||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
#define PLUGIN_URI "http://example.org/failed-instantiation" | |||
enum { | |||
TEST_INPUT = 0, | |||
TEST_OUTPUT = 1 | |||
}; | |||
typedef struct { | |||
float* input; | |||
float* output; | |||
} Test; | |||
static void | |||
cleanup(LV2_Handle instance) | |||
{} | |||
static void | |||
connect_port(LV2_Handle instance, uint32_t port, void* data) | |||
{} | |||
static LV2_Handle | |||
instantiate(const LV2_Descriptor* descriptor, | |||
double rate, | |||
const char* path, | |||
const LV2_Feature* const* features) | |||
{ | |||
return NULL; | |||
} | |||
static void | |||
run(LV2_Handle instance, uint32_t sample_count) | |||
{} | |||
static const LV2_Descriptor descriptor = { | |||
PLUGIN_URI, | |||
instantiate, | |||
connect_port, | |||
NULL, // activate, | |||
run, | |||
NULL, // deactivate, | |||
cleanup, | |||
NULL // extension_data | |||
}; | |||
LV2_SYMBOL_EXPORT | |||
const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||
{ | |||
return (index == 0) ? &descriptor : NULL; | |||
} |
@@ -0,0 +1,40 @@ | |||
# Lilv Test Plugin - Failed instantiation | |||
# Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
@prefix doap: <http://usefulinc.com/ns/doap#> . | |||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . | |||
<http://example.org/failed-instantiation> | |||
a lv2:Plugin ; | |||
doap:license <http://opensource.org/licenses/isc> ; | |||
doap:name "New version" ; | |||
lv2:optionalFeature lv2:hardRTCapable ; | |||
lv2:minorVersion 2 ; | |||
lv2:microVersion 1 ; | |||
lv2:port [ | |||
a lv2:InputPort , | |||
lv2:ControlPort ; | |||
lv2:index 0 ; | |||
lv2:symbol "input" ; | |||
lv2:name "Input" | |||
] , [ | |||
a lv2:OutputPort , | |||
lv2:ControlPort ; | |||
lv2:index 1 ; | |||
lv2:symbol "output" ; | |||
lv2:name "Output" | |||
] . |
@@ -0,0 +1,7 @@ | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |||
<http://example.org/failed-instantiation> | |||
a lv2:Plugin ; | |||
lv2:binary <failed_instantiation@SHLIB_EXT@> ; | |||
rdfs:seeAlso <failed_instantiation.ttl> . |
@@ -0,0 +1,45 @@ | |||
#include "lilv/lilv.h" | |||
#include "../src/lilv_internal.h" | |||
#define PLUGIN_URI "http://example.org/failed-instantiation" | |||
#define TEST_ASSERT(check) do {\ | |||
if (!(check)) {\ | |||
fprintf(stderr, "%s:%d: failed test: %s\n", __FILE__, __LINE__, #check);\ | |||
return 1;\ | |||
}\ | |||
} while (0) | |||
int | |||
main(int argc, char** argv) | |||
{ | |||
if (argc != 2) { | |||
fprintf(stderr, "USAGE: %s BUNDLE\n", argv[0]); | |||
return 1; | |||
} | |||
const char* bundle_path = argv[1]; | |||
LilvWorld* world = lilv_world_new(); | |||
// Load test plugin bundle | |||
uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(bundle_path); | |||
SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true); | |||
LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf); | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri); | |||
TEST_ASSERT(plugin); | |||
TEST_ASSERT(!lilv_plugin_instantiate(plugin, 48000, NULL)); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; | |||
} | |||
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
@@ -37,6 +38,7 @@ main(int argc, char** argv) | |||
LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | |||
TEST_ASSERT(!instance); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; |
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
@@ -36,15 +37,21 @@ main(int argc, char** argv) | |||
LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | |||
TEST_ASSERT(instance); | |||
lilv_instance_free(instance); | |||
LilvNode* eg_blob = lilv_new_uri(world, "http://example.org/blob"); | |||
LilvNode* blob = lilv_world_get(world, plugin_uri, eg_blob, NULL); | |||
TEST_ASSERT(lilv_node_is_literal(blob)); | |||
lilv_node_free(blob); | |||
lilv_node_free(eg_blob); | |||
LilvNode* eg_junk = lilv_new_uri(world, "http://example.org/junk"); | |||
LilvNode* junk = lilv_world_get(world, plugin_uri, eg_junk, NULL); | |||
TEST_ASSERT(lilv_node_is_literal(junk)); | |||
lilv_node_free(junk); | |||
lilv_node_free(eg_junk); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2007-2015 David Robillard <http://drobilla.net> | |||
Copyright 2007-2016 David Robillard <http://drobilla.net> | |||
Copyright 2008 Krzysztof Foltman | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
@@ -15,7 +15,8 @@ | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#define _POSIX_C_SOURCE 200112L /* for setenv */ | |||
#define _POSIX_C_SOURCE 200809L /* for setenv */ | |||
#define _XOPEN_SOURCE 600 /* for mkstemp */ | |||
#include <assert.h> | |||
#include <ctype.h> | |||
@@ -159,9 +160,9 @@ cleanup(void) | |||
#define TEST_ASSERT(check) do {\ | |||
test_count++;\ | |||
if (!(check)) {\ | |||
assert(false);\ | |||
error_count++;\ | |||
fprintf(stderr, "lilv_test.c:%d: error: %s\n", __LINE__, #check);\ | |||
fprintf(stderr, "lilv_test.c:%d: error: test `%s' failed\n", __LINE__, #check);\ | |||
assert(check);\ | |||
}\ | |||
} while (0) | |||
@@ -252,6 +253,23 @@ test_value(void) | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(sval), "Foo")); | |||
TEST_ASSERT(lilv_node_as_int(ival) == 42); | |||
TEST_ASSERT(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON); | |||
TEST_ASSERT(isnan(lilv_node_as_float(sval))); | |||
#if defined(__clang__) | |||
# pragma clang diagnostic push | |||
# pragma clang diagnostic ignored "-Wdeprecated-declarations" | |||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |||
#endif | |||
TEST_ASSERT(!strcmp(lilv_uri_to_path("file:///foo"), "/foo")); | |||
#if defined(__clang__) | |||
# pragma clang diagnostic pop | |||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | |||
# pragma GCC diagnostic pop | |||
#endif | |||
LilvNode* loc_abs = lilv_new_file_uri(world, NULL, "/foo/bar"); | |||
LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo"); | |||
@@ -345,6 +363,29 @@ test_util(void) | |||
{ | |||
TEST_ASSERT(!lilv_realpath(NULL)); | |||
char a_path[16]; | |||
char b_path[16]; | |||
strcpy(a_path, "copy_a_XXXXXX"); | |||
strcpy(b_path, "copy_b_XXXXXX"); | |||
mkstemp(a_path); | |||
mkstemp(b_path); | |||
FILE* fa = fopen(a_path, "w"); | |||
FILE* fb = fopen(b_path, "w"); | |||
fprintf(fa, "AA\n"); | |||
fprintf(fb, "AB\n"); | |||
fclose(fa); | |||
fclose(fb); | |||
TEST_ASSERT(lilv_copy_file("does/not/exist", "copy")); | |||
TEST_ASSERT(lilv_copy_file(a_path, "not/a/dir/copy")); | |||
TEST_ASSERT(!lilv_copy_file(a_path, "copy_c")); | |||
TEST_ASSERT(!lilv_file_equals(a_path, b_path)); | |||
TEST_ASSERT(lilv_file_equals(a_path, a_path)); | |||
TEST_ASSERT(lilv_file_equals(a_path, "copy_c")); | |||
TEST_ASSERT(!lilv_file_equals("does/not/exist", b_path)); | |||
TEST_ASSERT(!lilv_file_equals(a_path, "does/not/exist")); | |||
TEST_ASSERT(!lilv_file_equals("does/not/exist", "/does/not/either")); | |||
return 1; | |||
} | |||
@@ -1418,6 +1459,7 @@ test_ui(void) | |||
uint32_t atom_Float = 0; | |||
float in = 1.0; | |||
float out = 42.0; | |||
float control = 1234.0; | |||
static const void* | |||
get_port_value(const char* port_symbol, | |||
@@ -1433,6 +1475,10 @@ get_port_value(const char* port_symbol, | |||
*size = sizeof(float); | |||
*type = atom_Float; | |||
return &out; | |||
} else if (!strcmp(port_symbol, "control")) { | |||
*size = sizeof(float); | |||
*type = atom_Float; | |||
return &control; | |||
} else { | |||
fprintf(stderr, "error: get_port_value for nonexistent port `%s'\n", | |||
port_symbol); | |||
@@ -1452,6 +1498,8 @@ set_port_value(const char* port_symbol, | |||
in = *(const float*)value; | |||
} else if (!strcmp(port_symbol, "output")) { | |||
out = *(const float*)value; | |||
} else if (!strcmp(port_symbol, "control")) { | |||
control = *(const float*)value; | |||
} else { | |||
fprintf(stderr, "error: set_port_value for nonexistent port `%s'\n", | |||
port_symbol); | |||
@@ -1613,6 +1661,18 @@ test_state(void) | |||
get_port_value, world, 0, NULL); | |||
TEST_ASSERT(lilv_state_equals(state2, state4)); | |||
// Set some metadata properties | |||
lilv_state_set_metadata(state, map.map(map.handle, LILV_NS_RDFS "comment"), | |||
"This is a comment", | |||
strlen("This is a comment") + 1, | |||
map.map(map.handle, "http://lv2plug.in/ns/ext/atom#Literal"), | |||
LV2_STATE_IS_POD); | |||
lilv_state_set_metadata(state, map.map(map.handle, "http://example.org/metablob"), | |||
"LIVEBEEF", | |||
strlen("LIVEBEEF") + 1, | |||
map.map(map.handle, "http://example.org/MetaBlob"), | |||
0); | |||
// Save state to a directory | |||
int ret = lilv_state_save(world, &map, &unmap, state, NULL, | |||
"state/state.lv2", "state.ttl"); | |||
@@ -1623,6 +1683,16 @@ test_state(void) | |||
"state/state.lv2/state.ttl"); | |||
TEST_ASSERT(lilv_state_equals(state, state5)); // Round trip accuracy | |||
TEST_ASSERT(lilv_state_get_num_properties(state) == 8); | |||
// Attempt to save state to nowhere (error) | |||
ret = lilv_state_save(world, &map, &unmap, state, NULL, NULL, NULL); | |||
TEST_ASSERT(ret); | |||
// Save another state to the same directory (update manifest) | |||
ret = lilv_state_save(world, &map, &unmap, state, NULL, | |||
"state/state.lv2", "state2.ttl"); | |||
TEST_ASSERT(!ret); | |||
// Save state with URI to a directory | |||
const char* state_uri = "http://example.org/state"; | |||
@@ -1893,6 +1963,7 @@ test_string(void) | |||
TEST_ASSERT(!strcmp((s = lilv_path_join("/a/", "/b")), "/a/b")); free(s); | |||
TEST_ASSERT(!strcmp((s = lilv_path_join("/a/", "b")), "/a/b")); free(s); | |||
TEST_ASSERT(!strcmp((s = lilv_path_join("/a", NULL)), "/a/")); free(s); | |||
TEST_ASSERT(!strcmp((s = lilv_path_join(NULL, "/b")), "/b")); free(s); | |||
#ifndef _WIN32 | |||
setenv("LILV_TEST_1", "test", 1); | |||
@@ -1940,6 +2011,209 @@ test_world(void) | |||
/*****************************************************************************/ | |||
static int | |||
test_reload_bundle(void) | |||
{ | |||
// Create a simple plugin bundle | |||
create_bundle(MANIFEST_PREFIXES | |||
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n", | |||
BUNDLE_PREFIXES | |||
":plug a lv2:Plugin ; " | |||
PLUGIN_NAME("First name") " ."); | |||
if (!init_world()) { | |||
return 0; | |||
} | |||
init_uris(); | |||
lilv_world_load_specifications(world); | |||
// Load bundle | |||
LilvNode* bundle_uri = lilv_new_uri(world, bundle_dir_uri); | |||
lilv_world_load_bundle(world, bundle_uri); | |||
// Check that plugin is present | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, plugin_uri_value); | |||
TEST_ASSERT(plug); | |||
// Check that plugin name is correct | |||
LilvNode* name = lilv_plugin_get_name(plug); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(name), "First name")); | |||
lilv_node_free(name); | |||
// Unload bundle from world and delete it | |||
lilv_world_unload_bundle(world, bundle_uri); | |||
delete_bundle(); | |||
// Create a new version of the same bundle, but with a different name | |||
create_bundle(MANIFEST_PREFIXES | |||
":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n", | |||
BUNDLE_PREFIXES | |||
":plug a lv2:Plugin ; " | |||
PLUGIN_NAME("Second name") " ."); | |||
// Check that plugin is no longer in the world's plugin list | |||
TEST_ASSERT(lilv_plugins_size(plugins) == 0); | |||
// Load new bundle | |||
lilv_world_load_bundle(world, bundle_uri); | |||
// Check that plugin is present again and is the same LilvPlugin | |||
const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, plugin_uri_value); | |||
TEST_ASSERT(plug2); | |||
TEST_ASSERT(plug2 == plug); | |||
// Check that plugin now has new name | |||
LilvNode* name2 = lilv_plugin_get_name(plug2); | |||
TEST_ASSERT(name2); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(name2), "Second name")); | |||
lilv_node_free(name2); | |||
// Load new bundle again (noop) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
cleanup_uris(); | |||
lilv_node_free(bundle_uri); | |||
lilv_world_free(world); | |||
world = NULL; | |||
return 1; | |||
} | |||
/*****************************************************************************/ | |||
static int | |||
test_replace_version(void) | |||
{ | |||
if (!init_world()) { | |||
return 0; | |||
} | |||
LilvNode* plug_uri = lilv_new_uri(world, "http://example.org/versioned"); | |||
LilvNode* lv2_minorVersion = lilv_new_uri(world, LV2_CORE__minorVersion); | |||
LilvNode* lv2_microVersion = lilv_new_uri(world, LV2_CORE__microVersion); | |||
LilvNode* minor = NULL; | |||
LilvNode* micro = NULL; | |||
char* old_bundle_path = (char*)malloc(strlen(LILV_TEST_DIR) + 32); | |||
strcpy(old_bundle_path, LILV_TEST_DIR); | |||
strcat(old_bundle_path, "old_version.lv2/"); | |||
// Load plugin from old bundle | |||
LilvNode* old_bundle = lilv_new_file_uri(world, NULL, old_bundle_path); | |||
lilv_world_load_bundle(world, old_bundle); | |||
lilv_world_load_resource(world, plug_uri); | |||
// Check version | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
const LilvPlugin* old_plug = lilv_plugins_get_by_uri(plugins, plug_uri); | |||
TEST_ASSERT(old_plug); | |||
minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0); | |||
micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(minor), "1")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(micro), "0")); | |||
lilv_node_free(micro); | |||
lilv_node_free(minor); | |||
char* new_bundle_path = (char*)malloc(strlen(LILV_TEST_DIR) + 32); | |||
strcpy(new_bundle_path, LILV_TEST_DIR); | |||
strcat(new_bundle_path, "new_version.lv2/"); | |||
// Load plugin from new bundle | |||
LilvNode* new_bundle = lilv_new_file_uri(world, NULL, new_bundle_path); | |||
lilv_world_load_bundle(world, new_bundle); | |||
lilv_world_load_resource(world, plug_uri); | |||
// Check that version in the world model has changed | |||
plugins = lilv_world_get_all_plugins(world); | |||
const LilvPlugin* new_plug = lilv_plugins_get_by_uri(plugins, plug_uri); | |||
TEST_ASSERT(new_plug); | |||
TEST_ASSERT(lilv_node_equals(lilv_plugin_get_bundle_uri(new_plug), new_bundle)); | |||
minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0); | |||
micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(minor), "2")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(micro), "1")); | |||
lilv_node_free(micro); | |||
lilv_node_free(minor); | |||
// Try to load the old version again | |||
lilv_world_load_bundle(world, old_bundle); | |||
lilv_world_load_resource(world, plug_uri); | |||
// Check that version in the world model has not changed | |||
plugins = lilv_world_get_all_plugins(world); | |||
new_plug = lilv_plugins_get_by_uri(plugins, plug_uri); | |||
TEST_ASSERT(new_plug); | |||
minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0); | |||
micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(minor), "2")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(micro), "1")); | |||
lilv_node_free(micro); | |||
lilv_node_free(minor); | |||
lilv_node_free(new_bundle); | |||
lilv_node_free(old_bundle); | |||
free(new_bundle_path); | |||
free(old_bundle_path); | |||
lilv_node_free(plug_uri); | |||
lilv_node_free(lv2_minorVersion); | |||
lilv_node_free(lv2_microVersion); | |||
return 1; | |||
} | |||
/*****************************************************************************/ | |||
static int | |||
test_get_symbol(void) | |||
{ | |||
if (!start_bundle( | |||
MANIFEST_PREFIXES | |||
":plug a lv2:Plugin ; lv2:symbol \"plugsym\" ; lv2:binary <foo" SHLIB_EXT "> ; rdfs:seeAlso <plugin.ttl> .\n", | |||
BUNDLE_PREFIXES PREFIX_LV2EV | |||
":plug a lv2:Plugin ; " | |||
PLUGIN_NAME("Test plugin") " ; " | |||
"lv2:symbol \"plugsym\" .")) { | |||
return 0; | |||
} | |||
init_uris(); | |||
LilvNode* plug_sym = lilv_world_get_symbol(world, plugin_uri_value); | |||
LilvNode* path = lilv_new_uri(world, "http://example.org/foo"); | |||
LilvNode* path_sym = lilv_world_get_symbol(world, path); | |||
LilvNode* query = lilv_new_uri(world, "http://example.org/foo?bar=baz"); | |||
LilvNode* query_sym = lilv_world_get_symbol(world, query); | |||
LilvNode* frag = lilv_new_uri(world, "http://example.org/foo#bar"); | |||
LilvNode* frag_sym = lilv_world_get_symbol(world, frag); | |||
LilvNode* queryfrag = lilv_new_uri(world, "http://example.org/foo?bar=baz#quux"); | |||
LilvNode* queryfrag_sym = lilv_world_get_symbol(world, queryfrag); | |||
LilvNode* nonuri = lilv_new_int(world, 42); | |||
TEST_ASSERT(lilv_world_get_symbol(world, nonuri) == NULL); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(plug_sym), "plugsym")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(path_sym), "foo")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(query_sym), "bar_baz")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(frag_sym), "bar")); | |||
TEST_ASSERT(!strcmp(lilv_node_as_string(queryfrag_sym), "quux")); | |||
lilv_node_free(nonuri); | |||
lilv_node_free(queryfrag_sym); | |||
lilv_node_free(queryfrag); | |||
lilv_node_free(frag_sym); | |||
lilv_node_free(frag); | |||
lilv_node_free(query_sym); | |||
lilv_node_free(query); | |||
lilv_node_free(path_sym); | |||
lilv_node_free(path); | |||
lilv_node_free(plug_sym); | |||
cleanup_uris(); | |||
return 1; | |||
} | |||
/*****************************************************************************/ | |||
/* add tests here */ | |||
static struct TestCase tests[] = { | |||
TEST_CASE(util), | |||
@@ -1963,6 +2237,9 @@ static struct TestCase tests[] = { | |||
TEST_CASE(string), | |||
TEST_CASE(world), | |||
TEST_CASE(state), | |||
TEST_CASE(reload_bundle), | |||
TEST_CASE(replace_version), | |||
TEST_CASE(get_symbol), | |||
{ NULL, NULL } | |||
}; | |||
@@ -17,4 +17,4 @@ | |||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
LV2_SYMBOL_EXPORT const char* msg = "this is not the thing you're looking for"; | |||
const char* msg = "this is not the thing you're looking for"; |
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
@@ -37,6 +38,7 @@ main(int argc, char** argv) | |||
LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | |||
TEST_ASSERT(!instance); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; |
@@ -1,5 +1,5 @@ | |||
/* | |||
Lilv Test Plugin - Missing descriptor | |||
Lilv Test Plugin - Missing name | |||
Copyright 2011-2015 David Robillard <d@drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any |
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
@@ -36,7 +37,9 @@ main(int argc, char** argv) | |||
LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | |||
TEST_ASSERT(instance); | |||
lilv_instance_free(instance); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; |
@@ -21,8 +21,23 @@ | |||
#define PLUGIN_URI "http://example.org/missing-plugin" | |||
static const LV2_Descriptor descriptor = { | |||
"http://example.org/not-the-plugin-you-are-looking-for", | |||
NULL, | |||
NULL, | |||
NULL, | |||
NULL, | |||
NULL, | |||
NULL, | |||
NULL | |||
}; | |||
LV2_SYMBOL_EXPORT | |||
const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||
{ | |||
if (index == 0) { | |||
return &descriptor; | |||
} | |||
return NULL; | |||
} |
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
@@ -37,6 +38,7 @@ main(int argc, char** argv) | |||
LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | |||
TEST_ASSERT(!instance); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; |
@@ -0,0 +1,7 @@ | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |||
<http://example.org/missing-port> | |||
a lv2:Plugin ; | |||
lv2:binary <missing_port@SHLIB_EXT@> ; | |||
rdfs:seeAlso <missing_port.ttl> . |
@@ -0,0 +1,93 @@ | |||
/* | |||
Lilv Test Plugin - Missing port | |||
Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include <stdlib.h> | |||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
#define PLUGIN_URI "http://example.org/missing-port" | |||
enum { | |||
TEST_INPUT = 0, | |||
TEST_OUTPUT = 1 | |||
}; | |||
typedef struct { | |||
float* input; | |||
float* output; | |||
} Test; | |||
static void | |||
cleanup(LV2_Handle instance) | |||
{ | |||
free((Test*)instance); | |||
} | |||
static void | |||
connect_port(LV2_Handle instance, uint32_t port, void* data) | |||
{ | |||
Test* test = (Test*)instance; | |||
switch (port) { | |||
case TEST_INPUT: | |||
test->input = (float*)data; | |||
break; | |||
case TEST_OUTPUT: | |||
test->output = (float*)data; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
static LV2_Handle | |||
instantiate(const LV2_Descriptor* descriptor, | |||
double rate, | |||
const char* path, | |||
const LV2_Feature* const* features) | |||
{ | |||
Test* test = (Test*)calloc(1, sizeof(Test)); | |||
if (!test) { | |||
return NULL; | |||
} | |||
return (LV2_Handle)test; | |||
} | |||
static void | |||
run(LV2_Handle instance, uint32_t sample_count) | |||
{ | |||
Test* test = (Test*)instance; | |||
*test->output = *test->input; | |||
} | |||
static const LV2_Descriptor descriptor = { | |||
PLUGIN_URI, | |||
instantiate, | |||
connect_port, | |||
NULL, // activate, | |||
run, | |||
NULL, // deactivate, | |||
cleanup, | |||
NULL // extension_data | |||
}; | |||
LV2_SYMBOL_EXPORT | |||
const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||
{ | |||
return (index == 0) ? &descriptor : NULL; | |||
} |
@@ -0,0 +1,31 @@ | |||
# Lilv Test Plugin - Missing plugin port | |||
# Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
@prefix doap: <http://usefulinc.com/ns/doap#> . | |||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . | |||
<http://example.org/missing-port> | |||
a lv2:Plugin ; | |||
doap:license <http://opensource.org/licenses/isc> ; | |||
lv2:optionalFeature lv2:hardRTCapable ; | |||
lv2:port [ | |||
a lv2:OutputPort , | |||
lv2:ControlPort ; | |||
lv2:index 1 ; | |||
lv2:symbol "output" ; | |||
lv2:name "Output" | |||
] . |
@@ -0,0 +1,45 @@ | |||
#include "lilv/lilv.h" | |||
#include "../src/lilv_internal.h" | |||
#define PLUGIN_URI "http://example.org/missing-port" | |||
#define TEST_ASSERT(check) do {\ | |||
if (!(check)) {\ | |||
fprintf(stderr, "%s:%d: failed test: %s\n", __FILE__, __LINE__, #check);\ | |||
return 1;\ | |||
}\ | |||
} while (0) | |||
int | |||
main(int argc, char** argv) | |||
{ | |||
if (argc != 2) { | |||
fprintf(stderr, "USAGE: %s BUNDLE\n", argv[0]); | |||
return 1; | |||
} | |||
const char* bundle_path = argv[1]; | |||
LilvWorld* world = lilv_world_new(); | |||
// Load test plugin bundle | |||
uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(bundle_path); | |||
SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true); | |||
LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf); | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri); | |||
// Check that all ports are ignored | |||
TEST_ASSERT(lilv_plugin_get_num_ports(plugin) == 0); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; | |||
} | |||
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||
lilv_world_load_bundle(world, bundle_uri); | |||
free(abs_bundle); | |||
serd_node_free(&bundle); | |||
lilv_node_free(bundle_uri); | |||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | |||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | |||
@@ -38,7 +39,9 @@ main(int argc, char** argv) | |||
TEST_ASSERT(port); | |||
LilvNode* name = lilv_port_get_name(plugin, port); | |||
TEST_ASSERT(!name); | |||
lilv_node_free(name); | |||
lilv_node_free(plugin_uri); | |||
lilv_world_free(world); | |||
return 0; |
@@ -0,0 +1,7 @@ | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |||
<http://example.org/versioned> | |||
a lv2:Plugin ; | |||
lv2:binary <new_version@SHLIB_EXT@> ; | |||
rdfs:seeAlso <new_version.ttl> . |
@@ -0,0 +1,93 @@ | |||
/* | |||
Lilv Test Plugin - New version | |||
Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include <stdlib.h> | |||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
#define PLUGIN_URI "http://example.org/versioned" | |||
enum { | |||
TEST_INPUT = 0, | |||
TEST_OUTPUT = 1 | |||
}; | |||
typedef struct { | |||
float* input; | |||
float* output; | |||
} Test; | |||
static void | |||
cleanup(LV2_Handle instance) | |||
{ | |||
free((Test*)instance); | |||
} | |||
static void | |||
connect_port(LV2_Handle instance, uint32_t port, void* data) | |||
{ | |||
Test* test = (Test*)instance; | |||
switch (port) { | |||
case TEST_INPUT: | |||
test->input = (float*)data; | |||
break; | |||
case TEST_OUTPUT: | |||
test->output = (float*)data; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
static LV2_Handle | |||
instantiate(const LV2_Descriptor* descriptor, | |||
double rate, | |||
const char* path, | |||
const LV2_Feature* const* features) | |||
{ | |||
Test* test = (Test*)calloc(1, sizeof(Test)); | |||
if (!test) { | |||
return NULL; | |||
} | |||
return (LV2_Handle)test; | |||
} | |||
static void | |||
run(LV2_Handle instance, uint32_t sample_count) | |||
{ | |||
Test* test = (Test*)instance; | |||
*test->output = *test->input; | |||
} | |||
static const LV2_Descriptor descriptor = { | |||
PLUGIN_URI, | |||
instantiate, | |||
connect_port, | |||
NULL, // activate, | |||
run, | |||
NULL, // deactivate, | |||
cleanup, | |||
NULL // extension_data | |||
}; | |||
LV2_SYMBOL_EXPORT | |||
const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||
{ | |||
return (index == 0) ? &descriptor : NULL; | |||
} |
@@ -0,0 +1,40 @@ | |||
# Lilv Test Plugin - New version | |||
# Copyright 2011-2016 David Robillard <d@drobilla.net> | |||
# | |||
# Permission to use, copy, modify, and/or distribute this software for any | |||
# purpose with or without fee is hereby granted, provided that the above | |||
# copyright notice and this permission notice appear in all copies. | |||
# | |||
# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
@prefix doap: <http://usefulinc.com/ns/doap#> . | |||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . | |||
<http://example.org/versioned> | |||
a lv2:Plugin ; | |||
doap:license <http://opensource.org/licenses/isc> ; | |||
doap:name "New version" ; | |||
lv2:optionalFeature lv2:hardRTCapable ; | |||
lv2:minorVersion 2 ; | |||
lv2:microVersion 1 ; | |||
lv2:port [ | |||
a lv2:InputPort , | |||
lv2:ControlPort ; | |||
lv2:index 0 ; | |||
lv2:symbol "input" ; | |||
lv2:name "Input" | |||
] , [ | |||
a lv2:OutputPort , | |||
lv2:ControlPort ; | |||
lv2:index 1 ; | |||
lv2:symbol "output" ; | |||
lv2:name "Output" | |||
] . |
@@ -0,0 +1,7 @@ | |||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | |||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |||
<http://example.org/versioned> | |||
a lv2:Plugin ; | |||
lv2:binary <old_version@SHLIB_EXT@> ; | |||
rdfs:seeAlso <old_version.ttl> . |