@@ -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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | 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; | 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] | data = [(i - float(range/2)) / float(range/2) for i in data] | ||||
channels = [] | 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 | return channels | ||||
@@ -57,6 +57,7 @@ def main(): | |||||
# Initialise Lilv | # Initialise Lilv | ||||
world = lilv.World() | world = lilv.World() | ||||
ns = world.ns | |||||
world.load_all() | world.load_all() | ||||
plugin_uri = sys.argv[1] | plugin_uri = sys.argv[1] | ||||
@@ -65,19 +66,14 @@ def main(): | |||||
# Find plugin | # Find plugin | ||||
plugin_uri_node = world.new_uri(plugin_uri) | 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) | 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: | if n_audio_out == 0: | ||||
print("Plugin has no audio outputs\n") | print("Plugin has no audio outputs\n") | ||||
sys.exit(1) | sys.exit(1) | ||||
@@ -120,22 +116,21 @@ def main(): | |||||
control_output_buffers = [] | control_output_buffers = [] | ||||
for index in range(plugin.get_num_ports()): | for index in range(plugin.get_num_ports()): | ||||
port = plugin.get_port_by_index(index) | 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)) | audio_input_buffers.append(numpy.array(channels[len(audio_input_buffers)], numpy.float32)) | ||||
instance.connect_port(index, audio_input_buffers[-1]) | 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)) | control_input_buffers.append(numpy.array([default], numpy.float32)) | ||||
instance.connect_port(index, control_input_buffers[-1]) | instance.connect_port(index, control_input_buffers[-1]) | ||||
else: | else: | ||||
raise ValueError("Unhandled port type") | 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)) | audio_output_buffers.append(numpy.array([0] * wav_in.nframes, numpy.float32)) | ||||
instance.connect_port(index, audio_output_buffers[-1]) | 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)) | control_output_buffers.append(numpy.array([0], numpy.float32)) | ||||
instance.connect_port(index, control_output_buffers[-1]) | instance.connect_port(index, control_output_buffers[-1]) | ||||
else: | else: | ||||
@@ -156,7 +151,7 @@ def main(): | |||||
# Write output file in chunks to stop memory usage getting out of hand: | # Write output file in chunks to stop memory usage getting out of hand: | ||||
CHUNK_SIZE = 8192 | CHUNK_SIZE = 8192 | ||||
for chunk in numpy.array_split(data, CHUNK_SIZE): | 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() | wav_out.close() | ||||
@@ -54,7 +54,7 @@ typedef enum { | |||||
every instance method. In this simple plugin, only port buffers need to be | every instance method. In this simple plugin, only port buffers need to be | ||||
stored, since there is no additional instance data. */ | stored, since there is no additional instance data. */ | ||||
typedef struct { | typedef struct { | ||||
// Port buffers | |||||
float* buf; | |||||
} Test; | } 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 | 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 | indentifier, the URI of the returned descriptor is used to determine the | ||||
identify of the plugin. | identify of the plugin. | ||||
This method is in the ``discovery'' threading class, so no other functions | This method is in the ``discovery'' threading class, so no other functions | ||||
or methods in this plugin library will be called concurrently with it. | or methods in this plugin library will be called concurrently with it. | ||||
*/ | */ |
@@ -16,18 +16,27 @@ | |||||
@prefix doap: <http://usefulinc.com/ns/doap#> . | @prefix doap: <http://usefulinc.com/ns/doap#> . | ||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> . | @prefix foaf: <http://xmlns.com/foaf/0.1/> . | ||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . | @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#> . | @prefix ui: <http://lv2plug.in/ns/extensions/ui#> . | ||||
<http://example.org/lilv-bindings-test-plugin> | <http://example.org/lilv-bindings-test-plugin> | ||||
a lv2:Plugin ; | a lv2:Plugin ; | ||||
doap:name "Lilv Bindings Test" ; | doap:name "Lilv Bindings Test" ; | ||||
doap:license <http://opensource.org/licenses/isc> ; | doap:license <http://opensource.org/licenses/isc> ; | ||||
lv2:optionalFeature lv2:hardRTCapable ; | |||||
ui:ui <http://example.org/lilv-bindings-test-plugin-ui> ; | |||||
lv2:port [ | lv2:port [ | ||||
a lv2:InputPort , | a lv2:InputPort , | ||||
lv2:ControlPort ; | lv2:ControlPort ; | ||||
lv2:index 0 ; | lv2:index 0 ; | ||||
lv2:symbol "input" ; | 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 , | a lv2:OutputPort , | ||||
lv2:ControlPort ; | lv2:ControlPort ; | ||||
@@ -47,3 +56,7 @@ | |||||
lv2:symbol "audio_output" ; | lv2:symbol "audio_output" ; | ||||
lv2:name "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 | .SH NAME | ||||
.B lv2info \- print information about an installed LV2 plugin. | |||||
.B lv2info \- print information about an installed LV2 plugin | |||||
.SH SYNOPSIS | .SH SYNOPSIS | ||||
.B lv2info PLUGIN_URI | .B lv2info PLUGIN_URI | ||||
.SH OPTIONS | .SH OPTIONS | ||||
.TP | .TP | ||||
\fB\-p FILE | |||||
\fB\-p FILE\fR | |||||
Write Turtle description of plugin to FILE | Write Turtle description of plugin to FILE | ||||
.TP | .TP | ||||
\fB\-m FILE | |||||
\fB\-m FILE\fR | |||||
Add record of plugin to manifest FILE | Add record of plugin to manifest FILE | ||||
.TP | .TP | ||||
@@ -22,7 +22,7 @@ Display help and exit | |||||
\fB\-\-version\fR | \fB\-\-version\fR | ||||
Display version information and exit | Display version information and exit | ||||
.SH SEE ALSO | |||||
.SH "SEE ALSO" | |||||
.BR lilv(3), | .BR lilv(3), | ||||
.BR lv2ls(1) | .BR lv2ls(1) | ||||
@@ -1,7 +1,7 @@ | |||||
.TH LV2LS 1 "17 Jan 2012" | |||||
.TH LV2LS 1 "26 Aug 2016" | |||||
.SH NAME | .SH NAME | ||||
.B lv2ls \- List all installed LV2 plugins. | |||||
.B lv2ls \- list all installed LV2 plugins | |||||
.SH SYNOPSIS | .SH SYNOPSIS | ||||
.B lv2ls [OPTION]... | .B lv2ls [OPTION]... | ||||
@@ -19,7 +19,7 @@ Display help and exit | |||||
\fB\-\-version\fR | \fB\-\-version\fR | ||||
Display version information and exit | Display version information and exit | ||||
.SH SEE ALSO | |||||
.SH "SEE ALSO" | |||||
.BR lilv(3), | .BR lilv(3), | ||||
.BR lv2info(1) | .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 | # This file describes the settings to be used by the documentation system | ||||
# doxygen (www.doxygen.org) for a project. | # doxygen (www.doxygen.org) for a project. | ||||
@@ -46,10 +46,10 @@ PROJECT_NUMBER = @LILV_VERSION@ | |||||
PROJECT_BRIEF = | 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 = | PROJECT_LOGO = | ||||
@@ -60,7 +60,7 @@ PROJECT_LOGO = | |||||
OUTPUT_DIRECTORY = . | 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 | # directories (in 2 levels) under the output directory of each output format and | ||||
# will distribute the generated files over these directories. Enabling this | # will distribute the generated files over these directories. Enabling this | ||||
# option can be useful when feeding doxygen a huge amount of source files, where | # 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 | 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 | # descriptions after the members that are listed in the file and class | ||||
# documentation (similar to Javadoc). Set to NO to disable this. | # documentation (similar to Javadoc). Set to NO to disable this. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
BRIEF_MEMBER_DESC = NO | 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 | # 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 | # 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 | 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 | # 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 | # shortest path that makes the file name unique will be used | ||||
# The default value is: YES. | # The default value is: YES. | ||||
@@ -205,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO | |||||
INHERIT_DOCS = YES | 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. | # The default value is: NO. | ||||
SEPARATE_MEMBER_PAGES = 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), | # 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. | # 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 | # Note that for custom extensions you also need to set FILE_PATTERNS otherwise | ||||
# the files are not read by doxygen. | # the files are not read by doxygen. | ||||
@@ -293,10 +293,19 @@ EXTENSION_MAPPING = | |||||
MARKDOWN_SUPPORT = YES | 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 | # When enabled doxygen tries to link words that correspond to documented | ||||
# classes, or namespaces to their corresponding documentation. Such a link can | # 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. | # The default value is: YES. | ||||
AUTOLINK_SUPPORT = YES | AUTOLINK_SUPPORT = YES | ||||
@@ -336,13 +345,20 @@ SIP_SUPPORT = NO | |||||
IDL_PROPERTY_SUPPORT = YES | IDL_PROPERTY_SUPPORT = YES | ||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC | # 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 | # member in the group (if any) for the other members of the group. By default | ||||
# all members of a group must be documented explicitly. | # all members of a group must be documented explicitly. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
DISTRIBUTE_GROUP_DOC = 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 | # 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 | # (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 | # 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 | # 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 | # documentation are documented, even if no documentation was available. Private | ||||
# class members and static file members will be hidden unless the | # class members and static file members will be hidden unless the | ||||
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. | # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. | ||||
@@ -411,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 | |||||
EXTRACT_ALL = YES | 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. | # be included in the documentation. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
EXTRACT_PRIVATE = 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. | # scope will be included in the documentation. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
EXTRACT_PACKAGE = 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. | # included in the documentation. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
EXTRACT_STATIC = YES | 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 | # only classes defined in header files are included. Does not have any effect | ||||
# for Java sources. | # for Java sources. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
EXTRACT_LOCAL_CLASSES = NO | 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 | # 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. | # included. | ||||
# The default value is: NO. | # 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 | # 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 | # 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. | # The default value is: NO. | ||||
HIDE_UNDOC_CLASSES = YES | HIDE_UNDOC_CLASSES = YES | ||||
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend | # 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. | # included in the documentation. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
HIDE_FRIEND_COMPOUNDS = NO | HIDE_FRIEND_COMPOUNDS = NO | ||||
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any | # 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. | # blocks will be appended to the function's detailed documentation block. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -492,7 +508,7 @@ HIDE_IN_BODY_DOCS = YES | |||||
INTERNAL_DOCS = NO | INTERNAL_DOCS = NO | ||||
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file | # 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 | # 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 | # in case and if your file system supports case sensitive file names. Windows | ||||
# and Mac users are advised to set this option to NO. | # and Mac users are advised to set this option to NO. | ||||
@@ -501,12 +517,19 @@ INTERNAL_DOCS = NO | |||||
CASE_SENSE_NAMES = YES | CASE_SENSE_NAMES = YES | ||||
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with | # 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. | # scope will be hidden. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
HIDE_SCOPE_NAMES = 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 | # 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 files that are included by a file in the documentation of that file. | ||||
# The default value is: YES. | # 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 | # 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 | # (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. | # The default value is: YES. | ||||
SORT_MEMBER_DOCS = NO | SORT_MEMBER_DOCS = NO | ||||
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief | # 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 | # 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. | # this will also influence the order of the classes in the class list. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -586,27 +609,25 @@ SORT_BY_SCOPE_NAME = YES | |||||
STRICT_PROTO_MATCHING = NO | 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. | # The default value is: YES. | ||||
GENERATE_TODOLIST = NO | 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. | # The default value is: YES. | ||||
GENERATE_TESTLIST = NO | 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. | # list. This list is created by putting \bug commands in the documentation. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
GENERATE_BUGLIST = NO | 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 deprecated list. This list is created by putting \deprecated commands in | ||||
# the documentation. | # the documentation. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
@@ -631,8 +652,8 @@ ENABLED_SECTIONS = | |||||
MAX_INITIALIZER_LINES = 30 | MAX_INITIALIZER_LINES = 30 | ||||
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at | # 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. | # The default value is: YES. | ||||
SHOW_USED_FILES = 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. | # 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 | # 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 | # 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 = | CITE_BIB_FILES = | ||||
@@ -697,7 +717,7 @@ CITE_BIB_FILES = | |||||
QUIET = YES | QUIET = YES | ||||
# The WARNINGS tag can be used to turn on/off the warning messages that are | # 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. | # this implies that the warnings are on. | ||||
# | # | ||||
# Tip: Turn warnings on while writing the documentation. | # Tip: Turn warnings on while writing the documentation. | ||||
@@ -705,7 +725,7 @@ QUIET = YES | |||||
WARNINGS = 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 | # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag | ||||
# will automatically be disabled. | # will automatically be disabled. | ||||
# The default value is: YES. | # 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 | # 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 | # 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. | # The default value is: NO. | ||||
WARN_NO_PARAMDOC = YES | 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 | # 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 | # 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 | # 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 | # 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 | # documented source files. You may enter file names like myfile.cpp or | ||||
# directories like /usr/src/myproject. Separate the files or directories with | # 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. | # Note: If this tag is empty the current directory is searched. | ||||
INPUT = @LILV_SRCDIR@/lilv/lilv.h | 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 | # 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 | # 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 = | FILE_PATTERNS = | ||||
@@ -858,6 +889,10 @@ IMAGE_PATH = | |||||
# Note that the filter must not add or remove lines; it is applied before the | # 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 | # code is scanned, but not when the output code is generated. If lines are added | ||||
# or removed, the anchors will not be placed correctly. | # 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 = | INPUT_FILTER = | ||||
@@ -867,11 +902,15 @@ INPUT_FILTER = | |||||
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how | # (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 | # filters are used. If the FILTER_PATTERNS tag is empty or if none of the | ||||
# patterns match the file name, INPUT_FILTER is applied. | # 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 = | FILTER_PATTERNS = | ||||
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using | # 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). | # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -931,7 +970,7 @@ REFERENCED_BY_RELATION = YES | |||||
REFERENCES_RELATION = YES | REFERENCES_RELATION = YES | ||||
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set | # 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 | # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will | ||||
# link to the documentation. | # link to the documentation. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
@@ -1008,7 +1047,7 @@ IGNORE_PREFIX = | |||||
# Configuration options related to the HTML output | # 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. | # The default value is: YES. | ||||
GENERATE_HTML = YES | GENERATE_HTML = YES | ||||
@@ -1070,13 +1109,15 @@ HTML_FOOTER = | |||||
HTML_STYLESHEET = @LILV_SRCDIR@/doc/style.css | 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. | # 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 | # 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. | # This tag requires that the tag GENERATE_HTML is set to YES. | ||||
HTML_EXTRA_STYLESHEET = | HTML_EXTRA_STYLESHEET = | ||||
@@ -1092,7 +1133,7 @@ HTML_EXTRA_STYLESHEET = | |||||
HTML_EXTRA_FILES = | HTML_EXTRA_FILES = | ||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen | # 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 | # 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 | # 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 | # 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 | # 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 | # 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. | # This tag requires that the tag GENERATE_HTML is set to YES. | ||||
HTML_TIMESTAMP = NO | HTML_TIMESTAMP = NO | ||||
@@ -1220,28 +1262,28 @@ GENERATE_HTMLHELP = NO | |||||
CHM_FILE = | CHM_FILE = | ||||
# The HHC_LOCATION tag can be used to specify the location (absolute path | # 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. | # doxygen will try to run the HTML help compiler on the generated index.hhp. | ||||
# The file has to be specified with full path. | # The file has to be specified with full path. | ||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | ||||
HHC_LOCATION = | 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. | # The default value is: NO. | ||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | ||||
GENERATE_CHI = NO | 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. | # and project file content. | ||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | ||||
CHM_INDEX_ENCODING = | 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. | # enables the Previous and Next buttons. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. | # 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 | # 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 | # 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 | # (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 | # 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 | # 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 | # 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. | # Minimum value: 0, maximum value: 20, default value: 4. | ||||
# This tag requires that the tag GENERATE_HTML is set to YES. | # 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 | # 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. | # 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 | 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. | # external symbols imported via tag files in a separate window. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
# This tag requires that the tag GENERATE_HTML is set to YES. | # 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 | # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see | ||||
# http://www.mathjax.org) which uses client side Javascript for the rendering | # 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 | # 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 | # enabled you may also need to install MathJax separately and configure the path | ||||
# to it using the MATHJAX_RELPATH option. | # 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 | # external search engine pointed to by the SEARCHENGINE_URL option to obtain the | ||||
# search results. | # 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 | # (doxysearch.cgi) which are based on the open source search engine library | ||||
# Xapian (see: http://xapian.org/). | # 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 | # 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. | # 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 | # (doxysearch.cgi) which are based on the open source search engine library | ||||
# Xapian (see: http://xapian.org/). See the section "External Indexing and | # Xapian (see: http://xapian.org/). See the section "External Indexing and | ||||
# Searching" for details. | # Searching" for details. | ||||
@@ -1549,7 +1591,7 @@ EXTRA_SEARCH_MAPPINGS = | |||||
# Configuration options related to the LaTeX output | # 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. | # The default value is: YES. | ||||
GENERATE_LATEX = NO | GENERATE_LATEX = NO | ||||
@@ -1580,7 +1622,7 @@ LATEX_CMD_NAME = latex | |||||
MAKEINDEX_CMD_NAME = makeindex | 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 | # documents. This may be useful for small projects and may help to save some | ||||
# trees in general. | # trees in general. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1598,9 +1640,12 @@ COMPACT_LATEX = NO | |||||
PAPER_TYPE = a4wide | PAPER_TYPE = a4wide | ||||
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names | # 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. | # If left blank no extra packages will be included. | ||||
# This tag requires that the tag GENERATE_LATEX is set to YES. | # 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 | # 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, | # 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. | # This tag requires that the tag GENERATE_LATEX is set to YES. | ||||
LATEX_HEADER = | LATEX_HEADER = | ||||
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the | # 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 | # 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! | # 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. | # This tag requires that the tag GENERATE_LATEX is set to YES. | ||||
LATEX_FOOTER = | 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 | # 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 | # 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 | # 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. | # The default value is: YES. | ||||
# This tag requires that the tag GENERATE_LATEX is set to 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. | # higher quality PDF documentation. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
# This tag requires that the tag GENERATE_LATEX is set to 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 | # 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 | # 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 | 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 | # 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 | # RTF output is optimized for Word 97 and may not look too pretty with other RTF | ||||
# readers/editors. | # readers/editors. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1709,7 +1775,7 @@ GENERATE_RTF = NO | |||||
RTF_OUTPUT = rtf | 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 | # documents. This may be useful for small projects and may help to save some | ||||
# trees in general. | # trees in general. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1746,11 +1812,21 @@ RTF_STYLESHEET_FILE = | |||||
RTF_EXTENSIONS_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 | # 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. | # classes and files. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1794,7 +1870,7 @@ MAN_LINKS = NO | |||||
# Configuration options related to the XML output | # 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. | # captures the structure of the code including all documentation. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1808,7 +1884,7 @@ GENERATE_XML = NO | |||||
XML_OUTPUT = xml | 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 | # listings (including syntax highlighting and cross-referencing information) to | ||||
# the XML output. Note that enabling this will significantly increase the size | # the XML output. Note that enabling this will significantly increase the size | ||||
# of the XML output. | # of the XML output. | ||||
@@ -1821,7 +1897,7 @@ XML_PROGRAMLISTING = YES | |||||
# Configuration options related to the DOCBOOK output | # 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. | # that can be used to generate PDF. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1835,14 +1911,23 @@ GENERATE_DOCBOOK = NO | |||||
DOCBOOK_OUTPUT = docbook | 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 | # 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. | # The default value is: NO. | ||||
GENERATE_AUTOGEN_DEF = NO | GENERATE_AUTOGEN_DEF = NO | ||||
@@ -1851,7 +1936,7 @@ GENERATE_AUTOGEN_DEF = NO | |||||
# Configuration options related to the Perl module output | # 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. | # file that captures the structure of the code including all documentation. | ||||
# | # | ||||
# Note that this feature is still experimental and incomplete at the moment. | # Note that this feature is still experimental and incomplete at the moment. | ||||
@@ -1859,7 +1944,7 @@ GENERATE_AUTOGEN_DEF = NO | |||||
GENERATE_PERLMOD = 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 | # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI | ||||
# output from the Perl module output. | # output from the Perl module output. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1867,9 +1952,9 @@ GENERATE_PERLMOD = NO | |||||
PERLMOD_LATEX = 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 | # 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 | # size of the Perl module output will be much smaller and Perl will parse it | ||||
# just the same. | # just the same. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
@@ -1889,14 +1974,14 @@ PERLMOD_MAKEVAR_PREFIX = | |||||
# Configuration options related to the preprocessor | # 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. | # C-preprocessor directives found in the sources and include files. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
ENABLE_PREPROCESSING = 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 | # performed. Macro expansion can be done in a controlled way by setting | ||||
# EXPAND_ONLY_PREDEF to YES. | # EXPAND_ONLY_PREDEF to YES. | ||||
# The default value is: NO. | # The default value is: NO. | ||||
@@ -1912,7 +1997,7 @@ MACRO_EXPANSION = NO | |||||
EXPAND_ONLY_PREDEF = 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. | # INCLUDE_PATH will be searched if a #include is found. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | ||||
@@ -1988,20 +2073,21 @@ TAGFILES = | |||||
GENERATE_TAGFILE = | 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. | # The default value is: NO. | ||||
ALLEXTERNALS = 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. | # listed. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
EXTERNAL_GROUPS = 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 | # the related pages index. If set to NO, only the current project's pages will | ||||
# be listed. | # be listed. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
@@ -2018,7 +2104,7 @@ PERL_PATH = /usr/bin/perl | |||||
# Configuration options related to the dot tool | # 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 | # (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 | # 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 | # disabled, but it is recommended to install and use dot, since it yields more | ||||
@@ -2043,7 +2129,7 @@ MSCGEN_PATH = | |||||
DIA_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. | # and usage relations if the target is undocumented or is not a class. | ||||
# The default value is: YES. | # 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 | # 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 | # Bell Labs. The other options in this section have no effect if this option is | ||||
# set to NO | # set to NO | ||||
# The default value is: YES. | |||||
# The default value is: NO. | |||||
HAVE_DOT = NO | HAVE_DOT = NO | ||||
@@ -2068,7 +2154,7 @@ HAVE_DOT = NO | |||||
DOT_NUM_THREADS = 0 | 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 | # 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 | # 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 | # standard location or by setting the DOTFONTPATH environment variable or by | ||||
@@ -2116,7 +2202,7 @@ COLLABORATION_GRAPH = NO | |||||
GROUP_GRAPHS = YES | 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 | # collaboration diagrams in a style similar to the OMG's Unified Modeling | ||||
# Language. | # Language. | ||||
# The default value is: NO. | # 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. | # 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 | # 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. | # The default value is: NO. | ||||
# This tag requires that the tag HAVE_DOT is set to YES. | # 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. | # 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 | # 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. | # The default value is: NO. | ||||
# This tag requires that the tag HAVE_DOT is set to YES. | # This tag requires that the tag HAVE_DOT is set to YES. | ||||
@@ -2202,13 +2290,15 @@ GRAPHICAL_HIERARCHY = NO | |||||
DIRECTORY_GRAPH = NO | DIRECTORY_GRAPH = NO | ||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images | # 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 | # 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 | # to make the SVG files visible in IE 9+ (other browsers do not have this | ||||
# requirement). | # 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. | # The default value is: png. | ||||
# This tag requires that the tag HAVE_DOT is set to YES. | # This tag requires that the tag HAVE_DOT is set to YES. | ||||
@@ -2251,6 +2341,19 @@ MSCFILE_DIRS = | |||||
DIAFILE_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 | # 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 | # 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 | # larger than this value, doxygen will truncate the graph, which is visualized | ||||
@@ -2287,7 +2390,7 @@ MAX_DOT_GRAPH_DEPTH = 0 | |||||
DOT_TRANSPARENT = NO | 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 | # 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 | # makes dot run faster, but since only newer versions of dot (>1.8.10) support | ||||
# this, this feature is disabled by default. | # this, this feature is disabled by default. | ||||
@@ -2304,7 +2407,7 @@ DOT_MULTI_TARGETS = NO | |||||
GENERATE_LEGEND = 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. | # files that are used to generate the various graphs. | ||||
# The default value is: YES. | # The default value is: YES. | ||||
# This tag requires that the tag HAVE_DOT is set to YES. | # This tag requires that the tag HAVE_DOT is set to YES. |
@@ -1,69 +1,54 @@ | |||||
body { | body { | ||||
font-size: medium; | |||||
font-family: sans-serif; | |||||
} | |||||
#top { | |||||
background-color: #F3F3F3; | |||||
max-width: 80em; | |||||
margin: 0; | 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; | display: none; | ||||
} | } | ||||
h1 h2 h3 h4 h5 h6 { | |||||
font-weight: bold; | |||||
} | |||||
h1 { | h1 { | ||||
font-size: 164%; | |||||
font-size: 180%; | |||||
font-weight: 900; | |||||
} | } | ||||
h2 { | h2 { | ||||
font-size: 132%; | |||||
font-size: 140%; | |||||
font-weight: 700; | |||||
} | } | ||||
h3 { | h3 { | ||||
font-size: 124%; | |||||
font-size: 120%; | |||||
font-weight: 700; | |||||
} | } | ||||
h4 { | h4 { | ||||
font-size: 116%; | |||||
font-size: 110%; | |||||
font-weight: 700; | |||||
} | } | ||||
h5 { | h5 { | ||||
font-size: 108%; | |||||
font-size: 100%; | |||||
font-weight: 700; | |||||
} | } | ||||
h6 { | h6 { | ||||
font-size: 100%; | font-size: 100%; | ||||
font-weight: 600; | |||||
} | } | ||||
p { | p { | ||||
margin: 0 0 1ex 0; | |||||
} | |||||
br { | |||||
display: none; | |||||
margin: 0 0 1em 0; | |||||
} | } | ||||
dt { | dt { | ||||
font-weight: 700; | font-weight: 700; | ||||
} | } | ||||
div.multicol { | |||||
} | |||||
p.startli,p.startdd,p.starttd { | p.startli,p.startdd,p.starttd { | ||||
margin-top: 2px; | margin-top: 2px; | ||||
} | } | ||||
@@ -85,12 +70,12 @@ caption { | |||||
} | } | ||||
span.legend { | span.legend { | ||||
font-size: 70%; | |||||
font-size: small; | |||||
text-align: center; | text-align: center; | ||||
} | } | ||||
h3.version { | h3.version { | ||||
font-size: 90%; | |||||
font-size: small; | |||||
text-align: center; | text-align: center; | ||||
} | } | ||||
@@ -102,23 +87,18 @@ div.qindex,div.navtab { | |||||
padding: 2px; | padding: 2px; | ||||
} | } | ||||
div.qindex,div.navpath { | |||||
width: 100%; | |||||
line-height: 140%; | |||||
} | |||||
div.navtab { | div.navtab { | ||||
margin-right: 15px; | margin-right: 15px; | ||||
} | } | ||||
/* @group Link Styling */ | /* @group Link Styling */ | ||||
a { | a { | ||||
color: #3D8C57; | |||||
color: #546E00; | |||||
text-decoration: none; | text-decoration: none; | ||||
} | } | ||||
.contents a:visited { | .contents a:visited { | ||||
color: #50755E; | |||||
color: #344E00; | |||||
} | } | ||||
a:hover { | a:hover { | ||||
@@ -131,6 +111,10 @@ a.qindexHL { | |||||
border: 1px double #869DCA; | border: 1px double #869DCA; | ||||
} | } | ||||
code { | |||||
color: #444; | |||||
} | |||||
a.code { | a.code { | ||||
color: #4665A2; | color: #4665A2; | ||||
} | } | ||||
@@ -146,7 +130,6 @@ dl.el { | |||||
.fragment { | .fragment { | ||||
font-family: monospace, fixed; | font-family: monospace, fixed; | ||||
font-size: 105%; | |||||
} | } | ||||
pre.fragment { | pre.fragment { | ||||
@@ -155,7 +138,6 @@ pre.fragment { | |||||
padding: 4px 6px; | padding: 4px 6px; | ||||
margin: 4px 8px 4px 2px; | margin: 4px 8px 4px 2px; | ||||
overflow: auto; | overflow: auto; | ||||
font-size: 9pt; | |||||
line-height: 125%; | line-height: 125%; | ||||
} | } | ||||
@@ -176,17 +158,15 @@ div.groupHeader { | |||||
font-weight: 700; | font-weight: 700; | ||||
} | } | ||||
a + h2.groupheader { | |||||
display: none; | |||||
} | |||||
div.groupText { | div.groupText { | ||||
margin-left: 16px; | margin-left: 16px; | ||||
font-style: italic; | font-style: italic; | ||||
} | } | ||||
body { | |||||
background: #FFF; | |||||
color: #000; | |||||
margin: 0; | |||||
} | |||||
div.contents { | div.contents { | ||||
margin-top: 10px; | margin-top: 10px; | ||||
margin-left: 10px; | margin-left: 10px; | ||||
@@ -216,9 +196,6 @@ p.formulaDsp { | |||||
text-align: center; | text-align: center; | ||||
} | } | ||||
img.formulaDsp { | |||||
} | |||||
img.formulaInl { | img.formulaInl { | ||||
vertical-align: middle; | vertical-align: middle; | ||||
} | } | ||||
@@ -236,7 +213,7 @@ div.center img { | |||||
address.footer { | address.footer { | ||||
text-align: right; | text-align: right; | ||||
padding: 0 0.25em 0.25em 0; | |||||
padding-right: 12px; | |||||
} | } | ||||
img.footer { | img.footer { | ||||
@@ -250,7 +227,7 @@ span.keyword { | |||||
} | } | ||||
span.keywordtype { | span.keywordtype { | ||||
color: #604020; | |||||
color: #3E873E; | |||||
} | } | ||||
span.keywordflow { | span.keywordflow { | ||||
@@ -287,7 +264,7 @@ span.vhdllogic { | |||||
/* @end */ | /* @end */ | ||||
td.tiny { | td.tiny { | ||||
font-size: 75%; | |||||
font-size: x-small; | |||||
} | } | ||||
.dirtab { | .dirtab { | ||||
@@ -314,14 +291,16 @@ hr.footer { | |||||
/* @group Member Descriptions */ | /* @group Member Descriptions */ | ||||
table.memberdecls { | 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 { | .mdescLeft,.mdescRight,.memItemLeft,.memItemRight,.memTemplItemLeft,.memTemplItemRight,.memTemplParams { | ||||
background-color: #FBFBFB; | |||||
margin: 0; | margin: 0; | ||||
padding: 0.25ex; | |||||
padding: 0; | |||||
} | } | ||||
.mdescLeft,.mdescRight { | .mdescLeft,.mdescRight { | ||||
@@ -329,12 +308,18 @@ table.memberdecls { | |||||
} | } | ||||
.memItemLeft,.memItemRight,.memTemplParams { | .memItemLeft,.memItemRight,.memTemplParams { | ||||
border-top: 1px solid #DDD; | |||||
border: 0; | |||||
font-family: monospace, fixed; | |||||
} | } | ||||
.memItemLeft,.memTemplItemLeft { | .memItemLeft,.memTemplItemLeft { | ||||
white-space: nowrap; | white-space: nowrap; | ||||
padding-left: 2em; | padding-left: 2em; | ||||
padding-right: 1em; | |||||
} | |||||
.memItemLeft a.el { | |||||
font-weight: bold; | |||||
} | } | ||||
.memTemplParams { | .memTemplParams { | ||||
@@ -342,11 +327,24 @@ table.memberdecls { | |||||
white-space: nowrap; | white-space: nowrap; | ||||
} | } | ||||
td.memSeparator { | |||||
display: none; | |||||
} | |||||
td.mlabels-right { | |||||
vertical-align: top; | |||||
padding-top: 4px; | |||||
color: #AA6; | |||||
} | |||||
.memtitle { | |||||
display: none; | |||||
} | |||||
/* @end */ | /* @end */ | ||||
/* @group Member Details */ | /* @group Member Details */ | ||||
/* Styles for detailed member documentation */ | /* Styles for detailed member documentation */ | ||||
.memtemplate { | .memtemplate { | ||||
font-size: 80%; | |||||
color: #4665A2; | color: #4665A2; | ||||
font-weight: bold; | font-weight: bold; | ||||
} | } | ||||
@@ -362,26 +360,22 @@ table.memberdecls { | |||||
.memitem { | .memitem { | ||||
padding: 0; | 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; | 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 { | .memdoc { | ||||
padding: 1ex; | |||||
background-color: #FBFBFB; | |||||
border-top-width: 0; | |||||
padding: 0 0 0.5em 2em; | |||||
} | } | ||||
.paramkey { | .paramkey { | ||||
@@ -389,16 +383,37 @@ table.memberdecls { | |||||
} | } | ||||
.paramtype { | .paramtype { | ||||
color: #3E873E; | |||||
white-space: nowrap; | white-space: nowrap; | ||||
} | } | ||||
.paramname { | .paramname { | ||||
color: #602020; | |||||
color: #444; | |||||
white-space: nowrap; | 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 */ | /* @end */ | ||||
@@ -411,9 +426,8 @@ table.memberdecls { | |||||
/* these are for tree view when used as main index */ | /* these are for tree view when used as main index */ | ||||
.directory { | .directory { | ||||
font-size: 9pt; | |||||
font-weight: bold; | |||||
margin: 5px; | |||||
font-size: small; | |||||
margin: 0.5em; | |||||
} | } | ||||
.directory h3 { | .directory h3 { | ||||
@@ -482,7 +496,7 @@ address { | |||||
table.doxtable { | table.doxtable { | ||||
border-collapse: collapse; | border-collapse: collapse; | ||||
margin: 0.5ex; | |||||
margin: 0.5em; | |||||
} | } | ||||
table.doxtable td,table.doxtable th { | table.doxtable td,table.doxtable th { | ||||
@@ -508,12 +522,13 @@ table.doxtable th { | |||||
font-size: 13px; | font-size: 13px; | ||||
} | } | ||||
div.navpath { | |||||
padding: 0.25em; | |||||
} | |||||
.navpath ul { | .navpath ul { | ||||
font-size: 11px; | |||||
height: 30px; | |||||
line-height: 30px; | |||||
font-size: x-small; | |||||
color: #8AA0CC; | color: #8AA0CC; | ||||
border: 1px solid #C2CDE4; | |||||
overflow: hidden; | overflow: hidden; | ||||
margin: 0; | margin: 0; | ||||
padding: 0; | padding: 0; | ||||
@@ -528,7 +543,6 @@ table.doxtable th { | |||||
} | } | ||||
.navpath a { | .navpath a { | ||||
height: 32px; | |||||
display: block; | display: block; | ||||
text-decoration: none; | text-decoration: none; | ||||
outline: none; | outline: none; | ||||
@@ -540,8 +554,8 @@ table.doxtable th { | |||||
div.summary { | div.summary { | ||||
float: right; | float: right; | ||||
font-size: 8pt; | |||||
padding-right: 5px; | |||||
font-size: x-small; | |||||
padding: 0.25em 0.5em 0 0; | |||||
width: 50%; | width: 50%; | ||||
text-align: right; | text-align: right; | ||||
} | } | ||||
@@ -553,11 +567,125 @@ div.summary a { | |||||
div.header { | div.header { | ||||
background-color: #F3F3F3; | background-color: #F3F3F3; | ||||
margin: 0; | margin: 0; | ||||
border-bottom: 1px solid #DDD; | |||||
border: 0; | |||||
} | } | ||||
div.headertitle { | div.headertitle { | ||||
padding: 5px 5px 5px 10px; | |||||
font-size: 180%; | font-size: 180%; | ||||
font-weight: bold; | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | 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_RDFS "http://www.w3.org/2000/01/rdf-schema#" | ||||
#define LILV_NS_XSD "http://www.w3.org/2001/XMLSchema#" | #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_AUDIO_PORT "http://lv2plug.in/ns/lv2core#AudioPort" | ||||
#define LILV_URI_CONTROL_PORT "http://lv2plug.in/ns/lv2core#ControlPort" | #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_EVENT_PORT "http://lv2plug.in/ns/ext/event#EventPort" | ||||
#define LILV_URI_INPUT_PORT "http://lv2plug.in/ns/lv2core#InputPort" | #define LILV_URI_INPUT_PORT "http://lv2plug.in/ns/lv2core#InputPort" | ||||
#define LILV_URI_MIDI_EVENT "http://lv2plug.in/ns/ext/midi#MidiEvent" | #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. | other things) MUST be identified by URIs (not paths) in save files. | ||||
*/ | */ | ||||
LILV_API void | 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. | 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 | This unloads statements loaded by lilv_world_load_bundle(). Note that this | ||||
is not necessarily all information loaded from the bundle. If any resources | 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(). | separately unloaded with lilv_world_unload_resource(). | ||||
*/ | */ | ||||
LILV_API int | 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`. | Load all the data associated with the given `resource`. | ||||
@@ -706,6 +708,16 @@ lilv_world_ask(LilvWorld* world, | |||||
const LilvNode* predicate, | const LilvNode* predicate, | ||||
const LilvNode* object); | 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 | @name Plugin | ||||
@@ -751,7 +763,7 @@ lilv_plugin_get_uri(const LilvPlugin* plugin); | |||||
Typical hosts should not need to use this function. | Typical hosts should not need to use this function. | ||||
Note this always returns a fully qualified URI. If you want a local | 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. | @return a shared string which must not be modified or freed. | ||||
*/ | */ | ||||
LILV_API const LilvNode* | 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. | Get the (resolvable) URIs of the RDF data files that define a plugin. | ||||
Typical hosts should not need to use this function. | Typical hosts should not need to use this function. | ||||
Note this always returns fully qualified URIs. If you want local | 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", | @return a list of complete URLs eg. "file:///foo/ABundle.lv2/aplug.ttl", | ||||
which is shared and must not be modified or freed. | 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`. | Get the (resolvable) URI of the shared library for `plugin`. | ||||
Note this always returns a fully qualified URI. If you want a local | 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. | @return a shared string which must not be modified or freed. | ||||
*/ | */ | ||||
LILV_API const LilvNode* | LILV_API const LilvNode* | ||||
@@ -1381,6 +1393,28 @@ LILV_API void | |||||
lilv_state_set_label(LilvState* state, | lilv_state_set_label(LilvState* state, | ||||
const char* label); | 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. | Function to set a port value. | ||||
@param port_symbol The symbol of the port. | @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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | 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) | const LV2_Feature*const* features) | ||||
{ | { | ||||
lilv_plugin_load_if_necessary(plugin); | 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); | LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features); | ||||
if (!lib) { | if (!lib) { | ||||
@@ -41,15 +42,6 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||||
return NULL; | 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; | const LV2_Feature** local_features = NULL; | ||||
if (features == NULL) { | if (features == NULL) { | ||||
local_features = (const LV2_Feature**)malloc(sizeof(LV2_Feature*)); | local_features = (const LV2_Feature**)malloc(sizeof(LV2_Feature*)); | ||||
@@ -67,18 +59,7 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||||
break; // return NULL | 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 | // Create LilvInstance to return | ||||
result = (LilvInstance*)malloc(sizeof(LilvInstance)); | result = (LilvInstance*)malloc(sizeof(LilvInstance)); | ||||
result->lv2_descriptor = ld; | result->lv2_descriptor = ld; | ||||
@@ -86,10 +67,7 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||||
ld, sample_rate, bundle_path, | ld, sample_rate, bundle_path, | ||||
(features) ? features : local_features); | (features) ? features : local_features); | ||||
result->pimpl = lib; | result->pimpl = lib; | ||||
serd_node_free(&abs_uri_node); | |||||
break; | break; | ||||
} else { | |||||
serd_node_free(&abs_uri_node); | |||||
} | } | ||||
} | } | ||||
@@ -97,15 +75,17 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||||
lilv_free(bundle_path); | lilv_free(bundle_path); | ||||
if (result) { | if (result) { | ||||
// Failed to instantiate | |||||
if (result->lv2_handle == NULL) { | if (result->lv2_handle == NULL) { | ||||
// Failed to instantiate | |||||
free(result); | free(result); | ||||
lilv_lib_close(lib); | |||||
return NULL; | return NULL; | ||||
} | } | ||||
// "Connect" all ports to NULL (catches bugs) | // "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); | result->lv2_descriptor->connect_port(result->lv2_handle, i, NULL); | ||||
} | |||||
} | } | ||||
return result; | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -56,7 +56,8 @@ lilv_lib_open(LilvWorld* world, | |||||
if (ldf) { | if (ldf) { | ||||
desc = ldf(bundle_path, features); | desc = ldf(bundle_path, features); | ||||
if (!desc) { | 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); | lilv_free(lib_path); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
@@ -87,8 +88,7 @@ lilv_lib_get_plugin(LilvLib* lib, uint32_t index) | |||||
{ | { | ||||
if (lib->lv2_descriptor) { | if (lib->lv2_descriptor) { | ||||
return lib->lv2_descriptor(index); | return lib->lv2_descriptor(index); | ||||
} | |||||
if (lib->desc) { | |||||
} else if (lib->desc) { | |||||
return lib->desc->get_plugin(lib->desc->handle, index); | return lib->desc->get_plugin(lib->desc->handle, index); | ||||
} | } | ||||
return NULL; | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -43,7 +43,7 @@ extern "C" { | |||||
#ifndef NAN | #ifndef NAN | ||||
# define NAN INFINITY - INFINITY | # define NAN INFINITY - INFINITY | ||||
#endif | #endif | ||||
static inline char* dlerror(void) { return "Unknown error"; } | |||||
static inline const char* dlerror(void) { return "Unknown error"; } | |||||
#else | #else | ||||
# include <dlfcn.h> | # include <dlfcn.h> | ||||
# include <unistd.h> | # include <unistd.h> | ||||
@@ -127,6 +127,7 @@ struct LilvPluginImpl { | |||||
LilvPort** ports; | LilvPort** ports; | ||||
uint32_t num_ports; | uint32_t num_ports; | ||||
bool loaded; | bool loaded; | ||||
bool parse_errors; | |||||
bool replaced; | bool replaced; | ||||
}; | }; | ||||
@@ -156,6 +157,7 @@ struct LilvWorldImpl { | |||||
LilvPluginClasses* plugin_classes; | LilvPluginClasses* plugin_classes; | ||||
LilvSpec* specs; | LilvSpec* specs; | ||||
LilvPlugins* plugins; | LilvPlugins* plugins; | ||||
LilvPlugins* zombies; | |||||
LilvNodes* loaded_files; | LilvNodes* loaded_files; | ||||
ZixTree* libs; | ZixTree* libs; | ||||
struct { | struct { | ||||
@@ -172,7 +174,9 @@ struct LilvWorldImpl { | |||||
SordNode* lv2_index; | SordNode* lv2_index; | ||||
SordNode* lv2_latency; | SordNode* lv2_latency; | ||||
SordNode* lv2_maximum; | SordNode* lv2_maximum; | ||||
SordNode* lv2_microVersion; | |||||
SordNode* lv2_minimum; | SordNode* lv2_minimum; | ||||
SordNode* lv2_minorVersion; | |||||
SordNode* lv2_name; | SordNode* lv2_name; | ||||
SordNode* lv2_optionalFeature; | SordNode* lv2_optionalFeature; | ||||
SordNode* lv2_port; | SordNode* lv2_port; | ||||
@@ -181,6 +185,8 @@ struct LilvWorldImpl { | |||||
SordNode* lv2_requiredFeature; | SordNode* lv2_requiredFeature; | ||||
SordNode* lv2_symbol; | SordNode* lv2_symbol; | ||||
SordNode* lv2_prototype; | SordNode* lv2_prototype; | ||||
SordNode* mod_builderVersion; | |||||
SordNode* mod_releaseNumber; | |||||
SordNode* owl_Ontology; | SordNode* owl_Ontology; | ||||
SordNode* pset_value; | SordNode* pset_value; | ||||
SordNode* rdf_a; | SordNode* rdf_a; | ||||
@@ -233,6 +239,13 @@ struct LilvUIImpl { | |||||
LilvNodes* classes; | LilvNodes* classes; | ||||
}; | }; | ||||
typedef struct LilvVersion { | |||||
int builder; | |||||
int minor; | |||||
int micro; | |||||
int release; | |||||
} LilvVersion; | |||||
/* | /* | ||||
* | * | ||||
* Functions | * Functions | ||||
@@ -248,6 +261,7 @@ void lilv_port_free(const LilvPlugin* plugin, LilvPort* port); | |||||
LilvPlugin* lilv_plugin_new(LilvWorld* world, | LilvPlugin* lilv_plugin_new(LilvWorld* world, | ||||
LilvNode* uri, | LilvNode* uri, | ||||
LilvNode* bundle_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_load_if_necessary(const LilvPlugin* p); | ||||
void lilv_plugin_free(LilvPlugin* plugin); | void lilv_plugin_free(LilvPlugin* plugin); | ||||
LilvNode* lilv_plugin_get_unique(const LilvPlugin* p, | LilvNode* lilv_plugin_get_unique(const LilvPlugin* p, | ||||
@@ -282,7 +296,8 @@ LilvScalePoints* lilv_scale_points_new(void); | |||||
LilvPluginClasses* lilv_plugin_classes_new(void); | LilvPluginClasses* lilv_plugin_classes_new(void); | ||||
LilvUIs* lilv_uis_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); | 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_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); | 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* | struct LilvHeader* | ||||
lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri); | lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri); | ||||
@@ -405,6 +469,10 @@ static const LV2_Feature* const dman_features = { NULL }; | |||||
__func__) | __func__) | ||||
#define LILV_WARNF(fmt, ...) fprintf(stderr, "%s(): warning: " fmt, \ | #define LILV_WARNF(fmt, ...) fprintf(stderr, "%s(): warning: " fmt, \ | ||||
__func__, __VA_ARGS__) | __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 | #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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -15,16 +15,16 @@ | |||||
*/ | */ | ||||
#include <math.h> | #include <math.h> | ||||
#include <stdio.h> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include "lilv_internal.h" | #include "lilv_internal.h" | ||||
static void | 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); | const char* str = (const char*)sord_node_get_string(val->node); | ||||
char* endptr; | |||||
switch (val->type) { | switch (val->type) { | ||||
case LILV_VALUE_URI: | case LILV_VALUE_URI: | ||||
@@ -33,10 +33,10 @@ lilv_node_set_numerics_from_string(LilvNode* val, size_t len) | |||||
case LILV_VALUE_BLOB: | case LILV_VALUE_BLOB: | ||||
break; | break; | ||||
case LILV_VALUE_INT: | case LILV_VALUE_INT: | ||||
val->val.int_val = strtol(str, &endptr, 10); | |||||
val->val.int_val = strtol(str, NULL, 10); | |||||
break; | break; | ||||
case LILV_VALUE_FLOAT: | case LILV_VALUE_FLOAT: | ||||
val->val.float_val = serd_strtod(str, &endptr); | |||||
val->val.float_val = serd_strtod(str, NULL); | |||||
break; | break; | ||||
case LILV_VALUE_BOOL: | case LILV_VALUE_BOOL: | ||||
val->val.bool_val = !strcmp(str, "true"); | val->val.bool_val = !strcmp(str, "true"); | ||||
@@ -104,7 +104,6 @@ lilv_node_new_from_node(LilvWorld* world, const SordNode* node) | |||||
LilvNode* result = NULL; | LilvNode* result = NULL; | ||||
SordNode* datatype_uri = NULL; | SordNode* datatype_uri = NULL; | ||||
LilvNodeType type = LILV_VALUE_STRING; | LilvNodeType type = LILV_VALUE_STRING; | ||||
size_t len = 0; | |||||
switch (sord_node_get_type(node)) { | switch (sord_node_get_type(node)) { | ||||
case SORD_URI: | case SORD_URI: | ||||
@@ -137,8 +136,8 @@ lilv_node_new_from_node(LilvWorld* world, const SordNode* node) | |||||
sord_node_get_string(datatype_uri)); | sord_node_get_string(datatype_uri)); | ||||
} | } | ||||
result = lilv_node_new( | 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; | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | 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_FOAF (const uint8_t*)"http://xmlns.com/foaf/0.1/" | ||||
#define NS_MOD (const uint8_t*)"http://moddevices.com/ns/modgui#" | #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->bundle_uri = bundle_uri; | ||||
plugin->binary_uri = NULL; | plugin->binary_uri = NULL; | ||||
#ifdef LILV_DYN_MANIFEST | #ifdef LILV_DYN_MANIFEST | ||||
@@ -51,11 +46,32 @@ lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri) | |||||
plugin->ports = NULL; | plugin->ports = NULL; | ||||
plugin->num_ports = 0; | plugin->num_ports = 0; | ||||
plugin->loaded = false; | plugin->loaded = false; | ||||
plugin->parse_errors = false; | |||||
plugin->replaced = 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; | 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 | static void | ||||
lilv_plugin_free_ports(LilvPlugin* p) | lilv_plugin_free_ports(LilvPlugin* p) | ||||
{ | { | ||||
@@ -113,7 +129,8 @@ lilv_plugin_get_one(const LilvPlugin* p, | |||||
SordIter* stream = lilv_world_query_internal( | SordIter* stream = lilv_world_query_internal( | ||||
p->world, subject, predicate, NULL); | p->world, subject, predicate, NULL); | ||||
if (!sord_iter_end(stream)) { | 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); | sord_iter_free(stream); | ||||
return ret; | return ret; | ||||
@@ -126,7 +143,7 @@ lilv_plugin_get_unique(const LilvPlugin* p, | |||||
{ | { | ||||
LilvNode* ret = lilv_plugin_get_one(p, subject, predicate); | LilvNode* ret = lilv_plugin_get_one(p, subject, predicate); | ||||
if (!ret) { | 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(subject), | ||||
sord_node_get_string(predicate)); | 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, | SerdReader* reader = sord_new_reader(p->world->model, env, SERD_TURTLE, | ||||
bundle_uri_node); | 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); | 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)) { | for (; !sord_iter_end(iter); sord_iter_next(iter)) { | ||||
const SordNode* t = sord_iter_get_node(iter, SORD_OBJECT); | const SordNode* t = sord_iter_get_node(iter, SORD_OBJECT); | ||||
LilvNode* prototype = lilv_node_new_from_node(p->world, t); | LilvNode* prototype = lilv_node_new_from_node(p->world, t); | ||||
@@ -177,14 +194,26 @@ lilv_plugin_load(LilvPlugin* p) | |||||
} | } | ||||
sord_iter_free(iter); | sord_iter_free(iter); | ||||
sord_free(skel); | sord_free(skel); | ||||
sord_free(prototypes); | |||||
sord_free(prots); | |||||
// Parse all the plugin's data files into RDF model | // Parse all the plugin's data files into RDF model | ||||
SerdStatus st = SERD_SUCCESS; | |||||
LILV_FOREACH(nodes, i, p->data_uris) { | LILV_FOREACH(nodes, i, p->data_uris) { | ||||
const LilvNode* data_uri = lilv_nodes_get(p->data_uris, i); | 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)); | 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 | #ifdef LILV_DYN_MANIFEST | ||||
@@ -235,8 +264,8 @@ static void | |||||
lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) | lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) | ||||
{ | { | ||||
LilvPlugin* p = (LilvPlugin*)const_p; | LilvPlugin* p = (LilvPlugin*)const_p; | ||||
if (!p->loaded) | |||||
lilv_plugin_load(p); | |||||
lilv_plugin_load_if_necessary(p); | |||||
if (!p->ports) { | if (!p->ports) { | ||||
p->ports = (LilvPort**)malloc(sizeof(LilvPort*)); | 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( | LilvNode* symbol = lilv_plugin_get_unique( | ||||
p, port, p->world->uris.lv2_symbol); | p, port, p->world->uris.lv2_symbol); | ||||
bool error = false; | |||||
if (!lilv_node_is_string(symbol) || | if (!lilv_node_is_string(symbol) || | ||||
!is_symbol((const char*)sord_node_get_string(symbol->node))) { | !is_symbol((const char*)sord_node_get_string(symbol->node))) { | ||||
LILV_ERRORF("Plugin <%s> port symbol `%s' is invalid\n", | LILV_ERRORF("Plugin <%s> port symbol `%s' is invalid\n", | ||||
lilv_node_as_uri(p->plugin_uri), | lilv_node_as_uri(p->plugin_uri), | ||||
lilv_node_as_string(symbol)); | 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)) { | if (!lilv_node_is_int(index)) { | ||||
LILV_ERRORF("Plugin <%s> port index is not an integer\n", | LILV_ERRORF("Plugin <%s> port index is not an integer\n", | ||||
lilv_node_as_uri(p->plugin_uri)); | 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); | 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); | sord_iter_free(types); | ||||
done: | |||||
lilv_node_free(symbol); | lilv_node_free(symbol); | ||||
lilv_node_free(index); | lilv_node_free(index); | ||||
if (error) { // Invalid plugin | |||||
lilv_plugin_free_ports(p); | |||||
break; | |||||
} | |||||
} | } | ||||
sord_iter_free(ports); | sord_iter_free(ports); | ||||
@@ -389,12 +416,12 @@ lilv_plugin_get_class(const LilvPlugin* const_p) | |||||
lilv_plugin_load_if_necessary(p); | lilv_plugin_load_if_necessary(p); | ||||
if (!p->plugin_class) { | if (!p->plugin_class) { | ||||
// <plugin> a ?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) { | if (sord_node_get_type(class_node) != SORD_URI) { | ||||
continue; | continue; | ||||
} | } | ||||
@@ -413,7 +440,7 @@ lilv_plugin_get_class(const LilvPlugin* const_p) | |||||
lilv_node_free(klass); | lilv_node_free(klass); | ||||
} | } | ||||
sord_iter_free(results); | |||||
sord_iter_free(c); | |||||
if (p->plugin_class == NULL) | if (p->plugin_class == NULL) | ||||
p->plugin_class = p->world->lv2_plugin_class; | p->plugin_class = p->world->lv2_plugin_class; | ||||
@@ -433,6 +460,11 @@ lilv_plugin_get_value_internal(const LilvPlugin* p, | |||||
LILV_API bool | LILV_API bool | ||||
lilv_plugin_verify(const LilvPlugin* plugin) | 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"); | LilvNode* rdf_type = lilv_new_uri(plugin->world, LILV_NS_RDF "type"); | ||||
LilvNodes* results = lilv_plugin_get_value(plugin, rdf_type); | LilvNodes* results = lilv_plugin_get_value(plugin, rdf_type); | ||||
lilv_node_free(rdf_type); | lilv_node_free(rdf_type); | ||||
@@ -867,46 +899,36 @@ lilv_plugin_get_author(const LilvPlugin* p) | |||||
return author; | 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); | const SordNode* author = lilv_plugin_get_author(plugin); | ||||
if (author) { | 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 ret; | ||||
} | } | ||||
return NULL; | 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_API LilvNode* | ||||
lilv_plugin_get_author_email(const LilvPlugin* plugin) | 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_API LilvNode* | ||||
lilv_plugin_get_author_homepage(const LilvPlugin* plugin) | 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* | static const SordNode* | ||||
@@ -1060,7 +1082,10 @@ lilv_plugin_get_uis(const LilvPlugin* p) | |||||
const SordNode* ui = sord_iter_get_node(uis, SORD_OBJECT); | const SordNode* ui = sord_iter_get_node(uis, SORD_OBJECT); | ||||
LilvNode* type = lilv_plugin_get_unique(p, ui, p->world->uris.rdf_a); | 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 | if (sord_node_get_type(ui) != SORD_URI | ||||
|| !lilv_node_is_uri(type) | || !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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | 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) | char* rel; ///< Abstract path (relative path in state dir) | ||||
} PathMap; | } PathMap; | ||||
typedef struct { | |||||
size_t n; | |||||
Property* props; | |||||
} PropertyArray; | |||||
struct LilvStateImpl { | 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 | static int | ||||
@@ -106,18 +111,18 @@ append_port_value(LilvState* state, | |||||
uint32_t size, | uint32_t size, | ||||
uint32_t type) | uint32_t type) | ||||
{ | { | ||||
PortValue* pv = NULL; | |||||
if (value) { | if (value) { | ||||
state->values = (PortValue*)realloc( | 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->symbol = lilv_strdup(port_symbol); | ||||
pv->value = malloc(size); | pv->value = malloc(size); | ||||
pv->size = size; | pv->size = size; | ||||
pv->type = type; | pv->type = type; | ||||
memcpy(pv->value, value, size); | memcpy(pv->value, value, size); | ||||
return pv; | |||||
} | } | ||||
return NULL; | |||||
return pv; | |||||
} | } | ||||
static const char* | static const char* | ||||
@@ -131,24 +136,23 @@ lilv_state_rel2abs(const LilvState* state, const char* path) | |||||
return 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) { | if ((flags & LV2_STATE_IS_POD) || type == state->atom_Path) { | ||||
prop->value = malloc(size); | prop->value = malloc(size); | ||||
memcpy(prop->value, value, size); | memcpy(prop->value, value, size); | ||||
} else { | } else { | ||||
LILV_WARN("Storing non-POD value\n"); | |||||
prop->value = (void*)value; | prop->value = (void*)value; | ||||
} | } | ||||
@@ -156,7 +160,18 @@ store_callback(LV2_State_Handle handle, | |||||
prop->key = key; | prop->key = key; | ||||
prop->type = type; | prop->type = type; | ||||
prop->flags = flags; | 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; | return LV2_STATE_SUCCESS; | ||||
} | } | ||||
@@ -170,7 +185,7 @@ retrieve_callback(LV2_State_Handle handle, | |||||
const LilvState* const state = (LilvState*)handle; | const LilvState* const state = (LilvState*)handle; | ||||
const Property search_key = { NULL, 0, key, 0, 0 }; | const Property search_key = { NULL, 0, key, 0, 0 }; | ||||
const Property* const prop = (Property*)bsearch( | 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); | sizeof(Property), property_cmp); | ||||
if (prop) { | if (prop) { | ||||
@@ -230,6 +245,7 @@ abstract_path(LV2_State_Map_Path_Handle handle, | |||||
char* copy = lilv_get_latest_copy(real_path, cpath); | char* copy = lilv_get_latest_copy(real_path, cpath); | ||||
if (!copy || !lilv_file_equals(real_path, copy)) { | if (!copy || !lilv_file_equals(real_path, copy)) { | ||||
// No recent enough copy, make a new one | // No recent enough copy, make a new one | ||||
free(copy); | |||||
copy = lilv_find_free_path(cpath, lilv_path_exists, NULL); | copy = lilv_find_free_path(cpath, lilv_path_exists, NULL); | ||||
const int st = lilv_copy_file(real_path, copy); | const int st = lilv_copy_file(real_path, copy); | ||||
if (st) { | if (st) { | ||||
@@ -388,15 +404,15 @@ lilv_state_new_from_instance(const LilvPlugin* plugin, | |||||
instance->lv2_handle, store_callback, state, flags, features); | instance->lv2_handle, store_callback, state, flags, features); | ||||
if (st) { | if (st) { | ||||
LILV_ERRORF("Error saving plugin state: %s\n", state_strerror(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 { | } 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); | free(sfeatures); | ||||
return state; | return state; | ||||
@@ -407,7 +423,7 @@ lilv_state_emit_port_values(const LilvState* state, | |||||
LilvSetPortValueFunc set_value, | LilvSetPortValueFunc set_value, | ||||
void* user_data) | 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]; | const PortValue* val = &state->values[i]; | ||||
set_value(val->symbol, user_data, val->value, val->size, val->type); | 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, | uint32_t flags, | ||||
const LV2_Feature *const * features) | const LV2_Feature *const * features) | ||||
{ | { | ||||
if (iface) { | |||||
if (iface && iface->restore) { | |||||
iface->restore(handle, retrieve_callback, | iface->restore(handle, retrieve_callback, | ||||
(LV2_State_Handle)state, flags, features); | (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* object = sord_iter_get_node(i, SORD_OBJECT); | ||||
const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH); | const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH); | ||||
state->label = lilv_strdup((const char*)sord_node_get_string(object)); | 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)); | state->dir = lilv_strdup((const char*)sord_node_get_string(graph)); | ||||
} | } | ||||
sord_iter_free(i); | sord_iter_free(i); | ||||
@@ -531,8 +547,9 @@ new_state_from_model(LilvWorld* world, | |||||
if (state_node) { | if (state_node) { | ||||
SordIter* props = sord_search(model, state_node, 0, 0, 0); | SordIter* props = sord_search(model, state_node, 0, 0, 0); | ||||
FOREACH_MATCH(props) { | 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; | chunk.len = 0; | ||||
lv2_atom_forge_set_sink( | 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; | uint32_t flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; | ||||
Property prop = { NULL, 0, 0, 0, flags }; | 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.type = atom->type; | ||||
prop.size = atom->size; | prop.size = atom->size; | ||||
prop.value = malloc(atom->size); | prop.value = malloc(atom->size); | ||||
memcpy(prop.value, LV2_ATOM_BODY_CONST(atom), atom->size); | memcpy(prop.value, LV2_ATOM_BODY_CONST(atom), atom->size); | ||||
if (atom->type == forge.Path) { | if (atom->type == forge.Path) { | ||||
prop.flags = LV2_STATE_IS_PORTABLE; | |||||
prop.flags = LV2_STATE_IS_POD; | |||||
} | } | ||||
if (prop.value) { | 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); | sord_iter_free(props); | ||||
@@ -566,8 +583,12 @@ new_state_from_model(LilvWorld* world, | |||||
free((void*)chunk.buf); | free((void*)chunk.buf); | ||||
sratom_free(sratom); | 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; | return state; | ||||
} | } | ||||
@@ -683,7 +704,9 @@ ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env) | |||||
SerdWriter* writer = serd_writer_new( | SerdWriter* writer = serd_writer_new( | ||||
SERD_TURTLE, | SERD_TURTLE, | ||||
(SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED), | |||||
(SerdStyle)(SERD_STYLE_RESOLVED | | |||||
SERD_STYLE_ABBREVIATED| | |||||
SERD_STYLE_CURIED), | |||||
env, | env, | ||||
&base_uri, | &base_uri, | ||||
sink, | sink, | ||||
@@ -839,6 +862,37 @@ link_exists(const char* path, void* data) | |||||
return !matches; | 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 | static int | ||||
lilv_state_write(LilvWorld* world, | lilv_state_write(LilvWorld* world, | ||||
LV2_URID_Map* map, | LV2_URID_Map* map, | ||||
@@ -885,11 +939,14 @@ lilv_state_write(LilvWorld* world, | |||||
(SerdEndSink)serd_writer_end_anon, | (SerdEndSink)serd_writer_end_anon, | ||||
writer); | 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 | // 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]; | PortValue* const value = &state->values[i]; | ||||
const SerdNode port = serd_node_from_string( | const SerdNode port = serd_node_from_string( | ||||
@@ -914,35 +971,19 @@ lilv_state_write(LilvWorld* world, | |||||
serd_writer_end_anon(writer, &port); | serd_writer_end_anon(writer, &port); | ||||
} | } | ||||
// Write property values with precise types | |||||
sratom_set_pretty_numbers(sratom, false); | |||||
// Write properties | // 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)); | p = serd_node_from_string(SERD_URI, USTR(LV2_STATE__state)); | ||||
serd_writer_write_statement(writer, SERD_ANON_O_BEGIN, NULL, | 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); | sratom_free(sratom); | ||||
@@ -1099,12 +1140,12 @@ lilv_state_delete(LilvWorld* world, | |||||
model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL); | model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL); | ||||
if (file) { | if (file) { | ||||
// Remove state 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); | (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 | // Remove any existing manifest entries for this state | ||||
@@ -1141,14 +1182,26 @@ lilv_state_delete(LilvWorld* world, | |||||
return 0; | 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_API void | ||||
lilv_state_free(LilvState* state) | lilv_state_free(LilvState* state) | ||||
{ | { | ||||
if (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].value); | ||||
free(state->values[i].symbol); | free(state->values[i].symbol); | ||||
} | } | ||||
@@ -1156,7 +1209,6 @@ lilv_state_free(LilvState* state) | |||||
lilv_node_free(state->uri); | lilv_node_free(state->uri); | ||||
zix_tree_free(state->abs2rel); | zix_tree_free(state->abs2rel); | ||||
zix_tree_free(state->rel2abs); | zix_tree_free(state->rel2abs); | ||||
free(state->props); | |||||
free(state->values); | free(state->values); | ||||
free(state->label); | free(state->label); | ||||
free(state->dir); | free(state->dir); | ||||
@@ -1174,12 +1226,12 @@ lilv_state_equals(const LilvState* a, const LilvState* b) | |||||
|| (a->label && !b->label) | || (a->label && !b->label) | ||||
|| (b->label && !a->label) | || (b->label && !a->label) | ||||
|| (a->label && b->label && strcmp(a->label, b->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; | 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 av = &a->values[i]; | ||||
PortValue* const bv = &b->values[i]; | PortValue* const bv = &b->values[i]; | ||||
if (av->size != bv->size || av->type != bv->type | 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 | if (ap->key != bp->key | ||||
|| ap->type != bp->type | || ap->type != bp->type | ||||
|| ap->flags != bp->flags) { | || ap->flags != bp->flags) { | ||||
@@ -1213,7 +1265,7 @@ lilv_state_equals(const LilvState* a, const LilvState* b) | |||||
LILV_API unsigned | LILV_API unsigned | ||||
lilv_state_get_num_properties(const LilvState* state) | lilv_state_get_num_properties(const LilvState* state) | ||||
{ | { | ||||
return state->num_props; | |||||
return state->props.n; | |||||
} | } | ||||
LILV_API const LilvNode* | 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); | state->label = (char*)realloc(state->label, len + 1); | ||||
memcpy(state->label, 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -16,6 +16,7 @@ | |||||
#define _POSIX_C_SOURCE 200809L /* for fileno */ | #define _POSIX_C_SOURCE 200809L /* for fileno */ | ||||
#define _BSD_SOURCE 1 /* for realpath, symlink */ | #define _BSD_SOURCE 1 /* for realpath, symlink */ | ||||
#define _DEFAULT_SOURCE 1 /* for realpath, symlink */ | |||||
#ifdef __APPLE__ | #ifdef __APPLE__ | ||||
# define _DARWIN_C_SOURCE 1 /* for flock */ | # define _DARWIN_C_SOURCE 1 /* for flock */ | ||||
@@ -27,24 +28,27 @@ | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <stddef.h> | |||||
#ifdef _WIN32 | #ifdef _WIN32 | ||||
#ifndef _WIN32_WINNT | |||||
# define _WIN32_WINNT 0x0600 /* for CreateSymbolicLink */ | |||||
#endif | |||||
# include <windows.h> | # include <windows.h> | ||||
# include <direct.h> | # include <direct.h> | ||||
# include <io.h> | # include <io.h> | ||||
# define F_OK 0 | # define F_OK 0 | ||||
# define mkdir(path, flags) _mkdir(path) | # define mkdir(path, flags) _mkdir(path) | ||||
# if (defined(_MSC_VER) && (_MSC_VER < 1500)) | |||||
/** Implement 'CreateSymbolicLink()' for MSVC 8 or earlier */ | /** Implement 'CreateSymbolicLink()' for MSVC 8 or earlier */ | ||||
BOOLEAN WINAPI | BOOLEAN WINAPI | ||||
CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | ||||
{ | { | ||||
typedef BOOLEAN (WINAPI* PFUNC)(LPCTSTR, LPCTSTR, DWORD); | 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; | return pfn ? pfn(linkpath, targetpath, flags) : 0; | ||||
} | } | ||||
# endif /* _MSC_VER < 1500 */ | |||||
#else | #else | ||||
# include <dirent.h> | # include <dirent.h> | ||||
# include <limits.h> | # include <limits.h> | ||||
@@ -61,7 +65,7 @@ CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | |||||
#endif | #endif | ||||
#ifndef PAGE_SIZE | #ifndef PAGE_SIZE | ||||
# define PAGE_SIZE 4096 | |||||
# define PAGE_SIZE 4096 | |||||
#endif | #endif | ||||
void | void | ||||
@@ -296,6 +300,7 @@ lilv_copy_file(const char* src, const char* dst) | |||||
FILE* out = fopen(dst, "w"); | FILE* out = fopen(dst, "w"); | ||||
if (!out) { | if (!out) { | ||||
fclose(in); | |||||
return errno; | return errno; | ||||
} | } | ||||
@@ -370,26 +375,8 @@ lilv_path_join(const char* a, const char* b) | |||||
return path; | 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 { | typedef struct { | ||||
char* pattern; | char* pattern; | ||||
off_t orig_size; | |||||
time_t time; | time_t time; | ||||
char* latest; | char* latest; | ||||
} Latest; | } Latest; | ||||
@@ -397,16 +384,18 @@ typedef struct { | |||||
static void | static void | ||||
update_latest(const char* path, const char* name, void* data) | 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; | unsigned num; | ||||
if (sscanf(entry_path, latest->pattern, &num) == 1) { | 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) { | if (entry_path != latest->latest) { | ||||
@@ -419,8 +408,14 @@ char* | |||||
lilv_get_latest_copy(const char* path, const char* copy_path) | lilv_get_latest_copy(const char* path, const char* copy_path) | ||||
{ | { | ||||
char* copy_dir = lilv_dirname(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); | 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; | FILE* b_file = NULL; | ||||
char* const a_real = lilv_realpath(a_path); | char* const a_real = lilv_realpath(a_path); | ||||
char* const b_real = lilv_realpath(b_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 | match = true; // Real paths match | ||||
} else if (lilv_file_size(a_path) != lilv_file_size(b_path)) { | } else if (lilv_file_size(a_path) != lilv_file_size(b_path)) { | ||||
match = false; // Sizes differ | 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 | match = false; // Missing file matches nothing | ||||
} else { | } else { | ||||
match = true; | |||||
// TODO: Improve performance by reading chunks | // TODO: Improve performance by reading chunks | ||||
match = true; | |||||
while (!feof(a_file) && !feof(b_file)) { | while (!feof(a_file) && !feof(b_file)) { | ||||
if (fgetc(a_file) != fgetc(b_file)) { | if (fgetc(a_file) != fgetc(b_file)) { | ||||
match = false; | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -23,6 +23,9 @@ | |||||
#include "lilv_internal.h" | #include "lilv_internal.h" | ||||
static int | |||||
lilv_world_drop_graph(LilvWorld* world, const SordNode* graph); | |||||
LILV_API LilvWorld* | LILV_API LilvWorld* | ||||
lilv_world_new(void) | lilv_world_new(void) | ||||
{ | { | ||||
@@ -39,6 +42,7 @@ lilv_world_new(void) | |||||
world->specs = NULL; | world->specs = NULL; | ||||
world->plugin_classes = lilv_plugin_classes_new(); | world->plugin_classes = lilv_plugin_classes_new(); | ||||
world->plugins = lilv_plugins_new(); | world->plugins = lilv_plugins_new(); | ||||
world->zombies = lilv_plugins_new(); | |||||
world->loaded_files = zix_tree_new( | world->loaded_files = zix_tree_new( | ||||
false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free); | 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_index = NEW_URI(LV2_CORE__index); | ||||
world->uris.lv2_latency = NEW_URI(LV2_CORE__latency); | world->uris.lv2_latency = NEW_URI(LV2_CORE__latency); | ||||
world->uris.lv2_maximum = NEW_URI(LV2_CORE__maximum); | 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_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_name = NEW_URI(LV2_CORE__name); | ||||
world->uris.lv2_optionalFeature = NEW_URI(LV2_CORE__optionalFeature); | world->uris.lv2_optionalFeature = NEW_URI(LV2_CORE__optionalFeature); | ||||
world->uris.lv2_port = NEW_URI(LV2_CORE__port); | world->uris.lv2_port = NEW_URI(LV2_CORE__port); | ||||
@@ -133,6 +139,13 @@ lilv_world_free(LilvWorld* world) | |||||
zix_tree_free((ZixTree*)world->plugins); | zix_tree_free((ZixTree*)world->plugins); | ||||
world->plugins = NULL; | 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); | zix_tree_free((ZixTree*)world->loaded_files); | ||||
world->loaded_files = NULL; | world->loaded_files = NULL; | ||||
@@ -180,6 +193,9 @@ lilv_world_find_nodes(LilvWorld* world, | |||||
LILV_ERRORF("Subject `%s' is not a resource\n", | LILV_ERRORF("Subject `%s' is not a resource\n", | ||||
sord_node_get_string(subject->node)); | sord_node_get_string(subject->node)); | ||||
return NULL; | return NULL; | ||||
} else if (!predicate) { | |||||
LILV_ERROR("Missing required predicate\n"); | |||||
return NULL; | |||||
} else if (!lilv_node_is_uri(predicate)) { | } else if (!lilv_node_is_uri(predicate)) { | ||||
LILV_ERRORF("Predicate `%s' is not a URI\n", | LILV_ERRORF("Predicate `%s' is not a URI\n", | ||||
sord_node_get_string(predicate->node)); | 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) | const uint8_t* base_uri_str) | ||||
{ | { | ||||
SerdURI base_uri; | 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* | 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. */ | /** 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 | static void | ||||
@@ -371,33 +384,55 @@ lilv_world_add_spec(LilvWorld* world, | |||||
} | } | ||||
static void | 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); | 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 | #ifdef LILV_DYN_MANIFEST | ||||
// Set dynamic manifest library URI, if applicable | // Set dynamic manifest library URI, if applicable | ||||
@@ -420,9 +455,6 @@ lilv_world_add_plugin(LilvWorld* world, | |||||
NULL); | NULL); | ||||
} | } | ||||
sord_iter_free(files); | sord_iter_free(files); | ||||
// Add plugin to world plugin sequence | |||||
zix_tree_insert((ZixTree*)world->plugins, plugin, NULL); | |||||
} | } | ||||
SerdStatus | SerdStatus | ||||
@@ -480,7 +512,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||||
// Get binary path | // Get binary path | ||||
const SordNode* binary = sord_iter_get_node(binaries, SORD_OBJECT); | const SordNode* binary = sord_iter_get_node(binaries, SORD_OBJECT); | ||||
const uint8_t* lib_uri = sord_node_get_string(binary); | 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) { | if (!lib_path) { | ||||
LILV_ERROR("No dynamic manifest library path\n"); | LILV_ERROR("No dynamic manifest library path\n"); | ||||
sord_iter_free(binaries); | 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", | LILV_ERRORF("Failed to open dynmanifest library `%s' (%s)\n", | ||||
lib_path, dlerror()); | lib_path, dlerror()); | ||||
sord_iter_free(binaries); | sord_iter_free(binaries); | ||||
lilv_free(lib_path); | |||||
continue; | continue; | ||||
} | } | ||||
@@ -505,6 +538,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||||
LILV_ERRORF("No `lv2_dyn_manifest_open' in `%s'\n", lib_path); | LILV_ERRORF("No `lv2_dyn_manifest_open' in `%s'\n", lib_path); | ||||
sord_iter_free(binaries); | sord_iter_free(binaries); | ||||
dlclose(lib); | dlclose(lib); | ||||
lilv_free(lib_path); | |||||
continue; | continue; | ||||
} | } | ||||
@@ -517,6 +551,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||||
lib_path); | lib_path); | ||||
sord_iter_free(binaries); | sord_iter_free(binaries); | ||||
dlclose(lib); | dlclose(lib); | ||||
lilv_free(lib_path); | |||||
continue; | continue; | ||||
} | } | ||||
@@ -563,6 +598,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||||
} | } | ||||
sord_iter_free(p); | sord_iter_free(p); | ||||
sord_free(plugins); | sord_free(plugins); | ||||
lilv_free(lib_path); | |||||
} | } | ||||
sord_iter_free(iter); | sord_iter_free(iter); | ||||
sord_free(model); | sord_free(model); | ||||
@@ -570,7 +606,7 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||||
} | } | ||||
LilvNode* | 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( | SerdNode manifest_uri = lilv_new_uri_relative_to_base( | ||||
(const uint8_t*)"manifest.ttl", | (const uint8_t*)"manifest.ttl", | ||||
@@ -580,8 +616,67 @@ lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri) | |||||
return manifest; | 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_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)) { | if (!lilv_node_is_uri(bundle_uri)) { | ||||
LILV_ERRORF("Bundle URI `%s' is not a URI\n", | 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.rdf_a, | ||||
world->uris.lv2_Plugin, | world->uris.lv2_Plugin, | ||||
bundle_node); | 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) { | FOREACH_MATCH(plug_results) { | ||||
const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT); | const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT); | ||||
lilv_world_add_plugin(world, plug, manifest, NULL, bundle_node); | 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 | 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)) { | while (!sord_iter_end(i)) { | ||||
const SerdStatus st = sord_erase(world->model, i); | const SerdStatus st = sord_erase(world->model, i); | ||||
if (st) { | if (st) { | ||||
LILV_ERRORF("Error removing statement from <%s> (%s)\n", | 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; | 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. */ | /** Remove loaded_files entry so file will be reloaded if requested. */ | ||||
static int | static int | ||||
lilv_world_unload_file(LilvWorld* world, LilvNode* file) | |||||
lilv_world_unload_file(LilvWorld* world, const LilvNode* file) | |||||
{ | { | ||||
ZixTreeIter* iter; | ZixTreeIter* iter; | ||||
if (!zix_tree_find((ZixTree*)world->loaded_files, file, &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_API int | ||||
lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||||
lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri) | |||||
{ | { | ||||
if (!bundle_uri) { | if (!bundle_uri) { | ||||
return 0; | 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 | // Drop everything in bundle graph | ||||
return lilv_world_drop_graph(world, bundle_uri); | |||||
return lilv_world_drop_graph(world, bundle_uri->node); | |||||
} | } | ||||
static void | static void | ||||
@@ -903,7 +1115,7 @@ lilv_world_unload_resource(LilvWorld* world, | |||||
if (sord_node_get_type(file) != SORD_URI) { | if (sord_node_get_type(file) != SORD_URI) { | ||||
LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", | LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", | ||||
sord_node_get_string(file)); | 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); | lilv_world_unload_file(world, file_node); | ||||
++n_dropped; | ++n_dropped; | ||||
} | } | ||||
@@ -932,3 +1144,51 @@ lilv_world_get_all_plugins(const LilvWorld* world) | |||||
{ | { | ||||
return world->plugins; | 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 | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -59,7 +59,7 @@ typedef enum { | |||||
ZIX_STATUS_NOT_FOUND, | ZIX_STATUS_NOT_FOUND, | ||||
ZIX_STATUS_EXISTS, | ZIX_STATUS_EXISTS, | ||||
ZIX_STATUS_BAD_ARG, | ZIX_STATUS_BAD_ARG, | ||||
ZIX_STATUS_BAD_PERMS, | |||||
ZIX_STATUS_BAD_PERMS | |||||
} ZixStatus; | } 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); | lilv_world_load_bundle(world, bundle_uri); | ||||
free(abs_bundle); | free(abs_bundle); | ||||
serd_node_free(&bundle); | serd_node_free(&bundle); | ||||
lilv_node_free(bundle_uri); | |||||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | ||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | 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); | LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | ||||
TEST_ASSERT(!instance); | TEST_ASSERT(!instance); | ||||
lilv_node_free(plugin_uri); | |||||
lilv_world_free(world); | lilv_world_free(world); | ||||
return 0; | return 0; |
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||||
lilv_world_load_bundle(world, bundle_uri); | lilv_world_load_bundle(world, bundle_uri); | ||||
free(abs_bundle); | free(abs_bundle); | ||||
serd_node_free(&bundle); | serd_node_free(&bundle); | ||||
lilv_node_free(bundle_uri); | |||||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | ||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | 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); | LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | ||||
TEST_ASSERT(instance); | TEST_ASSERT(instance); | ||||
lilv_instance_free(instance); | |||||
LilvNode* eg_blob = lilv_new_uri(world, "http://example.org/blob"); | LilvNode* eg_blob = lilv_new_uri(world, "http://example.org/blob"); | ||||
LilvNode* blob = lilv_world_get(world, plugin_uri, eg_blob, NULL); | LilvNode* blob = lilv_world_get(world, plugin_uri, eg_blob, NULL); | ||||
TEST_ASSERT(lilv_node_is_literal(blob)); | 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* eg_junk = lilv_new_uri(world, "http://example.org/junk"); | ||||
LilvNode* junk = lilv_world_get(world, plugin_uri, eg_junk, NULL); | LilvNode* junk = lilv_world_get(world, plugin_uri, eg_junk, NULL); | ||||
TEST_ASSERT(lilv_node_is_literal(junk)); | 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); | lilv_world_free(world); | ||||
return 0; | 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 | Copyright 2008 Krzysztof Foltman | ||||
Permission to use, copy, modify, and/or distribute this software for any | 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. | 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 <assert.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
@@ -159,9 +160,9 @@ cleanup(void) | |||||
#define TEST_ASSERT(check) do {\ | #define TEST_ASSERT(check) do {\ | ||||
test_count++;\ | test_count++;\ | ||||
if (!(check)) {\ | if (!(check)) {\ | ||||
assert(false);\ | |||||
error_count++;\ | 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) | } while (0) | ||||
@@ -252,6 +253,23 @@ test_value(void) | |||||
TEST_ASSERT(!strcmp(lilv_node_as_string(sval), "Foo")); | TEST_ASSERT(!strcmp(lilv_node_as_string(sval), "Foo")); | ||||
TEST_ASSERT(lilv_node_as_int(ival) == 42); | TEST_ASSERT(lilv_node_as_int(ival) == 42); | ||||
TEST_ASSERT(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON); | 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_abs = lilv_new_file_uri(world, NULL, "/foo/bar"); | ||||
LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo"); | LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo"); | ||||
@@ -345,6 +363,29 @@ test_util(void) | |||||
{ | { | ||||
TEST_ASSERT(!lilv_realpath(NULL)); | 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; | return 1; | ||||
} | } | ||||
@@ -1418,6 +1459,7 @@ test_ui(void) | |||||
uint32_t atom_Float = 0; | uint32_t atom_Float = 0; | ||||
float in = 1.0; | float in = 1.0; | ||||
float out = 42.0; | float out = 42.0; | ||||
float control = 1234.0; | |||||
static const void* | static const void* | ||||
get_port_value(const char* port_symbol, | get_port_value(const char* port_symbol, | ||||
@@ -1433,6 +1475,10 @@ get_port_value(const char* port_symbol, | |||||
*size = sizeof(float); | *size = sizeof(float); | ||||
*type = atom_Float; | *type = atom_Float; | ||||
return &out; | return &out; | ||||
} else if (!strcmp(port_symbol, "control")) { | |||||
*size = sizeof(float); | |||||
*type = atom_Float; | |||||
return &control; | |||||
} else { | } else { | ||||
fprintf(stderr, "error: get_port_value for nonexistent port `%s'\n", | fprintf(stderr, "error: get_port_value for nonexistent port `%s'\n", | ||||
port_symbol); | port_symbol); | ||||
@@ -1452,6 +1498,8 @@ set_port_value(const char* port_symbol, | |||||
in = *(const float*)value; | in = *(const float*)value; | ||||
} else if (!strcmp(port_symbol, "output")) { | } else if (!strcmp(port_symbol, "output")) { | ||||
out = *(const float*)value; | out = *(const float*)value; | ||||
} else if (!strcmp(port_symbol, "control")) { | |||||
control = *(const float*)value; | |||||
} else { | } else { | ||||
fprintf(stderr, "error: set_port_value for nonexistent port `%s'\n", | fprintf(stderr, "error: set_port_value for nonexistent port `%s'\n", | ||||
port_symbol); | port_symbol); | ||||
@@ -1613,6 +1661,18 @@ test_state(void) | |||||
get_port_value, world, 0, NULL); | get_port_value, world, 0, NULL); | ||||
TEST_ASSERT(lilv_state_equals(state2, state4)); | 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 | // Save state to a directory | ||||
int ret = lilv_state_save(world, &map, &unmap, state, NULL, | int ret = lilv_state_save(world, &map, &unmap, state, NULL, | ||||
"state/state.lv2", "state.ttl"); | "state/state.lv2", "state.ttl"); | ||||
@@ -1623,6 +1683,16 @@ test_state(void) | |||||
"state/state.lv2/state.ttl"); | "state/state.lv2/state.ttl"); | ||||
TEST_ASSERT(lilv_state_equals(state, state5)); // Round trip accuracy | 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 | // Save state with URI to a directory | ||||
const char* state_uri = "http://example.org/state"; | 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/", "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("/a", NULL)), "/a/")); free(s); | ||||
TEST_ASSERT(!strcmp((s = lilv_path_join(NULL, "/b")), "/b")); free(s); | |||||
#ifndef _WIN32 | #ifndef _WIN32 | ||||
setenv("LILV_TEST_1", "test", 1); | 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 */ | /* add tests here */ | ||||
static struct TestCase tests[] = { | static struct TestCase tests[] = { | ||||
TEST_CASE(util), | TEST_CASE(util), | ||||
@@ -1963,6 +2237,9 @@ static struct TestCase tests[] = { | |||||
TEST_CASE(string), | TEST_CASE(string), | ||||
TEST_CASE(world), | TEST_CASE(world), | ||||
TEST_CASE(state), | TEST_CASE(state), | ||||
TEST_CASE(reload_bundle), | |||||
TEST_CASE(replace_version), | |||||
TEST_CASE(get_symbol), | |||||
{ NULL, NULL } | { NULL, NULL } | ||||
}; | }; | ||||
@@ -17,4 +17,4 @@ | |||||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | #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); | lilv_world_load_bundle(world, bundle_uri); | ||||
free(abs_bundle); | free(abs_bundle); | ||||
serd_node_free(&bundle); | serd_node_free(&bundle); | ||||
lilv_node_free(bundle_uri); | |||||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | ||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | 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); | LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | ||||
TEST_ASSERT(!instance); | TEST_ASSERT(!instance); | ||||
lilv_node_free(plugin_uri); | |||||
lilv_world_free(world); | lilv_world_free(world); | ||||
return 0; | return 0; |
@@ -1,5 +1,5 @@ | |||||
/* | /* | ||||
Lilv Test Plugin - Missing descriptor | |||||
Lilv Test Plugin - Missing name | |||||
Copyright 2011-2015 David Robillard <d@drobilla.net> | Copyright 2011-2015 David Robillard <d@drobilla.net> | ||||
Permission to use, copy, modify, and/or distribute this software for any | 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); | lilv_world_load_bundle(world, bundle_uri); | ||||
free(abs_bundle); | free(abs_bundle); | ||||
serd_node_free(&bundle); | serd_node_free(&bundle); | ||||
lilv_node_free(bundle_uri); | |||||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | ||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | 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); | LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | ||||
TEST_ASSERT(instance); | TEST_ASSERT(instance); | ||||
lilv_instance_free(instance); | |||||
lilv_node_free(plugin_uri); | |||||
lilv_world_free(world); | lilv_world_free(world); | ||||
return 0; | return 0; |
@@ -21,8 +21,23 @@ | |||||
#define PLUGIN_URI "http://example.org/missing-plugin" | #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 | LV2_SYMBOL_EXPORT | ||||
const LV2_Descriptor* lv2_descriptor(uint32_t index) | const LV2_Descriptor* lv2_descriptor(uint32_t index) | ||||
{ | { | ||||
if (index == 0) { | |||||
return &descriptor; | |||||
} | |||||
return NULL; | return NULL; | ||||
} | } |
@@ -28,6 +28,7 @@ main(int argc, char** argv) | |||||
lilv_world_load_bundle(world, bundle_uri); | lilv_world_load_bundle(world, bundle_uri); | ||||
free(abs_bundle); | free(abs_bundle); | ||||
serd_node_free(&bundle); | serd_node_free(&bundle); | ||||
lilv_node_free(bundle_uri); | |||||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | ||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | 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); | LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); | ||||
TEST_ASSERT(!instance); | TEST_ASSERT(!instance); | ||||
lilv_node_free(plugin_uri); | |||||
lilv_world_free(world); | lilv_world_free(world); | ||||
return 0; | 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); | lilv_world_load_bundle(world, bundle_uri); | ||||
free(abs_bundle); | free(abs_bundle); | ||||
serd_node_free(&bundle); | serd_node_free(&bundle); | ||||
lilv_node_free(bundle_uri); | |||||
LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | LilvNode* plugin_uri = lilv_new_uri(world, PLUGIN_URI); | ||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | const LilvPlugins* plugins = lilv_world_get_all_plugins(world); | ||||
@@ -38,7 +39,9 @@ main(int argc, char** argv) | |||||
TEST_ASSERT(port); | TEST_ASSERT(port); | ||||
LilvNode* name = lilv_port_get_name(plugin, port); | LilvNode* name = lilv_port_get_name(plugin, port); | ||||
TEST_ASSERT(!name); | TEST_ASSERT(!name); | ||||
lilv_node_free(name); | |||||
lilv_node_free(plugin_uri); | |||||
lilv_world_free(world); | lilv_world_free(world); | ||||
return 0; | 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> . |