| @@ -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> . | |||||