summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-tidy41
-rw-r--r--.clant.json4
-rw-r--r--.gitignore11
-rw-r--r--.gitmodules3
-rw-r--r--.reuse/dep518
-rw-r--r--COPYING16
-rw-r--r--INSTALL66
-rw-r--r--INSTALL.md77
-rw-r--r--LICENSES/0BSD.txt12
l---------LICENSES/ISC.txt1
-rw-r--r--NEWS104
-rw-r--r--README.md3
-rw-r--r--bindings/python/Makefile2
-rw-r--r--bindings/python/conf.py8
-rw-r--r--bindings/python/index.rst4
-rw-r--r--bindings/python/lilv.py11
-rwxr-xr-xbindings/python/lv2_apply.py3
-rwxr-xr-xbindings/python/lv2_list.py3
-rwxr-xr-xbindings/python/lv2_list_presets.py3
-rw-r--r--bindings/python/meson.build9
-rw-r--r--bindings/test/bindings_test_plugin.c80
-rw-r--r--bindings/test/python/test_api.py13
-rw-r--r--doc/Doxyfile.in31
-rw-r--r--doc/api/meson.build9
-rw-r--r--doc/conf.py.in127
-rw-r--r--doc/footer.html20
-rw-r--r--doc/header.html37
-rw-r--r--doc/html/meson.build39
-rw-r--r--doc/index.rst23
-rw-r--r--doc/layout.xml226
-rw-r--r--doc/lv2apply.1100
-rw-r--r--doc/lv2bench.155
-rw-r--r--doc/lv2info.198
-rw-r--r--doc/lv2ls.189
-rw-r--r--doc/mainpage.md6
-rw-r--r--doc/meson.build71
-rw-r--r--doc/overview.rst22
-rw-r--r--doc/plugins.rst94
-rw-r--r--doc/reference.doxygen.in2462
-rw-r--r--doc/singlehtml/meson.build33
-rw-r--r--doc/style.css739
-rw-r--r--doc/uis.rst25
-rw-r--r--doc/world.rst157
-rw-r--r--doc/xml/meson.build36
-rw-r--r--include/lilv/lilv.h (renamed from lilv/lilv.h)1252
-rw-r--r--include/lilv/lilvmm.hpp453
-rw-r--r--lilv.pc.in11
-rw-r--r--lilv.ttl48
-rw-r--r--lilv/lilvmm.hpp353
-rw-r--r--meson.build265
-rw-r--r--meson/suppressions/meson.build141
-rw-r--r--meson_options.txt29
-rw-r--r--src/.clang-tidy21
-rw-r--r--src/collections.c215
-rw-r--r--src/filesystem.c495
-rw-r--r--src/filesystem.h156
-rw-r--r--src/instance.c176
-rw-r--r--src/lib.c185
-rw-r--r--src/lilv_config.h33
-rw-r--r--src/lilv_internal.h530
-rw-r--r--src/node.c518
-rw-r--r--src/plugin.c1637
-rw-r--r--src/pluginclass.c81
-rw-r--r--src/port.c309
-rw-r--r--src/query.c206
-rw-r--r--src/scalepoint.c39
-rw-r--r--src/state.c2318
-rw-r--r--src/ui.c111
-rw-r--r--src/util.c368
-rw-r--r--src/world.c1946
-rw-r--r--src/zix/common.h88
-rw-r--r--src/zix/tree.c715
-rw-r--r--src/zix/tree.h149
-rw-r--r--subprojects/sphinxygen.wrap14
-rw-r--r--test/.clang-tidy19
-rw-r--r--test/bad_syntax.lv2/bad_syntax.c93
-rw-r--r--test/bad_syntax.lv2/meson.build36
-rw-r--r--test/bad_syntax.lv2/test_bad_syntax.c62
-rw-r--r--test/cpp/.clang-tidy19
-rw-r--r--test/cpp/meson.build37
-rw-r--r--test/cpp/test_lilv_hpp.cpp12
-rw-r--r--test/failed_instantiation.lv2/failed_instantiation.c70
-rw-r--r--test/failed_instantiation.lv2/meson.build36
-rw-r--r--test/failed_instantiation.lv2/test_failed_instantiation.c62
-rw-r--r--test/failed_lib_descriptor.lv2/failed_lib_descriptor.c26
-rw-r--r--test/failed_lib_descriptor.lv2/meson.build36
-rw-r--r--test/failed_lib_descriptor.lv2/test_failed_lib_descriptor.c64
-rw-r--r--test/lib_descriptor.lv2/lib_descriptor.c114
-rw-r--r--test/lib_descriptor.lv2/meson.build36
-rw-r--r--test/lib_descriptor.lv2/test_lib_descriptor.c90
-rw-r--r--test/lilv_cxx_test.cpp25
-rw-r--r--test/lilv_test_uri_map.h75
-rw-r--r--test/lilv_test_utils.c287
-rw-r--r--test/lilv_test_utils.h64
-rw-r--r--test/lv2/core.lv2/lv2core.ttl (renamed from test/core.lv2/lv2core.ttl)0
-rw-r--r--test/lv2/core.lv2/manifest.ttl (renamed from test/core.lv2/manifest.ttl)0
-rw-r--r--test/lv2/core.lv2/meson.build11
-rw-r--r--test/meson.build115
-rw-r--r--test/missing_descriptor.lv2/meson.build36
-rw-r--r--test/missing_descriptor.lv2/missing_descriptor.c18
-rw-r--r--test/missing_descriptor.lv2/test_missing_descriptor.c64
-rw-r--r--test/missing_name.lv2/meson.build36
-rw-r--r--test/missing_name.lv2/missing_name.c93
-rw-r--r--test/missing_name.lv2/test_missing_name.c66
-rw-r--r--test/missing_plugin.lv2/meson.build36
-rw-r--r--test/missing_plugin.lv2/missing_plugin.c46
-rw-r--r--test/missing_plugin.lv2/test_missing_plugin.c64
-rw-r--r--test/missing_port.lv2/meson.build36
-rw-r--r--test/missing_port.lv2/missing_port.c93
-rw-r--r--test/missing_port.lv2/test_missing_port.c62
-rw-r--r--test/missing_port_name.lv2/meson.build36
-rw-r--r--test/missing_port_name.lv2/missing_port_name.c93
-rw-r--r--test/missing_port_name.lv2/test_missing_port_name.c70
-rw-r--r--test/new_version.lv2/meson.build24
-rw-r--r--test/new_version.lv2/new_version.c93
-rw-r--r--test/old_version.lv2/meson.build24
-rw-r--r--test/old_version.lv2/old_version.c93
-rw-r--r--test/test.lv2/test.c439
-rw-r--r--test/test_bad_port_index.c45
-rw-r--r--test/test_bad_port_symbol.c45
-rw-r--r--test/test_classes.c76
-rw-r--r--test/test_discovery.c96
-rw-r--r--test/test_filesystem.c473
-rw-r--r--test/test_get_symbol.c90
-rw-r--r--test/test_no_author.c54
-rw-r--r--test/test_no_verify.c45
-rw-r--r--test/test_plugin.c445
-rw-r--r--test/test_plugin.lv2/manifest.ttl.in (renamed from test/test.lv2/manifest.ttl.in)4
-rw-r--r--test/test_plugin.lv2/meson.build24
-rw-r--r--test/test_plugin.lv2/test_plugin.c427
-rw-r--r--test/test_plugin.lv2/test_plugin.ttl.in (renamed from test/test.lv2/test.ttl.in)0
-rw-r--r--test/test_port.c519
-rw-r--r--test/test_preset.c52
-rw-r--r--test/test_project.c61
-rw-r--r--test/test_project_no_author.c55
-rw-r--r--test/test_prototype.c56
-rw-r--r--test/test_reload_bundle.c144
-rw-r--r--test/test_replace_version.c161
-rw-r--r--test/test_state.c1735
-rw-r--r--test/test_string.c67
-rw-r--r--test/test_ui.c151
-rw-r--r--test/test_util.c81
-rw-r--r--test/test_value.c262
-rw-r--r--test/test_verify.c45
-rw-r--r--test/test_world.c47
-rw-r--r--tools/.clang-tidy16
-rw-r--r--tools/bench.h38
-rw-r--r--tools/lilv.bash_completion (renamed from utils/lilv.bash_completion)14
-rw-r--r--tools/lv2apply.c355
-rw-r--r--tools/lv2bench.c269
-rw-r--r--tools/lv2info.c443
-rw-r--r--tools/lv2ls.c81
-rw-r--r--tools/meson.build91
-rw-r--r--tools/uri_table.h67
-rw-r--r--utils/bench.h52
-rw-r--r--utils/lilv-bench.c34
-rw-r--r--utils/lv2apply.c364
-rw-r--r--utils/lv2bench.c276
-rw-r--r--utils/lv2info.c457
-rw-r--r--utils/lv2ls.c94
-rw-r--r--utils/uri_table.h80
-rwxr-xr-xwaf27
m---------waflib0
-rw-r--r--wscript633
164 files changed, 12619 insertions, 16796 deletions
diff --git a/.clang-tidy b/.clang-tidy
index 5ccbad9..aa54c19 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,27 +1,24 @@
+# Copyright 2020-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
Checks: >
*,
- -*-else-after-return,
- -*-magic-numbers,
- -*-uppercase-literal-suffix,
- -android-cloexec-fopen,
- -bugprone-branch-clone,
+ -*-vararg,
+ -altera-*,
+ -bugprone-assignment-in-if-condition,
+ -bugprone-easily-swappable-parameters,
-bugprone-macro-parentheses,
- -bugprone-narrowing-conversions,
- -bugprone-not-null-terminated-result,
- -bugprone-reserved-identifier,
- -bugprone-suspicious-string-compare,
- -cert-dcl37-c,
- -cert-dcl51-cpp,
- -cert-err34-c,
- -clang-analyzer-alpha.*,
- -cppcoreguidelines-narrowing-conversions,
- -google-readability-todo,
- -hicpp-multiway-paths-covered,
- -hicpp-signed-bitwise,
- -llvm-header-guard,
+ -bugprone-suspicious-realloc-usage,
+ -clang-diagnostic-unused-function,
+ -clang-diagnostic-unused-macros,
-llvmlibc-*,
- -misc-unused-parameters,
- -readability-implicit-bool-conversion,
-WarningsAsErrors: '*'
-HeaderFilterRegex: '.*'
+ -modernize-macro-to-enum,
+ -readability-identifier-length,
+CheckOptions:
+ - key: hicpp-uppercase-literal-suffix.NewSuffixes
+ value: 'L;U;UL;ULL'
+ - key: readability-uppercase-literal-suffix.NewSuffixes
+ value: 'L;U;UL;ULL'
FormatStyle: file
+HeaderFilterRegex: '.*/lilv/[^/]+.h'
+WarningsAsErrors: '*'
diff --git a/.clant.json b/.clant.json
new file mode 100644
index 0000000..33154c7
--- /dev/null
+++ b/.clant.json
@@ -0,0 +1,4 @@
+{
+ "exclude_patterns": ["lilvmm\\.hpp"],
+ "version": "1.0.0"
+}
diff --git a/.gitignore b/.gitignore
index 204c242..7bc1d37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,9 @@
-build/**
-.waf-*
-.lock-waf*
+# Copyright 2018-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+.meson-subproject-wrap-hash.txt
__pycache__
+build/**
+subprojects/packagecache/
+subprojects/sphinxygen-1.0.4/
+subprojects/sphinxygen/
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index cc8b569..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "waflib"]
- path = waflib
- url = ../../drobilla/autowaf.git
diff --git a/.reuse/dep5 b/.reuse/dep5
new file mode 100644
index 0000000..f9693c0
--- /dev/null
+++ b/.reuse/dep5
@@ -0,0 +1,18 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: lilv
+Upstream-Contact: David Robillard <d@drobilla.net>
+Source: https://gitlab.com/drobilla/lilv
+
+Files: AUTHORS NEWS lilv.ttl
+Copyright: 2006-2022 David Robillard <d@drobilla.net>
+Comment: Contributed to the Commons as a representation of simple facts
+License: 0BSD OR ISC
+
+Files: .clant.json
+Copyright: 2020 David Robillard <d@drobilla.net>
+Comment: Contributed to the Commons as a tool configuration
+License: 0BSD OR ISC
+
+Files: bindings/test/*.ttl.in test/*/*.ttl.in test/lv2/core.lv2/*.ttl
+Copyright: 2015-2022 David Robillard <d@drobilla.net>
+License: ISC
diff --git a/COPYING b/COPYING
index ec28a67..977d7b6 100644
--- a/COPYING
+++ b/COPYING
@@ -1,13 +1,13 @@
-Copyright 2011-2020 David Robillard <http://drobilla.net>
+Copyright 2011-2022 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. \ No newline at end of file
+THE 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.
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 9b54f51..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,66 +0,0 @@
-Installation Instructions
-=========================
-
-Basic Installation
-------------------
-
-Building this software requires only Python. To install with default options:
-
- ./waf configure
- ./waf
- ./waf install # or sudo ./waf install
-
-Configuration Options
----------------------
-
-All supported options can be viewed using the command:
-
- ./waf --help
-
-Most options only need to be passed during the configure stage, for example:
-
- ./waf configure --prefix=/usr
- ./waf
- ./waf install
-
-Compiler Configuration
-----------------------
-
-Several standard environment variables can be used to control how compilers are
-invoked:
-
- * CC: Path to C compiler
- * CFLAGS: C compiler options
- * CXX: Path to C++ compiler
- * CXXFLAGS: C++ compiler options
- * CPPFLAGS: C preprocessor options
- * LINKFLAGS: Linker options
-
-Library Versioning
-------------------
-
-This library uses semantic versioning <http://semver.org/>.
-
-Several major versions can be installed in parallel. The shared library name,
-include directory, and pkg-config file are suffixed with the major version
-number. For example, a library named "foo" at version 1.x.y might install:
-
- /usr/include/foo-1/foo/foo.h
- /usr/lib/foo-1.so.1.x.y
- /usr/lib/pkgconfig/foo-1.pc
-
-Dependencies can check for the package "foo-1" with pkg-config.
-
-Packaging
----------
-
-Everything can be installed to a specific root directory by passing a --destdir
-option to the install stage (or setting the DESTDIR environment variable),
-which adds a prefix to all install paths. For example:
-
- ./waf configure --prefix=/usr
- ./waf
- ./waf install --destdir=/tmp/package
-
-Packages should allow parallel installation of several major versions. For
-example, the above would be packaged as "foo-1". \ No newline at end of file
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..2adecf0
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,77 @@
+<!-- Copyright 2022 David Robillard <d@drobilla.net> -->
+<!-- SPDX-License-Identifier: ISC -->
+
+Installation Instructions
+=========================
+
+Prerequisites
+-------------
+
+To build from source, you will need:
+
+ * A relatively modern C compiler (GCC, Clang, and MSVC are known to work).
+
+ * [Meson](http://mesonbuild.com/), which depends on
+ [Python](http://python.org/).
+
+This is a brief overview of building this project with meson. See the meson
+documentation for more detailed information.
+
+Configuration
+-------------
+
+The build is configured with the `setup` command, which creates a new build
+directory with the given name:
+
+ meson setup build
+
+Some environment variables are read during `setup` and stored with the
+configuration:
+
+ * `CC`: Path to C compiler.
+ * `CFLAGS`: C compiler options.
+ * `LDFLAGS`: Linker options.
+
+However, it is better to use meson options for configuration. All options can
+be inspected with the `configure` command from within the build directory:
+
+ cd build
+ meson configure
+
+Options can be set by passing C-style "define" options to `configure`:
+
+ meson configure -Dc_args="-march=native" -Dprefix="/opt/mypackage/"
+
+Note that some options, such as `strict` and `werror` are for
+developer/maintainer use only. Please don't file issues about anything that
+happens when they are enabled.
+
+Building
+--------
+
+From within a configured build directory, everything can be built with the
+`compile` command:
+
+ meson compile
+
+Similarly, tests can be run with the `test` command:
+
+ meson test
+
+Meson can also generate a project for several popular IDEs, see the `backend`
+option for details.
+
+Installation
+------------
+
+A compiled project can be installed with the `install` command:
+
+ meson install
+
+You may need to acquire root permissions to install to a system-wide prefix.
+For packaging, the installation may be staged to a directory using the
+`DESTDIR` environment variable or the `--destdir` option:
+
+ DESTDIR=/tmp/mypackage/ meson install
+
+ meson install --destdir=/tmp/mypackage/
diff --git a/LICENSES/0BSD.txt b/LICENSES/0BSD.txt
new file mode 100644
index 0000000..b3e8cfd
--- /dev/null
+++ b/LICENSES/0BSD.txt
@@ -0,0 +1,12 @@
+Copyright 2011-2022 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.
+
+THE 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.
diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt
new file mode 120000
index 0000000..012065c
--- /dev/null
+++ b/LICENSES/ISC.txt
@@ -0,0 +1 @@
+../COPYING \ No newline at end of file
diff --git a/NEWS b/NEWS
index 4cdd86c..92b4030 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,77 @@
-lilv (0.24.11) unstable;
+lilv (0.24.25) unstable; urgency=medium
+ * Fix C++ test build on MacOS
+ * Fix library current_version on MacOS
+ * Fix test suite when TMPDIR has no trailing slash
+
+ -- David Robillard <d@drobilla.net> Sat, 16 Mar 2024 13:51:02 +0000
+
+lilv (0.24.24) stable; urgency=medium
+
+ * Avoid overriding state features passed by the host
+ * Fix null dereference when trying to load state from a missing file
+ * Fix potential null dereferences and conversion warnings
+
+ -- David Robillard <d@drobilla.net> Tue, 23 Jan 2024 19:39:29 +0000
+
+lilv (0.24.22) stable; urgency=medium
+
+ * Allow LILV_API to be defined by the user
+ * Clean up code
+ * Clean up inconsistent tool command line interfaces
+ * Convert man pages to mdoc
+ * Fix crash when plugins pass NULL to the LV2_State_Retrieve_Function
+ * Fix dependencies in pkg-config file
+ * Fix potential crash when writing state files fails
+ * Order plugin classes by URI
+ * Override pkg-config dependency within meson
+ * Remove junk files from documentation install
+ * Replace duplicated dox_to_sphinx script with sphinxygen dependency
+ * Switch to external zix dependency
+
+ -- David Robillard <d@drobilla.net> Sun, 22 Oct 2023 20:14:02 +0000
+
+lilv (0.24.20) stable; urgency=medium
+
+ * Adopt REUSE machine-readable licensing standard
+ * Update project metadata
+
+ -- David Robillard <d@drobilla.net> Fri, 09 Sep 2022 17:28:30 +0000
+
+lilv (0.24.18) stable; urgency=medium
+
+ * Allow programs to be used from subproject
+ * Fix default LV2_PATH
+
+ -- David Robillard <d@drobilla.net> Fri, 12 Aug 2022 22:15:29 +0000
+
+lilv (0.24.16) stable; urgency=medium
+
+ * Fix fallback flock() detection on MacOS
+ * Switch to meson build system
+
+ -- David Robillard <d@drobilla.net> Tue, 19 Jul 2022 01:16:26 +0000
+
+lilv (0.24.14) stable; urgency=medium
+
+ * Fix build issues with newer toolchains
+ * Fix unused parameter warnings
+ * Update zix tree
+
+ -- David Robillard <d@drobilla.net> Fri, 27 May 2022 01:38:26 +0000
+
+lilv (0.24.12) stable; urgency=medium
+
+ * Allow connecting ports to structures in Python
* Fix potential memory error when joining filesystem paths
+ * Fix saving state with files on Windows
* Fix unlikely undefined behavior when saving state
+ * Fix writing state manifests on Windows
+ * Remove the need for a generated configuration header
- -- David Robillard <d@drobilla.net> Wed, 11 Nov 2020 16:12:07 +0000
+ -- David Robillard <d@drobilla.net> Thu, 07 Jan 2021 21:46:06 +0000
-lilv (0.24.10) stable;
+lilv (0.24.10) stable; urgency=medium
* Fix memory leaks in lv2bench
* Fix various minor warnings and other code quality issues
@@ -14,7 +80,7 @@ lilv (0.24.10) stable;
-- David Robillard <d@drobilla.net> Sun, 27 Sep 2020 12:17:02 +0000
-lilv (0.24.8) stable;
+lilv (0.24.8) stable; urgency=medium
* Allow passing strings for URIs in Python API when unambiguous
* Fix cases where incorrect translation is used
@@ -24,7 +90,7 @@ lilv (0.24.8) stable;
-- David Robillard <d@drobilla.net> Sun, 26 Apr 2020 15:55:26 +0000
-lilv (0.24.6) stable;
+lilv (0.24.6) stable; urgency=medium
* Add more strict error detection when storing plugin state properties
* Add option to override LV2_PATH in applications
@@ -38,7 +104,7 @@ lilv (0.24.6) stable;
-- David Robillard <d@drobilla.net> Sun, 10 Nov 2019 21:39:37 +0000
-lilv (0.24.4) stable;
+lilv (0.24.4) stable; urgency=medium
* Don't attempt to load remote or non-Turtle files
* Fix saving state when broken links are encountered
@@ -53,14 +119,14 @@ lilv (0.24.4) stable;
-- David Robillard <d@drobilla.net> Sun, 22 Jul 2018 18:42:00 +0000
-lilv (0.24.2) stable;
+lilv (0.24.2) stable; urgency=medium
* Fix comparison of restored states with paths
* Fix saving state to paths that contain URI delimiters (#, ?, etc)
-- David Robillard <d@drobilla.net> Wed, 04 Jan 2017 16:48:08 +0000
-lilv (0.24.0) stable;
+lilv (0.24.0) stable; urgency=medium
* Add LILV_URI_ATOM_PORT and LILV_URI_CV_PORT defines
* Add lilv_state_set_metadata() for adding state banks/comments/etc (based
@@ -83,7 +149,7 @@ lilv (0.24.0) stable;
-- David Robillard <d@drobilla.net> Tue, 20 Sep 2016 02:24:57 +0000
-lilv (0.22.0) stable;
+lilv (0.22.0) stable; urgency=medium
* Add lilv_file_uri_parse() for correct URI to path conversion
* Add lilv_free() for systems picky about such things
@@ -110,7 +176,7 @@ lilv (0.22.0) stable;
-- David Robillard <d@drobilla.net> Thu, 08 Oct 2015 19:39:29 +0000
-lilv (0.20.0) stable;
+lilv (0.20.0) stable; urgency=medium
* Add convenient lilv_new_file_uri for creating file URIs
* Add lilv_world_unload_bundle() and lilv_world_unload_resource()
@@ -131,7 +197,7 @@ lilv (0.20.0) stable;
-- David Robillard <d@drobilla.net> Fri, 08 Aug 2014 22:21:32 +0000
-lilv (0.18.0) stable;
+lilv (0.18.0) stable; urgency=medium
* Add lilv_port_get_node() for using world query functions with ports
* Add support for running plugins from Python by Kaspar Emanuel
@@ -148,7 +214,7 @@ lilv (0.18.0) stable;
-- David Robillard <d@drobilla.net> Sat, 04 Jan 2014 21:06:42 +0000
-lilv (0.16.0) stable;
+lilv (0.16.0) stable; urgency=medium
* Add lilv_nodes_merge()
* Add lilv_world_ask() for easily checking if a statement exists
@@ -170,7 +236,7 @@ lilv (0.16.0) stable;
-- David Robillard <d@drobilla.net> Mon, 18 Feb 2013 21:43:10 +0000
-lilv (0.14.4) stable;
+lilv (0.14.4) stable; urgency=medium
* Add lv2bench utility
* Add option to build utilities as static binaries
@@ -190,13 +256,13 @@ lilv (0.14.4) stable;
-- David Robillard <d@drobilla.net> Thu, 23 Aug 2012 05:38:29 +0000
-lilv (0.14.2) stable;
+lilv (0.14.2) stable; urgency=medium
* Fix dynmanifest support
-- David Robillard <d@drobilla.net> Thu, 19 Apr 2012 20:11:31 +0000
-lilv (0.14.0) stable;
+lilv (0.14.0) stable; urgency=medium
* Add LilvState API for handling plugin state. This makes it simple to save
and restore plugin state both in memory and on disk, as well as save
@@ -227,7 +293,7 @@ lilv (0.14.0) stable;
-- David Robillard <d@drobilla.net> Thu, 19 Apr 2012 00:06:28 +0000
-lilv (0.5.0) stable;
+lilv (0.5.0) stable; urgency=medium
* Add ability to build static library
* Add lv2core as a pkg-config dependency (for lv2.h header include)
@@ -238,7 +304,7 @@ lilv (0.5.0) stable;
-- David Robillard <d@drobilla.net> Thu, 29 Sep 2011 04:00:00 +0000
-lilv (0.4.4) stable;
+lilv (0.4.4) stable; urgency=medium
* Fix building python bindings
* Fix lilv_ui_is_supported when Lilv is built independently
@@ -248,14 +314,14 @@ lilv (0.4.4) stable;
-- David Robillard <d@drobilla.net> Sat, 11 Jun 2011 15:20:11 +0000
-lilv (0.4.2) stable;
+lilv (0.4.2) stable; urgency=medium
* Fix build system Python 3 compatibility
* Fix compilation issues on some systems
-- David Robillard <d@drobilla.net> Wed, 25 May 2011 23:00:00 +0000
-lilv (0.4.0) stable;
+lilv (0.4.0) stable; urgency=medium
* Initial version (forked from SLV2)
diff --git a/README.md b/README.md
index 807fc2b..6d3ff88 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+<!-- Copyright 2006-2019 David Robillard <d@drobilla.net> -->
+<!-- SPDX-License-Identifier: ISC -->
+
Lilv
====
diff --git a/bindings/python/Makefile b/bindings/python/Makefile
index e63c124..32f199d 100644
--- a/bindings/python/Makefile
+++ b/bindings/python/Makefile
@@ -1,5 +1,7 @@
# Makefile for Sphinx documentation
#
+# Copyright 2016 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
# You can set these variables from the command line.
SPHINXOPTS =
diff --git a/bindings/python/conf.py b/bindings/python/conf.py
index 576919e..52d514a 100644
--- a/bindings/python/conf.py
+++ b/bindings/python/conf.py
@@ -1,4 +1,8 @@
# -*- coding: utf-8 -*-
+
+# Copyright 2016-2024 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
#
# Lilv documentation build configuration file, created by
# sphinx-quickstart on Sun Sep 4 18:25:58 2016.
@@ -56,9 +60,9 @@ copyright = u'2016, David Robillard'
# built documents.
#
# The short X.Y version.
-version = '0.24.2'
+version = '0.24.25'
# The full version, including alpha/beta/rc tags.
-release = '0.24.2'
+release = '0.24.25'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/bindings/python/index.rst b/bindings/python/index.rst
index 4616054..b44fa08 100644
--- a/bindings/python/index.rst
+++ b/bindings/python/index.rst
@@ -1,3 +1,7 @@
+..
+ Copyright 2016 David Robillard <d@drobilla.net>
+ SPDX-License-Identifier: ISC
+
Lilv Python Documentation
=========================
diff --git a/bindings/python/lilv.py b/bindings/python/lilv.py
index 45b8e05..69f6e7d 100644
--- a/bindings/python/lilv.py
+++ b/bindings/python/lilv.py
@@ -1,9 +1,12 @@
"""Lilv Python interface"""
+# Copyright 2016-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: ISC
+
__author__ = "David Robillard"
-__copyright__ = "Copyright 2016-2020 David Robillard"
+__copyright__ = "Copyright 2016-2024 David Robillard"
__license__ = "ISC"
-__version__ = "0.24.7"
+__version__ = "0.24.25"
__maintainer__ = "David Robillard"
__email__ = "d@drobilla.net"
__status__ = "Production"
@@ -1460,6 +1463,10 @@ class Instance(Structure):
self.get_descriptor().connect_port(
self.get_handle(), port_index, data
)
+ elif isinstance(data, Structure):
+ self.get_descriptor().connect_port(
+ self.get_handle(), port_index, cast(byref(data), c_void_p)
+ )
elif type(data) == numpy.ndarray:
self.get_descriptor().connect_port(
self.get_handle(),
diff --git a/bindings/python/lv2_apply.py b/bindings/python/lv2_apply.py
index 4c7d9b4..bb95682 100755
--- a/bindings/python/lv2_apply.py
+++ b/bindings/python/lv2_apply.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+# Copyright 2011-2016 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: ISC
+
import math
import lilv
import sys
diff --git a/bindings/python/lv2_list.py b/bindings/python/lv2_list.py
index babe1b4..1bb233c 100755
--- a/bindings/python/lv2_list.py
+++ b/bindings/python/lv2_list.py
@@ -1,5 +1,8 @@
#!/usr/bin/env python
+# Copyright 2007-2011 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: ISC
+
import lilv
world = lilv.World()
diff --git a/bindings/python/lv2_list_presets.py b/bindings/python/lv2_list_presets.py
index 4e0c9b1..a6439d6 100755
--- a/bindings/python/lv2_list_presets.py
+++ b/bindings/python/lv2_list_presets.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+# Copyright 2019-2020 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: ISC
+
import sys
import lilv
diff --git a/bindings/python/meson.build b/bindings/python/meson.build
new file mode 100644
index 0000000..1cffd71
--- /dev/null
+++ b/bindings/python/meson.build
@@ -0,0 +1,9 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+pymod = import('python')
+py = pymod.find_installation('python3', required: get_option('bindings_py'))
+
+if py.found()
+ py.install_sources(files('lilv.py'))
+endif
diff --git a/bindings/test/bindings_test_plugin.c b/bindings/test/bindings_test_plugin.c
index 1945c0d..18907d5 100644
--- a/bindings/test/bindings_test_plugin.c
+++ b/bindings/test/bindings_test_plugin.c
@@ -1,19 +1,6 @@
-/*
- Copyright 2006-2019 David Robillard <d@drobilla.net>
- Copyright 2006 Steve Harris <steve@plugin.org.uk>
-
- 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.
-*/
+// Copyright 2006-2019 David Robillard <d@drobilla.net>
+// Copyright 2006 Steve Harris <steve@plugin.org.uk>
+// SPDX-License-Identifier: ISC
/**
LV2 headers are based on the URI of the specification they come from, so a
@@ -42,10 +29,10 @@
should be defined for readability.
*/
typedef enum {
- TEST_CONTROL_IN = 0,
- TEST_CONTROL_OUT = 1,
- TEST_AUDIO_IN = 2,
- TEST_AUDIO_OUT = 3
+ TEST_CONTROL_IN = 0,
+ TEST_CONTROL_OUT = 1,
+ TEST_AUDIO_IN = 2,
+ TEST_AUDIO_OUT = 3
} PortIndex;
/**
@@ -54,7 +41,7 @@ typedef enum {
every instance method. In this simple plugin, only port buffers need to be
stored, since there is no additional instance data. */
typedef struct {
- float* buf;
+ float* buf;
} Test;
/**
@@ -73,9 +60,14 @@ instantiate(const LV2_Descriptor* descriptor,
const char* bundle_path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)malloc(sizeof(Test));
+ (void)descriptor;
+ (void)rate;
+ (void)bundle_path;
+ (void)features;
+
+ Test* test = (Test*)malloc(sizeof(Test));
- return (LV2_Handle)test;
+ return (LV2_Handle)test;
}
/**
@@ -87,10 +79,11 @@ instantiate(const LV2_Descriptor* descriptor,
context as run().
*/
static void
-connect_port(LV2_Handle instance,
- uint32_t port,
- void* data)
+connect_port(LV2_Handle instance, uint32_t port, void* data)
{
+ (void)instance;
+ (void)port;
+ (void)data;
}
/**
@@ -105,12 +98,15 @@ connect_port(LV2_Handle instance,
static void
activate(LV2_Handle instance)
{
+ (void)instance;
}
/** Process a block of audio (audio thread, must be RT safe). */
static void
run(LV2_Handle instance, uint32_t n_samples)
{
+ (void)instance;
+ (void)n_samples;
}
/**
@@ -127,6 +123,7 @@ run(LV2_Handle instance, uint32_t n_samples)
static void
deactivate(LV2_Handle instance)
{
+ (void)instance;
}
/**
@@ -138,7 +135,7 @@ deactivate(LV2_Handle instance)
static void
cleanup(LV2_Handle instance)
{
- free(instance);
+ free(instance);
}
/**
@@ -154,7 +151,9 @@ cleanup(LV2_Handle instance)
static const void*
extension_data(const char* uri)
{
- return NULL;
+ (void)uri;
+
+ return NULL;
}
/**
@@ -162,16 +161,14 @@ extension_data(const char* uri)
statically to avoid leaking memory and non-portable shared library
constructors and destructors to clean up properly.
*/
-static const LV2_Descriptor descriptor = {
- TEST_URI,
- instantiate,
- connect_port,
- activate,
- run,
- deactivate,
- cleanup,
- extension_data
-};
+static const LV2_Descriptor descriptor = {TEST_URI,
+ instantiate,
+ connect_port,
+ activate,
+ run,
+ deactivate,
+ cleanup,
+ extension_data};
/**
The lv2_descriptor() function is the entry point to the plugin library. The
@@ -187,10 +184,5 @@ LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor(uint32_t index)
{
- switch (index) {
- case 0:
- return &descriptor;
- default:
- return NULL;
- }
+ return index ? NULL : &descriptor;
}
diff --git a/bindings/test/python/test_api.py b/bindings/test/python/test_api.py
index 8d3a94a..d70dbe6 100644
--- a/bindings/test/python/test_api.py
+++ b/bindings/test/python/test_api.py
@@ -1,17 +1,6 @@
# Copyright 2016-2020 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.
+# SPDX-License-Identifier: ISC
import lilv
import os
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..2ca5694
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,31 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+PROJECT_NAME = Lilv
+PROJECT_BRIEF = "A library for simple use of LV2 plugins"
+
+QUIET = YES
+WARN_AS_ERROR = NO
+WARN_IF_UNDOCUMENTED = NO
+WARN_NO_PARAMDOC = NO
+
+JAVADOC_AUTOBRIEF = YES
+
+CASE_SENSE_NAMES = YES
+HIDE_IN_BODY_DOCS = YES
+REFERENCES_LINK_SOURCE = NO
+
+GENERATE_HTML = NO
+GENERATE_LATEX = NO
+GENERATE_XML = YES
+XML_PROGRAMLISTING = NO
+SHOW_FILES = NO
+
+MACRO_EXPANSION = YES
+PREDEFINED = LILV_API LILV_DEPRECATED
+
+RECURSIVE = YES
+STRIP_FROM_PATH = @LILV_SRCDIR@
+INPUT = @LILV_SRCDIR@/include/lilv/lilv.h
+
+OUTPUT_DIRECTORY = @DOX_OUTPUT@
diff --git a/doc/api/meson.build b/doc/api/meson.build
new file mode 100644
index 0000000..a470564
--- /dev/null
+++ b/doc/api/meson.build
@@ -0,0 +1,9 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+api_lilv_rst = custom_target(
+ 'lilv.rst',
+ command: [sphinxygen, '-f', '@INPUT0@', '@OUTDIR@'],
+ input: doxygen_xml,
+ output: 'lilv.rst',
+)
diff --git a/doc/conf.py.in b/doc/conf.py.in
new file mode 100644
index 0000000..444b70a
--- /dev/null
+++ b/doc/conf.py.in
@@ -0,0 +1,127 @@
+# Copyright 2020-2021 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: ISC
+
+# Project information
+
+project = "@LILV_TITLE@"
+copyright = "2020-2023, David Robillard"
+author = "David Robillard"
+release = "@LILV_VERSION@"
+version = "@LILV_VERSION@"
+desc = "A library for loading LV2 plugins"
+
+# General configuration
+
+exclude_patterns = ["xml"]
+language = "en"
+nitpicky = True
+pygments_style = "friendly"
+
+try:
+ import sphinx_lv2_theme
+
+ have_lv2_theme = True
+except ModuleNotFoundError:
+ have_lv2_theme = False
+
+# Ignore everything opaque or external for nitpicky mode
+_opaque = [
+ "FILE",
+ "LV2_Descriptor",
+ "LV2_Feature",
+ "LV2_Handle",
+ "LV2_URID_Map",
+ "LV2_URID_Unmap",
+ "LilvInstanceImpl",
+ "LilvNodeImpl",
+ "LilvPluginClassImpl",
+ "LilvPluginImpl",
+ "LilvPortImpl",
+ "LilvScalePointImpl",
+ "LilvStateImpl",
+ "LilvUIImpl",
+ "LilvWorldImpl",
+ "size_t",
+ "uint32_t",
+ "va_list",
+]
+
+nitpick_ignore = list(map(lambda x: ("c:identifier", x), _opaque))
+
+# HTML output
+
+html_copy_source = False
+html_secnumber_suffix = " "
+html_short_title = "@LILV_TITLE@"
+
+html_theme_options = {
+ "description": desc,
+ "logo_name": True,
+ "logo_width": "8em",
+}
+
+if tags.has("singlehtml"):
+ html_sidebars = {"**": ["globaltoc.html"]}
+ html_theme_options.update(
+ {
+ "globaltoc_collapse": False,
+ "globaltoc_maxdepth": 3,
+ "nosidebar": False,
+ "page_width": "80em",
+ }
+ )
+else:
+ html_theme_options.update(
+ {
+ "globaltoc_collapse": True,
+ "globaltoc_maxdepth": 1,
+ "nosidebar": True,
+ "page_width": "60em",
+ }
+ )
+
+if have_lv2_theme:
+ html_theme = "sphinx_lv2_theme"
+
+ html_theme_options.update(
+ {
+ "show_footer_version": True,
+ "show_logo_version": True,
+ }
+ )
+
+ if tags.has("singlehtml"):
+ html_theme_options.update(
+ {
+ "body_max_width": "64em",
+ "body_min_width": "64em",
+ "nosidebar": False,
+ "sidebar_width": "12em",
+ }
+ )
+
+ else:
+ html_theme_options.update(
+ {
+ "body_max_width": "60em",
+ "body_min_width": "40em",
+ }
+ )
+
+else:
+ html_theme = "alabaster"
+
+ if tags.has("singlehtml"):
+ html_theme_options = {
+ "body_max_width": "58em",
+ "body_min_width": "40em",
+ "sidebar_width": "16em",
+ }
+
+ else:
+ html_theme_options = {
+ "body_max_width": "60em",
+ "body_min_width": "40em",
+ "nosidebar": True,
+ "show_relbars": True,
+ }
diff --git a/doc/footer.html b/doc/footer.html
deleted file mode 100644
index 0dc6919..0000000
--- a/doc/footer.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!-- HTML footer for doxygen 1.8.15-->
-<!-- start footer part -->
-<!--BEGIN GENERATE_TREEVIEW-->
-<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
- <ul>
- $navpath
- <li class="footer">$generatedby
- <a href="http://www.doxygen.org/index.html">Doxygen $doxygenversion</li>
- </ul>
-</div>
-<!--END GENERATE_TREEVIEW-->
-<!--BEGIN !GENERATE_TREEVIEW-->
-<div id="footer">
- <address class="footer">$generatedby
- <a href="http://www.doxygen.org/">Doxygen</a> $doxygenversion
- </address>
-</div>
-<!--END !GENERATE_TREEVIEW-->
-</body>
-</html>
diff --git a/doc/header.html b/doc/header.html
deleted file mode 100644
index 2e419e3..0000000
--- a/doc/header.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
- <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
- <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
- <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
- $extrastylesheet
- </head>
- <body>
- <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-
- <!--BEGIN TITLEAREA-->
- <div id="titlearea">
- <div id="header">
- <div id="titlebox">
- <!--BEGIN PROJECT_LOGO-->
- <div id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></div>
- <!--END PROJECT_LOGO-->
- <!--BEGIN PROJECT_NAME-->
- <h1 id="title">$projectname</h1>
- <!--END PROJECT_NAME-->
- <!--BEGIN PROJECT_BRIEF-->
- <div id="shortdesc">$projectbrief</div>
- <!--END PROJECT_BRIEF-->
- </div>
- <div id="metabox">
- <table id="meta">
- <!--BEGIN PROJECT_NUMBER-->
- <tr><th>Version</th><td>$projectnumber</td></tr>
- <!--END PROJECT_NUMBER-->
- </table>
- </div>
- </div>
- </div>
- <!--END TITLEAREA-->
- <!-- end header part -->
diff --git a/doc/html/meson.build b/doc/html/meson.build
new file mode 100644
index 0000000..59da474
--- /dev/null
+++ b/doc/html/meson.build
@@ -0,0 +1,39 @@
+# Copyright 2021-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+html_dir = docdir / versioned_name / 'html'
+
+# TODO: Add install_tag: 'doc' after requiring meson 0.60.0
+
+custom_target(
+ 'html',
+ build_by_default: true,
+ command: sphinx_build_command + [
+ '-b', 'html',
+ '-t', 'html',
+ sphinx_in_dir,
+ '@OUTDIR@',
+ ],
+ input: [api_lilv_rst, conf_py, sphinx_input],
+ install: true,
+ install_dir: html_dir,
+ output: [
+ 'index.html',
+
+ '_static',
+ 'api',
+ 'genindex.html',
+ 'overview.html',
+ 'plugins.html',
+ 'uis.html',
+ 'world.html',
+ ],
+)
+
+if not meson.is_subproject()
+ summary(
+ 'HTML',
+ get_option('prefix') / html_dir,
+ section: 'Directories',
+ )
+endif
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..46a9026
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,23 @@
+..
+ Copyright 2020-2022 David Robillard <d@drobilla.net>
+ SPDX-License-Identifier: ISC
+
+####
+Lilv
+####
+
+Lilv is a library for working with LV2_ plugins.
+It provides several types and functions that can be used to discover plugins,
+investigate their data, load and run them, and save and restore their state.
+
+Lilv is the standard implementation used by nearly all LV2 hosts.
+It implements the details of the LV2 specification on POSIX, MacOS, and Windows,
+and provides a simpler portable API for applications.
+
+.. toctree::
+
+ overview
+ api/lilv
+
+.. _LV2: http://lv2plug.in/
+
diff --git a/doc/layout.xml b/doc/layout.xml
deleted file mode 100644
index 3eed79f..0000000
--- a/doc/layout.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-<doxygenlayout version="1.0">
- <!-- Generated by doxygen 1.8.15 -->
- <!-- Navigation index tabs for HTML output -->
- <navindex>
- <tab type="mainpage" visible="yes" title=""/>
- <tab type="pages" visible="yes" title="" intro=""/>
- <tab type="modules" visible="yes" title="" intro=""/>
- <tab type="namespaces" visible="yes" title="">
- <tab type="namespacelist" visible="yes" title="" intro=""/>
- <tab type="namespacemembers" visible="yes" title="" intro=""/>
- </tab>
- <tab type="interfaces" visible="yes" title="">
- <tab type="interfacelist" visible="yes" title="" intro=""/>
- <tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>
- <tab type="interfacehierarchy" visible="yes" title="" intro=""/>
- </tab>
- <tab type="classes" visible="yes" title="">
- <tab type="classlist" visible="yes" title="" intro=""/>
- <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
- <tab type="hierarchy" visible="yes" title="" intro=""/>
- <tab type="classmembers" visible="yes" title="" intro=""/>
- </tab>
- <tab type="structs" visible="yes" title="">
- <tab type="structlist" visible="yes" title="" intro=""/>
- <tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
- </tab>
- <tab type="exceptions" visible="yes" title="">
- <tab type="exceptionlist" visible="yes" title="" intro=""/>
- <tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>
- <tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
- </tab>
- <tab type="files" visible="yes" title="">
- <tab type="filelist" visible="yes" title="" intro=""/>
- <tab type="globals" visible="yes" title="" intro=""/>
- </tab>
- <tab type="examples" visible="yes" title="" intro=""/>
- </navindex>
-
- <!-- Layout definition for a class page -->
- <class>
- <briefdescription visible="yes"/>
- <includes visible="$SHOW_INCLUDE_FILES"/>
- <inheritancegraph visible="$CLASS_GRAPH"/>
- <collaborationgraph visible="$COLLABORATION_GRAPH"/>
- <memberdecl>
- <nestedclasses visible="yes" title=""/>
- <publictypes title=""/>
- <services title=""/>
- <interfaces title=""/>
- <publicslots title=""/>
- <signals title=""/>
- <publicmethods title=""/>
- <publicstaticmethods title=""/>
- <publicattributes title=""/>
- <publicstaticattributes title=""/>
- <protectedtypes title=""/>
- <protectedslots title=""/>
- <protectedmethods title=""/>
- <protectedstaticmethods title=""/>
- <protectedattributes title=""/>
- <protectedstaticattributes title=""/>
- <packagetypes title=""/>
- <packagemethods title=""/>
- <packagestaticmethods title=""/>
- <packageattributes title=""/>
- <packagestaticattributes title=""/>
- <properties title=""/>
- <events title=""/>
- <privatetypes title=""/>
- <privateslots title=""/>
- <privatemethods title=""/>
- <privatestaticmethods title=""/>
- <privateattributes title=""/>
- <privatestaticattributes title=""/>
- <friends title=""/>
- <related title="" subtitle=""/>
- <membergroups visible="yes"/>
- </memberdecl>
- <detaileddescription title=""/>
- <memberdef>
- <inlineclasses title=""/>
- <typedefs title=""/>
- <enums title=""/>
- <services title=""/>
- <interfaces title=""/>
- <constructors title=""/>
- <functions title=""/>
- <related title=""/>
- <variables title=""/>
- <properties title=""/>
- <events title=""/>
- </memberdef>
- <allmemberslink visible="yes"/>
- <usedfiles visible="$SHOW_USED_FILES"/>
- <authorsection visible="yes"/>
- </class>
-
- <!-- Layout definition for a namespace page -->
- <namespace>
- <briefdescription visible="yes"/>
- <memberdecl>
- <nestednamespaces visible="yes" title=""/>
- <constantgroups visible="yes" title=""/>
- <interfaces visible="yes" title=""/>
- <classes visible="yes" title=""/>
- <structs visible="yes" title=""/>
- <exceptions visible="yes" title=""/>
- <typedefs title=""/>
- <sequences title=""/>
- <dictionaries title=""/>
- <enums title=""/>
- <functions title=""/>
- <variables title=""/>
- <membergroups visible="yes"/>
- </memberdecl>
- <detaileddescription title=""/>
- <memberdef>
- <inlineclasses title=""/>
- <typedefs title=""/>
- <sequences title=""/>
- <dictionaries title=""/>
- <enums title=""/>
- <functions title=""/>
- <variables title=""/>
- </memberdef>
- <authorsection visible="yes"/>
- </namespace>
-
- <!-- Layout definition for a file page -->
- <file>
- <briefdescription visible="yes"/>
- <includes visible="$SHOW_INCLUDE_FILES"/>
- <includegraph visible="$INCLUDE_GRAPH"/>
- <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
- <sourcelink visible="yes"/>
- <memberdecl>
- <interfaces visible="yes" title=""/>
- <classes visible="yes" title=""/>
- <structs visible="yes" title=""/>
- <exceptions visible="yes" title=""/>
- <namespaces visible="yes" title=""/>
- <constantgroups visible="yes" title=""/>
- <defines title=""/>
- <typedefs title=""/>
- <sequences title=""/>
- <dictionaries title=""/>
- <enums title=""/>
- <functions title=""/>
- <variables title=""/>
- <membergroups visible="yes"/>
- </memberdecl>
- <detaileddescription title=""/>
- <memberdef>
- <inlineclasses title=""/>
- <defines title=""/>
- <typedefs title=""/>
- <sequences title=""/>
- <dictionaries title=""/>
- <enums title=""/>
- <functions title=""/>
- <variables title=""/>
- </memberdef>
- <authorsection/>
- </file>
-
- <!-- Layout definition for a group page -->
- <group>
- <briefdescription visible="yes"/>
- <detaileddescription title=""/>
- <groupgraph visible="$GROUP_GRAPHS"/>
- <memberdecl>
- <nestedgroups visible="yes" title=""/>
- <dirs visible="yes" title=""/>
- <files visible="yes" title=""/>
- <namespaces visible="yes" title=""/>
- <classes visible="yes" title=""/>
- <defines title=""/>
- <typedefs title=""/>
- <sequences title=""/>
- <dictionaries title=""/>
- <enums title=""/>
- <enumvalues title=""/>
- <functions title=""/>
- <variables title=""/>
- <signals title=""/>
- <publicslots title=""/>
- <protectedslots title=""/>
- <privateslots title=""/>
- <events title=""/>
- <properties title=""/>
- <friends title=""/>
- <membergroups visible="yes"/>
- </memberdecl>
- <memberdef>
- <pagedocs/>
- <inlineclasses title=""/>
- <defines title=""/>
- <typedefs title=""/>
- <sequences title=""/>
- <dictionaries title=""/>
- <enums title=""/>
- <enumvalues title=""/>
- <functions title=""/>
- <variables title=""/>
- <signals title=""/>
- <publicslots title=""/>
- <protectedslots title=""/>
- <privateslots title=""/>
- <events title=""/>
- <properties title=""/>
- <friends title=""/>
- </memberdef>
- <authorsection visible="yes"/>
- </group>
-
- <!-- Layout definition for a directory page -->
- <directory>
- <briefdescription visible="yes"/>
- <directorygraph visible="yes"/>
- <memberdecl>
- <dirs visible="yes"/>
- <files visible="yes"/>
- </memberdecl>
- <detaileddescription title=""/>
- </directory>
-</doxygenlayout>
diff --git a/doc/lv2apply.1 b/doc/lv2apply.1
index 4877aba..3bb0218 100644
--- a/doc/lv2apply.1
+++ b/doc/lv2apply.1
@@ -1,34 +1,66 @@
-.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>
+.\" # Copyright 2010-2024 David Robillard <d@drobilla.net>
+.\" # SPDX-License-Identifier: ISC
+.Dd Nov 29, 2022
+.Dt LV2APPLY 1
+.Os Lilv 0.24.25
+.Sh NAME
+.Nm lv2apply
+.Nd apply an LV2 plugin to an audio file
+.Sh SYNOPSIS
+.Nm lv2apply
+.Op Fl Vh
+.Op Fl c Ar symbol value
+.Op Fl i Ar in_file
+.Op Fl o Ar out_file
+.Op Fl Fl help
+.Op Fl Fl version
+.Ar plugin_uri
+.Sh DESCRIPTION
+.Nm
+runs an LV2 plugin on an audio file and writes the processed output to another.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -compact -width 3n
+.It Fl V , Fl Fl version
+Display version information and exit.
+.Pp
+.It Fl c Ar symbol value
+Set control port
+.Ar symbol
+to
+.Ar value.
+.Pp
+.It Fl h , Fl Fl help
+Print the command line options.
+.Pp
+.It Fl i Ar in_file
+Input file path.
+.Pp
+.It Fl o Ar out_file
+Output file path.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width LV2_PATH -compact
+.It Ev LV2_PATH
+List of directories to search for LV2 plugin bundles,
+in the style of
+.Ev PATH .
+.El
+.Sh EXIT STATUS
+.Nm
+exits with a status of 0, or non-zero if an error occurred.
+.Sh SEE ALSO
+.Bl -item -compact
+.It
+.Xr lv2bench 1
+.It
+.Xr lv2info 1
+.It
+.Xr lv2ls 1
+.El
+.Sh AUTHORS
+.Nm
+is a part of lilv, by
+.An David Robillard
+.Mt d@drobilla.net .
diff --git a/doc/lv2bench.1 b/doc/lv2bench.1
new file mode 100644
index 0000000..e70c47d
--- /dev/null
+++ b/doc/lv2bench.1
@@ -0,0 +1,55 @@
+.\" # Copyright 2024 David Robillard <d@drobilla.net>
+.\" # SPDX-License-Identifier: ISC
+.Dd Nov 29, 2022
+.Dt LV2BENCH 1
+.Os Lilv 0.24.25
+.Sh NAME
+.Nm lv2bench
+.Nd benchmark all installed and supported LV2 plugins
+.Sh SYNOPSIS
+.Nm lv2bench
+.Op Fl fhV
+.Op Fl b Ar block_size
+.Op Fl n Ar frames
+.Op Fl Fl full
+.Op Fl Fl help
+.Op Fl Fl version
+.Sh DESCRIPTION
+.Nm
+is a simple utility for running basic benchmarks of installed LV2 plugins.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -compact -width 3n
+.It Fl V , Fl Fl version
+Display version information and exit.
+.Pp
+.It Fl b Ar block_size
+Block size, in audio frames.
+.Pp
+.It Fl f , Fl Fl full
+Emit full plottable output with values for every block.
+.Pp
+.It Fl h , Fl Fl help
+Print the command line options.
+.Pp
+.It Fl n Ar frames
+Total number of audio frames to process.
+.El
+.Sh EXIT STATUS
+.Nm
+exits with a status of 0, or non-zero if an error occurred.
+.Sh SEE ALSO
+.Bl -item -compact
+.It
+.Xr lv2apply 1
+.It
+.Xr lv2info 1
+.It
+.Xr lv2ls 1
+.El
+.Sh AUTHORS
+.Nm
+is a part of lilv, by
+.An David Robillard
+.Mt d@drobilla.net .
diff --git a/doc/lv2info.1 b/doc/lv2info.1
index 32a3bec..43cde63 100644
--- a/doc/lv2info.1
+++ b/doc/lv2info.1
@@ -1,33 +1,65 @@
-.TH LV2INFO 1 "05 Sep 2016"
-
-.SH NAME
-.B lv2info \- print information about an installed LV2 plugin
-.SH SYNOPSIS
-.B lv2info PLUGIN_URI
-
-.SH OPTIONS
-.TP
-\fB\-p FILE\fR
-Write Turtle description of plugin to FILE
-
-.TP
-\fB\-m FILE\fR
-Add record of plugin to manifest FILE
-
-.TP
-\fB\-\-help\fR
-Display help and exit
-
-.TP
-\fB\-\-version\fR
-Display version information and exit
-
-.SH "SEE ALSO"
-.BR lilv(3),
-.BR lv2ls(1)
-
-.SH AUTHOR
-lv2info was written by David Robillard <d@drobilla.net>
-.PP
-This manual page was written by Jaromír Mikes <mira.mikes@seznam.cz>
-and David Robillard <d@drobilla.net>
+.\" # Copyright 2009-2024 David Robillard <d@drobilla.net>
+.\" # SPDX-License-Identifier: ISC
+.Dd Nov 29, 2022
+.Dt LV2INFO 1
+.Os Lilv 0.24.25
+.Sh NAME
+.Nm lv2info
+.Nd print information about an installed LV2 plugin
+.Sh SYNOPSIS
+.Nm lv2info
+.Op Fl hV
+.Op Fl m Ar file
+.Op Fl p Ar file
+.Ar plugin_uri
+.Sh DESCRIPTION
+.Nm
+prints a human-readable summary of information about an LV2 plugin.
+.Pp
+The plugin must be installed;
+.Nm
+will search for one with the given
+.Ar plugin_uri
+in the LV2 path.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -compact -width 3n
+.It Fl V , Fl Fl version
+Display version information and exit.
+.Pp
+.It Fl h , Fl Fl help
+Print the command line options.
+.Pp
+.It Fl m Ar file
+Add record of plugin to Turtle manifest
+.Ar file .
+.Pp
+.It Fl p Ar file
+Write description of plugin to Turtle
+.Ar file .
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width LV2_PATH -compact
+.It Ev LV2_PATH
+List of directories to search for LV2 plugin bundles,
+in the style of
+.Ev PATH .
+.El
+.Sh EXIT STATUS
+.Nm
+exits with a status of 0, or non-zero if an error occurred.
+.Sh SEE ALSO
+.Bl -item -compact
+.It
+.Xr lv2apply 1
+.It
+.Xr lv2bench 1
+.It
+.Xr lv2ls 1
+.El
+.Sh AUTHORS
+.Nm
+is a part of lilv, by
+.An David Robillard
+.Mt d@drobilla.net .
diff --git a/doc/lv2ls.1 b/doc/lv2ls.1
index 320b71c..3b96370 100644
--- a/doc/lv2ls.1
+++ b/doc/lv2ls.1
@@ -1,30 +1,59 @@
-.TH LV2LS 1 "26 Aug 2016"
-
-.SH NAME
-.B lv2ls \- list all installed LV2 plugins
-
-.SH SYNOPSIS
-.B lv2ls [OPTION]...
-
-.SH OPTIONS
-.TP
-\fB\-n\fR, \fB\-\-names\fR
-Show names instead of URIs
-
-.TP
-\fB\-\-help\fR
-Display help and exit
-
-.TP
-\fB\-\-version\fR
-Display version information and exit
-
-.SH "SEE ALSO"
-.BR lilv(3),
-.BR lv2info(1)
-
-.SH AUTHOR
-lv2ls was written by David Robillard <d@drobilla.net>
-.PP
-This manual page was written by Jaromír Mikes <mira.mikes@seznam.cz>
-and David Robillard <d@drobilla.net>
+.\" # Copyright 2010-2024 David Robillard <d@drobilla.net>
+.\" # SPDX-License-Identifier: ISC
+.Dd Nov 29, 2022
+.Dt LV2LS 1
+.Os Lilv 0.24.25
+.Sh NAME
+.Nm lv2ls
+.Nd list all installed LV2 plugins
+.Sh SYNOPSIS
+.Nm lv2ls
+.Op Fl Vhn
+.Op Fl Fl help
+.Op Fl Fl names
+.Op Fl Fl version
+.Sh DESCRIPTION
+.Nm
+prints the URI of every installed LV2 plugin to stdout.
+.Pp
+Plugins are discovered with the same mechanism used by most hosts.
+The default path can be overridden by setting the
+.Ev LV2_PATH
+environment variable.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -compact -width 3n
+.It Fl V , Fl Fl version
+Display version information and exit.
+.Pp
+.It Fl h , Fl Fl help
+Print the command line options.
+.Pp
+.It Fl n , Fl Fl names
+Show names instead of URIs.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width LV2_PATH -compact
+.It Ev LV2_PATH
+List of directories to search for LV2 plugin bundles,
+in the style of
+.Ev PATH .
+.El
+.Sh EXIT STATUS
+.Nm
+exits with a status of 0, or non-zero if an error occurred.
+.Sh SEE ALSO
+.Bl -item -compact
+.It
+.Xr lv2apply 1
+.It
+.Xr lv2bench 1
+.It
+.Xr lv2info 1
+.El
+.Sh AUTHORS
+.Nm
+is a part of lilv, by
+.An David Robillard
+.Mt d@drobilla.net .
diff --git a/doc/mainpage.md b/doc/mainpage.md
deleted file mode 100644
index d9b8c12..0000000
--- a/doc/mainpage.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Lilv is a C library to make the use of [LV2] plugins as simple as possible for
-applications.
-
-The complete API is documented in the [lilv](@ref lilv) group.
-
-[LV2]: http://lv2plug.in/
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 0000000..32a885b
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,71 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+docdir = get_option('datadir') / 'doc'
+
+# Find required programs
+doxygen = find_program('doxygen', required: get_option('docs'))
+sphinx_build = find_program('sphinx-build', required: get_option('docs'))
+
+# Find sphinxygen or fall back to subproject
+sphinxygen = disabler()
+if doxygen.found() and sphinx_build.found()
+ sphinxygen = find_program('sphinxygen', required: false)
+ if not sphinxygen.found()
+ subproject('sphinxygen')
+ sphinxygen = find_program('sphinxygen', required: get_option('docs'))
+ endif
+endif
+
+# Build documentation if all required tools are found
+build_docs = doxygen.found() and sphinxygen.found() and sphinx_build.found()
+if build_docs
+ # Configure conf.py for Sphinx
+ conf_config = configuration_data()
+ conf_config.set('LILV_SRCDIR', lilv_src_root)
+ conf_config.set('LILV_TITLE', get_option('title'))
+ conf_config.set('LILV_VERSION', meson.project_version())
+ conf_py = configure_file(
+ configuration: conf_config,
+ input: files('conf.py.in'),
+ output: 'conf.py',
+ )
+
+ # Copy hand-written documentation files
+ rst_sources = files(
+ 'index.rst',
+ 'overview.rst',
+ 'plugins.rst',
+ 'uis.rst',
+ 'world.rst',
+ )
+ sphinx_input = []
+ foreach f : rst_sources
+ sphinx_input += [
+ configure_file(copy: true, input: f, output: '@PLAINNAME@'),
+ ]
+ endforeach
+
+ # Generate reference documentation input with Doxygen and Sphinxygen
+ subdir('xml')
+ subdir('api')
+
+ # Build strict Sphinx flags, with termination on warnings if werror=true
+ sphinx_in_dir = meson.current_build_dir()
+ sphinx_flags = ['-E', '-a', '-q']
+ if get_option('werror')
+ sphinx_flags += ['-W']
+ endif
+
+ # Run Sphinx to generate final documentation for each format
+ sphinx_build_command = [sphinx_build] + sphinx_flags
+ foreach format : ['html', 'singlehtml']
+ if not get_option(format).disabled()
+ subdir(format)
+ endif
+ endforeach
+endif
+
+if not meson.is_subproject()
+ summary('Documentation', build_docs, bool_yn: true, section: 'Components')
+endif
diff --git a/doc/overview.rst b/doc/overview.rst
new file mode 100644
index 0000000..17ebec9
--- /dev/null
+++ b/doc/overview.rst
@@ -0,0 +1,22 @@
+..
+ Copyright 2020-2022 David Robillard <d@drobilla.net>
+ SPDX-License-Identifier: ISC
+
+.. default-domain:: c
+.. highlight:: c
+
+########
+Overview
+########
+
+The complete API is declared in ``lilv.h``:
+
+.. code-block:: c
+
+ #include <lilv/lilv.h>
+
+.. toctree::
+
+ world
+ plugins
+ uis
diff --git a/doc/plugins.rst b/doc/plugins.rst
new file mode 100644
index 0000000..c7ad547
--- /dev/null
+++ b/doc/plugins.rst
@@ -0,0 +1,94 @@
+..
+ Copyright 2020-2022 David Robillard <d@drobilla.net>
+ SPDX-License-Identifier: ISC
+
+.. default-domain:: c
+.. highlight:: c
+
+#######
+Plugins
+#######
+
+After bundles are loaded,
+all discovered plugins can be accessed via :func:`lilv_world_get_all_plugins`:
+
+.. code-block:: c
+
+ LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+
+:struct:`LilvPlugins` is a collection of plugins that can be accessed by index or plugin URI.
+The convenicne macro :macro:`LILV_FOREACH` is provided to make iterating over collections simple.
+For example, to print the URI of every plugin:
+
+.. code-block:: c
+
+ LILV_FOREACH (plugins, i, list) {
+ const LilvPlugin* p = lilv_plugins_get(list, i);
+ printf("%s\n", lilv_node_as_uri(lilv_plugin_get_uri(p)));
+ }
+ }
+
+More typically,
+you want to load a specific plugin,
+which can be done with :func:`lilv_plugins_get_by_uri`:
+
+.. code-block:: c
+
+ LilvNode* plugin_uri = lilv_new_uri(world, "http://example.org/Osc");
+
+ const LilvPlugin* plugin = lilv_plugins_get_by_uri(list, plugin_uri);
+
+:struct:`LilvPlugin` has various accessors that can be used to get information about the plugin.
+See the :doc:`API reference <api/lilv_plugin>` for details.
+
+*********
+Instances
+*********
+
+:struct:`LilvPlugin` only represents the data of the plugin,
+it does not load or access the actual plugin code.
+To do that, you must instantiate a plugin to create :struct:`LilvInstance`:
+
+.. code-block:: c
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
+
+Connecting Ports
+================
+
+Before running a plugin instance, its ports must be connected to some data.
+This is done with :func:`lilv_instance_connect_port`.
+Assuming the plugins has two control input ports and one audio output port,
+in that order:
+
+.. code-block:: c
+
+ float control_in_1 = 0.0f;
+ float control_in_2 = 0.0f;
+
+ float audio_out[128];
+
+ lilv_instance_connect_port(instance, 0, &control_in_1);
+ lilv_instance_connect_port(instance, 1, &control_in_2);
+ lilv_instance_connect_port(instance, 2, &audio_out);
+
+Processing Data
+===============
+
+Once the ports are connected, the instance can be activated and run:
+
+.. code-block:: c
+
+ lilv_instance_activate(instance);
+
+ lilv_instance_run(instance, 128);
+ // Copy buffers around and probably run several times here...
+
+ lilv_instance_deactivate(instance);
+
+Once you are done with an instance,
+it can be destroyed with :func:`lilv_instance_free`:
+
+.. code-block:: c
+
+ lilv_instance_free(instance);
diff --git a/doc/reference.doxygen.in b/doc/reference.doxygen.in
deleted file mode 100644
index 340af35..0000000
--- a/doc/reference.doxygen.in
+++ /dev/null
@@ -1,2462 +0,0 @@
-# Doxyfile 1.8.15
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the configuration
-# file that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME = Lilv
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER = @LILV_VERSION@
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF = "A library for simple use of LV2 plugins"
-
-# 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 =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = .
-
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE = English
-
-# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all generated output in the proper direction.
-# Possible values are: None, LTR, RTL and Context.
-# The default value is: None.
-
-OUTPUT_TEXT_DIRECTION = None
-
-# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC = NO
-
-# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
-# 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
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES = NO
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: 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.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines (in the resulting output). You can put ^^ in the value part of an
-# alias to insert a newline as if a physical newline was in the original file.
-# When you need a literal { or } or , in the value part of an alias you have to
-# escape them by means of a backslash (\), this can lead to conflicts with the
-# commands \{ and \} for these it is advised to use the version @{ and @} or use
-# a double escape (\\{ and \\})
-
-ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
-# sources only. Doxygen will then generate output that is more tailored for that
-# language. For instance, namespaces will be presented as modules, types will be
-# separated into more groups, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_SLICE = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
-# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
-# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
-# tries to guess whether the code is fixed or free formatted code, this is the
-# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
-# .inc files as Fortran files (default is PHP), and .f files as C (default is
-# Fortran), use: inc=Fortran f=C.
-#
-# Note: For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See https://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: 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
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# If one adds a struct or class to a group and this option is enabled, then also
-# any nested class or struct is added to the same group. By default this option
-# is disabled and one has to add nested compounds explicitly via \ingroup.
-# The default value is: NO.
-
-GROUP_NESTED_COMPOUNDS = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = YES
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS = YES
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT = YES
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO,
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES = NO
-
-# This flag is only useful for Objective-C code. If set to YES, local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO, only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS = YES
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES = YES
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO, these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO, these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS = YES
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES, upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES, the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
-# append additional text to a page's title, such as Class Reference. If set to
-# YES the compound reference will be hidden.
-# The default value is: NO.
-
-HIDE_COMPOUND_REFERENCE= NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS = NO
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME = YES
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: 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 default value is: YES.
-
-GENERATE_TODOLIST = NO
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
-# list. This list is created by putting \test commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST = NO
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST = NO
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES, the
-# list will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES = NO
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES = NO
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE = @LILV_SRCDIR@/doc/layout.xml
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET = YES
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation. If
-# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC = YES
-
-# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
-# a warning is encountered.
-# The default value is: NO.
-
-WARN_AS_ERROR = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
-# Note: If this tag is empty the current directory is searched.
-
-INPUT = @LILV_SRCDIR@/lilv/lilv.h \
- @LILV_SRCDIR@/doc/mainpage.md
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories.
-#
-# 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, *.qsf and *.ice.
-
-FILE_PATTERNS =
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS = *.c
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE = @LILV_SRCDIR@/doc/mainpage.md
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# entity all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION = YES
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS = NO
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see https://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX = NO
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER = @LILV_SRCDIR@/doc/header.html
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER = @LILV_SRCDIR@/doc/footer.html
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET = @LILV_SRCDIR@/doc/style.css
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefore more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# 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
-# https://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
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE = 160
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP = NO
-
-# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
-# documentation will contain a main index with vertical navigation menus that
-# are dynamically created via Javascript. If disabled, the navigation index will
-# consists of multiple levels of tabs that are statically embedded in every HTML
-# page. Disable this option to support browsers that do not have Javascript,
-# like the Qt help browser.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_MENUS = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: https://developer.apple.com/xcode/), introduced with OSX
-# 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
-# genXcode/_index.html for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler (hhc.exe). If non-empty,
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the master .chm file (NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated
-# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE =
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE = 1
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH = 250
-
-# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# https://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from https://www.mathjax.org before deployment.
-# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE = NO
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: https://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: https://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when not enabling USE_PDFLATEX the default is latex when enabling
-# USE_PDFLATEX the default is pdflatex and when in the later case latex is
-# chosen this is overwritten by pdflatex. For specific output languages the
-# default can have been set differently, this depends on the implementation of
-# the output language.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# Note: This tag is used in the Makefile / make.bat.
-# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
-# (.tex).
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
-# generate index for LaTeX.
-# Note: This tag is used in the generated output file (.tex).
-# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
-# The default value is: \makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_MAKEINDEX_CMD = \makeindex
-
-# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. The package can be specified just
-# by its name or with the correct syntax as to be used with the LaTeX
-# \usepackage command. To get the times font for instance you can specify :
-# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
-# To use the option intlimits with the amsmath package you can specify:
-# EXTRA_PACKAGES=[intlimits]{amsmath}
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
-# string, for the replacement values of the other commands the user is referred
-# to HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER =
-
-# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# LaTeX style sheets that are included after the standard style sheets created
-# by doxygen. Using this option one can overrule certain style aspects. Doxygen
-# will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_STYLESHEET =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES, to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX 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_LATEX is set to YES.
-
-LATEX_SOURCE_CODE = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-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
-
-# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
-# path from which the emoji images will be read. If a relative path is entered,
-# it will be relative to the LATEX_OUTPUT directory. If left blank the
-# LATEX_OUTPUT directory will be used.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EMOJI_DIRECTORY =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# configuration file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's configuration file. A template extensions file can be
-# generated using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE =
-
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN = YES
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING = YES
-
-# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
-# namespace members in file scope as well, matching the HTML output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_NS_MEMB_FILE_SCOPE = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT = docbook
-
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
-# the structure of the code including all documentation. Note that this feature
-# is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO, the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
-# in the source code. If set to NO, only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF = YES
-
-# If the SEARCH_INCLUDES tag is set to YES, the include files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED = LILV_API
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-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.
-# The default value is: NO.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS = YES
-
-# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS = NO
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH =
-
-# If set to YES the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME =
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH = NO
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH = NO
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH = NO
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH = NO
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command. Disabling a call graph can be
-# accomplished by means of the command \hidecallgraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command. Disabling a caller graph can be
-# accomplished by means of the command \hidecallergraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY = NO
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH = NO
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. For an explanation of the image formats see the section
-# output formats in the documentation of the dot tool (Graphviz (see:
-# http://www.graphviz.org/)).
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
-# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
-# png:gdiplus:gdiplus.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-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 PLANTUML_CFG_FILE tag can be used to specify a
-# configuration file for plantuml.
-
-PLANTUML_CFG_FILE =
-
-# When using plantuml, the specified paths are searched for files specified by
-# the !include statement in a plantuml block.
-
-PLANTUML_INCLUDE_PATH =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND = NO
-
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP = YES
diff --git a/doc/singlehtml/meson.build b/doc/singlehtml/meson.build
new file mode 100644
index 0000000..ed4bb71
--- /dev/null
+++ b/doc/singlehtml/meson.build
@@ -0,0 +1,33 @@
+# Copyright 2021-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+singlehtml_dir = docdir / versioned_name / 'singlehtml'
+
+# TODO: Add install_tag: 'doc' after requiring meson 0.60.0
+
+custom_target(
+ 'singlehtml',
+ build_by_default: true,
+ command: sphinx_build_command + [
+ '-b', 'singlehtml',
+ '-t', 'singlehtml',
+ sphinx_in_dir,
+ '@OUTDIR@',
+ ],
+ input: [api_lilv_rst, conf_py, sphinx_input],
+ install: true,
+ install_dir: singlehtml_dir,
+ output: [
+ 'index.html',
+
+ '_static',
+ ],
+)
+
+if not meson.is_subproject()
+ summary(
+ 'Single HTML',
+ get_option('prefix') / singlehtml_dir,
+ section: 'Directories',
+ )
+endif
diff --git a/doc/style.css b/doc/style.css
deleted file mode 100644
index 52fdc05..0000000
--- a/doc/style.css
+++ /dev/null
@@ -1,739 +0,0 @@
-body {
- background: #FFF;
- color: #222;
- font-style: normal;
- line-height: 1.6em;
- margin-left: auto;
- margin-right: auto;
- padding: 1em;
- max-width: 60em;
- font-family: "DejaVu Serif",Palatino,serif;
- text-rendering: optimizeLegibility;
-}
-
-h1, .title, #projectname, h2, h3, h4, h5, h6 {
- line-height: 1.0125em;
- color: #444;
- font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
- margin: 1em 0 0.5em 0;
-}
-
-h1, .titlearea .header .titlebox, #projectname {
- font-size: 300%;
- font-weight: 400;
- margin-bottom: 0.25em;
- margin-top: 0;
-}
-
-.header .headertitle .title {
- font-size: 180%;
- font-weight: 400;
- margin: 0.75em 0.25em 0.5em 0;
-}
-
-.ingroups {
- display: inline;
-}
-.title .ingroups a {
- font-size: small;
- margin-left: 1em;
-}
-
-#titlebox, #metabox {
- display: inline-block;
-}
-#titlebox{
- display: inline-block;
- width: 75%;
- left: 0;
- top: 0;
-}
-
-#title {
- margin-bottom: 0.25em;
-}
-
-#shortdesc {
- margin: 0;
- color: #666;
- display: inline-block;
- font-style: italic;
- padding: 0;
-}
-
-#titlearea {
- margin: 0.25em auto 0.25em auto;
- padding: 0;
- position: relative;
- clear: both;
- line-height: 1.0em;
-}
-
-h2 {
- font-size: 160%;
- font-weight: 400;
-}
-
-h3 {
- font-size: 140%;
- font-weight: 400;
-}
-
-h4 {
- font-size: 120%;
- font-weight: 500;
-}
-
-h5, h6 {
- font-size: 110%;
- font-weight: 600;
-}
-
-h1 a, h1 a:link, h1 a:visited ,
-h2 a, h2 a:link, h2 a:visited ,
-h3 a, h3 a:link, h3 a:visited ,
-h4 a, h4 a:link, h4 a:visited ,
-h5 a, h5 a:link, h5 a:visited ,
-h6 a, h6 a:link, h6 a:visited {
- color: #444;
-}
-
-p {
- margin: 0.5em 0 0.5em 0;
-}
-
-dt {
- font-weight: 700;
-}
-
-dd {
- margin-left: 2em;
-}
-
-caption {
- font-weight: 700;
-}
-
-span.legend {
- font-size: small;
- text-align: center;
-}
-
-h3.version {
- font-size: small;
- text-align: center;
-}
-
-div.qindex,div.navtab {
- background-color: #EBEFF6;
- border: 1px solid #A3B4D7;
- text-align: center;
- margin: 2px;
- padding: 2px;
-}
-
-div.navtab {
- margin-right: 15px;
-}
-
-/* @group Link Styling */
-a {
- color: #546E00;
- text-decoration: none;
-}
-
-.contents a:visited {
- color: #344E00;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-a.qindexHL {
- background-color: #9CAFD4;
- color: #FFF;
- border: 1px double #869DCA;
-}
-
-code {
- color: #444;
-}
-
-/* @end */
-dl.el {
- margin-left: -1cm;
-}
-
-.fragment {
- font-family: "DejaVu Sans Mono",monospace,fixed;
-}
-
-pre.fragment {
- border: 1px solid #C4C4C4;
- background-color: #F9F9F9;
- padding: 0.5em;
- overflow: auto;
-}
-
-div.ah {
- background-color: #000;
- font-weight: 700;
- color: #FFF;
- margin-bottom: 3px;
- margin-top: 3px;
- padding: .2em;
- border: thin solid #333;
-}
-
-div.groupHeader {
- margin-left: 16px;
- margin-top: 12px;
- margin-bottom: 6px;
- font-weight: 700;
-}
-
-a + h2.groupheader {
- display: none;
-}
-
-div.groupText {
- margin-left: 16px;
- font-style: italic;
-}
-
-div.contents, #content {
- padding: 0 0.25em 0 0.25em;
- max-width: 60em;
- margin-left: auto;
- margin-right: auto;
-}
-
-td.indexkey {
- background-color: #EBEFF6;
- font-weight: 700;
- border: 1px solid #C4CFE5;
- margin: 2px 0;
- padding: 2px 10px;
-}
-
-td.indexvalue {
- background-color: #EBEFF6;
- border: 1px solid #C4CFE5;
- padding: 2px 10px;
- margin: 2px 0;
-}
-
-table.memname {
- font-family: "DejaVu Sans Mono",monospace,fixed;
-}
-
-tr.memlist {
- background-color: #EEF1F7;
-}
-
-p.formulaDsp {
- text-align: center;
-}
-
-img.formulaInl {
- vertical-align: middle;
-}
-
-div.center {
- text-align: center;
- margin-top: 0;
- margin-bottom: 0;
- padding: 0;
-}
-
-div.center img {
- border: 0;
-}
-
-address.footer {
- text-align: right;
-}
-
-img.footer {
- border: 0;
- vertical-align: middle;
-}
-
-/* @group Code Colorization */
-span.keyword {
- color: #586E75;
-}
-
-span.keywordtype {
- color: #546E00;
-}
-
-span.keywordflow {
- color: #586E75;
-}
-
-span.comment {
- color: #6C71C4;
-}
-
-span.preprocessor {
- color: #D33682;
-}
-
-span.stringliteral {
- color: #CB4B16;
-}
-
-span.charliteral {
- color: #CB4B16;
-}
-
-/* @end */
-td.tiny {
- font-size: x-small;
-}
-
-.dirtab {
- padding: 4px;
- border-collapse: collapse;
- border: 1px solid #A3B4D7;
-}
-
-th.dirtab {
- background: #EBEFF6;
- font-weight: 700;
-}
-
-hr {
- height: 0;
- border: none;
- border-top: 1px solid #DDD;
- margin: 2em 0 1em;
-}
-
-#footer {
- bottom: 0;
- clear: both;
- font-size: x-small;
- margin: 2em 0 0;
- padding: 0 1em 1em 1em;
- vertical-align: top;
- color: #888;
-}
-
-/* @group Member Descriptions */
-table.memberdecls {
- border-spacing: 0.125em;
- line-height: 1.3em;
-}
-
-.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,.memTemplItemLeft,.memTemplItemRight,.memTemplParams {
- margin: 0;
- padding: 0;
-}
-
-.mdescLeft,.mdescRight {
- color: #555;
-}
-
-.memItemLeft,.memItemRight,.memTemplParams {
- border: 0;
- font-family: "DejaVu Sans Mono",monospace,fixed;
-}
-
-.memItemLeft,.memTemplItemLeft {
- white-space: nowrap;
- padding-left: 2em;
- padding-right: 1em;
-}
-
-.memItemLeft a.el {
- font-weight: bold;
-}
-
-.memTemplParams {
- color: #464646;
- white-space: nowrap;
-}
-
-td.memSeparator {
- display: none;
-}
-
-td.mlabels-right {
- vertical-align: top;
- padding-top: 4px;
- color: #B4C342;
-}
-
-.memtitle {
- display: none;
-}
-
-/* @end */
-/* @group Member Details */
-/* Styles for detailed member documentation */
-.memtemplate {
- color: #888;
- font-style: italic;
- font-family: "DejaVu Sans Mono",monospace,fixed;
- font-size: small;
-}
-
-.memnav {
- background-color: #EEE;
- border: 1px solid #B4C342;
- text-align: center;
- margin: 2px;
- margin-right: 15px;
- padding: 2px;
-}
-
-.memitem {
- padding: 0.25em 0.5em 0.25em 0.5em;
- margin: 0 0 1em 0;
- border-radius: 6px;
- border: 1px solid #DDD;
-}
-
-.memproto {
- font-size: 110%;
- font-weight: 400;
- line-height: 1em;
- color: #000;
-}
-
-.memproto .paramname {
- font-style: normal;
-}
-
-.memdoc {
- padding: 0 0.25em 0 0.25em;
-}
-
-.paramkey {
- text-align: right;
-}
-
-.paramtype {
- color: #666;
- padding-right: 0.5em;
- white-space: nowrap;
-}
-
-.paramname {
- color: #111;
- white-space: nowrap;
- font-family: "DejaVu Sans Mono",monospace,fixed;
- font-style: italic;
- padding-right: 0.5em;
-}
-
-.fieldname {
- color: #000;
-}
-
-.fieldtable {
- padding-top: 0.25em;
- border-top: 1px dashed #DDD;
-}
-
-.fieldtable tbody tr:first-child {
- display: none;
-}
-
-td.fieldname {
- padding: 0 0.5em 0 0.25em;
- vertical-align: top;
- font-family: "DejaVu Sans Mono",monospace,fixed;
-}
-
-td.fieldtype {
- color: #666;
- padding: 0 0.5em 0 0;
- vertical-align: top;
- font-family: "DejaVu Sans Mono",monospace,fixed;
-}
-
-td.fielddoc p {
- margin: 0;
- vertical-align: top;
- padding: 0 0.5em 0 0;
-}
-
-p.reference {
- font-size: x-small;
- font-style: italic;
-}
-
-/* @end */
-/* @group Directory (tree) */
-/* for the tree view */
-.ftvtree {
- font-family: sans-serif;
- margin: 0;
-}
-
-/* these are for tree view when used as main index */
-.directory {
- font-size: small;
- margin: 0.5em;
-}
-
-.directory h3 {
- margin: 0;
- margin-top: 1em;
- font-size: 11pt;
-}
-
-.directory > h3 {
- margin-top: 0;
-}
-
-.directory p {
- margin: 0;
- white-space: nowrap;
-}
-
-.directory div {
- display: none;
- margin: 0;
-}
-
-.directory img {
- vertical-align: -30%;
-}
-
-td.entry {
- font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
- font-weight: 400;
- padding-right: 1em;
-}
-
-td.entry .arrow {
- display: none;
-}
-
-td.entry b {
- font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
- font-weight: 400;
- font-size: 130%;
-}
-
-/* these are for tree view when not used as main index */
-.directory-alt {
- font-size: 100%;
- font-weight: bold;
-}
-
-.directory-alt h3 {
- margin: 0;
- margin-top: 1em;
- font-size: 11pt;
-}
-
-.directory-alt > h3 {
- margin-top: 0;
-}
-
-.directory-alt p {
- margin: 0;
- white-space: nowrap;
-}
-
-.directory-alt div {
- display: none;
- margin: 0;
-}
-
-.directory-alt img {
- vertical-align: -30%;
-}
-
-/* @end */
-div.dynheader {
- margin-top: 8px;
-}
-
-address {
- font-style: normal;
- color: #444;
-}
-
-table.doxtable {
- border-collapse: collapse;
- margin: 0.5em;
-}
-
-table.doxtable td,table.doxtable th {
- border: 1px solid #DDD;
- padding: 3px 7px 2px;
-}
-
-table.doxtable th {
- background-color: #F3F3F3;
- color: #000;
- padding-bottom: 4px;
- padding-top: 5px;
- text-align: left;
- font-weight: bold;
-}
-
-.tabsearch {
- top: 0;
- left: 10px;
- height: 36px;
- z-index: 101;
- overflow: hidden;
- font-size: 13px;
-}
-
-div.navpath {
- color: #DDD;
-}
-
-.navpath ul {
- overflow: hidden;
- margin: 0;
- padding: 0;
-}
-
-.navpath li {
- float: left;
- padding-left: 0;
- margin-left: 0.5em;
- padding-right: 1em;
-}
-
-.navpath a {
- display: block;
- text-decoration: none;
- outline: none;
-}
-
-div.summary {
- font-size: small;
- font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
- margin: 0;
- color: #FFF; /* Hide separator bars */
- border-bottom: 1px solid #DDD;
- padding: 0.25em 0;
-}
-
-div.summary a {
- white-space: nowrap;
-}
-
-/* Metadata box (right aligned next to title) */
-
-#metabox {
- display: inline-block;
- font-size: x-small;
- margin: 0 0 0.25em 0;
- position: absolute;
- right: 0;
- top: 0;
- color: #666;
- font-style: italic;
- padding: 0 1em;
-}
-
-#meta {
- border-style: hidden;
- margin-right: 0.25em;
-}
-
-#meta tr, #meta th, #meta td {
- background-color: transparent;
- border: 0;
- margin: 0;
- font-weight: normal;
-}
-
-#meta th {
- text-align: right;
-}
-
-#meta th:after {
- content: ":";
-}
-
-div.line {
- font-family: "DejaVu Sans Mono",monospace,fixed;
- line-height: 1.4em;
- white-space: pre-wrap;
-}
-
-.glow {
- background-color: #2AA198;
- box-shadow: 0 0 10px #2AA198;
-}
-
-span.lineno {
- padding-right: 4px;
- text-align: right;
- border-right: 2px solid #546E00;
- background-color: #E8E8E8;
- white-space: pre;
-}
-span.lineno a {
- background-color: #D8D8D8;
-}
-
-span.lineno a:hover {
- background-color: #C8C8C8;
-}
-
-.tabs, .tabs2, .navpath {
- padding: 0.25em 0;
- border-bottom: 1px solid #DDD;
- font-size: small;
- font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
- margin: 0;
-}
-
-th {
- text-align: left;
- font-size: 110%;
- font-weight: 500;
-}
-
-.mlabel {
- padding: 0.125em;
-}
-
-/* tabs*/
-
-.tablist {
- margin: 0;
- padding: 0;
- display: table;
-}
-
-.tablist li {
- display: table-cell;
- line-height: 2em;
- list-style: none;
- border-bottom: 0;
-}
-
-.tablist a {
- display: block;
- padding: 0 1em 0 0;
- font-family: "DejaVu Sans",Helvetica,Arial,sans-serif;
- text-decoration: none;
- outline: none;
-}
-
-.tabs3 .tablist a {
- padding: 0 10px;
-}
-
-.tablist li.current a {
- color: #222;
-}
-
-span.icon {
- display: none;
-}
diff --git a/doc/uis.rst b/doc/uis.rst
new file mode 100644
index 0000000..1169060
--- /dev/null
+++ b/doc/uis.rst
@@ -0,0 +1,25 @@
+..
+ Copyright 2020-2022 David Robillard <d@drobilla.net>
+ SPDX-License-Identifier: ISC
+
+.. default-domain:: c
+.. highlight:: c
+
+###############
+User Interfaces
+###############
+
+Plugins may have custom user interfaces, or `UIs`,
+which are installed in bundles just like plugins.
+
+The available UIs for a plugin can be accessed with :func:`lilv_plugin_get_uis`:
+
+.. code-block:: c
+
+ LilvUIs* uis = lilv_plugin_get_uis(plugin);
+
+:struct:`LilvUIs` is a collection much like `LilvPlugins`,
+except it is of course a set of :struct:`LilvUI` rather than a set of :struct:`LilvPlugin`.
+Also like plugins,
+the :struct:`LilvUI` class has various accessors that can be used to get information about the UI.
+See the :doc:`API reference <api/lilv_ui>` for details.
diff --git a/doc/world.rst b/doc/world.rst
new file mode 100644
index 0000000..8b71165
--- /dev/null
+++ b/doc/world.rst
@@ -0,0 +1,157 @@
+..
+ Copyright 2020-2022 David Robillard <d@drobilla.net>
+ SPDX-License-Identifier: ISC
+
+.. default-domain:: c
+.. highlight:: c
+
+#####
+World
+#####
+
+The world is the top-level object which represents an instance of Lilv.
+It is used to discover and load LV2 data,
+and stores an internal cache of loaded data for fast searching.
+
+An application typically has a single world,
+which is constructed once on startup and used throughout the application's lifetime.
+
+************
+Construction
+************
+
+A world must be created before anything else.
+A world is created with :func:`lilv_world_new`, for example:
+
+.. code-block:: c
+
+ LilvWorld* world = lilv_world_new();
+
+***************
+Setting Options
+***************
+
+Various options to control Lilv's behavior can be set with :func:`lilv_world_set_option`.
+The currently supported options are :c:macro:`LILV_OPTION_FILTER_LANG`,
+:c:macro:`LILV_OPTION_DYN_MANIFEST`, and :c:macro:`LILV_OPTION_LV2_PATH`.
+
+For example, to set the LV2 path to only load plugins bundled in the application:
+
+.. code-block:: c
+
+ LilvNode* lv2_path = lilv_new_file_uri(world, NULL, "/myapp/lv2");
+
+ lilv_world_set_option(world, LILV_OPTION_LV2_PATH, lv2_path);
+
+************
+Loading Data
+************
+
+Before using anything, data must be loaded from disk.
+All LV2 data (plugins, UIs, specifications, presets, and so on) is installed in `bundles`,
+a standard directory format
+
+Discovering and Loading Bundles
+===============================
+
+Typical hosts will simply load all bundles in the standard LV2 locations on the system:
+
+.. code-block:: c
+
+ lilv_world_load_all(world);
+
+This will discover all bundles on the system,
+as well as load the required data defined in any discovered specifications.
+
+It is also possible to load a specific bundle:
+
+.. code-block:: c
+
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, "/some/plugin.lv2");
+
+ lilv_world_load_bundle(world, bundle_uri);
+
+The LV2 specification itself is also installed in bundles,
+so if you are not using :func:`lilv_world_load_all`,
+it is necessary to manually load the discovered specification data:
+
+.. code-block:: c
+
+ lilv_world_load_specifications(world);
+ lilv_world_load_plugin_classes(world);
+
+*************
+Querying Data
+*************
+
+The world contains a model of all the loaded data in memory which can be queried.
+
+Data Model
+==========
+
+LV2 data is a set of "statements",
+where a statement is a bit like a simple machine-readable sentence.
+The "subject" and "object" are as in natural language,
+and the "predicate" is like the verb, but more general.
+
+For example, we could make a statement about a plugin in english:
+
+ MyOsc has the name "Super Oscillator"
+
+We can break this statement into 3 pieces like so:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Subject
+ - Predicate
+ - Object
+ * - MyOsc
+ - has the name
+ - "My Super Oscillator"
+
+Statements use URIs to identify things.
+In this case, we assume that this plugin has the URI ``http://example.org/Osc``.
+The LV2 specification defines that ``http://usefulinc.com/ns/doap#name`` is the property used to describe a plugin's name.
+So, this statement is:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Subject
+ - Predicate
+ - Object
+ * - ``http://example.org/Osc``
+ - ``http://usefulinc.com/ns/doap#name``
+ - "My Oscillator"
+
+Finding Values
+==============
+
+Based on this model, you can find all values that match a certain pattern.
+Patterns are just statements,
+but with ``NULL`` used as a wildcard that matches anything.
+So, for example, you can get the name of a plugin using :func:`lilv_world_find_nodes`:
+
+.. code-block:: c
+
+ LilvNode* plugin_uri = lilv_new_uri(world, "http://example.org/Osc");
+ LilvNode* doap_name = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name");
+
+ LilvNodes* values = lilv_world_find_nodes(world, plugin_uri, doap_name, NULL);
+
+Note that a set of values is returned,
+because some properties may have several values.
+When you are only interested in one value,
+you can use the simpler :func:`lilv_world_get` instead:
+
+.. code-block:: c
+
+ LilvNode* value = lilv_world_get(world, plugin_uri, doap_name, NULL);
+
+If you are only interested if a value exists at all,
+use :func:`lilv_world_ask`:
+
+.. code-block:: c
+
+ bool has_name = lilv_world_ask(world, plugin_uri, doap_name, NULL);
diff --git a/doc/xml/meson.build b/doc/xml/meson.build
new file mode 100644
index 0000000..eb66325
--- /dev/null
+++ b/doc/xml/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+doxygen = find_program('doxygen')
+
+config = configuration_data()
+config.set('LILV_SRCDIR', lilv_src_root)
+config.set('DOX_OUTPUT', meson.current_build_dir() / '..')
+
+doxyfile = configure_file(
+ configuration: config,
+ input: files('../Doxyfile.in'),
+ output: 'Doxyfile',
+)
+
+doxygen_xml = custom_target(
+ 'index.xml',
+ command: [doxygen, '@INPUT0@'],
+ input: [doxyfile] + c_headers,
+ output: [
+ 'index.xml',
+
+ 'group__lilv.xml',
+ 'group__lilv__class.xml',
+ 'group__lilv__collections.xml',
+ 'group__lilv__instance.xml',
+ 'group__lilv__node.xml',
+ 'group__lilv__plugin.xml',
+ 'group__lilv__port.xml',
+ 'group__lilv__scalepoint.xml',
+ 'group__lilv__state.xml',
+ 'group__lilv__ui.xml',
+ 'group__lilv__world.xml',
+ 'lilv_8h.xml',
+ ],
+)
diff --git a/lilv/lilv.h b/include/lilv/lilv.h
index 83b28e2..9f52925 100644
--- a/lilv/lilv.h
+++ b/include/lilv/lilv.h
@@ -1,22 +1,7 @@
-/*
- Copyright 2007-2019 David Robillard <http://drobilla.net>
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
- 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.
-*/
-
-/**
- @file lilv.h API for Lilv, a lightweight LV2 host library.
-*/
+/// @file lilv.h API for Lilv, a lightweight LV2 host library.
#ifndef LILV_LILV_H
#define LILV_LILV_H
@@ -24,89 +9,83 @@
#include "lv2/core/lv2.h"
#include "lv2/urid/urid.h"
-#include <stdarg.h>
+#include <stdarg.h> // IWYU pragma: keep
#include <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
-#ifdef LILV_SHARED
-# ifdef _WIN32
-# define LILV_LIB_IMPORT __declspec(dllimport)
-# define LILV_LIB_EXPORT __declspec(dllexport)
-# else
-# define LILV_LIB_IMPORT __attribute__((visibility("default")))
-# define LILV_LIB_EXPORT __attribute__((visibility("default")))
-# endif
-# ifdef LILV_INTERNAL
-# define LILV_API LILV_LIB_EXPORT
-# else
-# define LILV_API LILV_LIB_IMPORT
-# endif
-#else
+// LILV_API must be used to decorate things in the public API
+#ifndef LILV_API
+# if defined(_WIN32) && !defined(LILV_STATIC) && defined(LILV_INTERNAL)
+# define LILV_API __declspec(dllexport)
+# elif defined(_WIN32) && !defined(LILV_STATIC)
+# define LILV_API __declspec(dllimport)
+# elif defined(__GNUC__)
+# define LILV_API __attribute__((visibility("default")))
+# else
# define LILV_API
+# endif
#endif
-#if defined(__GNUC__) && (__GNUC__ > 3 || \
- (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
-# define LILV_DEPRECATED __attribute__((__deprecated__))
+
+#if defined(__GNUC__) && \
+ (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+# define LILV_DEPRECATED __attribute__((__deprecated__))
#else
-# define LILV_DEPRECATED
+# define LILV_DEPRECATED
#endif
#ifdef __cplusplus
extern "C" {
-# if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
-# endif
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+# endif
#endif
#define LILV_NS_DOAP "http://usefulinc.com/ns/doap#"
#define LILV_NS_FOAF "http://xmlns.com/foaf/0.1/"
#define LILV_NS_LILV "http://drobilla.net/ns/lilv#"
-#define LILV_NS_LV2 "http://lv2plug.in/ns/lv2core#"
-#define LILV_NS_OWL "http://www.w3.org/2002/07/owl#"
-#define LILV_NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+#define LILV_NS_LV2 "http://lv2plug.in/ns/lv2core#"
+#define LILV_NS_OWL "http://www.w3.org/2002/07/owl#"
+#define LILV_NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
#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_ATOM_PORT "http://lv2plug.in/ns/ext/atom#AtomPort"
+#define LILV_URI_AUDIO_PORT "http://lv2plug.in/ns/lv2core#AudioPort"
#define LILV_URI_CONTROL_PORT "http://lv2plug.in/ns/lv2core#ControlPort"
-#define LILV_URI_CV_PORT "http://lv2plug.in/ns/lv2core#CVPort"
-#define LILV_URI_EVENT_PORT "http://lv2plug.in/ns/ext/event#EventPort"
-#define LILV_URI_INPUT_PORT "http://lv2plug.in/ns/lv2core#InputPort"
-#define LILV_URI_MIDI_EVENT "http://lv2plug.in/ns/ext/midi#MidiEvent"
-#define LILV_URI_OUTPUT_PORT "http://lv2plug.in/ns/lv2core#OutputPort"
-#define LILV_URI_PORT "http://lv2plug.in/ns/lv2core#Port"
+#define LILV_URI_CV_PORT "http://lv2plug.in/ns/lv2core#CVPort"
+#define LILV_URI_EVENT_PORT "http://lv2plug.in/ns/ext/event#EventPort"
+#define LILV_URI_INPUT_PORT "http://lv2plug.in/ns/lv2core#InputPort"
+#define LILV_URI_MIDI_EVENT "http://lv2plug.in/ns/ext/midi#MidiEvent"
+#define LILV_URI_OUTPUT_PORT "http://lv2plug.in/ns/lv2core#OutputPort"
+#define LILV_URI_PORT "http://lv2plug.in/ns/lv2core#Port"
-typedef struct LilvPluginImpl LilvPlugin; /**< LV2 Plugin. */
-typedef struct LilvPluginClassImpl LilvPluginClass; /**< Plugin Class. */
-typedef struct LilvPortImpl LilvPort; /**< Port. */
-typedef struct LilvScalePointImpl LilvScalePoint; /**< Scale Point. */
-typedef struct LilvUIImpl LilvUI; /**< Plugin UI. */
-typedef struct LilvNodeImpl LilvNode; /**< Typed Value. */
-typedef struct LilvWorldImpl LilvWorld; /**< Lilv World. */
-typedef struct LilvInstanceImpl LilvInstance; /**< Plugin instance. */
-typedef struct LilvStateImpl LilvState; /**< Plugin state. */
-
-typedef void LilvIter; /**< Collection iterator */
-typedef void LilvPluginClasses; /**< set<PluginClass>. */
-typedef void LilvPlugins; /**< set<Plugin>. */
-typedef void LilvScalePoints; /**< set<ScalePoint>. */
-typedef void LilvUIs; /**< set<UI>. */
-typedef void LilvNodes; /**< set<Node>. */
+struct LilvInstanceImpl;
/**
- @defgroup lilv Lilv
-
- A library for discovering and using LV2 plugins.
-
- For more information about LV2, see <http://lv2plug.in/>.
-
+ @defgroup lilv Lilv C API
+ This is the complete public C API of lilv.
@{
*/
+typedef struct LilvPluginImpl LilvPlugin; /**< LV2 Plugin. */
+typedef struct LilvPluginClassImpl LilvPluginClass; /**< Plugin Class. */
+typedef struct LilvPortImpl LilvPort; /**< Port. */
+typedef struct LilvScalePointImpl LilvScalePoint; /**< Scale Point. */
+typedef struct LilvUIImpl LilvUI; /**< Plugin UI. */
+typedef struct LilvNodeImpl LilvNode; /**< Typed Value. */
+typedef struct LilvWorldImpl LilvWorld; /**< Lilv World. */
+typedef struct LilvInstanceImpl LilvInstance; /**< Plugin instance. */
+typedef struct LilvStateImpl LilvState; /**< Plugin state. */
+
+typedef void LilvIter; /**< Collection iterator */
+typedef void LilvPluginClasses; /**< A set of #LilvPluginClass. */
+typedef void LilvPlugins; /**< A set of #LilvPlugin. */
+typedef void LilvScalePoints; /**< A set of #LilvScalePoint. */
+typedef void LilvUIs; /**< A set of #LilvUI. */
+typedef void LilvNodes; /**< A set of #LilvNode. */
+
/**
Free memory allocated by Lilv.
@@ -114,234 +93,283 @@ typedef void LilvNodes; /**< set<Node>. */
library to be freed by code in the same library. It is otherwise equivalent
to the standard C free() function.
*/
-LILV_API void
+LILV_API
+void
lilv_free(void* ptr);
/**
- @name Node
+ @defgroup lilv_node Nodes
@{
*/
/**
Convert a file URI string to a local path string.
+
For example, "file://foo/bar/baz.ttl" returns "/foo/bar/baz.ttl".
Return value is shared and must not be deleted by caller.
This function does not handle escaping correctly and should not be used for
general file URIs. Use lilv_file_uri_parse() instead.
+
@return `uri` converted to a path, or NULL on failure (URI is not local).
*/
-LILV_API LILV_DEPRECATED const char*
+LILV_API
+LILV_DEPRECATED
+const char*
lilv_uri_to_path(const char* uri);
/**
Convert a file URI string to a local path string.
+
For example, "file://foo/bar%20one/baz.ttl" returns "/foo/bar one/baz.ttl".
Return value must be freed by caller with lilv_free().
+
@param uri The file URI to parse.
@param hostname If non-NULL, set to the hostname in the URI, if any.
@return `uri` converted to a path, or NULL on failure (URI is not local).
*/
-LILV_API char*
+LILV_API
+char*
lilv_file_uri_parse(const char* uri, char** hostname);
/**
Create a new URI value.
+
Returned value must be freed by caller with lilv_node_free().
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_new_uri(LilvWorld* world, const char* uri);
/**
Create a new file URI value.
+
+ Relative paths are resolved against the current working directory. Note
+ that this may yield unexpected results if `host` is another machine.
+
@param world The world.
@param host Host name, or NULL.
@param path Path on host.
@return A new node that must be freed by caller.
-
- Relative paths are resolved against the current working directory. Note
- that this may yield unexpected results if `host` is another machine.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_new_file_uri(LilvWorld* world, const char* host, const char* path);
/**
Create a new string value (with no language).
+
Returned value must be freed by caller with lilv_node_free().
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_new_string(LilvWorld* world, const char* str);
/**
Create a new integer value.
+
Returned value must be freed by caller with lilv_node_free().
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_new_int(LilvWorld* world, int val);
/**
Create a new floating point value.
+
Returned value must be freed by caller with lilv_node_free().
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_new_float(LilvWorld* world, float val);
/**
Create a new boolean value.
+
Returned value must be freed by caller with lilv_node_free().
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_new_bool(LilvWorld* world, bool val);
/**
Free a LilvNode.
+
It is safe to call this function on NULL.
*/
-LILV_API void
+LILV_API
+void
lilv_node_free(LilvNode* val);
/**
Duplicate a LilvNode.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_node_duplicate(const LilvNode* val);
/**
Return whether two values are equivalent.
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_equals(const LilvNode* value, const LilvNode* other);
/**
Return this value as a Turtle/SPARQL token.
+
Returned value must be freed by caller with lilv_free().
- <table>
- <caption>Example Turtle Tokens</caption>
- <tr><th>URI</th><td>&lt;http://example.org/foo &gt;</td></tr>
- <tr><th>QName</th><td>doap:name</td></tr>
- <tr><th>String</th><td>"this is a string"</td></tr>
- <tr><th>Float</th><td>1.0</td></tr>
- <tr><th>Integer</th><td>1</td></tr>
- <tr><th>Boolean</th><td>true</td></tr>
- </table>
-*/
-LILV_API char*
+
+ Example tokens:
+
+ - URI: &lt;http://example.org/foo&gt;
+ - QName: doap:name
+ - String: "this is a string"
+ - Float: 1.0
+ - Integer: 1
+ - Boolean: true
+*/
+LILV_API
+char*
lilv_node_get_turtle_token(const LilvNode* value);
/**
Return whether the value is a URI (resource).
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_uri(const LilvNode* value);
/**
- Return this value as a URI string, e.g. "http://example.org/foo".
+ Return this value as a URI string, like "http://example.org/foo".
+
Valid to call only if `lilv_node_is_uri(value)` returns true.
Returned value is owned by `value` and must not be freed by caller.
*/
-LILV_API const char*
+LILV_API
+const char*
lilv_node_as_uri(const LilvNode* value);
/**
Return whether the value is a blank node (resource with no URI).
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_blank(const LilvNode* value);
/**
- Return this value as a blank node identifier, e.g. "genid03".
+ Return this value as a blank node identifier, like "genid03".
+
Valid to call only if `lilv_node_is_blank(value)` returns true.
Returned value is owned by `value` and must not be freed by caller.
*/
-LILV_API const char*
+LILV_API
+const char*
lilv_node_as_blank(const LilvNode* value);
/**
- Return whether this value is a literal (i.e. not a URI).
+ Return whether this value is a literal (that is, not a URI).
+
Returns true if `value` is a string or numeric value.
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_literal(const LilvNode* value);
/**
Return whether this value is a string literal.
+
Returns true if `value` is a string value (and not numeric).
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_string(const LilvNode* value);
/**
Return `value` as a string.
*/
-LILV_API const char*
+LILV_API
+const char*
lilv_node_as_string(const LilvNode* value);
/**
Return the path of a file URI node.
+
Returns NULL if `value` is not a file URI.
Returned value must be freed by caller with lilv_free().
*/
-LILV_API char*
+LILV_API
+char*
lilv_node_get_path(const LilvNode* value, char** hostname);
/**
Return whether this value is a decimal literal.
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_float(const LilvNode* value);
/**
Return `value` as a float.
+
Valid to call only if `lilv_node_is_float(value)` or
`lilv_node_is_int(value)` returns true.
*/
-LILV_API float
+LILV_API
+float
lilv_node_as_float(const LilvNode* value);
/**
Return whether this value is an integer literal.
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_int(const LilvNode* value);
/**
Return `value` as an integer.
+
Valid to call only if `lilv_node_is_int(value)` returns true.
*/
-LILV_API int
+LILV_API
+int
lilv_node_as_int(const LilvNode* value);
/**
Return whether this value is a boolean.
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_is_bool(const LilvNode* value);
/**
Return `value` as a bool.
+
Valid to call only if `lilv_node_is_bool(value)` returns true.
*/
-LILV_API bool
+LILV_API
+bool
lilv_node_as_bool(const LilvNode* value);
/**
@}
- @name Collections
- Lilv has several collection types for holding various types of value:
- <ul>
- <li>LilvPlugins (function prefix "lilv_plugins_")</li>
- <li>LilvPluginClasses (function prefix "lilv_plugin_classes_")</li>
- <li>LilvScalePoints (function prefix "lilv_scale_points_")</li>
- <li>LilvNodes (function prefix "lilv_nodes_")</li>
- <li>LilvUIs (function prefix "lilv_uis_")</li>
- </ul>
-
- Each collection type supports a similar basic API (except LilvPlugins which
- is internal and thus lacks a free function):
- <ul>
- <li>void PREFIX_free (coll)</li>
- <li>unsigned PREFIX_size (coll)</li>
- <li>LilvIter* PREFIX_begin (coll)</li>
- </ul>
+ @defgroup lilv_collections Collections
+
+ Lilv has several collection types for holding various types of value.
+ Each collection type supports a similar basic API, except #LilvPlugins which
+ is internal and thus lacks a free function:
+
+ - void PREFIX_free (coll)
+ - unsigned PREFIX_size (coll)
+ - LilvIter* PREFIX_begin (coll)
+
+ The types of collection are:
+
+ - LilvPlugins, with function prefix `lilv_plugins_`.
+ - LilvPluginClasses, with function prefix `lilv_plugin_classes_`.
+ - LilvScalePoints, with function prefix `lilv_scale_points_`.
+ - LilvNodes, with function prefix `lilv_nodes_`.
+ - LilvUIs, with function prefix `lilv_uis_`.
+
@{
*/
@@ -349,6 +377,7 @@ lilv_node_as_bool(const LilvNode* value);
/**
Iterate over each element of a collection.
+
@code
LILV_FOREACH(plugin_classes, i, classes) {
LilvPluginClass c = lilv_plugin_classes_get(classes, i);
@@ -356,172 +385,217 @@ lilv_node_as_bool(const LilvNode* value);
}
@endcode
*/
-#define LILV_FOREACH(colltype, iter, collection) \
- for (LilvIter* iter = lilv_ ## colltype ## _begin(collection); \
- !lilv_ ## colltype ## _is_end(collection, iter); \
- (iter) = lilv_ ## colltype ## _next(collection, iter))
+#define LILV_FOREACH(colltype, iter, collection) \
+ /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
+ for (LilvIter* iter = lilv_##colltype##_begin(collection); \
+ !lilv_##colltype##_is_end(collection, iter); \
+ (iter) = lilv_##colltype##_next(collection, iter))
/* LilvPluginClasses */
-LILV_API void
+LILV_API
+void
lilv_plugin_classes_free(LilvPluginClasses* collection);
-LILV_API unsigned
+LILV_API
+unsigned
lilv_plugin_classes_size(const LilvPluginClasses* collection);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_plugin_classes_begin(const LilvPluginClasses* collection);
-LILV_API const LilvPluginClass*
+LILV_API
+const LilvPluginClass*
lilv_plugin_classes_get(const LilvPluginClasses* collection, LilvIter* i);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_plugin_classes_next(const LilvPluginClasses* collection, LilvIter* i);
-LILV_API bool
+LILV_API
+bool
lilv_plugin_classes_is_end(const LilvPluginClasses* collection, LilvIter* i);
/**
Get a plugin class from `classes` by URI.
+
Return value is shared (stored in `classes`) and must not be freed or
modified by the caller in any way.
+
@return NULL if no plugin class with `uri` is found in `classes`.
*/
-LILV_API const LilvPluginClass*
+LILV_API
+const LilvPluginClass*
lilv_plugin_classes_get_by_uri(const LilvPluginClasses* classes,
const LilvNode* uri);
/* ScalePoints */
-LILV_API void
+LILV_API
+void
lilv_scale_points_free(LilvScalePoints* collection);
-LILV_API unsigned
+LILV_API
+unsigned
lilv_scale_points_size(const LilvScalePoints* collection);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_scale_points_begin(const LilvScalePoints* collection);
-LILV_API const LilvScalePoint*
+LILV_API
+const LilvScalePoint*
lilv_scale_points_get(const LilvScalePoints* collection, LilvIter* i);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_scale_points_next(const LilvScalePoints* collection, LilvIter* i);
-LILV_API bool
+LILV_API
+bool
lilv_scale_points_is_end(const LilvScalePoints* collection, LilvIter* i);
/* UIs */
-LILV_API void
+LILV_API
+void
lilv_uis_free(LilvUIs* collection);
-LILV_API unsigned
+LILV_API
+unsigned
lilv_uis_size(const LilvUIs* collection);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_uis_begin(const LilvUIs* collection);
-LILV_API const LilvUI*
+LILV_API
+const LilvUI*
lilv_uis_get(const LilvUIs* collection, LilvIter* i);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_uis_next(const LilvUIs* collection, LilvIter* i);
-LILV_API bool
+LILV_API
+bool
lilv_uis_is_end(const LilvUIs* collection, LilvIter* i);
/**
Get a UI from `uis` by URI.
+
Return value is shared (stored in `uis`) and must not be freed or
modified by the caller in any way.
+
@return NULL if no UI with `uri` is found in `list`.
*/
-LILV_API const LilvUI*
-lilv_uis_get_by_uri(const LilvUIs* uis,
- const LilvNode* uri);
+LILV_API
+const LilvUI*
+lilv_uis_get_by_uri(const LilvUIs* uis, const LilvNode* uri);
/* Nodes */
-LILV_API void
+LILV_API
+void
lilv_nodes_free(LilvNodes* collection);
-LILV_API unsigned
+LILV_API
+unsigned
lilv_nodes_size(const LilvNodes* collection);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_nodes_begin(const LilvNodes* collection);
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_nodes_get(const LilvNodes* collection, LilvIter* i);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_nodes_next(const LilvNodes* collection, LilvIter* i);
-LILV_API bool
+LILV_API
+bool
lilv_nodes_is_end(const LilvNodes* collection, LilvIter* i);
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_nodes_get_first(const LilvNodes* collection);
/**
Return whether `values` contains `value`.
*/
-LILV_API bool
+LILV_API
+bool
lilv_nodes_contains(const LilvNodes* nodes, const LilvNode* value);
/**
Return a new LilvNodes that contains all nodes from both `a` and `b`.
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_nodes_merge(const LilvNodes* a, const LilvNodes* b);
/* Plugins */
-LILV_API unsigned
+LILV_API
+unsigned
lilv_plugins_size(const LilvPlugins* collection);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_plugins_begin(const LilvPlugins* collection);
-LILV_API const LilvPlugin*
+LILV_API
+const LilvPlugin*
lilv_plugins_get(const LilvPlugins* collection, LilvIter* i);
-LILV_API LilvIter*
+LILV_API
+LilvIter*
lilv_plugins_next(const LilvPlugins* collection, LilvIter* i);
-LILV_API bool
+LILV_API
+bool
lilv_plugins_is_end(const LilvPlugins* collection, LilvIter* i);
/**
Get a plugin from `plugins` by URI.
+
Return value is shared (stored in `plugins`) and must not be freed or
modified by the caller in any way.
+
@return NULL if no plugin with `uri` is found in `plugins`.
*/
-LILV_API const LilvPlugin*
-lilv_plugins_get_by_uri(const LilvPlugins* plugins,
- const LilvNode* uri);
+LILV_API
+const LilvPlugin*
+lilv_plugins_get_by_uri(const LilvPlugins* plugins, const LilvNode* uri);
/**
@}
- @name World
+ @defgroup lilv_world World
+
The "world" represents all Lilv state, and is used to discover/load/cache
LV2 data (plugins, UIs, and extensions).
Normal hosts which just need to load plugins by URI should simply use
lilv_world_load_all() to discover/load the system's LV2 resources.
+
@{
*/
/**
Initialize a new, empty world.
+
If initialization fails, NULL is returned.
*/
-LILV_API LilvWorld*
+LILV_API
+LilvWorld*
lilv_world_new(void);
/**
Enable/disable language filtering.
+
Language filtering applies to any functions that return (a) value(s).
With filtering enabled, Lilv will automatically return the best value(s)
for the current LANG. With filtering disabled, all matching values will
@@ -531,69 +605,76 @@ lilv_world_new(void);
/**
Enable/disable dynamic manifest support.
+
Dynamic manifest data will only be loaded if this option is true.
*/
#define LILV_OPTION_DYN_MANIFEST "http://drobilla.net/ns/lilv#dyn-manifest"
/**
- Set application-specific LV2_PATH. This overrides the LV2_PATH from the
- environment, so that lilv will only look inside the given path. This can be
- used to make self-contained applications.
+ Set application-specific LV2_PATH.
+
+ This overrides the LV2_PATH from the environment, so that lilv will only
+ look inside the given path. This can be used to make self-contained
+ applications.
*/
#define LILV_OPTION_LV2_PATH "http://drobilla.net/ns/lilv#lv2-path"
/**
- Set an option option for `world`.
+ Set an option for `world`.
Currently recognized options:
- @ref LILV_OPTION_FILTER_LANG
- @ref LILV_OPTION_DYN_MANIFEST
- @ref LILV_OPTION_LV2_PATH
+
+ - #LILV_OPTION_FILTER_LANG
+ - #LILV_OPTION_DYN_MANIFEST
+ - #LILV_OPTION_LV2_PATH
*/
-LILV_API void
-lilv_world_set_option(LilvWorld* world,
- const char* uri,
- const LilvNode* value);
+LILV_API
+void
+lilv_world_set_option(LilvWorld* world, const char* uri, const LilvNode* value);
/**
- Destroy the world, mwahaha.
- It is safe to call this function on NULL.
- Note that destroying `world` will destroy all the objects it contains
- (e.g. instances of LilvPlugin). Do not destroy the world until you are
+ Destroy the world.
+
+ It is safe to call this function on NULL. Note that destroying `world` will
+ destroy all the objects it contains. Do not destroy the world until you are
finished with all objects that came from it.
*/
-LILV_API void
+LILV_API
+void
lilv_world_free(LilvWorld* world);
/**
Load all installed LV2 bundles on the system.
+
This is the recommended way for hosts to load LV2 data. It implements the
established/standard best practice for discovering all LV2 data on the
system. The environment variable LV2_PATH may be used to control where
this function will look for bundles.
Hosts should use this function rather than explicitly load bundles, except
- in special circumstances (e.g. development utilities, or hosts that ship
- with special plugin bundles which are installed to a known location).
+ in special circumstances such as development utilities, or hosts that ship
+ with special plugin bundles which are installed to a known location.
*/
-LILV_API void
+LILV_API
+void
lilv_world_load_all(LilvWorld* world);
/**
Load a specific bundle.
+
`bundle_uri` must be a fully qualified URI to the bundle directory,
with the trailing slash, eg. file:///usr/lib/lv2/foo.lv2/
Normal hosts should not need this function (use lilv_world_load_all()).
Hosts MUST NOT attach any long-term significance to bundle paths
- (e.g. in save files), since there are no guarantees they will remain
+ (for example in save files), since there are no guarantees they will remain
unchanged between (or even during) program invocations. Plugins (among
other things) MUST be identified by URIs (not paths) in save files.
*/
-LILV_API void
-lilv_world_load_bundle(LilvWorld* world,
- const LilvNode* bundle_uri);
+LILV_API
+void
+lilv_world_load_bundle(LilvWorld* world, const LilvNode* bundle_uri);
/**
Load all specifications from currently loaded bundles.
@@ -602,7 +683,8 @@ lilv_world_load_bundle(LilvWorld* world,
necessary when using lilv_world_load_all(). This function parses the
specifications and adds them to the model.
*/
-LILV_API void
+LILV_API
+void
lilv_world_load_specifications(LilvWorld* world);
/**
@@ -612,7 +694,8 @@ lilv_world_load_specifications(LilvWorld* world);
that explicitly load specific bundles, its use is not necessary when using
lilv_world_load_all().
*/
-LILV_API void
+LILV_API
+void
lilv_world_load_plugin_classes(LilvWorld* world);
/**
@@ -623,49 +706,56 @@ lilv_world_load_plugin_classes(LilvWorld* world);
have been separately loaded with lilv_world_load_resource(), they must be
separately unloaded with lilv_world_unload_resource().
*/
-LILV_API int
+LILV_API
+int
lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri);
/**
Load all the data associated with the given `resource`.
- @param world The world.
- @param resource Must be a subject (i.e. a URI or a blank node).
- @return The number of files parsed, or -1 on error
All accessible data files linked to `resource` with rdfs:seeAlso will be
loaded into the world model.
+
+ @param world The world.
+ @param resource Must be a subject (a URI or a blank node).
+ @return The number of files parsed, or -1 on error
*/
-LILV_API int
-lilv_world_load_resource(LilvWorld* world,
- const LilvNode* resource);
+LILV_API
+int
+lilv_world_load_resource(LilvWorld* world, const LilvNode* resource);
/**
Unload all the data associated with the given `resource`.
- @param world The world.
- @param resource Must be a subject (i.e. a URI or a blank node).
This unloads all data loaded by a previous call to
lilv_world_load_resource() with the given `resource`.
+
+ @param world The world.
+ @param resource Must be a subject (a URI or a blank node).
*/
-LILV_API int
-lilv_world_unload_resource(LilvWorld* world,
- const LilvNode* resource);
+LILV_API
+int
+lilv_world_unload_resource(LilvWorld* world, const LilvNode* resource);
/**
Get the parent of all other plugin classes, lv2:Plugin.
*/
-LILV_API const LilvPluginClass*
+LILV_API
+const LilvPluginClass*
lilv_world_get_plugin_class(const LilvWorld* world);
/**
Return a list of all found plugin classes.
+
Returned list is owned by world and must not be freed by the caller.
*/
-LILV_API const LilvPluginClasses*
+LILV_API
+const LilvPluginClasses*
lilv_world_get_plugin_classes(const LilvWorld* world);
/**
Return a list of all found plugins.
+
The returned list contains just enough references to query
or instantiate plugins. The data for a particular plugin will not be
loaded into memory until a call to an lilv_plugin_* function results in
@@ -675,15 +765,19 @@ lilv_world_get_plugin_classes(const LilvWorld* world);
The returned list and the plugins it contains are owned by `world`
and must not be freed by caller.
*/
-LILV_API const LilvPlugins*
+LILV_API
+const LilvPlugins*
lilv_world_get_all_plugins(const LilvWorld* world);
/**
Find nodes matching a triple pattern.
- Either `subject` or `object` may be NULL (i.e. a wildcard), but not both.
+
+ Either `subject` or `object` may be NULL (a wildcard), but not both.
+
@return All matches for the wildcard field, or NULL.
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_world_find_nodes(LilvWorld* world,
const LilvNode* subject,
const LilvNode* predicate,
@@ -691,13 +785,16 @@ lilv_world_find_nodes(LilvWorld* world,
/**
Find a single node that matches a pattern.
+
Exactly one of `subject`, `predicate`, `object` must be NULL.
This function is equivalent to
lilv_nodes_get_first(lilv_world_find_nodes(...)) but simplifies the common
case of only wanting a single value.
- @return the first matching node, or NULL if no matches are found.
+
+ @return The first matching node, or NULL if no matches are found.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_world_get(LilvWorld* world,
const LilvNode* subject,
const LilvNode* predicate,
@@ -714,7 +811,8 @@ lilv_world_get(LilvWorld* world,
@param predicate Predicate (key) of statement, or NULL for anything.
@param object Object (value) of statement, or NULL for anything.
*/
-LILV_API bool
+LILV_API
+bool
lilv_world_ask(LilvWorld* world,
const LilvNode* subject,
const LilvNode* predicate,
@@ -725,32 +823,39 @@ lilv_world_ask(LilvWorld* world,
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_API
+LilvNode*
lilv_world_get_symbol(LilvWorld* world, const LilvNode* subject);
/**
@}
- @name Plugin
+ @defgroup lilv_plugin Plugins
@{
*/
/**
Check if `plugin` is valid.
+
This is not a rigorous validator, but can be used to reject some malformed
- plugins that could cause bugs (e.g. plugins with missing required fields).
+ plugins that could cause bugs (for example, plugins with missing required
+ fields).
Note that normal hosts do NOT need to use this - lilv does not
load invalid plugins into plugin lists. This is included for plugin
testing utilities, etc.
- @return true iff `plugin` is valid.
+
+ @return True iff `plugin` is valid.
*/
-LILV_API bool
+LILV_API
+bool
lilv_plugin_verify(const LilvPlugin* plugin);
/**
Get the URI of `plugin`.
+
Any serialization that refers to plugins should refer to them by this.
Hosts SHOULD NOT save any filesystem paths, plugin indexes, etc. in saved
files; save only the URI.
@@ -763,11 +868,13 @@ lilv_plugin_verify(const LilvPlugin* plugin);
@return A shared URI value which must not be modified or freed.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_plugin_get_uri(const LilvPlugin* plugin);
/**
Get the (resolvable) URI of the plugin's "main" bundle.
+
This returns the URI of the bundle where the plugin itself was found. Note
that the data for a plugin may be spread over many bundles, that is,
lilv_plugin_get_data_uris() may return URIs which are not within this
@@ -776,49 +883,62 @@ lilv_plugin_get_uri(const LilvPlugin* plugin);
Typical hosts should not need to use this function.
Note this always returns a fully qualified URI. If you want a local
filesystem path, use lilv_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*
lilv_plugin_get_bundle_uri(const LilvPlugin* plugin);
/**
Get the (resolvable) URIs of the RDF data files that define a plugin.
+
Typical hosts should not need to use this function.
Note this always returns fully qualified URIs. If you want local
filesystem paths, use lilv_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.
*/
-LILV_API const LilvNodes*
+LILV_API
+const LilvNodes*
lilv_plugin_get_data_uris(const LilvPlugin* plugin);
/**
Get the (resolvable) URI of the shared library for `plugin`.
+
Note this always returns a fully qualified URI. If you want a local
filesystem path, use lilv_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*
lilv_plugin_get_library_uri(const LilvPlugin* plugin);
/**
Get the name of `plugin`.
+
This returns the name (doap:name) of the plugin. The name may be
translated according to the current locale, this value MUST NOT be used
as a plugin identifier (use the URI for that).
+
Returned value must be freed by the caller.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_plugin_get_name(const LilvPlugin* plugin);
/**
- Get the class this plugin belongs to (e.g. Filters).
+ Get the class this plugin belongs to (like "Filters" or "Effects").
*/
-LILV_API const LilvPluginClass*
+LILV_API
+const LilvPluginClass*
lilv_plugin_get_class(const LilvPlugin* plugin);
/**
Get a value associated with the plugin in a plugin's data files.
+
`predicate` must be either a URI or a QName.
Returns the ?object of all triples found of the form:
@@ -826,39 +946,45 @@ lilv_plugin_get_class(const LilvPlugin* plugin);
<code>&lt;plugin-uri&gt; predicate ?object</code>
May return NULL if the property was not found, or if object(s) is not
- sensibly represented as a LilvNodes (e.g. blank nodes).
+ sensibly represented as a LilvNodes.
+
Return value must be freed by caller with lilv_nodes_free().
*/
-LILV_API LilvNodes*
-lilv_plugin_get_value(const LilvPlugin* plugin,
- const LilvNode* predicate);
+LILV_API
+LilvNodes*
+lilv_plugin_get_value(const LilvPlugin* plugin, const LilvNode* predicate);
/**
Return whether a feature is supported by a plugin.
+
This will return true if the feature is an optional or required feature
of the plugin.
*/
-LILV_API bool
-lilv_plugin_has_feature(const LilvPlugin* plugin,
- const LilvNode* feature);
+LILV_API
+bool
+lilv_plugin_has_feature(const LilvPlugin* plugin, const LilvNode* feature);
/**
Get the LV2 Features supported (required or optionally) by a plugin.
+
A feature is "supported" by a plugin if it is required OR optional.
Since required features have special rules the host must obey, this function
- probably shouldn't be used by normal hosts. Using lilv_plugin_get_optional_features()
- and lilv_plugin_get_required_features() separately is best in most cases.
+ probably shouldn't be used by normal hosts. Using
+ lilv_plugin_get_optional_features() and lilv_plugin_get_required_features()
+ separately is best in most cases.
Returned value must be freed by caller with lilv_nodes_free().
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_plugin_get_supported_features(const LilvPlugin* plugin);
/**
Get the LV2 Features required by a plugin.
- If a feature is required by a plugin, hosts MUST NOT use the plugin if they do not
- understand (or are unable to support) that feature.
+
+ If a feature is required by a plugin, hosts MUST NOT use the plugin if they
+ do not understand (or are unable to support) that feature.
All values returned here MUST be passed to the plugin's instantiate method
(along with data, if necessary, as defined by the feature specification)
@@ -866,43 +992,50 @@ lilv_plugin_get_supported_features(const LilvPlugin* plugin);
Return value must be freed by caller with lilv_nodes_free().
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_plugin_get_required_features(const LilvPlugin* plugin);
/**
Get the LV2 Features optionally supported by a plugin.
+
Hosts MAY ignore optional plugin features for whatever reasons. Plugins
MUST operate (at least somewhat) if they are instantiated without being
passed optional features.
Return value must be freed by caller with lilv_nodes_free().
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_plugin_get_optional_features(const LilvPlugin* plugin);
/**
Return whether or not a plugin provides a specific extension data.
*/
-LILV_API bool
-lilv_plugin_has_extension_data(const LilvPlugin* plugin,
- const LilvNode* uri);
+LILV_API
+bool
+lilv_plugin_has_extension_data(const LilvPlugin* plugin, const LilvNode* uri);
/**
Get a sequence of all extension data provided by a plugin.
+
This can be used to find which URIs lilv_instance_get_extension_data()
will return a value for without instantiating the plugin.
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_plugin_get_extension_data(const LilvPlugin* plugin);
/**
Get the number of ports on this plugin.
*/
-LILV_API uint32_t
+LILV_API
+uint32_t
lilv_plugin_get_num_ports(const LilvPlugin* plugin);
/**
Get the port ranges (minimum, maximum and default values) for all ports.
+
`min_values`, `max_values` and `def_values` must either point to an array
of N floats, where N is the value returned by lilv_plugin_get_num_ports()
for this plugin, or NULL. The elements of the array will be set to the
@@ -915,7 +1048,8 @@ lilv_plugin_get_num_ports(const LilvPlugin* plugin);
all float ports on a plugin, and may be significantly faster than
repeated calls to lilv_port_get_range().
*/
-LILV_API void
+LILV_API
+void
lilv_plugin_get_port_ranges_float(const LilvPlugin* plugin,
float* min_values,
float* max_values,
@@ -923,34 +1057,41 @@ lilv_plugin_get_port_ranges_float(const LilvPlugin* plugin,
/**
Get the number of ports on this plugin that are members of some class(es).
+
Note that this is a varargs function so ports fitting any type 'profile'
desired can be found quickly. REMEMBER TO TERMINATE THE PARAMETER LIST
OF THIS FUNCTION WITH NULL OR VERY NASTY THINGS WILL HAPPEN.
*/
-LILV_API uint32_t
+LILV_API
+uint32_t
lilv_plugin_get_num_ports_of_class(const LilvPlugin* plugin,
- const LilvNode* class_1, ...);
+ const LilvNode* class_1,
+ ...);
/**
Variant of lilv_plugin_get_num_ports_of_class() that takes a va_list.
This function calls va_arg() on `args` but does not call va_end().
*/
-LILV_API uint32_t
+LILV_API
+uint32_t
lilv_plugin_get_num_ports_of_class_va(const LilvPlugin* plugin,
const LilvNode* class_1,
va_list args);
/**
Return whether or not the plugin introduces (and reports) latency.
+
The index of the latency port can be found with
lilv_plugin_get_latency_port() ONLY if this function returns true.
*/
-LILV_API bool
+LILV_API
+bool
lilv_plugin_has_latency(const LilvPlugin* plugin);
/**
Return the index of the plugin's latency port.
+
It is a fatal error to call this on a plugin without checking if the port
exists by first calling lilv_plugin_has_latency().
@@ -958,22 +1099,25 @@ lilv_plugin_has_latency(const LilvPlugin* plugin);
(by hosts with the ability/need) MUST provide this port, which is a control
rate output port that reports the latency for each cycle in frames.
*/
-LILV_API uint32_t
+LILV_API
+uint32_t
lilv_plugin_get_latency_port_index(const LilvPlugin* plugin);
/**
Get a port on `plugin` by `index`.
*/
-LILV_API const LilvPort*
-lilv_plugin_get_port_by_index(const LilvPlugin* plugin,
- uint32_t index);
+LILV_API
+const LilvPort*
+lilv_plugin_get_port_by_index(const LilvPlugin* plugin, uint32_t index);
/**
Get a port on `plugin` by `symbol`.
+
Note this function is slower than lilv_plugin_get_port_by_index(),
especially on plugins with a very large number of ports.
*/
-LILV_API const LilvPort*
+LILV_API
+const LilvPort*
lilv_plugin_get_port_by_symbol(const LilvPlugin* plugin,
const LilvNode* symbol);
@@ -981,13 +1125,14 @@ lilv_plugin_get_port_by_symbol(const LilvPlugin* plugin,
Get a port on `plugin` by its lv2:designation.
The designation of a port describes the meaning, assignment, allocation or
- role of the port, e.g. "left channel" or "gain". If found, the port with
+ role of the port, like "left channel" or "gain". If found, the port with
matching `port_class` and `designation` is be returned, otherwise NULL is
returned. The `port_class` can be used to distinguish the input and output
ports for a particular designation. If `port_class` is NULL, any port with
the given designation will be returned.
*/
-LILV_API const LilvPort*
+LILV_API
+const LilvPort*
lilv_plugin_get_port_by_designation(const LilvPlugin* plugin,
const LilvNode* port_class,
const LilvNode* designation);
@@ -996,33 +1141,40 @@ lilv_plugin_get_port_by_designation(const LilvPlugin* plugin,
Get the project the plugin is a part of.
More information about the project can be read via lilv_world_find_nodes(),
- typically using properties from DOAP (e.g. doap:name).
+ typically using properties from DOAP (such as doap:name).
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_plugin_get_project(const LilvPlugin* plugin);
/**
Get the full name of the plugin's author.
+
Returns NULL if author name is not present.
Returned value must be freed by caller.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_plugin_get_author_name(const LilvPlugin* plugin);
/**
Get the email address of the plugin's author.
+
Returns NULL if author email address is not present.
Returned value must be freed by caller.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_plugin_get_author_email(const LilvPlugin* plugin);
/**
Get the address of the plugin author's home page.
+
Returns NULL if author homepage is not present.
Returned value must be freed by caller.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_plugin_get_author_homepage(const LilvPlugin* plugin);
/**
@@ -1031,7 +1183,8 @@ lilv_plugin_get_author_homepage(const LilvPlugin* plugin);
The plugin will still be usable, but hosts should hide them from their
user interfaces to prevent users from using deprecated plugins.
*/
-LILV_API bool
+LILV_API
+bool
lilv_plugin_is_replaced(const LilvPlugin* plugin);
/**
@@ -1040,7 +1193,8 @@ lilv_plugin_is_replaced(const LilvPlugin* plugin);
This function is particularly useful for porting plugins in conjunction with
an LV2 bridge such as NASPRO.
*/
-LILV_API void
+LILV_API
+void
lilv_plugin_write_description(LilvWorld* world,
const LilvPlugin* plugin,
const LilvNode* base_uri,
@@ -1052,7 +1206,8 @@ lilv_plugin_write_description(LilvWorld* world,
This function is intended for use with lilv_plugin_write_description() to
write a complete description of a plugin to a bundle.
*/
-LILV_API void
+LILV_API
+void
lilv_plugin_write_manifest_entry(LilvWorld* world,
const LilvPlugin* plugin,
const LilvNode* base_uri,
@@ -1072,12 +1227,13 @@ lilv_plugin_write_manifest_entry(LilvWorld* world,
To actually load the data for each returned resource, use
lilv_world_load_resource().
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_plugin_get_related(const LilvPlugin* plugin, const LilvNode* type);
/**
@}
- @name Port
+ @defgroup lilv_port Ports
@{
*/
@@ -1088,14 +1244,15 @@ lilv_plugin_get_related(const LilvPlugin* plugin, const LilvNode* type);
@return A shared node which must not be modified or freed.
*/
-LILV_API const LilvNode*
-lilv_port_get_node(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+const LilvNode*
+lilv_port_get_node(const LilvPlugin* plugin, const LilvPort* port);
/**
Port analog of lilv_plugin_get_value().
*/
-LILV_API LilvNodes*
+LILV_API
+LilvNodes*
lilv_port_get_value(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* predicate);
@@ -1107,7 +1264,8 @@ lilv_port_get_value(const LilvPlugin* plugin,
simpler to use in the common case of only caring about one value. The
caller is responsible for freeing the returned node.
*/
-LILV_API LilvNode*
+LILV_API
+LilvNode*
lilv_port_get(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* predicate);
@@ -1115,14 +1273,15 @@ lilv_port_get(const LilvPlugin* plugin,
/**
Return the LV2 port properties of a port.
*/
-LILV_API LilvNodes*
-lilv_port_get_properties(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+LilvNodes*
+lilv_port_get_properties(const LilvPlugin* plugin, const LilvPort* port);
/**
Return whether a port has a certain property.
*/
-LILV_API bool
+LILV_API
+bool
lilv_port_has_property(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* property);
@@ -1133,59 +1292,66 @@ lilv_port_has_property(const LilvPlugin* plugin,
More precisely, this returns true iff the port has an atom:supports or an
ev:supportsEvent property with `event_type` as the value.
*/
-LILV_API bool
+LILV_API
+bool
lilv_port_supports_event(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* event_type);
/**
Get the index of a port.
+
The index is only valid for the life of the plugin and may change between
versions. For a stable identifier, use the symbol.
*/
-LILV_API uint32_t
-lilv_port_get_index(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+uint32_t
+lilv_port_get_index(const LilvPlugin* plugin, const LilvPort* port);
/**
Get the symbol of a port.
+
The 'symbol' is a short string, a valid C identifier.
Returned value is owned by `port` and must not be freed.
*/
-LILV_API const LilvNode*
-lilv_port_get_symbol(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+const LilvNode*
+lilv_port_get_symbol(const LilvPlugin* plugin, const LilvPort* port);
/**
Get the name of a port.
+
This is guaranteed to return the untranslated name (the doap:name in the
data file without a language tag). Returned value must be freed by
the caller.
*/
-LILV_API LilvNode*
-lilv_port_get_name(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+LilvNode*
+lilv_port_get_name(const LilvPlugin* plugin, const LilvPort* port);
/**
Get all the classes of a port.
+
This can be used to determine if a port is an input, output, audio,
control, midi, etc, etc, though it's simpler to use lilv_port_is_a().
The returned list does not include lv2:Port, which is implied.
Returned value is shared and must not be destroyed by caller.
*/
-LILV_API const LilvNodes*
-lilv_port_get_classes(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+const LilvNodes*
+lilv_port_get_classes(const LilvPlugin* plugin, const LilvPort* port);
/**
Determine if a port is of a given class (input, output, audio, etc).
+
For convenience/performance/extensibility reasons, hosts are expected to
create a LilvNode for each port class they "care about". Well-known type
- URI strings are defined (e.g. LILV_URI_INPUT_PORT) for convenience, but
+ URI strings like `LILV_URI_INPUT_PORT` are defined for convenience, but
this function is designed so that Lilv is usable with any port types
without requiring explicit support in Lilv.
*/
-LILV_API bool
+LILV_API
+bool
lilv_port_is_a(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* port_class);
@@ -1198,7 +1364,8 @@ lilv_port_is_a(const LilvPlugin* plugin,
be freed by the caller using lilv_node_free()), or NULL if the value does
not exist.
*/
-LILV_API void
+LILV_API
+void
lilv_port_get_range(const LilvPlugin* plugin,
const LilvPort* port,
LilvNode** def,
@@ -1207,51 +1374,58 @@ lilv_port_get_range(const LilvPlugin* plugin,
/**
Get the scale points (enumeration values) of a port.
- This returns a collection of 'interesting' named values of a port
- (e.g. appropriate entries for a UI selector associated with this port).
+
+ This returns a collection of 'interesting' named values of a port, which for
+ example might be appropriate entries for a value selector in a UI.
+
Returned value may be NULL if `port` has no scale points, otherwise it
must be freed by caller with lilv_scale_points_free().
*/
-LILV_API LilvScalePoints*
-lilv_port_get_scale_points(const LilvPlugin* plugin,
- const LilvPort* port);
+LILV_API
+LilvScalePoints*
+lilv_port_get_scale_points(const LilvPlugin* plugin, const LilvPort* port);
/**
@}
- @name Plugin State
+ @defgroup lilv_state Plugin State
@{
*/
/**
Load a state snapshot from the world RDF model.
+
This function can be used to load the default state of a plugin by passing
the plugin URI as the `subject` parameter.
+
@param world The world.
@param map URID mapper.
- @param node The subject of the state description (e.g. a preset URI).
+ @param node The subject of the state description (such as a preset URI).
@return A new LilvState which must be freed with lilv_state_free(), or NULL.
*/
-LILV_API LilvState*
+LILV_API
+LilvState*
lilv_state_new_from_world(LilvWorld* world,
LV2_URID_Map* map,
const LilvNode* node);
/**
Load a state snapshot from a file.
- @param world The world.
- @param map URID mapper.
- @param subject The subject of the state description (e.g. a preset URI).
- @param path The path of the file containing the state description.
- @return A new LilvState which must be freed with lilv_state_free().
- If `subject` is NULL, it is taken to be the URI of the file (i.e.
- "<>" in Turtle).
+ If `subject` is NULL, it is taken to be the URI of the file (`<>` in
+ Turtle).
This function parses the file separately to create the state, it does not
- parse the file into the world model, i.e. the returned state is the only
+ parse the file into the world model, that is, the returned state is the only
new memory consumed once this function returns.
+
+ @param world The world.
+ @param map URID mapper.
+ @param subject The subject of the state description (such as a preset URI).
+ @param path The path of the file containing the state description.
+ @return A new LilvState which must be freed with lilv_state_free().
*/
-LILV_API LilvState*
+LILV_API
+LilvState*
lilv_state_new_from_file(LilvWorld* world,
LV2_URID_Map* map,
const LilvNode* subject,
@@ -1260,20 +1434,22 @@ lilv_state_new_from_file(LilvWorld* world,
/**
Load a state snapshot from a string made by lilv_state_to_string().
*/
-LILV_API LilvState*
+LILV_API
+LilvState*
lilv_state_new_from_string(LilvWorld* world,
LV2_URID_Map* map,
const char* str);
/**
Function to get a port value.
+
+ This function MUST set `size` and `type` appropriately.
+
@param port_symbol The symbol of the port.
@param user_data The user_data passed to lilv_state_new_from_instance().
@param size (Output) The size of the returned value.
@param type (Output) The URID of the type of the returned value.
@return A pointer to the port value.
-
- This function MUST set `size` and `type` appropriately.
*/
typedef const void* (*LilvGetPortValueFunc)(const char* port_symbol,
void* user_data,
@@ -1283,6 +1459,35 @@ typedef const void* (*LilvGetPortValueFunc)(const char* port_symbol,
/**
Create a new state snapshot from a plugin instance.
+
+ This function may be called simultaneously with any instance function
+ (except discovery functions) unless the threading class of that function
+ explicitly disallows this.
+
+ To support advanced file functionality, there are several directory
+ parameters. The multiple parameters are necessary to support saving an
+ instance's state many times, or saving states from multiple instances, while
+ avoiding any duplication of data. For example, a host could pass the same
+ `copy_dir` and `link_dir` for all plugins in a session (for example
+ `session/shared/copy/` `session/shared/link/`), while the `save_dir` would
+ be unique to each plugin instance (for example `session/states/state1.lv2`
+ for one instance and `session/states/state2.lv2` for another instance).
+ Simple hosts that only wish to save a single plugin's state once may simply
+ use the same directory for all of them, or pass NULL to not support files at
+ all.
+
+ If supported (via state:makePath passed to LV2_Descriptor::instantiate()),
+ `scratch_dir` should be the directory where any files created by the plugin
+ (for example during instantiation or while running) are stored. Any files
+ here that are referred to in the state will be copied to preserve their
+ contents at the time of the save. Lilv will assume any files within this
+ directory (recursively) are created by the plugin and that all other files
+ are immutable. Note that this function does not completely save the state,
+ use lilv_state_save() for that.
+
+ See <a href="http://lv2plug.in/ns/ext/state/state.h">state.h</a> from the
+ LV2 State extension for details on the `flags` and `features` parameters.
+
@param plugin The plugin this state applies to.
@param instance An instance of `plugin`.
@@ -1306,11 +1511,11 @@ typedef const void* (*LilvGetPortValueFunc)(const char* port_symbol,
@param link_dir Directory of links to external files, or NULL. A link will
be made in this directory to any external files referred to in plugin state.
- In turn, links will be created in the save directory to these links (e.g.
+ In turn, links will be created in the save directory to these links (like
save_dir/file => link_dir/file => /foo/bar/file). This allows many state
- snapshots to share a single link to an external file, so archival (e.g. with
- tar -h) will not create several copies of the file. If this is not
- required, it can be the same as `save_dir`.
+ snapshots to share a single link to an external file, so archival (for
+ example, with `tar -h`) will not create several copies of the file. If this
+ is not required, it can be the same as `save_dir`.
@param save_dir Directory of files created by plugin during save (or NULL).
This is typically the bundle directory later passed to lilv_state_save().
@@ -1326,70 +1531,47 @@ typedef const void* (*LilvGetPortValueFunc)(const char* port_symbol,
@param features Features to pass LV2_State_Interface.save().
@return A new LilvState which must be freed with lilv_state_free().
-
- This function may be called simultaneously with any instance function
- (except discovery functions) unless the threading class of that function
- explicitly disallows this.
-
- To support advanced file functionality, there are several directory
- parameters. The multiple parameters are necessary to support saving an
- instance's state many times, or saving states from multiple instances, while
- avoiding any duplication of data. For example, a host could pass the same
- `copy_dir` and `link_dir` for all plugins in a session (for example
- `session/shared/copy/` `session/shared/link/`), while the `save_dir` would
- be unique to each plugin instance (for example `session/states/state1.lv2`
- for one instance and `session/states/state2.lv2` for another instance).
- Simple hosts that only wish to save a single plugin's state once may simply
- use the same directory for all of them, or pass NULL to not support files at
- all.
-
- If supported (via state:makePath passed to LV2_Descriptor::instantiate()),
- `scratch_dir` should be the directory where any files created by the plugin
- (for example during instantiation or while running) are stored. Any files
- here that are referred to in the state will be copied to preserve their
- contents at the time of the save. Lilv will assume any files within this
- directory (recursively) are created by the plugin and that all other files
- are immutable. Note that this function does not completely save the state,
- use lilv_state_save() for that.
-
- See <a href="http://lv2plug.in/ns/ext/state/state.h">state.h</a> from the
- LV2 State extension for details on the `flags` and `features` parameters.
*/
-LILV_API LilvState*
-lilv_state_new_from_instance(const LilvPlugin* plugin,
- LilvInstance* instance,
- LV2_URID_Map* map,
- const char* scratch_dir,
- const char* copy_dir,
- const char* link_dir,
- const char* save_dir,
- LilvGetPortValueFunc get_value,
- void* user_data,
- uint32_t flags,
- const LV2_Feature *const * features);
+LILV_API
+LilvState*
+lilv_state_new_from_instance(const LilvPlugin* plugin,
+ LilvInstance* instance,
+ LV2_URID_Map* map,
+ const char* scratch_dir,
+ const char* copy_dir,
+ const char* link_dir,
+ const char* save_dir,
+ LilvGetPortValueFunc get_value,
+ void* user_data,
+ uint32_t flags,
+ const LV2_Feature* const* features);
/**
Free `state`.
*/
-LILV_API void
+LILV_API
+void
lilv_state_free(LilvState* state);
/**
Return true iff `a` is equivalent to `b`.
*/
-LILV_API bool
+LILV_API
+bool
lilv_state_equals(const LilvState* a, const LilvState* b);
/**
Return the number of properties in `state`.
*/
-LILV_API unsigned
+LILV_API
+unsigned
lilv_state_get_num_properties(const LilvState* state);
/**
Get the URI of the plugin `state` applies to.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_state_get_plugin_uri(const LilvState* state);
/**
@@ -1397,37 +1579,41 @@ lilv_state_get_plugin_uri(const LilvState* state);
This may return NULL if the state has not been saved and has no URI.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_state_get_uri(const LilvState* state);
/**
Get the label of `state`.
*/
-LILV_API const char*
+LILV_API
+const char*
lilv_state_get_label(const LilvState* state);
/**
Set the label of `state`.
*/
-LILV_API void
-lilv_state_set_label(LilvState* state,
- const char* label);
+LILV_API
+void
+lilv_state_set_label(LilvState* state, const char* label);
/**
Set a metadata property on `state`.
+
+ 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.
+
@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.
+ @return Zero on success.
*/
-LILV_API int
+LILV_API
+int
lilv_state_set_metadata(LilvState* state,
uint32_t key,
const void* value,
@@ -1437,6 +1623,7 @@ lilv_state_set_metadata(LilvState* state,
/**
Function to set a port value.
+
@param port_symbol The symbol of the port.
@param user_data The user_data passed to lilv_state_restore().
@param size The size of `value`.
@@ -1451,28 +1638,24 @@ typedef void (*LilvSetPortValueFunc)(const char* port_symbol,
/**
Enumerate the port values in a state snapshot.
- @param state The state to retrieve port values from.
- @param set_value A function to receive port values.
- @param user_data User data to pass to `set_value`.
This function is a subset of lilv_state_restore() that only fires the
`set_value` callback and does not directly affect a plugin instance. This
is useful in hosts that need to retrieve the port values in a state snapshot
for special handling.
+
+ @param state The state to retrieve port values from.
+ @param set_value A function to receive port values.
+ @param user_data User data to pass to `set_value`.
*/
-LILV_API void
+LILV_API
+void
lilv_state_emit_port_values(const LilvState* state,
LilvSetPortValueFunc set_value,
void* user_data);
/**
Restore a plugin instance from a state snapshot.
- @param state The state to restore, which must apply to the correct plugin.
- @param instance An instance of the plugin `state` applies to, or NULL.
- @param set_value A function to set a port value (may be NULL).
- @param user_data User data to pass to `set_value`.
- @param flags Bitwise OR of LV2_State_Flags values.
- @param features Features to pass LV2_State_Interface.restore().
This will set all the properties of `instance`, if given, to the values
stored in `state`. If `set_value` is provided, it will be called (with the
@@ -1481,23 +1664,39 @@ lilv_state_emit_port_values(const LilvState* state,
to completely restore `state`.
If the state has properties and `instance` is given, this function is in
- the "instantiation" threading class, i.e. it MUST NOT be called
+ the "instantiation" threading class, so it MUST NOT be called
simultaneously with any function on the same plugin instance. If the state
has no properties, only port values are set via `set_value`.
See <a href="http://lv2plug.in/ns/ext/state/state.h">state.h</a> from the
LV2 State extension for details on the `flags` and `features` parameters.
+
+ @param state The state to restore, which must apply to the correct plugin.
+ @param instance An instance of the plugin `state` applies to, or NULL.
+ @param set_value A function to set a port value (may be NULL).
+ @param user_data User data to pass to `set_value`.
+ @param flags Bitwise OR of LV2_State_Flags values.
+ @param features Features to pass LV2_State_Interface.restore().
*/
-LILV_API void
-lilv_state_restore(const LilvState* state,
- LilvInstance* instance,
- LilvSetPortValueFunc set_value,
- void* user_data,
- uint32_t flags,
- const LV2_Feature *const * features);
+LILV_API
+void
+lilv_state_restore(const LilvState* state,
+ LilvInstance* instance,
+ LilvSetPortValueFunc set_value,
+ void* user_data,
+ uint32_t flags,
+ const LV2_Feature* const* features);
/**
Save state to a file.
+
+ The format of state on disk is compatible with that defined in the LV2
+ preset extension, so this function may be used to save presets which can
+ be loaded by any host.
+
+ If `uri` is NULL, the preset URI will be a file URI, but the bundle
+ can safely be moved (the state file will use `<>` as the subject).
+
@param world The world.
@param map URID mapper.
@param unmap URID unmapper.
@@ -1505,36 +1704,38 @@ lilv_state_restore(const LilvState* state,
@param uri URI of state, may be NULL.
@param dir Path of the bundle directory to save into.
@param filename Path of the state file relative to `dir`.
-
- The format of state on disk is compatible with that defined in the LV2
- preset extension, i.e. this function may be used to save presets which can
- be loaded by any host.
-
- If `uri` is NULL, the preset URI will be a file URI, but the bundle
- can safely be moved (i.e. the state file will use "<>" as the subject).
*/
-LILV_API int
-lilv_state_save(LilvWorld* world,
- LV2_URID_Map* map,
- LV2_URID_Unmap* unmap,
- const LilvState* state,
- const char* uri,
- const char* dir,
- const char* filename);
+LILV_API
+int
+lilv_state_save(LilvWorld* world,
+ LV2_URID_Map* map,
+ LV2_URID_Unmap* unmap,
+ const LilvState* state,
+ const char* uri,
+ const char* dir,
+ const char* filename);
/**
- Save state to a string. This function does not use the filesystem.
+ Save state to a string.
+
+ This function does not use the filesystem.
@param world The world.
+
@param map URID mapper.
+
@param unmap URID unmapper.
+
@param state The state to serialize.
+
@param uri URI for the state description (mandatory).
+
@param base_uri Base URI for serialisation. Unless you know what you are
doing, pass NULL for this, otherwise the state may not be restorable via
lilv_state_new_from_string().
*/
-LILV_API char*
+LILV_API
+char*
lilv_state_to_string(LilvWorld* world,
LV2_URID_Map* map,
LV2_URID_Unmap* unmap,
@@ -1544,8 +1745,6 @@ lilv_state_to_string(LilvWorld* world,
/**
Unload a state from the world and delete all associated files.
- @param world The world.
- @param state State to remove from the system.
This function DELETES FILES/DIRECTORIES FROM THE FILESYSTEM! It is intended
for removing user-saved presets, but can delete any state the user has
@@ -1555,69 +1754,84 @@ lilv_state_to_string(LilvWorld* world,
bundle's manifest.ttl is removed, and if this results in an empty manifest,
then the manifest file is removed. If this results in an empty bundle, then
the bundle directory is removed as well.
+
+ @param world The world.
+ @param state State to remove from the system.
*/
-LILV_API int
-lilv_state_delete(LilvWorld* world,
- const LilvState* state);
+LILV_API
+int
+lilv_state_delete(LilvWorld* world, const LilvState* state);
/**
@}
- @name Scale Point
+ @defgroup lilv_scalepoint Scale Points
@{
*/
/**
- Get the label of this scale point (enumeration value)
+ Get the label of this scale point (enumeration value).
+
Returned value is owned by `point` and must not be freed.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_scale_point_get_label(const LilvScalePoint* point);
/**
- Get the value of this scale point (enumeration value)
+ Get the value of this scale point (enumeration value).
+
Returned value is owned by `point` and must not be freed.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_scale_point_get_value(const LilvScalePoint* point);
/**
@}
- @name Plugin Class
+ @defgroup lilv_class Plugin Classes
@{
*/
/**
Get the URI of this class' superclass.
+
Returned value is owned by `plugin_class` and must not be freed by caller.
Returned value may be NULL, if class has no parent.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_plugin_class_get_parent_uri(const LilvPluginClass* plugin_class);
/**
Get the URI of this plugin class.
+
Returned value is owned by `plugin_class` and must not be freed by caller.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_plugin_class_get_uri(const LilvPluginClass* plugin_class);
/**
- Get the label of this plugin class, ie "Oscillators".
+ Get the label of this plugin class, like "Oscillators".
+
Returned value is owned by `plugin_class` and must not be freed by caller.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_plugin_class_get_label(const LilvPluginClass* plugin_class);
/**
Get the subclasses of this plugin class.
+
Returned value must be freed by caller with lilv_plugin_classes_free().
*/
-LILV_API LilvPluginClasses*
+LILV_API
+LilvPluginClasses*
lilv_plugin_class_get_children(const LilvPluginClass* plugin_class);
/**
@}
- @name Plugin Instance
+ @defgroup lilv_instance Plugin Instances
@{
*/
@@ -1626,6 +1840,7 @@ lilv_plugin_class_get_children(const LilvPluginClass* plugin_class);
*/
/* Instance of a plugin.
+
This is exposed in the ABI to allow inlining of performance critical
functions like lilv_instance_run() (simple wrappers of functions in lv2.h).
This is for performance reasons, user code should not use this definition
@@ -1633,9 +1848,9 @@ lilv_plugin_class_get_children(const LilvPluginClass* plugin_class);
Truly private implementation details are hidden via `pimpl`.
*/
struct LilvInstanceImpl {
- const LV2_Descriptor* lv2_descriptor;
- LV2_Handle lv2_handle;
- void* pimpl;
+ const LV2_Descriptor* lv2_descriptor;
+ LV2_Handle lv2_handle;
+ void* pimpl;
};
/**
@@ -1644,173 +1859,222 @@ struct LilvInstanceImpl {
/**
Instantiate a plugin.
+
The returned value is a lightweight handle for an LV2 plugin instance,
it does not refer to `plugin`, or any other Lilv state. The caller must
eventually free it with lilv_instance_free().
`features` is a NULL-terminated array of features the host supports.
NULL may be passed if the host supports no additional features.
+
+ This function is in the "discovery" threading class: it isn't real-time
+ safe, and may not be called concurrently with itself for the same plugin.
+
@return NULL if instantiation failed.
*/
-LILV_API LilvInstance*
-lilv_plugin_instantiate(const LilvPlugin* plugin,
- double sample_rate,
- const LV2_Feature*const* features);
+LILV_API
+LilvInstance*
+lilv_plugin_instantiate(const LilvPlugin* plugin,
+ double sample_rate,
+ const LV2_Feature* const* features);
/**
Free a plugin instance.
- It is safe to call this function on NULL.
- `instance` is invalid after this call.
+
+ It is safe to call this function on NULL. The `instance` is invalid after
+ this call.
+
+ This function is in the "discovery" threading class: it isn't real-time
+ safe, and may not be called concurrently with any other function for the
+ same instance, or with lilv_plugin_instantiate() for the same plugin.
*/
-LILV_API void
+LILV_API
+void
lilv_instance_free(LilvInstance* instance);
#ifndef LILV_INTERNAL
/**
Get the URI of the plugin which `instance` is an instance of.
- Returned string is shared and must not be modified or deleted.
+
+ This function is a simple accessor and may be called at any time. The
+ returned string is shared and must not be modified or deleted.
*/
static inline const char*
lilv_instance_get_uri(const LilvInstance* instance)
{
- return instance->lv2_descriptor->URI;
+ return instance->lv2_descriptor->URI;
}
/**
Connect a port to a data location.
+
This may be called regardless of whether the plugin is activated,
activation and deactivation does not destroy port connections.
+
+ This function is in the "audio" threading class: it's real-time safe if the
+ plugin is <http://lv2plug.in/ns/lv2core#hardRTCapable>, but may not be
+ called concurrently with any other function for the same instance.
*/
static inline void
lilv_instance_connect_port(LilvInstance* instance,
uint32_t port_index,
void* data_location)
{
- instance->lv2_descriptor->connect_port
- (instance->lv2_handle, port_index, data_location);
+ instance->lv2_descriptor->connect_port(
+ instance->lv2_handle, port_index, data_location);
}
/**
Activate a plugin instance.
+
This resets all state information in the plugin, except for port data
locations (as set by lilv_instance_connect_port()). This MUST be called
before calling lilv_instance_run().
+
+ This function is in the "instantiation" threading class: it isn't real-time
+ safe, and may not be called concurrently with any other function for the
+ same instance.
*/
static inline void
lilv_instance_activate(LilvInstance* instance)
{
- if (instance->lv2_descriptor->activate) {
- instance->lv2_descriptor->activate(instance->lv2_handle);
- }
+ if (instance->lv2_descriptor->activate) {
+ instance->lv2_descriptor->activate(instance->lv2_handle);
+ }
}
/**
Run `instance` for `sample_count` frames.
+
If the hint lv2:hardRTCapable is set for this plugin, this function is
guaranteed not to block.
+
+ This function is in the "audio" threading class: it's real-time safe if the
+ plugin is <http://lv2plug.in/ns/lv2core#hardRTCapable>, but may not be
+ called concurrently with any other function for the same instance.
*/
static inline void
-lilv_instance_run(LilvInstance* instance,
- uint32_t sample_count)
+lilv_instance_run(LilvInstance* instance, uint32_t sample_count)
{
- instance->lv2_descriptor->run(instance->lv2_handle, sample_count);
+ instance->lv2_descriptor->run(instance->lv2_handle, sample_count);
}
/**
Deactivate a plugin instance.
+
Note that to run the plugin after this you must activate it, which will
reset all state information (except port connections).
+
+ This function is in the "instantiation" threading class: it isn't real-time
+ safe and may not be called concurrently with any other function for the same
+ instance.
*/
static inline void
lilv_instance_deactivate(LilvInstance* instance)
{
- if (instance->lv2_descriptor->deactivate) {
- instance->lv2_descriptor->deactivate(instance->lv2_handle);
- }
+ if (instance->lv2_descriptor->deactivate) {
+ instance->lv2_descriptor->deactivate(instance->lv2_handle);
+ }
}
/**
Get extension data from the plugin instance.
+
The type and semantics of the data returned is specific to the particular
extension, though in all cases it is shared and must not be deleted.
+
+ This function is in the "discovery" threading class: it isn't real-time safe
+ and may not be called concurrently with any other function for the same
+ instance.
*/
static inline const void*
-lilv_instance_get_extension_data(const LilvInstance* instance,
- const char* uri)
+lilv_instance_get_extension_data(const LilvInstance* instance, const char* uri)
{
- if (instance->lv2_descriptor->extension_data) {
- return instance->lv2_descriptor->extension_data(uri);
- } else {
- return NULL;
- }
+ if (instance->lv2_descriptor->extension_data) {
+ return instance->lv2_descriptor->extension_data(uri);
+ }
+
+ return NULL;
}
/**
Get the LV2_Descriptor of the plugin instance.
+
Normally hosts should not need to access the LV2_Descriptor directly,
use the lilv_instance_* functions.
The returned descriptor is shared and must not be deleted.
+
+ This function is a simple accessor and may be called at any time.
*/
static inline const LV2_Descriptor*
lilv_instance_get_descriptor(const LilvInstance* instance)
{
- return instance->lv2_descriptor;
+ return instance->lv2_descriptor;
}
/**
Get the LV2_Handle of the plugin instance.
+
Normally hosts should not need to access the LV2_Handle directly,
use the lilv_instance_* functions.
The returned handle is shared and must not be deleted.
+
+ This function is a simple accessor and may be called at any time.
*/
static inline LV2_Handle
lilv_instance_get_handle(const LilvInstance* instance)
{
- return instance->lv2_handle;
+ return instance->lv2_handle;
}
#endif /* LILV_INTERNAL */
/**
@}
- @name Plugin UI
+ @defgroup lilv_ui Plugin UIs
@{
*/
/**
Get all UIs for `plugin`.
+
Returned value must be freed by caller using lilv_uis_free().
*/
-LILV_API LilvUIs*
+LILV_API
+LilvUIs*
lilv_plugin_get_uis(const LilvPlugin* plugin);
/**
Get the URI of a Plugin UI.
- @param ui The Plugin UI
- @return a shared value which must not be modified or freed.
+
+ @return A shared value which must not be modified or freed.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_ui_get_uri(const LilvUI* ui);
/**
Get the types (URIs of RDF classes) of a Plugin UI.
- @param ui The Plugin UI
- @return a shared value which must not be modified or freed.
Note that in most cases lilv_ui_is_supported() should be used, which avoids
the need to use this function (and type specific logic).
+
+ @return A shared value which must not be modified or freed.
*/
-LILV_API const LilvNodes*
+LILV_API
+const LilvNodes*
lilv_ui_get_classes(const LilvUI* ui);
/**
Check whether a plugin UI has a given type.
+
@param ui The Plugin UI
@param class_uri The URI of the LV2 UI type to check this UI against
*/
-LILV_API bool
+LILV_API
+bool
lilv_ui_is_a(const LilvUI* ui, const LilvNode* class_uri);
/**
@@ -1824,14 +2088,20 @@ typedef unsigned (*LilvUISupportedFunc)(const char* container_type_uri,
/**
Return true iff a Plugin UI is supported as a given widget type.
+
@param ui The Plugin UI
+
@param supported_func User provided supported predicate.
+
@param container_type The widget type to host the UI within.
+
@param ui_type (Output) If non-NULL, set to the native type of the UI
which is owned by `ui` and must not be freed by the caller.
+
@return The embedding quality level returned by `supported_func`.
*/
-LILV_API unsigned
+LILV_API
+unsigned
lilv_ui_is_supported(const LilvUI* ui,
LilvUISupportedFunc supported_func,
const LilvNode* container_type,
@@ -1839,18 +2109,20 @@ lilv_ui_is_supported(const LilvUI* ui,
/**
Get the URI for a Plugin UI's bundle.
- @param ui The Plugin UI
- @return a shared value which must not be modified or freed.
+
+ @return A shared value which must not be modified or freed.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_ui_get_bundle_uri(const LilvUI* ui);
/**
Get the URI for a Plugin UI's shared library.
- @param ui The Plugin UI
- @return a shared value which must not be modified or freed.
+
+ @return A shared value which must not be modified or freed.
*/
-LILV_API const LilvNode*
+LILV_API
+const LilvNode*
lilv_ui_get_binary_uri(const LilvUI* ui);
/**
@@ -1859,9 +2131,9 @@ lilv_ui_get_binary_uri(const LilvUI* ui);
*/
#ifdef __cplusplus
-# if defined(__clang__)
-# pragma clang diagnostic pop
-# endif
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
} /* extern "C" */
#endif
diff --git a/include/lilv/lilvmm.hpp b/include/lilv/lilvmm.hpp
new file mode 100644
index 0000000..6e270df
--- /dev/null
+++ b/include/lilv/lilvmm.hpp
@@ -0,0 +1,453 @@
+// Copyright 2007-2017 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#ifndef LILV_LILVMM_HPP
+#define LILV_LILVMM_HPP
+
+#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
+
+#include <cstdarg>
+#include <cstdint>
+
+namespace Lilv {
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__) && __GNUC__ > 4
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+struct Instance;
+struct Node;
+struct Nodes;
+struct Plugin;
+struct PluginClass;
+struct PluginClasses;
+struct Plugins;
+struct Port;
+struct ScalePoint;
+struct ScalePoints;
+struct UI;
+struct UIs;
+struct World;
+
+LILV_DEPRECATED
+static inline const char*
+uri_to_path(const char* uri)
+{
+ return lilv_uri_to_path(uri);
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__) && __GNUC__ > 4
+# pragma GCC diagnostic pop
+#endif
+
+#define LILV_WRAP0(RT, prefix, name) \
+ inline RT name() \
+ { \
+ return lilv_##prefix##_##name(me); \
+ }
+
+#define LILV_WRAP0_VOID(prefix, name) \
+ inline void name() \
+ { \
+ lilv_##prefix##_##name(me); \
+ }
+
+#define LILV_WRAP1(RT, prefix, name, T1, a1) \
+ inline RT name(T1 a1) \
+ { \
+ return lilv_##prefix##_##name(me, a1); \
+ }
+
+#define LILV_WRAP1_VOID(prefix, name, T1, a1) \
+ inline void name(T1 a1) \
+ { \
+ lilv_##prefix##_##name(me, a1); \
+ }
+
+#define LILV_WRAP2(RT, prefix, name, T1, a1, T2, a2) \
+ inline RT name(T1 a1, T2 a2) \
+ { \
+ return lilv_##prefix##_##name(me, a1, a2); \
+ }
+
+#define LILV_WRAP3(RT, prefix, name, T1, a1, T2, a2, T3, a3) \
+ inline RT name(T1 a1, T2 a2, T3 a3) \
+ { \
+ return lilv_##prefix##_##name(me, a1, a2, a3); \
+ }
+
+#define LILV_WRAP2_VOID(prefix, name, T1, a1, T2, a2) \
+ inline void name(T1 a1, T2 a2) \
+ { \
+ lilv_##prefix##_##name(me, a1, a2); \
+ }
+
+#ifndef SWIG
+# define LILV_WRAP_CONVERSION(CT) \
+ inline operator CT*() const \
+ { \
+ return me; \
+ }
+#else
+# define LILV_WRAP_CONVERSION(CT)
+#endif
+
+struct Node {
+ inline Node(const LilvNode* node)
+ : me(lilv_node_duplicate(node))
+ {}
+
+ inline Node(const Node& copy)
+ : me(lilv_node_duplicate(copy.me))
+ {}
+
+ inline Node& operator=(const Node& rhs)
+ {
+ if (&rhs != this) {
+ lilv_node_free(me);
+ me = lilv_node_duplicate(rhs.me);
+ }
+ return *this;
+ }
+
+ inline Node(Node&& other) noexcept
+ : me(other.me)
+ {
+ other.me = nullptr;
+ }
+
+ inline Node& operator=(Node&& rhs) noexcept
+ {
+ if (&rhs != this) {
+ me = rhs.me;
+ rhs.me = nullptr;
+ }
+ return *this;
+ }
+
+ inline ~Node() { lilv_node_free(me); }
+
+ inline bool equals(const Node& other) const
+ {
+ return lilv_node_equals(me, other.me);
+ }
+
+ inline bool operator==(const Node& other) const { return equals(other); }
+
+ LILV_WRAP_CONVERSION(LilvNode)
+
+ LILV_WRAP0(char*, node, get_turtle_token)
+ LILV_WRAP0(bool, node, is_uri)
+ LILV_WRAP0(const char*, node, as_uri)
+ LILV_WRAP0(bool, node, is_blank)
+ LILV_WRAP0(const char*, node, as_blank)
+ LILV_WRAP0(bool, node, is_literal)
+ LILV_WRAP0(bool, node, is_string)
+ LILV_WRAP0(const char*, node, as_string)
+ LILV_WRAP0(bool, node, is_float)
+ LILV_WRAP0(float, node, as_float)
+ LILV_WRAP0(bool, node, is_int)
+ LILV_WRAP0(int, node, as_int)
+ LILV_WRAP0(bool, node, is_bool)
+ LILV_WRAP0(bool, node, as_bool)
+
+ LilvNode* me;
+};
+
+struct ScalePoint {
+ inline ScalePoint(const LilvScalePoint* c_obj)
+ : me(c_obj)
+ {}
+
+ LILV_WRAP_CONVERSION(const LilvScalePoint)
+
+ LILV_WRAP0(const LilvNode*, scale_point, get_label)
+ LILV_WRAP0(const LilvNode*, scale_point, get_value)
+
+ const LilvScalePoint* me;
+};
+
+struct PluginClass {
+ inline PluginClass(const LilvPluginClass* c_obj)
+ : me(c_obj)
+ {}
+
+ LILV_WRAP_CONVERSION(const LilvPluginClass)
+
+ LILV_WRAP0(Node, plugin_class, get_parent_uri)
+ LILV_WRAP0(Node, plugin_class, get_uri)
+ LILV_WRAP0(Node, plugin_class, get_label)
+ LILV_WRAP0(LilvPluginClasses*, plugin_class, get_children)
+
+ const LilvPluginClass* me;
+};
+
+#define LILV_WRAP_COLL(CT, ET, prefix) \
+ inline CT(const Lilv##CT* c_obj) \
+ : me(c_obj) \
+ {} \
+ LILV_WRAP_CONVERSION(const Lilv##CT) \
+ LILV_WRAP0(unsigned, prefix, size) \
+ LILV_WRAP1(ET, prefix, get, LilvIter*, i) \
+ LILV_WRAP0(LilvIter*, prefix, begin) \
+ LILV_WRAP1(LilvIter*, prefix, next, LilvIter*, i) \
+ LILV_WRAP1(bool, prefix, is_end, LilvIter*, i) \
+ const Lilv##CT* me;
+
+struct PluginClasses {
+ LILV_WRAP_COLL(PluginClasses, PluginClass, plugin_classes)
+ LILV_WRAP1(PluginClass, plugin_classes, get_by_uri, const LilvNode*, uri)
+};
+
+struct ScalePoints {
+ LILV_WRAP_COLL(ScalePoints, ScalePoint, scale_points)
+};
+
+struct Nodes {
+ LILV_WRAP_COLL(Nodes, Node, nodes)
+ LILV_WRAP1(bool, nodes, contains, const Node&, node)
+ LILV_WRAP0(Node, nodes, get_first)
+};
+
+struct UI {
+ inline UI(const LilvUI* c_obj)
+ : me(c_obj)
+ {}
+
+ LILV_WRAP_CONVERSION(const LilvUI)
+
+ LILV_WRAP0(const LilvNode*, ui, get_uri)
+ LILV_WRAP0(const LilvNode*, ui, get_bundle_uri)
+ LILV_WRAP0(const LilvNode*, ui, get_binary_uri)
+ LILV_WRAP0(const LilvNodes*, ui, get_classes)
+ /*LILV_WRAP3(bool, ui, is_supported,
+ LilvUISupportedFunc, supported_func,
+ const LilvNode*, container_type,
+ const LilvNode**, ui_type);*/
+ LILV_WRAP1(bool, ui, is_a, const LilvNode*, class_uri)
+
+ const LilvUI* me;
+};
+
+struct UIs {
+ LILV_WRAP_COLL(UIs, UI, uis)
+};
+
+struct Port {
+ inline Port(const LilvPlugin* p, const LilvPort* c_obj)
+ : parent(p)
+ , me(c_obj)
+ {}
+
+ LILV_WRAP_CONVERSION(const LilvPort)
+
+#define LILV_PORT_WRAP0(RT, name) \
+ inline RT name() \
+ { \
+ return lilv_port_##name(parent, me); \
+ }
+
+#define LILV_PORT_WRAP1(RT, name, T1, a1) \
+ inline RT name(T1 a1) \
+ { \
+ return lilv_port_##name(parent, me, a1); \
+ }
+
+ LILV_PORT_WRAP1(LilvNodes*, get_value, LilvNode*, predicate)
+ LILV_PORT_WRAP0(LilvNodes*, get_properties)
+ LILV_PORT_WRAP1(bool, has_property, LilvNode*, property_uri)
+ LILV_PORT_WRAP1(bool, supports_event, LilvNode*, event_uri)
+ LILV_PORT_WRAP0(const LilvNode*, get_symbol)
+ LILV_PORT_WRAP0(LilvNode*, get_name)
+ LILV_PORT_WRAP0(const LilvNodes*, get_classes)
+ LILV_PORT_WRAP1(bool, is_a, LilvNode*, port_class)
+ LILV_PORT_WRAP0(LilvScalePoints*, get_scale_points)
+
+ // TODO: get_range (output parameters)
+
+ const LilvPlugin* parent;
+ const LilvPort* me;
+};
+
+struct Plugin {
+ inline Plugin(const LilvPlugin* c_obj)
+ : me(c_obj)
+ {}
+
+ LILV_WRAP_CONVERSION(const LilvPlugin)
+
+ LILV_WRAP0(bool, plugin, verify)
+ LILV_WRAP0(Node, plugin, get_uri)
+ LILV_WRAP0(Node, plugin, get_bundle_uri)
+ LILV_WRAP0(Nodes, plugin, get_data_uris)
+ LILV_WRAP0(Node, plugin, get_library_uri)
+ LILV_WRAP0(Node, plugin, get_name)
+ LILV_WRAP0(PluginClass, plugin, get_class)
+ LILV_WRAP1(Nodes, plugin, get_value, const Node&, pred)
+ LILV_WRAP1(bool, plugin, has_feature, const Node&, feature_uri)
+ LILV_WRAP0(Nodes, plugin, get_supported_features)
+ LILV_WRAP0(Nodes, plugin, get_required_features)
+ LILV_WRAP0(Nodes, plugin, get_optional_features)
+ LILV_WRAP0(unsigned, plugin, get_num_ports)
+ LILV_WRAP0(bool, plugin, has_latency)
+ LILV_WRAP0(unsigned, plugin, get_latency_port_index)
+ LILV_WRAP0(Node, plugin, get_author_name)
+ LILV_WRAP0(Node, plugin, get_author_email)
+ LILV_WRAP0(Node, plugin, get_author_homepage)
+ LILV_WRAP0(bool, plugin, is_replaced)
+ LILV_WRAP0(Nodes, plugin, get_extension_data)
+ LILV_WRAP0(UIs, plugin, get_uis)
+ LILV_WRAP1(Nodes, plugin, get_related, const Node&, type)
+
+ inline Port get_port_by_index(unsigned index) const
+ {
+ return Port(me, lilv_plugin_get_port_by_index(me, index));
+ }
+
+ inline Port get_port_by_symbol(LilvNode* symbol) const
+ {
+ return Port(me, lilv_plugin_get_port_by_symbol(me, symbol));
+ }
+
+ inline void get_port_ranges_float(float* min_values,
+ float* max_values,
+ float* def_values) const
+ {
+ return lilv_plugin_get_port_ranges_float(
+ me, min_values, max_values, def_values);
+ }
+
+ inline unsigned get_num_ports_of_class(LilvNode* class_1, ...) const
+ {
+ va_list args; // NOLINT(cppcoreguidelines-init-variables)
+ va_start(args, class_1);
+
+ const uint32_t count =
+ lilv_plugin_get_num_ports_of_class_va(me, class_1, args);
+
+ va_end(args);
+ return count;
+ }
+
+ const LilvPlugin* me;
+};
+
+struct Plugins {
+ LILV_WRAP_COLL(Plugins, Plugin, plugins)
+ LILV_WRAP1(Plugin, plugins, get_by_uri, const LilvNode*, uri)
+};
+
+struct Instance {
+ inline Instance(LilvInstance* instance)
+ : me(instance)
+ {}
+
+ LILV_DEPRECATED
+ inline Instance(Plugin plugin, double sample_rate)
+ : me(lilv_plugin_instantiate(plugin, sample_rate, nullptr))
+ {}
+
+ LILV_DEPRECATED
+ inline Instance(Plugin plugin,
+ double sample_rate,
+ LV2_Feature* const* features)
+ : me(lilv_plugin_instantiate(plugin, sample_rate, features))
+ {}
+
+ static inline Instance* create(Plugin plugin,
+ double sample_rate,
+ LV2_Feature* const* features)
+ {
+ LilvInstance* me = lilv_plugin_instantiate(plugin, sample_rate, features);
+
+ return me ? new Instance(me) : nullptr;
+ }
+
+ LILV_WRAP_CONVERSION(LilvInstance)
+
+ LILV_WRAP2_VOID(instance,
+ connect_port,
+ unsigned,
+ port_index,
+ void*,
+ data_location)
+
+ LILV_WRAP0_VOID(instance, activate)
+ LILV_WRAP1_VOID(instance, run, unsigned, sample_count)
+ LILV_WRAP0_VOID(instance, deactivate)
+
+ inline const void* get_extension_data(const char* uri) const
+ {
+ return lilv_instance_get_extension_data(me, uri);
+ }
+
+ inline const LV2_Descriptor* get_descriptor() const
+ {
+ return lilv_instance_get_descriptor(me);
+ }
+
+ inline LV2_Handle get_handle() const { return lilv_instance_get_handle(me); }
+
+ LilvInstance* me;
+};
+
+struct World {
+ inline World()
+ : me(lilv_world_new())
+ {}
+
+ inline ~World() { lilv_world_free(me); }
+
+ World(const World&) = delete;
+ World& operator=(const World&) = delete;
+
+ World(World&&) = delete;
+ World& operator=(World&&) = delete;
+
+ inline LilvNode* new_uri(const char* uri) const
+ {
+ return lilv_new_uri(me, uri);
+ }
+
+ inline LilvNode* new_string(const char* str) const
+ {
+ return lilv_new_string(me, str);
+ }
+
+ inline LilvNode* new_int(int val) const { return lilv_new_int(me, val); }
+
+ inline LilvNode* new_float(float val) const
+ {
+ return lilv_new_float(me, val);
+ }
+
+ inline LilvNode* new_bool(bool val) const { return lilv_new_bool(me, val); }
+
+ inline Nodes find_nodes(const LilvNode* subject,
+ const LilvNode* predicate,
+ const LilvNode* object) const
+ {
+ return lilv_world_find_nodes(me, subject, predicate, object);
+ }
+
+ LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value)
+ LILV_WRAP0_VOID(world, load_all)
+ LILV_WRAP1_VOID(world, load_bundle, LilvNode*, bundle_uri)
+ LILV_WRAP0(const LilvPluginClass*, world, get_plugin_class)
+ LILV_WRAP0(const LilvPluginClasses*, world, get_plugin_classes)
+ LILV_WRAP0(Plugins, world, get_all_plugins)
+ LILV_WRAP1(int, world, load_resource, const LilvNode*, resource)
+
+ LilvWorld* me;
+};
+
+} /* namespace Lilv */
+
+#endif /* LILV_LILVMM_HPP */
diff --git a/lilv.pc.in b/lilv.pc.in
deleted file mode 100644
index 97f4f8c..0000000
--- a/lilv.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@PREFIX@
-exec_prefix=@EXEC_PREFIX@
-libdir=@LIBDIR@
-includedir=@INCLUDEDIR@
-
-Name: Lilv
-Version: @LILV_VERSION@
-Description: Simple C library for hosting LV2 plugins
-Requires: @LILV_PKG_DEPS@
-Libs: -L${libdir} -l@LIB_LILV@ @LILV_PKG_LIBS@
-Cflags: -I${includedir}/lilv-@LILV_MAJOR_VERSION@
diff --git a/lilv.ttl b/lilv.ttl
index edfb0e5..9bdd56d 100644
--- a/lilv.ttl
+++ b/lilv.ttl
@@ -1,29 +1,29 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-@prefix : <http://usefulinc.com/ns/doap#> .
+@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
-<http://drobilla.net/software/lilv>
- a :Project ;
- :bug-database <http://dev.drobilla.net/query?status=new&status=assigned&status=reopened&component=LILV&order=priority> ;
- :developer [
- a foaf:Person ;
- rdfs:seeAlso <http://drobilla.net/drobilla.rdf> ;
- foaf:homepage <http://drobilla.net> ;
- foaf:mbox_sha1sum "253b3c58086250260bac1232d744d150274ad308" ;
- foaf:name "David Robillard"
- ] ;
- :download-page <http://download.drobilla.net> ;
- :homepage <http://drobilla.net/software/lilv> ;
- :license <http://usefulinc.com/doap/licenses/gpl> ;
- :name "LILV" ;
- :programming-language "C", "Turtle" ;
- :repository [
- :browse <http://dev.drobilla.net/browser/trunk/lilv> ;
- :location <http://svn.drobilla.net/lad/trunk/lilv> ;
- a :SVNRepository
- ] ;
- :shortdesc "Library for simple use of LV2 plugins" ;
- :shortname "LILV" .
-
+<http://drobilla.net/drobilla#me>
+ a foaf:Person ;
+ rdfs:seeAlso <http://drobilla.net/drobilla> ;
+ foaf:mbox <mailto:d@drobilla.net> ;
+ foaf:name "David Robillard" ;
+ foaf:nick "drobilla" .
+<http://drobilla.net/software/lilv>
+ a doap:Project ;
+ doap:blog <https://drobilla.net/category/lilv/> ;
+ doap:bug-database <https://gitlab.com/lv2/lilv/issues> ;
+ doap:description "C library for hosting LV2 plugins" ;
+ doap:developer <http://drobilla.net/drobilla#me> ;
+ doap:download-page <http://download.drobilla.net/> ;
+ doap:homepage <http://drobilla.net/software/lilv> ;
+ doap:implements <http://lv2plug.in/ns/lv2core> ;
+ doap:license <http://opensource.org/licenses/isc> ;
+ doap:maintainer <http://drobilla.net/drobilla#me> ;
+ doap:name "Lilv" ;
+ doap:programming-language "C" ;
+ doap:repository [
+ a doap:GitBranch ;
+ doap:location <https://gitlab.com/lv2/lilv.git>
+ ] .
diff --git a/lilv/lilvmm.hpp b/lilv/lilvmm.hpp
deleted file mode 100644
index 4a90e6d..0000000
--- a/lilv/lilvmm.hpp
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- Copyright 2007-2017 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.
-*/
-
-#ifndef LILV_LILVMM_HPP
-#define LILV_LILVMM_HPP
-
-#include "lilv/lilv.h"
-
-namespace Lilv {
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(__GNUC__) && __GNUC__ > 4
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-LILV_DEPRECATED
-static inline const char*
-uri_to_path(const char* uri) {
- return lilv_uri_to_path(uri);
-}
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#elif defined(__GNUC__) && __GNUC__ > 4
-# pragma GCC diagnostic pop
-#endif
-
-#define LILV_WRAP0(RT, prefix, name) \
- inline RT name() { return lilv_ ## prefix ## _ ## name (me); }
-
-#define LILV_WRAP0_VOID(prefix, name) \
- inline void name() { lilv_ ## prefix ## _ ## name(me); }
-
-#define LILV_WRAP1(RT, prefix, name, T1, a1) \
- inline RT name(T1 a1) { return lilv_ ## prefix ## _ ## name (me, a1); }
-
-#define LILV_WRAP1_VOID(prefix, name, T1, a1) \
- inline void name(T1 a1) { lilv_ ## prefix ## _ ## name(me, a1); }
-
-#define LILV_WRAP2(RT, prefix, name, T1, a1, T2, a2) \
- inline RT name(T1 a1, T2 a2) { \
- return lilv_ ## prefix ## _ ## name(me, a1, a2); \
- }
-
-#define LILV_WRAP3(RT, prefix, name, T1, a1, T2, a2, T3, a3) \
- inline RT name(T1 a1, T2 a2, T3 a3) { \
- return lilv_ ## prefix ## _ ## name(me, a1, a2, a3); \
- }
-
-#define LILV_WRAP2_VOID(prefix, name, T1, a1, T2, a2) \
- inline void name(T1 a1, T2 a2) { lilv_ ## prefix ## _ ## name(me, a1, a2); }
-
-#ifndef SWIG
-#define LILV_WRAP_CONVERSION(CT) \
- inline operator CT*() const { return me; }
-#else
-#define LILV_WRAP_CONVERSION(CT)
-#endif
-
-struct Node {
- inline Node(const LilvNode* node) : me(lilv_node_duplicate(node)) {}
- inline Node(const Node& copy) : me(lilv_node_duplicate(copy.me)) {}
-
- inline ~Node() { lilv_node_free(me); }
-
- inline bool equals(const Node& other) const {
- return lilv_node_equals(me, other.me);
- }
-
- inline bool operator==(const Node& other) const { return equals(other); }
-
- LILV_WRAP_CONVERSION(LilvNode);
-
- LILV_WRAP0(char*, node, get_turtle_token);
- LILV_WRAP0(bool, node, is_uri);
- LILV_WRAP0(const char*, node, as_uri);
- LILV_WRAP0(bool, node, is_blank);
- LILV_WRAP0(const char*, node, as_blank);
- LILV_WRAP0(bool, node, is_literal);
- LILV_WRAP0(bool, node, is_string);
- LILV_WRAP0(const char*, node, as_string);
- LILV_WRAP0(bool, node, is_float);
- LILV_WRAP0(float, node, as_float);
- LILV_WRAP0(bool, node, is_int);
- LILV_WRAP0(int, node, as_int);
- LILV_WRAP0(bool, node, is_bool);
- LILV_WRAP0(bool, node, as_bool);
-
- LilvNode* me;
-};
-
-struct ScalePoint {
- inline ScalePoint(const LilvScalePoint* c_obj) : me(c_obj) {}
- LILV_WRAP_CONVERSION(const LilvScalePoint);
-
- LILV_WRAP0(const LilvNode*, scale_point, get_label);
- LILV_WRAP0(const LilvNode*, scale_point, get_value);
-
- const LilvScalePoint* me;
-};
-
-struct PluginClass {
- inline PluginClass(const LilvPluginClass* c_obj) : me(c_obj) {}
- LILV_WRAP_CONVERSION(const LilvPluginClass);
-
- LILV_WRAP0(Node, plugin_class, get_parent_uri);
- LILV_WRAP0(Node, plugin_class, get_uri);
- LILV_WRAP0(Node, plugin_class, get_label);
- LILV_WRAP0(LilvPluginClasses*, plugin_class, get_children);
-
- const LilvPluginClass* me;
-};
-
-#define LILV_WRAP_COLL(CT, ET, prefix) \
- inline CT(const Lilv ## CT* c_obj) : me(c_obj) {} \
- LILV_WRAP_CONVERSION(const Lilv ## CT); \
- LILV_WRAP0(unsigned, prefix, size); \
- LILV_WRAP1(const ET, prefix, get, LilvIter*, i); \
- LILV_WRAP0(LilvIter*, prefix, begin); \
- LILV_WRAP1(LilvIter*, prefix, next, LilvIter*, i); \
- LILV_WRAP1(bool, prefix, is_end, LilvIter*, i); \
- const Lilv ## CT* me; \
-
-struct PluginClasses {
- LILV_WRAP_COLL(PluginClasses, PluginClass, plugin_classes);
- LILV_WRAP1(const PluginClass, plugin_classes,
- get_by_uri, const LilvNode*, uri);
-};
-
-struct ScalePoints {
- LILV_WRAP_COLL(ScalePoints, ScalePoint, scale_points);
-};
-
-struct Nodes {
- LILV_WRAP_COLL(Nodes, Node, nodes);
- LILV_WRAP1(bool, nodes, contains, const Node, node);
- LILV_WRAP0(Node, nodes, get_first);
-};
-
-struct UI {
- inline UI(const LilvUI* c_obj) : me(c_obj) {}
- LILV_WRAP_CONVERSION(const LilvUI);
-
- LILV_WRAP0(const LilvNode*, ui, get_uri);
- LILV_WRAP0(const LilvNode*, ui, get_bundle_uri);
- LILV_WRAP0(const LilvNode*, ui, get_binary_uri);
- LILV_WRAP0(const LilvNodes*, ui, get_classes);
- /*LILV_WRAP3(bool, ui, is_supported,
- LilvUISupportedFunc, supported_func,
- const LilvNode*, container_type,
- const LilvNode**, ui_type);*/
- LILV_WRAP1(bool, ui, is_a, const LilvNode*, class_uri);
-
- const LilvUI* me;
-};
-
-struct UIs {
- LILV_WRAP_COLL(UIs, UI, uis);
-};
-
-struct Port {
- inline Port(const LilvPlugin* p, const LilvPort* c_obj)
- : parent(p), me(c_obj)
- {}
-
- LILV_WRAP_CONVERSION(const LilvPort);
-
-#define LILV_PORT_WRAP0(RT, name) \
- inline RT name () { return lilv_port_ ## name (parent, me); }
-
-#define LILV_PORT_WRAP1(RT, name, T1, a1) \
- inline RT name (T1 a1) { return lilv_port_ ## name (parent, me, a1); }
-
- LILV_PORT_WRAP1(LilvNodes*, get_value, LilvNode*, predicate);
- LILV_PORT_WRAP0(LilvNodes*, get_properties)
- LILV_PORT_WRAP1(bool, has_property, LilvNode*, property_uri);
- LILV_PORT_WRAP1(bool, supports_event, LilvNode*, event_uri);
- LILV_PORT_WRAP0(const LilvNode*, get_symbol);
- LILV_PORT_WRAP0(LilvNode*, get_name);
- LILV_PORT_WRAP0(const LilvNodes*, get_classes);
- LILV_PORT_WRAP1(bool, is_a, LilvNode*, port_class);
- LILV_PORT_WRAP0(LilvScalePoints*, get_scale_points);
-
- // TODO: get_range (output parameters)
-
- const LilvPlugin* parent;
- const LilvPort* me;
-};
-
-struct Plugin {
- inline Plugin(const LilvPlugin* c_obj) : me(c_obj) {}
- LILV_WRAP_CONVERSION(const LilvPlugin);
-
- LILV_WRAP0(bool, plugin, verify);
- LILV_WRAP0(Node, plugin, get_uri);
- LILV_WRAP0(Node, plugin, get_bundle_uri);
- LILV_WRAP0(Nodes, plugin, get_data_uris);
- LILV_WRAP0(Node, plugin, get_library_uri);
- LILV_WRAP0(Node, plugin, get_name);
- LILV_WRAP0(PluginClass, plugin, get_class);
- LILV_WRAP1(Nodes, plugin, get_value, Node, pred);
- LILV_WRAP1(bool, plugin, has_feature, Node, feature_uri);
- LILV_WRAP0(Nodes, plugin, get_supported_features);
- LILV_WRAP0(Nodes, plugin, get_required_features);
- LILV_WRAP0(Nodes, plugin, get_optional_features);
- LILV_WRAP0(unsigned, plugin, get_num_ports);
- LILV_WRAP0(bool, plugin, has_latency);
- LILV_WRAP0(unsigned, plugin, get_latency_port_index);
- LILV_WRAP0(Node, plugin, get_author_name);
- LILV_WRAP0(Node, plugin, get_author_email);
- LILV_WRAP0(Node, plugin, get_author_homepage);
- LILV_WRAP0(bool, plugin, is_replaced);
- LILV_WRAP0(Nodes, plugin, get_extension_data);
- LILV_WRAP0(UIs, plugin, get_uis);
- LILV_WRAP1(Nodes, plugin, get_related, Node, type);
-
- inline Port get_port_by_index(unsigned index) {
- return Port(me, lilv_plugin_get_port_by_index(me, index));
- }
-
- inline Port get_port_by_symbol(LilvNode* symbol) {
- return Port(me, lilv_plugin_get_port_by_symbol(me, symbol));
- }
-
- inline void get_port_ranges_float(float* min_values,
- float* max_values,
- float* def_values) {
- return lilv_plugin_get_port_ranges_float(
- me, min_values, max_values, def_values);
- }
-
- inline unsigned get_num_ports_of_class(LilvNode* class_1, ...) {
- va_list args;
- va_start(args, class_1);
-
- const uint32_t count = lilv_plugin_get_num_ports_of_class_va(
- me, class_1, args);
-
- va_end(args);
- return count;
- }
-
- const LilvPlugin* me;
-};
-
-struct Plugins {
- LILV_WRAP_COLL(Plugins, Plugin, plugins);
- LILV_WRAP1(const Plugin, plugins, get_by_uri, const LilvNode*, uri);
-};
-
-struct Instance {
- inline Instance(LilvInstance* instance) : me(instance) {}
-
- LILV_DEPRECATED
- inline Instance(Plugin plugin, double sample_rate) {
- me = lilv_plugin_instantiate(plugin, sample_rate, nullptr);
- }
-
- LILV_DEPRECATED inline Instance(Plugin plugin,
- double sample_rate,
- LV2_Feature* const* features) {
- me = lilv_plugin_instantiate(plugin, sample_rate, features);
- }
-
- static inline Instance* create(Plugin plugin,
- double sample_rate,
- LV2_Feature* const* features) {
- LilvInstance* me = lilv_plugin_instantiate(
- plugin, sample_rate, features);
-
- return me ? new Instance(me) : nullptr;
- }
-
- LILV_WRAP_CONVERSION(LilvInstance);
-
- LILV_WRAP2_VOID(instance, connect_port,
- unsigned, port_index,
- void*, data_location);
-
- LILV_WRAP0_VOID(instance, activate);
- LILV_WRAP1_VOID(instance, run, unsigned, sample_count);
- LILV_WRAP0_VOID(instance, deactivate);
-
- inline const void* get_extension_data(const char* uri) {
- return lilv_instance_get_extension_data(me, uri);
- }
-
- inline const LV2_Descriptor* get_descriptor() {
- return lilv_instance_get_descriptor(me);
- }
-
- inline LV2_Handle get_handle() {
- return lilv_instance_get_handle(me);
- }
-
- LilvInstance* me;
-};
-
-struct World {
- inline World() : me(lilv_world_new()) {}
- inline ~World() { lilv_world_free(me); }
-
- inline LilvNode* new_uri(const char* uri) {
- return lilv_new_uri(me, uri);
- }
- inline LilvNode* new_string(const char* str) {
- return lilv_new_string(me, str);
- }
- inline LilvNode* new_int(int val) {
- return lilv_new_int(me, val);
- }
- inline LilvNode* new_float(float val) {
- return lilv_new_float(me, val);
- }
- inline LilvNode* new_bool(bool val) {
- return lilv_new_bool(me, val);
- }
- inline Nodes find_nodes(const LilvNode* subject,
- const LilvNode* predicate,
- const LilvNode* object) {
- return lilv_world_find_nodes(me, subject, predicate, object);
- }
-
- LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value);
- LILV_WRAP0_VOID(world, load_all);
- LILV_WRAP1_VOID(world, load_bundle, LilvNode*, bundle_uri);
- LILV_WRAP0(const LilvPluginClass*, world, get_plugin_class);
- LILV_WRAP0(const LilvPluginClasses*, world, get_plugin_classes);
- LILV_WRAP0(const Plugins, world, get_all_plugins);
- LILV_WRAP1(int, world, load_resource, const LilvNode*, resource);
-
- LilvWorld* me;
-};
-
-} /* namespace Lilv */
-
-#endif /* LILV_LILVMM_HPP */
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..6a9b52a
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,265 @@
+# Copyright 2021-2024 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+project(
+ 'lilv',
+ ['c'],
+ default_options: [
+ 'b_ndebug=if-release',
+ 'buildtype=release',
+ 'c_std=c99',
+ 'cpp_std=c++11',
+ ],
+ license: 'ISC',
+ meson_version: '>= 0.56.0',
+ version: '0.24.25',
+)
+
+lilv_src_root = meson.current_source_dir()
+major_version = meson.project_version().split('.')[0]
+version_suffix = '-@0@'.format(major_version)
+versioned_name = 'lilv' + version_suffix
+
+#######################
+# Compilers and Flags #
+#######################
+
+# Required tools
+pkg = import('pkgconfig')
+cc = meson.get_compiler('c')
+
+# Enable C++ support if bindings aren't disabled
+if not get_option('bindings_cpp').disabled()
+ if add_languages(['cpp'], native: false, required: false)
+ cpp = meson.get_compiler('cpp')
+ endif
+endif
+
+# Set global warning flags
+subdir('meson/suppressions')
+
+##########################
+# Platform Configuration #
+##########################
+
+platform_defines = ['-DLILV_VERSION="@0@"'.format(meson.project_version())]
+if host_machine.system() in ['gnu', 'linux']
+ platform_defines += [
+ '-D_POSIX_C_SOURCE=200809L',
+ ]
+endif
+
+default_lv2_path = get_option('default_lv2_path')
+if default_lv2_path == ''
+ if host_machine.system() == 'darwin'
+ lv2_dirs = [
+ '~/.lv2',
+ '~/Library/Audio/Plug-Ins/LV2',
+ '/usr/local/lib/lv2',
+ '/usr/lib/lv2',
+ '/Library/Audio/Plug-Ins/LV2',
+ ]
+
+ default_lv2_path = ':'.join(lv2_dirs)
+
+ elif host_machine.system() == 'haiku'
+ default_lv2_path = ':'.join(['~/.lv2', '/boot/common/add-ons/lv2'])
+
+ elif host_machine.system() == 'windows'
+ lv2_dirs = ['%%APPDATA%%\\\\LV2', '%%COMMONPROGRAMFILES%%\\\\LV2']
+ default_lv2_path = ';'.join(lv2_dirs)
+
+ else
+ lv2_dirs = [
+ '~' / '.lv2',
+ '/usr/local' / get_option('libdir') / 'lv2',
+ '/usr' / get_option('libdir') / 'lv2',
+ ]
+
+ default_lv2_path = ':'.join(lv2_dirs)
+ endif
+endif
+
+platform_defines += ['-DLILV_DEFAULT_LV2_PATH="@0@"'.format(default_lv2_path)]
+
+# Use versioned name everywhere to support parallel major version installations
+if host_machine.system() == 'windows'
+ if get_option('default_library') == 'both'
+ error('default_library=both is not supported on Windows')
+ endif
+ soversion = ''
+else
+ soversion = meson.project_version().split('.')[0]
+endif
+
+add_project_arguments(platform_defines, language: ['c'])
+
+################
+# Dependencies #
+################
+
+m_dep = cc.find_library('m', required: false)
+dl_dep = cc.find_library('dl', required: false)
+
+zix_dep = dependency('zix-0', fallback: 'zix', version: '>= 0.4.0')
+serd_dep = dependency('serd-0', fallback: 'serd', version: '>= 0.30.10')
+sord_dep = dependency('sord-0', fallback: 'sord', version: '>= 0.16.15')
+lv2_dep = dependency('lv2', fallback: 'lv2', version: '>= 1.18.2')
+sratom_dep = dependency('sratom-0', fallback: 'sratom', version: '>= 0.6.10')
+
+###########
+# Library #
+###########
+
+c_headers = files('include/lilv/lilv.h')
+cpp_headers = files('include/lilv/lilvmm.hpp')
+
+sources = files(
+ 'src/collections.c',
+ 'src/instance.c',
+ 'src/lib.c',
+ 'src/node.c',
+ 'src/plugin.c',
+ 'src/pluginclass.c',
+ 'src/port.c',
+ 'src/query.c',
+ 'src/scalepoint.c',
+ 'src/state.c',
+ 'src/ui.c',
+ 'src/util.c',
+ 'src/world.c',
+)
+
+common_dependencies = [
+ dl_dep,
+ lv2_dep,
+ m_dep,
+ serd_dep,
+ sord_dep,
+ sratom_dep,
+ zix_dep,
+]
+
+# Set appropriate arguments for building against the library type
+extra_c_args = []
+if get_option('default_library') == 'static'
+ extra_c_args = ['-DLILV_STATIC']
+endif
+
+# Build main shared and/or static library
+liblilv = library(
+ versioned_name,
+ sources,
+ c_args: c_suppressions + extra_c_args + ['-DLILV_INTERNAL'],
+ darwin_versions: [major_version + '.0.0', meson.project_version()],
+ dependencies: common_dependencies,
+ gnu_symbol_visibility: 'hidden',
+ include_directories: include_directories('include', 'src'),
+ install: true,
+ soversion: soversion,
+ version: meson.project_version(),
+)
+
+# Declare dependency for internal meson dependants
+lilv_dep = declare_dependency(
+ compile_args: extra_c_args,
+ dependencies: common_dependencies,
+ include_directories: include_directories('include'),
+ link_with: liblilv,
+)
+
+# Generage pkg-config file for external dependants
+pkg.generate(
+ liblilv,
+ description: 'Library for hosting LV2 plugins',
+ extra_cflags: extra_c_args,
+ filebase: versioned_name,
+ name: 'Lilv',
+ requires: ['lv2'],
+ subdirs: [versioned_name],
+ version: meson.project_version(),
+)
+
+# Override pkg-config dependency for internal meson dependants
+meson.override_dependency(versioned_name, lilv_dep)
+
+# Install headers to a versioned include directory
+install_headers(c_headers, subdir: versioned_name / 'lilv')
+install_headers(cpp_headers, subdir: versioned_name / 'lilv')
+
+# Display top-level summary (before subdirectories to appear first)
+if not meson.is_subproject()
+ summary(
+ {
+ 'Tests': not get_option('tests').disabled(),
+ 'Tools': not get_option('tools').disabled(),
+ },
+ bool_yn: true,
+ section: 'Components',
+ )
+
+ summary('Default LV2_PATH', default_lv2_path, section: 'Configuration')
+
+ summary(
+ {
+ 'Install prefix': get_option('prefix'),
+ 'Headers': get_option('prefix') / get_option('includedir'),
+ 'Libraries': get_option('prefix') / get_option('libdir'),
+ 'Executables': get_option('prefix') / get_option('bindir'),
+ 'Man pages': get_option('prefix') / get_option('mandir'),
+ },
+ section: 'Directories',
+ )
+endif
+
+#########
+# Tools #
+#########
+
+if not get_option('tools').disabled()
+ subdir('tools')
+endif
+
+############
+# Bindings #
+############
+
+if not get_option('bindings_py').disabled()
+ subdir('bindings/python')
+endif
+
+###########
+# Support #
+###########
+
+if not get_option('docs').disabled()
+ subdir('doc')
+endif
+
+if not get_option('tests').disabled()
+ # Get or build a static library for linking internal tests
+ if get_option('default_library') == 'both'
+ liblilv_static = liblilv.get_static_lib()
+ elif get_option('default_library') == 'shared'
+ liblilv_static = static_library(
+ versioned_name,
+ sources,
+ include_directories: include_directories('include', 'src'),
+ c_args: c_suppressions + ['-DLILV_INTERNAL', '-DLILV_STATIC'],
+ dependencies: common_dependencies,
+ gnu_symbol_visibility: 'default',
+ )
+ else
+ liblilv_static = liblilv
+ endif
+
+ lilv_static_dep = declare_dependency(
+ compile_args: extra_c_args,
+ dependencies: common_dependencies,
+ include_directories: include_directories('include'),
+ link_with: liblilv_static,
+ )
+
+ # Build and run tests against static library
+ subdir('test')
+endif
diff --git a/meson/suppressions/meson.build b/meson/suppressions/meson.build
new file mode 100644
index 0000000..d05af9e
--- /dev/null
+++ b/meson/suppressions/meson.build
@@ -0,0 +1,141 @@
+# Copyright 2020-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+# Project-specific warning suppressions
+
+warning_level = get_option('warning_level')
+
+#####
+# C #
+#####
+
+c_suppressions = []
+
+if cc.get_id() in ['clang', 'emscripten']
+ if warning_level == 'everything'
+ c_suppressions += [
+ '-Wno-cast-align',
+ '-Wno-cast-function-type-strict',
+ '-Wno-cast-qual',
+ '-Wno-declaration-after-statement',
+ '-Wno-documentation-unknown-command',
+ '-Wno-double-promotion',
+ '-Wno-float-equal',
+ '-Wno-format-nonliteral',
+ '-Wno-implicit-float-conversion',
+ '-Wno-implicit-int-conversion',
+ '-Wno-padded',
+ '-Wno-reserved-id-macro',
+ '-Wno-shorten-64-to-32',
+ '-Wno-sign-conversion',
+ '-Wno-switch-enum',
+ '-Wno-unsafe-buffer-usage',
+ '-Wno-vla',
+ ]
+
+ if not meson.is_cross_build()
+ c_suppressions += [
+ '-Wno-poison-system-directories',
+ ]
+ endif
+ endif
+
+ if warning_level in ['everything', '3']
+ c_suppressions += [
+ '-Wno-nullability-extension',
+ ]
+
+ if host_machine.system() == 'freebsd'
+ c_suppressions += [
+ '-Wno-c11-extensions',
+ ]
+ elif host_machine.system() == 'darwin'
+ c_suppressions += [
+ '-Wno-unused-macros',
+ ]
+ elif host_machine.system() == 'windows'
+ c_suppressions += [
+ '-Wno-deprecated-declarations',
+ '-Wno-nonportable-system-include-path',
+ '-Wno-unused-macros',
+ ]
+ endif
+ endif
+
+elif cc.get_id() == 'gcc'
+ if warning_level == 'everything'
+ c_suppressions += [
+ '-Wno-cast-align',
+ '-Wno-cast-qual',
+ '-Wno-conversion',
+ '-Wno-double-promotion',
+ '-Wno-float-equal',
+ '-Wno-format-nonliteral',
+ '-Wno-format-truncation',
+ '-Wno-inline',
+ '-Wno-padded',
+ '-Wno-stack-protector',
+ '-Wno-strict-overflow',
+ '-Wno-suggest-attribute=const',
+ '-Wno-suggest-attribute=pure',
+ '-Wno-switch-default',
+ '-Wno-switch-enum',
+ '-Wno-unsuffixed-float-constants',
+ '-Wno-unused-const-variable',
+ '-Wno-unused-parameter',
+ '-Wno-vla',
+ ]
+ endif
+
+ if warning_level in ['everything', '3']
+ c_suppressions += [
+ '-Wno-pedantic',
+ ]
+ endif
+
+ if host_machine.system() == 'windows'
+ c_suppressions += [
+ '-Wno-bad-function-cast',
+ '-Wno-unused-macros',
+ ]
+ endif
+
+elif cc.get_id() == 'msvc'
+ c_suppressions += [
+ '/experimental:external',
+ '/external:W0',
+ '/external:anglebrackets',
+ ]
+
+ if warning_level == 'everything'
+ c_suppressions += [
+ '/wd4061', # enumerator in switch is not explicitly handled
+ '/wd4191', # unsafe conversion from FARPROC
+ '/wd4365', # signed/unsigned mismatch
+ '/wd4514', # unreferenced inline function has been removed
+ '/wd4710', # function not inlined
+ '/wd4711', # function selected for automatic inline expansion
+ '/wd4774', # format string is not a string literal
+ '/wd4800', # implicit conversion to bool
+ '/wd4820', # padding added after construct
+ '/wd5045', # will insert Spectre mitigation for memory load
+ ]
+ endif
+
+ if warning_level in ['everything', '3']
+ c_suppressions += [
+ '/wd4090', # different const qualifiers
+ '/wd4706', # assignment within conditional expression
+ ]
+ endif
+
+ if warning_level in ['everything', '3', '2']
+ c_suppressions += [
+ '/wd4244', # conversion from floating point, possible loss of data
+ '/wd4267', # conversion from size_t, possible loss of data
+ '/wd4996', # POSIX name for this item is deprecated
+ ]
+ endif
+endif
+
+c_suppressions = cc.get_supported_arguments(c_suppressions)
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..4419e9d
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,29 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+option('bindings_py', type: 'feature', value: 'auto', yield: true,
+ description: 'Build Python bindings')
+
+option('bindings_cpp', type: 'feature', value: 'auto', yield: true,
+ description: 'Build C++ bindings')
+
+option('default_lv2_path', type: 'string', value: '', yield: true,
+ description: 'Default LV2_PATH to use if it is unset')
+
+option('docs', type: 'feature', value: 'auto', yield: true,
+ description: 'Build documentation')
+
+option('html', type: 'feature', value: 'auto', yield: true,
+ description: 'Build paginated HTML documentation')
+
+option('singlehtml', type: 'feature', value: 'auto', yield: true,
+ description: 'Build single-page HTML documentation')
+
+option('tests', type: 'feature', value: 'auto', yield: true,
+ description: 'Build tests')
+
+option('title', type: 'string', value: 'Lilv',
+ description: 'Project title')
+
+option('tools', type: 'feature', value: 'auto', yield: true,
+ description: 'Build command line utilities')
diff --git a/src/.clang-tidy b/src/.clang-tidy
new file mode 100644
index 0000000..0673649
--- /dev/null
+++ b/src/.clang-tidy
@@ -0,0 +1,21 @@
+# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+Checks: >
+ -*-magic-numbers,
+ -android-cloexec-fopen,
+ -bugprone-narrowing-conversions,
+ -cert-err33-c,
+ -cert-err34-c,
+ -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
+ -clang-analyzer-valist.Uninitialized,
+ -concurrency-mt-unsafe,
+ -cppcoreguidelines-narrowing-conversions,
+ -google-readability-todo,
+ -hicpp-multiway-paths-covered,
+ -hicpp-signed-bitwise,
+ -llvm-header-guard,
+ -performance-no-int-to-ptr,
+ -readability-function-cognitive-complexity,
+ -readability-suspicious-call-argument,
+InheritParentConfig: true
diff --git a/src/collections.c b/src/collections.c
index 8a25eaa..a7b6923 100644
--- a/src/collections.c
+++ b/src/collections.c
@@ -1,77 +1,78 @@
-/*
- Copyright 2008-2019 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.
-*/
+// Copyright 2008-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "sord/sord.h"
-#include "zix/common.h"
#include "zix/tree.h"
#include <stdbool.h>
#include <stddef.h>
-#include <stdint.h>
+
+typedef void (*LilvFreeFunc)(void* ptr);
int
-lilv_ptr_cmp(const void* a, const void* b, void* user_data)
+lilv_ptr_cmp(const void* a, const void* b, const void* user_data)
{
- return (intptr_t)a - (intptr_t)b;
+ (void)user_data;
+
+ return a < b ? -1 : b < a ? 1 : 0;
}
int
-lilv_resource_node_cmp(const void* a, const void* b, void* user_data)
+lilv_resource_node_cmp(const void* a, const void* b, const void* user_data)
{
- const SordNode* an = ((const LilvNode*)a)->node;
- const SordNode* bn = ((const LilvNode*)b)->node;
- return (intptr_t)an - (intptr_t)bn;
+ (void)user_data;
+
+ const SordNode* an = ((const LilvNode*)a)->node;
+ const SordNode* bn = ((const LilvNode*)b)->node;
+
+ return an < bn ? -1 : bn < an ? 1 : 0;
}
/* Generic collection functions */
+static void
+destroy(void* const ptr, const void* const user_data)
+{
+ if (user_data) {
+ ((LilvFreeFunc)user_data)(ptr);
+ }
+}
+
static inline LilvCollection*
-lilv_collection_new(ZixComparator cmp, ZixDestroyFunc destructor)
+lilv_collection_new(ZixTreeCompareFunc cmp, LilvFreeFunc free_func)
{
- return zix_tree_new(false, cmp, NULL, destructor);
+ return zix_tree_new(NULL, false, cmp, NULL, destroy, (const void*)free_func);
}
-void
+static void
lilv_collection_free(LilvCollection* collection)
{
- if (collection) {
- zix_tree_free((ZixTree*)collection);
- }
+ if (collection) {
+ zix_tree_free((ZixTree*)collection);
+ }
}
-unsigned
+static unsigned
lilv_collection_size(const LilvCollection* collection)
{
- return (collection ? zix_tree_size((const ZixTree*)collection) : 0);
+ return (collection ? zix_tree_size((const ZixTree*)collection) : 0);
}
-LilvIter*
+static LilvIter*
lilv_collection_begin(const LilvCollection* collection)
{
- return collection ? (LilvIter*)zix_tree_begin((ZixTree*)collection) : NULL;
+ return collection ? (LilvIter*)zix_tree_begin((ZixTree*)collection) : NULL;
}
void*
-lilv_collection_get(const LilvCollection* collection,
- const LilvIter* i)
+lilv_collection_get(const LilvCollection* collection, const LilvIter* i)
{
- return zix_tree_get((const ZixTreeIter*)i);
+ (void)collection;
+
+ return zix_tree_get((const ZixTreeIter*)i);
}
/* Constructors */
@@ -79,29 +80,27 @@ lilv_collection_get(const LilvCollection* collection,
LilvScalePoints*
lilv_scale_points_new(void)
{
- return lilv_collection_new(lilv_ptr_cmp,
- (ZixDestroyFunc)lilv_scale_point_free);
+ return lilv_collection_new(lilv_ptr_cmp, (LilvFreeFunc)lilv_scale_point_free);
}
LilvNodes*
lilv_nodes_new(void)
{
- return lilv_collection_new(lilv_ptr_cmp,
- (ZixDestroyFunc)lilv_node_free);
+ return lilv_collection_new(lilv_ptr_cmp, (LilvFreeFunc)lilv_node_free);
}
LilvUIs*
lilv_uis_new(void)
{
- return lilv_collection_new(lilv_header_compare_by_uri,
- (ZixDestroyFunc)lilv_ui_free);
+ return lilv_collection_new(lilv_header_compare_by_uri,
+ (LilvFreeFunc)lilv_ui_free);
}
LilvPluginClasses*
lilv_plugin_classes_new(void)
{
- return lilv_collection_new(lilv_header_compare_by_uri,
- (ZixDestroyFunc)lilv_plugin_class_free);
+ return lilv_collection_new(lilv_header_compare_by_uri,
+ (LilvFreeFunc)lilv_plugin_class_free);
}
/* URI based accessors (for collections of things with URIs) */
@@ -110,14 +109,14 @@ const LilvPluginClass*
lilv_plugin_classes_get_by_uri(const LilvPluginClasses* classes,
const LilvNode* uri)
{
- return (LilvPluginClass*)lilv_collection_get_by_uri(
- (const ZixTree*)classes, uri);
+ return (LilvPluginClass*)lilv_collection_get_by_uri((const ZixTree*)classes,
+ uri);
}
const LilvUI*
lilv_uis_get_by_uri(const LilvUIs* uis, const LilvNode* uri)
{
- return (LilvUI*)lilv_collection_get_by_uri((const ZixTree*)uis, uri);
+ return (LilvUI*)lilv_collection_get_by_uri((const ZixTree*)uis, uri);
}
/* Plugins */
@@ -125,14 +124,13 @@ lilv_uis_get_by_uri(const LilvUIs* uis, const LilvNode* uri)
LilvPlugins*
lilv_plugins_new(void)
{
- return lilv_collection_new(lilv_header_compare_by_uri, NULL);
+ return lilv_collection_new(lilv_header_compare_by_uri, NULL);
}
const LilvPlugin*
lilv_plugins_get_by_uri(const LilvPlugins* plugins, const LilvNode* uri)
{
- return (LilvPlugin*)lilv_collection_get_by_uri(
- (const ZixTree*)plugins, uri);
+ return (LilvPlugin*)lilv_collection_get_by_uri((const ZixTree*)plugins, uri);
}
/* Nodes */
@@ -140,65 +138,63 @@ lilv_plugins_get_by_uri(const LilvPlugins* plugins, const LilvNode* uri)
bool
lilv_nodes_contains(const LilvNodes* nodes, const LilvNode* value)
{
- LILV_FOREACH(nodes, i, nodes) {
- if (lilv_node_equals(lilv_nodes_get(nodes, i), value)) {
- return true;
- }
- }
+ LILV_FOREACH (nodes, i, nodes) {
+ if (lilv_node_equals(lilv_nodes_get(nodes, i), value)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
LilvNodes*
lilv_nodes_merge(const LilvNodes* a, const LilvNodes* b)
{
- LilvNodes* result = lilv_nodes_new();
+ LilvNodes* result = lilv_nodes_new();
- LILV_FOREACH(nodes, i, a)
- zix_tree_insert((ZixTree*)result,
- lilv_node_duplicate(lilv_nodes_get(a, i)),
- NULL);
+ LILV_FOREACH (nodes, i, a) {
+ zix_tree_insert(
+ (ZixTree*)result, lilv_node_duplicate(lilv_nodes_get(a, i)), NULL);
+ }
- LILV_FOREACH(nodes, i, b)
- zix_tree_insert((ZixTree*)result,
- lilv_node_duplicate(lilv_nodes_get(b, i)),
- NULL);
+ LILV_FOREACH (nodes, i, b) {
+ zix_tree_insert(
+ (ZixTree*)result, lilv_node_duplicate(lilv_nodes_get(b, i)), NULL);
+ }
- return result;
+ return result;
}
/* Iterator */
-#define LILV_COLLECTION_IMPL(prefix, CT, ET) \
-\
-unsigned \
-prefix##_size(const CT* collection) { \
- return lilv_collection_size(collection); \
-} \
-\
-\
-LilvIter* \
-prefix##_begin(const CT* collection) { \
- return lilv_collection_begin(collection); \
-} \
-\
-\
-const ET* \
-prefix##_get(const CT* collection, LilvIter* i) { \
- return (ET*)lilv_collection_get(collection, i); \
-} \
-\
-\
-LilvIter* \
-prefix##_next(const CT* collection, LilvIter* i) { \
- return zix_tree_iter_next((ZixTreeIter*)i); \
-} \
-\
-\
-bool \
-prefix##_is_end(const CT* collection, LilvIter* i) { \
- return zix_tree_iter_is_end((ZixTreeIter*)i); \
-}
+#define LILV_COLLECTION_IMPL(prefix, CT, ET) \
+ \
+ unsigned prefix##_size(const CT* collection) \
+ { \
+ return lilv_collection_size(collection); \
+ } \
+ \
+ LilvIter* prefix##_begin(const CT* collection) \
+ { \
+ return lilv_collection_begin(collection); \
+ } \
+ \
+ const ET* prefix##_get(const CT* collection, LilvIter* i) \
+ { \
+ return (ET*)lilv_collection_get(collection, i); \
+ } \
+ \
+ LilvIter* prefix##_next(const CT* collection, LilvIter* i) \
+ { \
+ (void)collection; \
+ return zix_tree_iter_next((ZixTreeIter*)i); \
+ } \
+ \
+ bool prefix##_is_end(const CT* collection, LilvIter* i) \
+ { \
+ (void)collection; \
+ return zix_tree_iter_is_end((ZixTreeIter*)i); \
+ }
LILV_COLLECTION_IMPL(lilv_plugin_classes, LilvPluginClasses, LilvPluginClass)
LILV_COLLECTION_IMPL(lilv_scale_points, LilvScalePoints, LilvScalePoint)
@@ -207,27 +203,32 @@ LILV_COLLECTION_IMPL(lilv_nodes, LilvNodes, LilvNode)
LILV_COLLECTION_IMPL(lilv_plugins, LilvPlugins, LilvPlugin)
void
-lilv_plugin_classes_free(LilvPluginClasses* collection) {
- lilv_collection_free(collection);
+lilv_plugin_classes_free(LilvPluginClasses* collection)
+{
+ lilv_collection_free(collection);
}
void
-lilv_scale_points_free(LilvScalePoints* collection) {
- lilv_collection_free(collection);
+lilv_scale_points_free(LilvScalePoints* collection)
+{
+ lilv_collection_free(collection);
}
void
-lilv_uis_free(LilvUIs* collection) {
- lilv_collection_free(collection);
+lilv_uis_free(LilvUIs* collection)
+{
+ lilv_collection_free(collection);
}
void
-lilv_nodes_free(LilvNodes* collection) {
- lilv_collection_free(collection);
+lilv_nodes_free(LilvNodes* collection)
+{
+ lilv_collection_free(collection);
}
LilvNode*
-lilv_nodes_get_first(const LilvNodes* collection) {
- return (LilvNode*)lilv_collection_get(collection,
- lilv_collection_begin(collection));
+lilv_nodes_get_first(const LilvNodes* collection)
+{
+ return (LilvNode*)lilv_collection_get(collection,
+ lilv_collection_begin(collection));
}
diff --git a/src/filesystem.c b/src/filesystem.c
deleted file mode 100644
index c8a58c1..0000000
--- a/src/filesystem.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- Copyright 2007-2020 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 "filesystem.h"
-#include "lilv_config.h"
-#include "lilv_internal.h"
-
-#ifdef _WIN32
-# include <windows.h>
-# include <direct.h>
-# include <io.h>
-# define F_OK 0
-# define mkdir(path, flags) _mkdir(path)
-# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
-#else
-# include <dirent.h>
-# include <unistd.h>
-#endif
-
-#if defined(HAVE_FLOCK) && defined(HAVE_FILENO)
-# include <sys/file.h>
-#endif
-
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
-static bool
-lilv_is_dir_sep(const char c)
-{
- return c == '/' || c == LILV_DIR_SEP[0];
-}
-
-#ifdef _WIN32
-static inline bool
-is_windows_path(const char* path)
-{
- return (isalpha(path[0]) && (path[1] == ':' || path[1] == '|') &&
- (path[2] == '/' || path[2] == '\\'));
-}
-#endif
-
-char*
-lilv_temp_directory_path(void)
-{
-#ifdef _WIN32
- DWORD len = GetTempPath(0, NULL);
- char* buf = (char*)calloc(len, 1);
- if (GetTempPath(len, buf) == 0) {
- free(buf);
- return NULL;
- }
-
- return buf;
-#else
- const char* const tmpdir = getenv("TMPDIR");
-
- return tmpdir ? lilv_strdup(tmpdir) : lilv_strdup("/tmp");
-#endif
-}
-
-bool
-lilv_path_is_absolute(const char* path)
-{
- if (lilv_is_dir_sep(path[0])) {
- return true;
- }
-
-#ifdef _WIN32
- if (is_windows_path(path)) {
- return true;
- }
-#endif
-
- return false;
-}
-
-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;
-}
-
-char*
-lilv_path_current(void)
-{
- return getcwd(NULL, 0);
-}
-
-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_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;
-}
-
-char*
-lilv_path_parent(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;
- }
-}
-
-char*
-lilv_path_join(const char* a, const char* b)
-{
- if (!a) {
- return (b && b[0]) ? lilv_strdup(b) : NULL;
- }
-
- const size_t a_len = strlen(a);
- const size_t b_len = b ? strlen(b) : 0;
- const bool a_end_is_sep = a_len > 0 && lilv_is_dir_sep(a[a_len - 1]);
- const size_t pre_len = a_len - (a_end_is_sep ? 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;
-}
-
-char*
-lilv_path_canonical(const char* path)
-{
- if (!path) {
- return NULL;
- }
-
-#if defined(_WIN32)
- char* out = (char*)malloc(MAX_PATH);
- GetFullPathName(path, MAX_PATH, out, NULL);
- return out;
-#else
- char* real_path = realpath(path, NULL);
- return real_path ? real_path : lilv_strdup(path);
-#endif
-}
-
-bool
-lilv_path_exists(const char* path)
-{
-#ifdef HAVE_LSTAT
- struct stat st;
- return !lstat(path, &st);
-#else
- return !access(path, F_OK);
-#endif
-}
-
-bool
-lilv_is_directory(const char* path)
-{
- struct stat st;
- return !stat(path, &st) && S_ISDIR(st.st_mode);
-}
-
-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 && fflush(out)) {
- st = errno;
- }
-
- if (!st && (ferror(in) || ferror(out))) {
- st = EBADF;
- }
-
- free(page);
- fclose(in);
- fclose(out);
-
- return st;
-}
-
-int
-lilv_symlink(const char* oldpath, const char* newpath)
-{
- int ret = 0;
- if (strcmp(oldpath, newpath)) {
-#ifdef _WIN32
-#ifdef HAVE_CREATESYMBOLICLINK
- ret = !CreateSymbolicLink(newpath, oldpath, 0);
-#endif
- if (ret) {
- ret = !CreateHardLink(newpath, oldpath, 0);
- }
-#else
- ret = symlink(oldpath, newpath);
-#endif
- }
- return ret;
-}
-
-int
-lilv_flock(FILE* file, bool lock, bool block)
-{
-#ifdef _WIN32
- HANDLE handle = (HANDLE)_get_osfhandle(fileno(file));
- OVERLAPPED overlapped = {0};
-
- if (lock) {
- const DWORD flags = (LOCKFILE_EXCLUSIVE_LOCK |
- (block ? 0 : LOCKFILE_FAIL_IMMEDIATELY));
-
- return !LockFileEx(
- handle, flags, 0, UINT32_MAX, UINT32_MAX, &overlapped);
- } else {
- return !UnlockFileEx(handle, 0, UINT32_MAX, UINT32_MAX, &overlapped);
- }
-#elif defined(HAVE_FLOCK) && defined(HAVE_FILENO)
- return flock(fileno(file),
- (lock ? LOCK_EX : LOCK_UN) | (block ? 0 : LOCK_NB));
-#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 {
- if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")) {
- f(path, fd.cFileName, data);
- }
- } while (FindNextFile(fh, &fd));
- }
- free(pat);
-#else
- DIR* dir = opendir(path);
- if (dir) {
- for (struct dirent* entry = NULL; (entry = readdir(dir));) {
- if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
- f(path, entry->d_name, data);
- }
- }
- closedir(dir);
- }
-#endif
-}
-
-char*
-lilv_create_temporary_directory(const char* pattern)
-{
-#ifdef _WIN32
- static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- static const int n_chars = sizeof(chars) - 1;
-
- const size_t pattern_len = strlen(pattern);
- if (pattern_len < 7 || strcmp(pattern + pattern_len - 6, "XXXXXX")) {
- errno = EINVAL;
- return NULL;
- }
-
- char* const tmpdir = lilv_temp_directory_path();
- char* const path_pattern = lilv_path_join(tmpdir, pattern);
- const size_t path_pattern_len = strlen(path_pattern);
- char* const suffix = path_pattern + path_pattern_len - 6;
-
- free(tmpdir);
-
- for (unsigned attempt = 0; attempt < 128; ++attempt) {
- for (unsigned i = 0; i < 6; ++i) {
- suffix[i] = chars[rand() % n_chars];
- }
-
- if (!mkdir(path_pattern, 0700)) {
- return path_pattern;
- }
- }
-
- return NULL;
-#else
- char* const tmpdir = lilv_temp_directory_path();
- char* const path_pattern = lilv_path_join(tmpdir, pattern);
-
- free(tmpdir);
- return mkdtemp(path_pattern); // NOLINT (not a leak)
-#endif
-}
-
-int
-lilv_create_directories(const char* dir_path)
-{
- char* path = lilv_strdup(dir_path);
- const size_t path_len = strlen(path);
- size_t i = 1;
-
-#ifdef _WIN32
- if (is_windows_path(dir_path)) {
- i = 3;
- }
-#endif
-
- for (; i <= path_len; ++i) {
- const char c = path[i];
- if (c == LILV_DIR_SEP[0] || c == '/' || c == '\0') {
- path[i] = '\0';
- if (mkdir(path, 0755) &&
- (errno != EEXIST || !lilv_is_directory(path))) {
- free(path);
- return errno;
- }
- path[i] = c;
- }
- }
-
- free(path);
- return 0;
-}
-
-static off_t
-lilv_file_size(const char* path)
-{
- struct stat buf;
- if (stat(path, &buf)) {
- return 0;
- }
- return buf.st_size;
-}
-
-int
-lilv_remove(const char* path)
-{
-#ifdef _WIN32
- if (lilv_is_directory(path)) {
- return !RemoveDirectory(path);
- }
-#endif
-
- return remove(path);
-}
-
-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_path_canonical(a_path);
- char* const b_real = lilv_path_canonical(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;
-}
diff --git a/src/filesystem.h b/src/filesystem.h
deleted file mode 100644
index 14f25d7..0000000
--- a/src/filesystem.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- Copyright 2007-2020 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.
-*/
-
-#include <stdbool.h>
-#include <stdio.h>
-
-/// Return the path to a directory suitable for making temporary files
-char*
-lilv_temp_directory_path(void);
-
-/// Return true iff `path` is an absolute path
-bool
-lilv_path_is_absolute(const char* path);
-
-/// Return true iff `path` is a child of `dir`
-bool
-lilv_path_is_child(const char* path, const char* dir);
-
-/// Return the current working directory
-char*
-lilv_path_current(void);
-
-/**
- Return `path` as an absolute path.
-
- If `path` is absolute, an identical copy of it is returned. Otherwise, the
- returned path is relative to the current working directory.
-*/
-char*
-lilv_path_absolute(const char* path);
-
-/**
- Return `path` relative to `base` if possible.
-
- If `path` is not within `base`, a copy is returned. Otherwise, an
- equivalent path relative to `base` is returned (which may contain
- up-references).
-*/
-char*
-lilv_path_relative_to(const char* path, const char* base);
-
-/**
- Return the path to the directory that contains `path`.
-
- Returns the root path if `path` is the root path.
-*/
-char*
-lilv_path_parent(const char* path);
-
-/// Join path `a` and path `b` with a single directory separator between them
-char*
-lilv_path_join(const char* a, const char* b);
-
-/**
- Return `path` as a canonicalized absolute path.
-
- This expands all symbolic links, relative references, and removes extra
- directory separators.
-*/
-char*
-lilv_path_canonical(const char* path);
-
-/// Return true iff `path` points to an existing file system entry
-bool
-lilv_path_exists(const char* path);
-
-/// Return true iff `path` points to an existing directory
-bool
-lilv_is_directory(const char* path);
-
-/**
- Copy the file at path `src` to path `dst`.
-
- @return Zero on success, or a standard `errno` error code.
-*/
-int
-lilv_copy_file(const char* src, const char* dst);
-
-/**
- Create a symlink at `newpath` that points to `oldpath`.
-
- @return Zero on success, otherwise non-zero and `errno` is set.
-*/
-int
-lilv_symlink(const char* oldpath, const char* newpath);
-
-/**
- Set or remove an advisory exclusive lock on `file`.
-
- If the `lock` is true and the file is already locked by another process, or
- by this process via a different file handle, then this will not succeed and
- non-zero will be returned.
-
- @param file Handle for open file to lock.
- @param lock True to set lock, false to release lock.
- @param block If true, then this call will block until the lock is acquired.
- @return Zero on success.
-*/
-int
-lilv_flock(FILE* file, bool lock, bool block);
-
-/**
- Visit every file in the directory at `path`.
-
- @param path A path to a directory.
-
- @param data Opaque user data that is passed to `f`.
-
- @param f A function called on every entry in the directory. The `path`
- parameter is always the directory path passed to this function, the `name`
- parameter is the name of the directory entry (not its full path).
-*/
-void
-lilv_dir_for_each(const char* path,
- void* data,
- void (*f)(const char* path, const char* name, void* data));
-
-/**
- Create a unique temporary directory.
-
- The last six characters of `pattern` must be `XXXXXX` and will be replaced
- with random characters. This works roughly like mkdtemp, except the pattern
- should only be a directory name, not a full path. The returned path will be
- in a suitable system temporary directory.
-*/
-char*
-lilv_create_temporary_directory(const char* pattern);
-
-/**
- Create the directory `dir_path` and any parent directories if necessary.
-
- @return Zero on success, or an `errno` error code.
-*/
-int
-lilv_create_directories(const char* dir_path);
-
-/// Remove the file or empty directory at `path`
-int
-lilv_remove(const char* path);
-
-/// Return true iff the given paths point to files with identical contents
-bool
-lilv_file_equals(const char* a_path, const char* b_path);
diff --git a/src/instance.c b/src/instance.c
index 42c13a2..379fe24 100644
--- a/src/instance.c
+++ b/src/instance.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -27,90 +14,89 @@
#include <string.h>
LilvInstance*
-lilv_plugin_instantiate(const LilvPlugin* plugin,
- double sample_rate,
- const LV2_Feature*const* features)
+lilv_plugin_instantiate(const LilvPlugin* plugin,
+ double sample_rate,
+ const LV2_Feature* const* features)
{
- lilv_plugin_load_if_necessary(plugin);
- if (plugin->parse_errors) {
- return NULL;
- }
-
- LilvInstance* result = NULL;
- const LilvNode* const lib_uri = lilv_plugin_get_library_uri(plugin);
- const LilvNode* const bundle_uri = lilv_plugin_get_bundle_uri(plugin);
- if (!lib_uri || !bundle_uri) {
- return NULL;
- }
-
- char* const bundle_path = lilv_file_uri_parse(
- lilv_node_as_uri(bundle_uri), NULL);
-
- LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features);
- if (!lib) {
- serd_free(bundle_path);
- return NULL;
- }
-
- const LV2_Feature** local_features = NULL;
- if (features == NULL) {
- local_features = (const LV2_Feature**)malloc(sizeof(LV2_Feature*));
- local_features[0] = NULL;
- }
-
- // Search for plugin by URI
- for (uint32_t i = 0; true; ++i) {
- const LV2_Descriptor* ld = lilv_lib_get_plugin(lib, i);
- if (!ld) {
- LILV_ERRORF("No plugin <%s> in <%s>\n",
- lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
- lilv_node_as_uri(lib_uri));
- lilv_lib_close(lib);
- break; // return NULL
- }
-
- if (!strcmp(ld->URI, lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) {
- // Create LilvInstance to return
- result = (LilvInstance*)malloc(sizeof(LilvInstance));
- result->lv2_descriptor = ld;
- result->lv2_handle = ld->instantiate(
- ld, sample_rate, bundle_path,
- (features) ? features : local_features);
- result->pimpl = lib;
- break;
- }
- }
-
- free(local_features);
- serd_free(bundle_path);
-
- if (result) {
- if (result->lv2_handle == NULL) {
- // Failed to instantiate
- free(result);
- lilv_lib_close(lib);
- return NULL;
- }
-
- // "Connect" all ports to NULL (catches bugs)
- for (uint32_t i = 0; i < lilv_plugin_get_num_ports(plugin); ++i) {
- result->lv2_descriptor->connect_port(result->lv2_handle, i, NULL);
- }
- }
-
- return result;
+ 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);
+ if (!lib_uri || !bundle_uri) {
+ return NULL;
+ }
+
+ char* const bundle_path =
+ lilv_file_uri_parse(lilv_node_as_uri(bundle_uri), NULL);
+
+ LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features);
+ if (!lib) {
+ serd_free(bundle_path);
+ return NULL;
+ }
+
+ const LV2_Feature** local_features = NULL;
+ if (features == NULL) {
+ local_features = (const LV2_Feature**)malloc(sizeof(LV2_Feature*));
+ local_features[0] = NULL;
+ }
+
+ // Search for plugin by URI
+ for (uint32_t i = 0; true; ++i) {
+ const LV2_Descriptor* ld = lilv_lib_get_plugin(lib, i);
+ if (!ld) {
+ LILV_ERRORF("No plugin <%s> in <%s>\n",
+ lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
+ lilv_node_as_uri(lib_uri));
+ lilv_lib_close(lib);
+ break; // return NULL
+ }
+
+ if (!strcmp(ld->URI, lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) {
+ // Create LilvInstance to return
+ result = (LilvInstance*)malloc(sizeof(LilvInstance));
+ result->lv2_descriptor = ld;
+ result->lv2_handle = ld->instantiate(
+ ld, sample_rate, bundle_path, (features) ? features : local_features);
+ result->pimpl = lib;
+ break;
+ }
+ }
+
+ free(local_features);
+ serd_free(bundle_path);
+
+ if (result) {
+ if (result->lv2_handle == NULL) {
+ // Failed to instantiate
+ free(result);
+ lilv_lib_close(lib);
+ return NULL;
+ }
+
+ // "Connect" all ports to NULL (catches bugs)
+ for (uint32_t i = 0; i < lilv_plugin_get_num_ports(plugin); ++i) {
+ result->lv2_descriptor->connect_port(result->lv2_handle, i, NULL);
+ }
+ }
+
+ return result;
}
void
lilv_instance_free(LilvInstance* instance)
{
- if (!instance) {
- return;
- }
-
- instance->lv2_descriptor->cleanup(instance->lv2_handle);
- instance->lv2_descriptor = NULL;
- lilv_lib_close((LilvLib*)instance->pimpl);
- instance->pimpl = NULL;
- free(instance);
+ if (!instance) {
+ return;
+ }
+
+ instance->lv2_descriptor->cleanup(instance->lv2_handle);
+ instance->lv2_descriptor = NULL;
+ lilv_lib_close((LilvLib*)instance->pimpl);
+ instance->pimpl = NULL;
+ free(instance);
}
diff --git a/src/lib.c b/src/lib.c
index b2a93bb..5f7a456 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2012-2019 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.
-*/
+// Copyright 2012-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -22,104 +9,106 @@
#include "zix/tree.h"
#ifndef _WIN32
-# include <dlfcn.h>
+# include <dlfcn.h>
#endif
#include <stdint.h>
#include <stdlib.h>
LilvLib*
-lilv_lib_open(LilvWorld* world,
- const LilvNode* uri,
- const char* bundle_path,
- const LV2_Feature*const* features)
+lilv_lib_open(LilvWorld* world,
+ const LilvNode* uri,
+ const char* bundle_path,
+ const LV2_Feature* const* features)
{
- ZixTreeIter* i = NULL;
- const LilvLib key = {
- world, (LilvNode*)uri, (char*)bundle_path, NULL, NULL, NULL, 0
- };
- if (!zix_tree_find(world->libs, &key, &i)) {
- LilvLib* llib = (LilvLib*)zix_tree_get(i);
- ++llib->refs;
- return llib;
- }
-
- const char* const lib_uri = lilv_node_as_uri(uri);
- char* const lib_path = (char*)serd_file_uri_parse(
- (const uint8_t*)lib_uri, NULL);
- if (!lib_path) {
- return NULL;
- }
-
- dlerror();
- void* lib = dlopen(lib_path, RTLD_NOW);
- if (!lib) {
- LILV_ERRORF("Failed to open library %s (%s)\n", lib_path, dlerror());
- serd_free(lib_path);
- return NULL;
- }
-
- LV2_Descriptor_Function df = (LV2_Descriptor_Function)
- lilv_dlfunc(lib, "lv2_descriptor");
-
- LV2_Lib_Descriptor_Function ldf = (LV2_Lib_Descriptor_Function)
- lilv_dlfunc(lib, "lv2_lib_descriptor");
-
- const LV2_Lib_Descriptor* desc = NULL;
- if (ldf) {
- desc = ldf(bundle_path, features);
- if (!desc) {
- LILV_ERRORF("Call to %s:lv2_lib_descriptor failed\n", lib_path);
- dlclose(lib);
- serd_free(lib_path);
- return NULL;
- }
- } else if (!df) {
- LILV_ERRORF("No `lv2_descriptor' or `lv2_lib_descriptor' in %s\n",
- lib_path);
- dlclose(lib);
- serd_free(lib_path);
- return NULL;
- }
- serd_free(lib_path);
-
- LilvLib* llib = (LilvLib*)malloc(sizeof(LilvLib));
- llib->world = world;
- llib->uri = lilv_node_duplicate(uri);
- llib->bundle_path = lilv_strdup(bundle_path);
- llib->lib = lib;
- llib->lv2_descriptor = df;
- llib->desc = desc;
- llib->refs = 1;
-
- zix_tree_insert(world->libs, llib, NULL);
- return llib;
+ ZixTreeIter* i = NULL;
+ const LilvLib key = {
+ world, (LilvNode*)uri, (char*)bundle_path, NULL, NULL, NULL, 0};
+ if (!zix_tree_find(world->libs, &key, &i)) {
+ LilvLib* llib = (LilvLib*)zix_tree_get(i);
+ ++llib->refs;
+ return llib;
+ }
+
+ const char* const lib_uri = lilv_node_as_uri(uri);
+ char* const lib_path =
+ (char*)serd_file_uri_parse((const uint8_t*)lib_uri, NULL);
+ if (!lib_path) {
+ return NULL;
+ }
+
+ dlerror();
+ void* lib = dlopen(lib_path, RTLD_NOW);
+ if (!lib) {
+ LILV_ERRORF("Failed to open library %s (%s)\n", lib_path, dlerror());
+ serd_free(lib_path);
+ return NULL;
+ }
+
+ LV2_Descriptor_Function df =
+ (LV2_Descriptor_Function)lilv_dlfunc(lib, "lv2_descriptor");
+
+ LV2_Lib_Descriptor_Function ldf =
+ (LV2_Lib_Descriptor_Function)lilv_dlfunc(lib, "lv2_lib_descriptor");
+
+ const LV2_Lib_Descriptor* desc = NULL;
+ if (ldf) {
+ desc = ldf(bundle_path, features);
+ if (!desc) {
+ LILV_ERRORF("Call to %s:lv2_lib_descriptor failed\n", lib_path);
+ dlclose(lib);
+ serd_free(lib_path);
+ return NULL;
+ }
+ } else if (!df) {
+ LILV_ERRORF("No `lv2_descriptor' or `lv2_lib_descriptor' in %s\n",
+ lib_path);
+ dlclose(lib);
+ serd_free(lib_path);
+ return NULL;
+ }
+ serd_free(lib_path);
+
+ LilvLib* llib = (LilvLib*)malloc(sizeof(LilvLib));
+ llib->world = world;
+ llib->uri = lilv_node_duplicate(uri);
+ llib->bundle_path = lilv_strdup(bundle_path);
+ llib->lib = lib;
+ llib->lv2_descriptor = df;
+ llib->desc = desc;
+ llib->refs = 1;
+
+ zix_tree_insert(world->libs, llib, NULL);
+ return llib;
}
const LV2_Descriptor*
lilv_lib_get_plugin(LilvLib* lib, uint32_t index)
{
- if (lib->lv2_descriptor) {
- return lib->lv2_descriptor(index);
- } else if (lib->desc) {
- return lib->desc->get_plugin(lib->desc->handle, index);
- }
- return NULL;
+ if (lib->lv2_descriptor) {
+ return lib->lv2_descriptor(index);
+ }
+
+ if (lib->desc) {
+ return lib->desc->get_plugin(lib->desc->handle, index);
+ }
+
+ return NULL;
}
void
lilv_lib_close(LilvLib* lib)
{
- if (--lib->refs == 0) {
- dlclose(lib->lib);
-
- ZixTreeIter* i = NULL;
- if (lib->world->libs && !zix_tree_find(lib->world->libs, lib, &i)) {
- zix_tree_remove(lib->world->libs, i);
- }
-
- lilv_node_free(lib->uri);
- free(lib->bundle_path);
- free(lib);
- }
+ if (--lib->refs == 0) {
+ dlclose(lib->lib);
+
+ ZixTreeIter* i = NULL;
+ if (lib->world->libs && !zix_tree_find(lib->world->libs, lib, &i)) {
+ zix_tree_remove(lib->world->libs, i);
+ }
+
+ lilv_node_free(lib->uri);
+ free(lib->bundle_path);
+ free(lib);
+ }
}
diff --git a/src/lilv_config.h b/src/lilv_config.h
new file mode 100644
index 0000000..2f7c498
--- /dev/null
+++ b/src/lilv_config.h
@@ -0,0 +1,33 @@
+// Copyright 2021-2024 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#ifndef LILV_CONFIG_H
+#define LILV_CONFIG_H
+
+// Define version unconditionally so a warning will catch a mismatch
+#define LILV_VERSION "0.24.25"
+
+// Separator between entries in variables like PATH
+#ifndef LILV_PATH_SEP
+# ifdef _WIN32
+# define LILV_PATH_SEP ";"
+# else
+# define LILV_PATH_SEP ":"
+# endif
+#endif
+
+// Default value for LV2_PATH environment variable
+#ifndef LILV_DEFAULT_LV2_PATH
+# if defined(__APPLE__)
+# define LILV_DEFAULT_LV2_PATH \
+ "~/.lv2:~/Library/Audio/Plug-Ins/LV2:" \
+ "/usr/local/lib/lv2:/usr/lib/lv2:" \
+ "/Library/Audio/Plug-Ins/LV2"
+# elif defined(_WIN32)
+# define LILV_DEFAULT_LV2_PATH "%APPDATA%\\LV2;%COMMONPROGRAMFILES%\\LV2"
+# else
+# define LILV_DEFAULT_LV2_PATH "~/.lv2:/usr/local/lib/lv2:/usr/lib/lv2"
+# endif
+#endif
+
+#endif // LILV_CONFIG_H
diff --git a/src/lilv_internal.h b/src/lilv_internal.h
index d603df7..f1bca25 100644
--- a/src/lilv_internal.h
+++ b/src/lilv_internal.h
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#ifndef LILV_INTERNAL_H
#define LILV_INTERNAL_H
@@ -21,44 +8,39 @@
extern "C" {
#endif
-#include "lilv_config.h"
+#include "lilv_config.h" // IWYU pragma: keep
#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
#include "serd/serd.h"
#include "sord/sord.h"
#include "zix/tree.h"
-#include <float.h>
-#include <stddef.h>
+#include <stdbool.h>
#include <stdint.h>
-#include <stdlib.h>
+#include <stdio.h>
#ifdef _WIN32
-# include <windows.h>
-# include <direct.h>
-# include <stdio.h>
-# define dlopen(path, flags) LoadLibrary(path)
-# define dlclose(lib) FreeLibrary((HMODULE)lib)
-# ifdef _MSC_VER
-# define __func__ __FUNCTION__
-# ifndef snprintf
-# define snprintf _snprintf
-# endif
+# include <direct.h>
+# include <windows.h>
+# define dlopen(path, flags) LoadLibrary(path)
+# define dlclose(lib) FreeLibrary((HMODULE)lib)
+# ifdef _MSC_VER
+# ifndef snprintf
+# define snprintf _snprintf
# endif
-#ifndef INFINITY
-# define INFINITY DBL_MAX + DBL_MAX
-#endif
-#ifndef NAN
-# define NAN INFINITY - INFINITY
-#endif
-static inline const char* dlerror(void) { return "Unknown error"; }
+# endif
+static inline const char*
+dlerror(void)
+{
+ return "Unknown error";
+}
#else
-# include <dlfcn.h>
-# include <unistd.h>
+# include <dlfcn.h>
#endif
#ifdef LILV_DYN_MANIFEST
-# include "lv2/dynmanifest/dynmanifest.h"
+# include "lv2/dynmanifest/dynmanifest.h"
#endif
/*
@@ -67,23 +49,21 @@ static inline const char* dlerror(void) { return "Unknown error"; }
*
*/
-typedef struct LilvSpecImpl LilvSpec;
-
typedef void LilvCollection;
struct LilvPortImpl {
- LilvNode* node; ///< RDF node
- uint32_t index; ///< lv2:index
- LilvNode* symbol; ///< lv2:symbol
- LilvNodes* classes; ///< rdf:type
+ LilvNode* node; ///< RDF node
+ uint32_t index; ///< lv2:index
+ LilvNode* symbol; ///< lv2:symbol
+ LilvNodes* classes; ///< rdf:type
};
-struct LilvSpecImpl {
- SordNode* spec;
- SordNode* bundle;
- LilvNodes* data_uris;
- struct LilvSpecImpl* next;
-};
+typedef struct LilvSpecImpl {
+ SordNode* spec;
+ SordNode* bundle;
+ LilvNodes* data_uris;
+ struct LilvSpecImpl* next;
+} LilvSpec;
/**
Header of an LilvPlugin, LilvPluginClass, or LilvUI.
@@ -91,156 +71,156 @@ struct LilvSpecImpl {
implement collections using the same comparator.
*/
struct LilvHeader {
- LilvWorld* world;
- LilvNode* uri;
+ LilvWorld* world;
+ LilvNode* uri;
};
#ifdef LILV_DYN_MANIFEST
typedef struct {
- LilvNode* bundle;
- void* lib;
- LV2_Dyn_Manifest_Handle handle;
- uint32_t refs;
+ LilvNode* bundle;
+ void* lib;
+ LV2_Dyn_Manifest_Handle handle;
+ uint32_t refs;
} LilvDynManifest;
#endif
typedef struct {
- LilvWorld* world;
- LilvNode* uri;
- char* bundle_path;
- void* lib;
- LV2_Descriptor_Function lv2_descriptor;
- const LV2_Lib_Descriptor* desc;
- uint32_t refs;
+ LilvWorld* world;
+ LilvNode* uri;
+ char* bundle_path;
+ void* lib;
+ LV2_Descriptor_Function lv2_descriptor;
+ const LV2_Lib_Descriptor* desc;
+ uint32_t refs;
} LilvLib;
struct LilvPluginImpl {
- LilvWorld* world;
- LilvNode* plugin_uri;
- LilvNode* bundle_uri; ///< Bundle plugin was loaded from
- LilvNode* binary_uri; ///< lv2:binary
+ LilvWorld* world;
+ LilvNode* plugin_uri;
+ LilvNode* bundle_uri; ///< Bundle plugin was loaded from
+ LilvNode* binary_uri; ///< lv2:binary
#ifdef LILV_DYN_MANIFEST
- LilvDynManifest* dynmanifest;
+ LilvDynManifest* dynmanifest;
#endif
- const LilvPluginClass* plugin_class;
- LilvNodes* data_uris; ///< rdfs::seeAlso
- LilvPort** ports;
- uint32_t num_ports;
- bool loaded;
- bool parse_errors;
- bool replaced;
+ const LilvPluginClass* plugin_class;
+ LilvNodes* data_uris; ///< rdfs::seeAlso
+ LilvPort** ports;
+ uint32_t num_ports;
+ bool loaded;
+ bool parse_errors;
+ bool replaced;
};
struct LilvPluginClassImpl {
- LilvWorld* world;
- LilvNode* uri;
- LilvNode* parent_uri;
- LilvNode* label;
+ LilvWorld* world;
+ LilvNode* uri;
+ LilvNode* parent_uri;
+ LilvNode* label;
};
struct LilvInstancePimpl {
- LilvWorld* world;
- LilvLib* lib;
+ LilvWorld* world;
+ LilvLib* lib;
};
typedef struct {
- bool dyn_manifest;
- bool filter_language;
- char* lv2_path;
+ bool dyn_manifest;
+ bool filter_language;
+ char* lv2_path;
} LilvOptions;
struct LilvWorldImpl {
- SordWorld* world;
- SordModel* model;
- SerdReader* reader;
- unsigned n_read_files;
- LilvPluginClass* lv2_plugin_class;
- LilvPluginClasses* plugin_classes;
- LilvSpec* specs;
- LilvPlugins* plugins;
- LilvPlugins* zombies;
- LilvNodes* loaded_files;
- ZixTree* libs;
- struct {
- SordNode* dc_replaces;
- SordNode* dman_DynManifest;
- SordNode* doap_name;
- SordNode* lv2_Plugin;
- SordNode* lv2_Specification;
- SordNode* lv2_appliesTo;
- SordNode* lv2_binary;
- SordNode* lv2_default;
- SordNode* lv2_designation;
- SordNode* lv2_extensionData;
- SordNode* lv2_index;
- SordNode* lv2_latency;
- SordNode* lv2_maximum;
- SordNode* lv2_microVersion;
- SordNode* lv2_minimum;
- SordNode* lv2_minorVersion;
- SordNode* lv2_name;
- SordNode* lv2_optionalFeature;
- SordNode* lv2_port;
- SordNode* lv2_portProperty;
- SordNode* lv2_reportsLatency;
- SordNode* lv2_requiredFeature;
- SordNode* lv2_symbol;
- SordNode* lv2_prototype;
- SordNode* owl_Ontology;
- SordNode* pset_value;
- SordNode* rdf_a;
- SordNode* rdf_value;
- SordNode* rdfs_Class;
- SordNode* rdfs_label;
- SordNode* rdfs_seeAlso;
- SordNode* rdfs_subClassOf;
- SordNode* xsd_base64Binary;
- SordNode* xsd_boolean;
- SordNode* xsd_decimal;
- SordNode* xsd_double;
- SordNode* xsd_integer;
- SordNode* null_uri;
- } uris;
- LilvOptions opt;
+ SordWorld* world;
+ SordModel* model;
+ SerdReader* reader;
+ unsigned n_read_files;
+ LilvPluginClass* lv2_plugin_class;
+ LilvPluginClasses* plugin_classes;
+ LilvSpec* specs;
+ LilvPlugins* plugins;
+ LilvPlugins* zombies;
+ LilvNodes* loaded_files;
+ ZixTree* libs;
+ struct {
+ SordNode* dc_replaces;
+ SordNode* dman_DynManifest;
+ SordNode* doap_name;
+ SordNode* lv2_Plugin;
+ SordNode* lv2_Specification;
+ SordNode* lv2_appliesTo;
+ SordNode* lv2_binary;
+ SordNode* lv2_default;
+ SordNode* lv2_designation;
+ SordNode* lv2_extensionData;
+ SordNode* lv2_index;
+ SordNode* lv2_latency;
+ SordNode* lv2_maximum;
+ SordNode* lv2_microVersion;
+ SordNode* lv2_minimum;
+ SordNode* lv2_minorVersion;
+ SordNode* lv2_name;
+ SordNode* lv2_optionalFeature;
+ SordNode* lv2_port;
+ SordNode* lv2_portProperty;
+ SordNode* lv2_reportsLatency;
+ SordNode* lv2_requiredFeature;
+ SordNode* lv2_symbol;
+ SordNode* lv2_prototype;
+ SordNode* owl_Ontology;
+ SordNode* pset_value;
+ SordNode* rdf_a;
+ SordNode* rdf_value;
+ SordNode* rdfs_Class;
+ SordNode* rdfs_label;
+ SordNode* rdfs_seeAlso;
+ SordNode* rdfs_subClassOf;
+ SordNode* xsd_base64Binary;
+ SordNode* xsd_boolean;
+ SordNode* xsd_decimal;
+ SordNode* xsd_double;
+ SordNode* xsd_integer;
+ SordNode* null_uri;
+ } uris;
+ LilvOptions opt;
};
typedef enum {
- LILV_VALUE_URI,
- LILV_VALUE_STRING,
- LILV_VALUE_INT,
- LILV_VALUE_FLOAT,
- LILV_VALUE_BOOL,
- LILV_VALUE_BLANK,
- LILV_VALUE_BLOB
+ LILV_VALUE_URI,
+ LILV_VALUE_STRING,
+ LILV_VALUE_INT,
+ LILV_VALUE_FLOAT,
+ LILV_VALUE_BOOL,
+ LILV_VALUE_BLANK,
+ LILV_VALUE_BLOB
} LilvNodeType;
struct LilvNodeImpl {
- LilvWorld* world;
- SordNode* node;
- LilvNodeType type;
- union {
- int int_val;
- float float_val;
- bool bool_val;
- } val;
+ LilvWorld* world;
+ SordNode* node;
+ LilvNodeType type;
+ union {
+ int int_val;
+ float float_val;
+ bool bool_val;
+ } val;
};
struct LilvScalePointImpl {
- LilvNode* value;
- LilvNode* label;
+ LilvNode* value;
+ LilvNode* label;
};
struct LilvUIImpl {
- LilvWorld* world;
- LilvNode* uri;
- LilvNode* bundle_uri;
- LilvNode* binary_uri;
- LilvNodes* classes;
+ LilvWorld* world;
+ LilvNode* uri;
+ LilvNode* bundle_uri;
+ LilvNode* binary_uri;
+ LilvNodes* classes;
};
typedef struct LilvVersion {
- int minor;
- int micro;
+ int minor;
+ int micro;
} LilvVersion;
/*
@@ -249,98 +229,125 @@ typedef struct LilvVersion {
*
*/
-LilvPort* lilv_port_new(LilvWorld* world,
- const SordNode* node,
- uint32_t index,
- const char* symbol);
-void lilv_port_free(const LilvPlugin* plugin, LilvPort* port);
-
-LilvPlugin* lilv_plugin_new(LilvWorld* world,
- LilvNode* uri,
- LilvNode* bundle_uri);
-void lilv_plugin_clear(LilvPlugin* plugin, LilvNode* bundle_uri);
-void lilv_plugin_load_if_necessary(const LilvPlugin* plugin);
-void lilv_plugin_free(LilvPlugin* plugin);
-LilvNode* lilv_plugin_get_unique(const LilvPlugin* plugin,
- const SordNode* subject,
- const SordNode* predicate);
-
-void lilv_collection_free(LilvCollection* collection);
-unsigned lilv_collection_size(const LilvCollection* collection);
-LilvIter* lilv_collection_begin(const LilvCollection* collection);
-void* lilv_collection_get(const LilvCollection* collection,
- const LilvIter* i);
-
-LilvPluginClass* lilv_plugin_class_new(LilvWorld* world,
- const SordNode* parent_node,
- const SordNode* uri,
- const char* label);
-
-void lilv_plugin_class_free(LilvPluginClass* plugin_class);
+LilvPort*
+lilv_port_new(LilvWorld* world,
+ const SordNode* node,
+ uint32_t index,
+ const char* symbol);
+void
+lilv_port_free(const LilvPlugin* plugin, LilvPort* port);
+
+LilvPlugin*
+lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri);
+
+void
+lilv_plugin_clear(LilvPlugin* plugin, LilvNode* bundle_uri);
+
+void
+lilv_plugin_load_if_necessary(const LilvPlugin* plugin);
+
+void
+lilv_plugin_free(LilvPlugin* plugin);
+
+LilvNode*
+lilv_plugin_get_unique(const LilvPlugin* plugin,
+ const SordNode* subject,
+ const SordNode* predicate);
+
+void*
+lilv_collection_get(const LilvCollection* collection, const LilvIter* i);
+
+LilvPluginClass*
+lilv_plugin_class_new(LilvWorld* world,
+ const SordNode* parent_node,
+ const SordNode* uri,
+ const char* label);
+
+void
+lilv_plugin_class_free(LilvPluginClass* plugin_class);
LilvLib*
-lilv_lib_open(LilvWorld* world,
- const LilvNode* uri,
- const char* bundle_path,
- const LV2_Feature*const* features);
+lilv_lib_open(LilvWorld* world,
+ const LilvNode* uri,
+ const char* bundle_path,
+ const LV2_Feature* const* features);
+
+const LV2_Descriptor*
+lilv_lib_get_plugin(LilvLib* lib, uint32_t index);
+
+void
+lilv_lib_close(LilvLib* lib);
-const LV2_Descriptor* lilv_lib_get_plugin(LilvLib* lib, uint32_t index);
-void lilv_lib_close(LilvLib* lib);
+LilvNodes*
+lilv_nodes_new(void);
+
+LilvPlugins*
+lilv_plugins_new(void);
+
+LilvScalePoints*
+lilv_scale_points_new(void);
-LilvNodes* lilv_nodes_new(void);
-LilvPlugins* lilv_plugins_new(void);
-LilvScalePoints* lilv_scale_points_new(void);
-LilvPluginClasses* lilv_plugin_classes_new(void);
-LilvUIs* lilv_uis_new(void);
+LilvPluginClasses*
+lilv_plugin_classes_new(void);
-LilvNode* lilv_world_get_manifest_uri(LilvWorld* world,
- const LilvNode* bundle_uri);
+LilvUIs*
+lilv_uis_new(void);
-const uint8_t* lilv_world_blank_node_prefix(LilvWorld* world);
+LilvNode*
+lilv_world_get_manifest_uri(LilvWorld* world, const LilvNode* bundle_uri);
-SerdStatus lilv_world_load_file(LilvWorld* world,
- SerdReader* reader,
- const LilvNode* uri);
+const uint8_t*
+lilv_world_blank_node_prefix(LilvWorld* world);
SerdStatus
-lilv_world_load_graph(LilvWorld* world,
- SordNode* graph,
- const LilvNode* uri);
+lilv_world_load_file(LilvWorld* world, SerdReader* reader, const LilvNode* uri);
+
+LilvUI*
+lilv_ui_new(LilvWorld* world,
+ LilvNode* uri,
+ LilvNode* type_uri,
+ LilvNode* binary_uri);
+
+void
+lilv_ui_free(LilvUI* ui);
-LilvUI* lilv_ui_new(LilvWorld* world,
- LilvNode* uri,
- LilvNode* type_uri,
- LilvNode* binary_uri);
+LilvNode*
+lilv_node_new(LilvWorld* world, LilvNodeType type, const char* str);
-void lilv_ui_free(LilvUI* ui);
+LilvNode*
+lilv_node_new_from_node(LilvWorld* world, const SordNode* node);
-LilvNode* lilv_node_new(LilvWorld* world, LilvNodeType type, const char* str);
-LilvNode* lilv_node_new_from_node(LilvWorld* world, const SordNode* node);
+int
+lilv_header_compare_by_uri(const void* a, const void* b, const void* user_data);
-int lilv_header_compare_by_uri(const void* a, const void* b, void* user_data);
-int lilv_lib_compare(const void* a, const void* b, void* user_data);
+int
+lilv_ptr_cmp(const void* a, const void* b, const 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, const 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;
- }
+ if (a->minor == b->minor && a->micro == b->micro) {
+ return 0;
+ }
+
+ if ((a->minor < b->minor) || (a->minor == b->minor && a->micro < b->micro)) {
+ return -1;
+ }
+
+ return 1;
}
struct LilvHeader*
lilv_collection_get_by_uri(const ZixTree* seq, const LilvNode* uri);
-LilvScalePoint* lilv_scale_point_new(LilvNode* value, LilvNode* label);
-void lilv_scale_point_free(LilvScalePoint* point);
+LilvScalePoint*
+lilv_scale_point_new(LilvNode* value, LilvNode* label);
+
+void
+lilv_scale_point_free(LilvScalePoint* point);
SordIter*
lilv_world_query_internal(LilvWorld* world,
@@ -368,18 +375,27 @@ lilv_world_filter_model(LilvWorld* world,
const SordNode* object,
const SordNode* graph);
-#define FOREACH_MATCH(iter) \
- for (; !sord_iter_end(iter); sord_iter_next(iter))
+#define FOREACH_MATCH(iter) for (; !sord_iter_end(iter); sord_iter_next(iter))
+
+LilvNodes*
+lilv_nodes_from_stream_objects(LilvWorld* world,
+ SordIter* stream,
+ SordQuadIndex field);
-LilvNodes* lilv_nodes_from_stream_objects(LilvWorld* world,
- SordIter* stream,
- SordQuadIndex field);
+char*
+lilv_strjoin(const char* first, ...);
-char* lilv_strjoin(const char* first, ...);
-char* lilv_strdup(const char* str);
-char* lilv_get_lang(void);
-char* lilv_expand(const char* path);
-char* lilv_get_latest_copy(const char* path, const char* copy_path);
+char*
+lilv_strdup(const char* str);
+
+char*
+lilv_get_lang(void);
+
+char*
+lilv_expand(const char* path);
+
+char*
+lilv_get_latest_copy(const char* path, const char* copy_path);
char*
lilv_find_free_path(const char* in_path,
@@ -393,32 +409,30 @@ static inline LilvVoidFunc
lilv_dlfunc(void* handle, const char* symbol)
{
#ifdef _WIN32
- return (LilvVoidFunc)GetProcAddress((HMODULE)handle, symbol);
+ return (LilvVoidFunc)GetProcAddress((HMODULE)handle, symbol);
#else
- typedef LilvVoidFunc (*VoidFuncGetter)(void*, const char*);
- VoidFuncGetter dlfunc = (VoidFuncGetter)dlsym;
- return dlfunc(handle, symbol);
+ typedef LilvVoidFunc (*VoidFuncGetter)(void*, const char*);
+ VoidFuncGetter dlfunc = (VoidFuncGetter)dlsym;
+ return dlfunc(handle, symbol);
#endif
}
#ifdef LILV_DYN_MANIFEST
-static const LV2_Feature* const dman_features = { NULL };
+static const LV2_Feature* const dman_features = {NULL};
-void lilv_dynmanifest_free(LilvDynManifest* dynmanifest);
+void
+lilv_dynmanifest_free(LilvDynManifest* dynmanifest);
#endif
-#define LILV_ERROR(str) fprintf(stderr, "%s(): error: " str, \
- __func__)
-#define LILV_ERRORF(fmt, ...) fprintf(stderr, "%s(): error: " fmt, \
- __func__, __VA_ARGS__)
-#define LILV_WARN(str) fprintf(stderr, "%s(): warning: " str, \
- __func__)
-#define LILV_WARNF(fmt, ...) fprintf(stderr, "%s(): warning: " fmt, \
- __func__, __VA_ARGS__)
-#define LILV_NOTE(str) fprintf(stderr, "%s(): note: " str, \
- __func__)
-#define LILV_NOTEF(fmt, ...) fprintf(stderr, "%s(): note: " fmt, \
- __func__, __VA_ARGS__)
+#define LILV_ERROR(str) fprintf(stderr, "%s(): error: " str, __func__)
+#define LILV_ERRORF(fmt, ...) \
+ fprintf(stderr, "%s(): error: " fmt, __func__, __VA_ARGS__)
+#define LILV_WARN(str) fprintf(stderr, "%s(): warning: " str, __func__)
+#define LILV_WARNF(fmt, ...) \
+ fprintf(stderr, "%s(): warning: " fmt, __func__, __VA_ARGS__)
+#define LILV_NOTE(str) fprintf(stderr, "%s(): note: " str, __func__)
+#define LILV_NOTEF(fmt, ...) \
+ fprintf(stderr, "%s(): note: " fmt, __func__, __VA_ARGS__)
#ifdef __cplusplus
}
diff --git a/src/node.c b/src/node.c
index 59b3353..a10ac86 100644
--- a/src/node.c
+++ b/src/node.c
@@ -1,25 +1,14 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "filesystem.h"
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
#include "sord/sord.h"
+#include "zix/allocator.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
#include <math.h>
#include <stdbool.h>
@@ -31,24 +20,24 @@
static void
lilv_node_set_numerics_from_string(LilvNode* val)
{
- const char* str = (const char*)sord_node_get_string(val->node);
-
- switch (val->type) {
- case LILV_VALUE_URI:
- case LILV_VALUE_BLANK:
- case LILV_VALUE_STRING:
- case LILV_VALUE_BLOB:
- break;
- case LILV_VALUE_INT:
- val->val.int_val = strtol(str, NULL, 10);
- break;
- case LILV_VALUE_FLOAT:
- val->val.float_val = serd_strtod(str, NULL);
- break;
- case LILV_VALUE_BOOL:
- val->val.bool_val = !strcmp(str, "true");
- break;
- }
+ const char* str = (const char*)sord_node_get_string(val->node);
+
+ switch (val->type) {
+ case LILV_VALUE_URI:
+ case LILV_VALUE_BLANK:
+ case LILV_VALUE_STRING:
+ case LILV_VALUE_BLOB:
+ break;
+ case LILV_VALUE_INT:
+ val->val.int_val = strtol(str, NULL, 10);
+ break;
+ case LILV_VALUE_FLOAT:
+ val->val.float_val = serd_strtod(str, NULL);
+ break;
+ case LILV_VALUE_BOOL:
+ val->val.bool_val = !strcmp(str, "true");
+ break;
+ }
}
/** Note that if `type` is numeric or boolean, the returned value is corrupt
@@ -59,354 +48,365 @@ lilv_node_set_numerics_from_string(LilvNode* val)
LilvNode*
lilv_node_new(LilvWorld* world, LilvNodeType type, const char* str)
{
- LilvNode* val = (LilvNode*)malloc(sizeof(LilvNode));
- val->world = world;
- val->type = type;
-
- const uint8_t* ustr = (const uint8_t*)str;
- switch (type) {
- case LILV_VALUE_URI:
- val->node = sord_new_uri(world->world, ustr);
- break;
- case LILV_VALUE_BLANK:
- val->node = sord_new_blank(world->world, ustr);
- break;
- case LILV_VALUE_STRING:
- val->node = sord_new_literal(world->world, NULL, ustr, NULL);
- break;
- case LILV_VALUE_INT:
- val->node = sord_new_literal(
- world->world, world->uris.xsd_integer, ustr, NULL);
- break;
- case LILV_VALUE_FLOAT:
- val->node = sord_new_literal(
- world->world, world->uris.xsd_decimal, ustr, NULL);
- break;
- case LILV_VALUE_BOOL:
- val->node = sord_new_literal(
- world->world, world->uris.xsd_boolean, ustr, NULL);
- break;
- case LILV_VALUE_BLOB:
- val->node = sord_new_literal(
- world->world, world->uris.xsd_base64Binary, ustr, NULL);
- break;
- }
-
- if (!val->node) {
- free(val);
- return NULL;
- }
-
- return val;
+ LilvNode* val = (LilvNode*)malloc(sizeof(LilvNode));
+ val->world = world;
+ val->type = type;
+
+ const uint8_t* ustr = (const uint8_t*)str;
+ switch (type) {
+ case LILV_VALUE_URI:
+ val->node = sord_new_uri(world->world, ustr);
+ break;
+ case LILV_VALUE_BLANK:
+ val->node = sord_new_blank(world->world, ustr);
+ break;
+ case LILV_VALUE_STRING:
+ val->node = sord_new_literal(world->world, NULL, ustr, NULL);
+ break;
+ case LILV_VALUE_INT:
+ val->node =
+ sord_new_literal(world->world, world->uris.xsd_integer, ustr, NULL);
+ break;
+ case LILV_VALUE_FLOAT:
+ val->node =
+ sord_new_literal(world->world, world->uris.xsd_decimal, ustr, NULL);
+ break;
+ case LILV_VALUE_BOOL:
+ val->node =
+ sord_new_literal(world->world, world->uris.xsd_boolean, ustr, NULL);
+ break;
+ case LILV_VALUE_BLOB:
+ val->node =
+ sord_new_literal(world->world, world->uris.xsd_base64Binary, ustr, NULL);
+ break;
+ }
+
+ if (!val->node) {
+ free(val);
+ return NULL;
+ }
+
+ return val;
}
/** Create a new LilvNode from `node`, or return NULL if impossible */
LilvNode*
lilv_node_new_from_node(LilvWorld* world, const SordNode* node)
{
- if (!node) {
- return NULL;
- }
-
- LilvNode* result = NULL;
- SordNode* datatype_uri = NULL;
- LilvNodeType type = LILV_VALUE_STRING;
-
- switch (sord_node_get_type(node)) {
- case SORD_URI:
- result = (LilvNode*)malloc(sizeof(LilvNode));
- result->world = world;
- result->type = LILV_VALUE_URI;
- result->node = sord_node_copy(node);
- break;
- case SORD_BLANK:
- result = (LilvNode*)malloc(sizeof(LilvNode));
- result->world = world;
- result->type = LILV_VALUE_BLANK;
- result->node = sord_node_copy(node);
- break;
- case SORD_LITERAL:
- datatype_uri = sord_node_get_datatype(node);
- if (datatype_uri) {
- if (sord_node_equals(datatype_uri, world->uris.xsd_boolean)) {
- type = LILV_VALUE_BOOL;
- } else if (sord_node_equals(datatype_uri, world->uris.xsd_decimal) ||
- sord_node_equals(datatype_uri, world->uris.xsd_double)) {
- type = LILV_VALUE_FLOAT;
- } else if (sord_node_equals(datatype_uri, world->uris.xsd_integer)) {
- type = LILV_VALUE_INT;
- } else if (sord_node_equals(datatype_uri,
- world->uris.xsd_base64Binary)) {
- type = LILV_VALUE_BLOB;
- } else {
- LILV_ERRORF("Unknown datatype `%s'\n",
- sord_node_get_string(datatype_uri));
- }
- }
- result = lilv_node_new(
- world, type, (const char*)sord_node_get_string(node));
- lilv_node_set_numerics_from_string(result);
- break;
- }
-
- return result;
+ if (!node) {
+ return NULL;
+ }
+
+ LilvNode* result = NULL;
+ SordNode* datatype_uri = NULL;
+ LilvNodeType type = LILV_VALUE_STRING;
+
+ switch (sord_node_get_type(node)) {
+ case SORD_URI:
+ result = (LilvNode*)malloc(sizeof(LilvNode));
+ result->world = world;
+ result->type = LILV_VALUE_URI;
+ result->node = sord_node_copy(node);
+ break;
+ case SORD_BLANK:
+ result = (LilvNode*)malloc(sizeof(LilvNode));
+ result->world = world;
+ result->type = LILV_VALUE_BLANK;
+ result->node = sord_node_copy(node);
+ break;
+ case SORD_LITERAL:
+ datatype_uri = sord_node_get_datatype(node);
+ if (datatype_uri) {
+ if (sord_node_equals(datatype_uri, world->uris.xsd_boolean)) {
+ type = LILV_VALUE_BOOL;
+ } else if (sord_node_equals(datatype_uri, world->uris.xsd_decimal) ||
+ sord_node_equals(datatype_uri, world->uris.xsd_double)) {
+ type = LILV_VALUE_FLOAT;
+ } else if (sord_node_equals(datatype_uri, world->uris.xsd_integer)) {
+ type = LILV_VALUE_INT;
+ } else if (sord_node_equals(datatype_uri, world->uris.xsd_base64Binary)) {
+ type = LILV_VALUE_BLOB;
+ } else {
+ LILV_ERRORF("Unknown datatype `%s'\n",
+ sord_node_get_string(datatype_uri));
+ }
+ }
+ result =
+ lilv_node_new(world, type, (const char*)sord_node_get_string(node));
+ lilv_node_set_numerics_from_string(result);
+ break;
+ }
+
+ return result;
}
LilvNode*
lilv_new_uri(LilvWorld* world, const char* uri)
{
- return lilv_node_new(world, LILV_VALUE_URI, uri);
+ return lilv_node_new(world, LILV_VALUE_URI, uri);
}
LilvNode*
lilv_new_file_uri(LilvWorld* world, const char* host, const char* path)
{
- char* abs_path = lilv_path_absolute(path);
- SerdNode s = serd_node_new_file_uri(
- (const uint8_t*)abs_path, (const uint8_t*)host, NULL, true);
-
- LilvNode* ret = lilv_node_new(world, LILV_VALUE_URI, (const char*)s.buf);
- serd_node_free(&s);
- free(abs_path);
- return ret;
+ SerdNode s = SERD_NODE_NULL;
+ if (zix_path_root_directory(path).length) {
+ s = serd_node_new_file_uri(
+ (const uint8_t*)path, (const uint8_t*)host, NULL, true);
+ } else {
+ char* const cwd = zix_current_path(NULL);
+ char* const abs_path = zix_path_join(NULL, cwd, path);
+
+ s = serd_node_new_file_uri(
+ (const uint8_t*)abs_path, (const uint8_t*)host, NULL, true);
+
+ zix_free(NULL, abs_path);
+ zix_free(NULL, cwd);
+ }
+
+ LilvNode* ret = lilv_node_new(world, LILV_VALUE_URI, (const char*)s.buf);
+ serd_node_free(&s);
+ return ret;
}
LilvNode*
lilv_new_string(LilvWorld* world, const char* str)
{
- return lilv_node_new(world, LILV_VALUE_STRING, str);
+ return lilv_node_new(world, LILV_VALUE_STRING, str);
}
LilvNode*
lilv_new_int(LilvWorld* world, int val)
{
- char str[32];
- snprintf(str, sizeof(str), "%d", val);
- LilvNode* ret = lilv_node_new(world, LILV_VALUE_INT, str);
- if (ret) {
- ret->val.int_val = val;
- }
- return ret;
+ char str[32];
+ snprintf(str, sizeof(str), "%d", val);
+ LilvNode* ret = lilv_node_new(world, LILV_VALUE_INT, str);
+ if (ret) {
+ ret->val.int_val = val;
+ }
+ return ret;
}
LilvNode*
lilv_new_float(LilvWorld* world, float val)
{
- char str[32];
- snprintf(str, sizeof(str), "%f", val);
- LilvNode* ret = lilv_node_new(world, LILV_VALUE_FLOAT, str);
- if (ret) {
- ret->val.float_val = val;
- }
- return ret;
+ char str[32];
+ snprintf(str, sizeof(str), "%f", val);
+ LilvNode* ret = lilv_node_new(world, LILV_VALUE_FLOAT, str);
+ if (ret) {
+ ret->val.float_val = val;
+ }
+ return ret;
}
LilvNode*
lilv_new_bool(LilvWorld* world, bool val)
{
- LilvNode* ret = lilv_node_new(world, LILV_VALUE_BOOL,
- val ? "true" : "false");
- if (ret) {
- ret->val.bool_val = val;
- }
- return ret;
+ LilvNode* ret = lilv_node_new(world, LILV_VALUE_BOOL, val ? "true" : "false");
+ if (ret) {
+ ret->val.bool_val = val;
+ }
+ return ret;
}
LilvNode*
lilv_node_duplicate(const LilvNode* val)
{
- if (!val) {
- return NULL;
- }
-
- LilvNode* result = (LilvNode*)malloc(sizeof(LilvNode));
- result->world = val->world;
- result->node = sord_node_copy(val->node);
- result->val = val->val;
- result->type = val->type;
- return result;
+ if (!val) {
+ return NULL;
+ }
+
+ LilvNode* result = (LilvNode*)malloc(sizeof(LilvNode));
+ result->world = val->world;
+ result->node = sord_node_copy(val->node);
+ result->val = val->val;
+ result->type = val->type;
+ return result;
}
void
lilv_node_free(LilvNode* val)
{
- if (val) {
- sord_node_free(val->world->world, val->node);
- free(val);
- }
+ if (val) {
+ sord_node_free(val->world->world, val->node);
+ free(val);
+ }
}
bool
lilv_node_equals(const LilvNode* value, const LilvNode* other)
{
- if (value == NULL && other == NULL) {
- return true;
- } else if (value == NULL || other == NULL) {
- return false;
- } else if (value->type != other->type) {
- return false;
- }
-
- switch (value->type) {
- case LILV_VALUE_URI:
- case LILV_VALUE_BLANK:
- case LILV_VALUE_STRING:
- case LILV_VALUE_BLOB:
- return sord_node_equals(value->node, other->node);
- case LILV_VALUE_INT:
- return (value->val.int_val == other->val.int_val);
- case LILV_VALUE_FLOAT:
- return (value->val.float_val == other->val.float_val);
- case LILV_VALUE_BOOL:
- return (value->val.bool_val == other->val.bool_val);
- }
-
- return false; /* shouldn't get here */
+ if (value == NULL && other == NULL) {
+ return true;
+ }
+
+ if (value == NULL || other == NULL || value->type != other->type) {
+ return false;
+ }
+
+ switch (value->type) {
+ case LILV_VALUE_URI:
+ case LILV_VALUE_BLANK:
+ case LILV_VALUE_STRING:
+ case LILV_VALUE_BLOB:
+ return sord_node_equals(value->node, other->node);
+ case LILV_VALUE_INT:
+ return (value->val.int_val == other->val.int_val);
+ case LILV_VALUE_FLOAT:
+ return (value->val.float_val == other->val.float_val);
+ case LILV_VALUE_BOOL:
+ return (value->val.bool_val == other->val.bool_val);
+ }
+
+ return false; /* shouldn't get here */
}
char*
lilv_node_get_turtle_token(const LilvNode* value)
{
- const char* str = (const char*)sord_node_get_string(value->node);
- size_t len = 0;
- char* result = NULL;
- SerdNode node;
-
- switch (value->type) {
- case LILV_VALUE_URI:
- len = strlen(str) + 3;
- result = (char*)calloc(len, 1);
- snprintf(result, len, "<%s>", str);
- break;
- case LILV_VALUE_BLANK:
- len = strlen(str) + 3;
- result = (char*)calloc(len, 1);
- snprintf(result, len, "_:%s", str);
- break;
- case LILV_VALUE_STRING:
- case LILV_VALUE_BOOL:
- case LILV_VALUE_BLOB:
- result = lilv_strdup(str);
- break;
- case LILV_VALUE_INT:
- node = serd_node_new_integer(value->val.int_val);
- result = lilv_strdup((char*)node.buf);
- serd_node_free(&node);
- break;
- case LILV_VALUE_FLOAT:
- node = serd_node_new_decimal(value->val.float_val, 8);
- result = lilv_strdup((char*)node.buf);
- serd_node_free(&node);
- break;
- }
-
- return result;
+ const char* str = (const char*)sord_node_get_string(value->node);
+ size_t len = 0;
+ char* result = NULL;
+ SerdNode node;
+
+ switch (value->type) {
+ case LILV_VALUE_URI:
+ len = strlen(str) + 3;
+ result = (char*)calloc(len, 1);
+ snprintf(result, len, "<%s>", str);
+ break;
+ case LILV_VALUE_BLANK:
+ len = strlen(str) + 3;
+ result = (char*)calloc(len, 1);
+ snprintf(result, len, "_:%s", str);
+ break;
+ case LILV_VALUE_STRING:
+ case LILV_VALUE_BOOL:
+ case LILV_VALUE_BLOB:
+ result = lilv_strdup(str);
+ break;
+ case LILV_VALUE_INT:
+ node = serd_node_new_integer(value->val.int_val);
+ result = lilv_strdup((char*)node.buf);
+ serd_node_free(&node);
+ break;
+ case LILV_VALUE_FLOAT:
+ node = serd_node_new_decimal(value->val.float_val, 8);
+ result = lilv_strdup((char*)node.buf);
+ serd_node_free(&node);
+ break;
+ }
+
+ return result;
}
bool
lilv_node_is_uri(const LilvNode* value)
{
- return (value && value->type == LILV_VALUE_URI);
+ return (value && value->type == LILV_VALUE_URI);
}
const char*
lilv_node_as_uri(const LilvNode* value)
{
- return (lilv_node_is_uri(value)
- ? (const char*)sord_node_get_string(value->node)
- : NULL);
+ return (lilv_node_is_uri(value)
+ ? (const char*)sord_node_get_string(value->node)
+ : NULL);
}
bool
lilv_node_is_blank(const LilvNode* value)
{
- return (value && value->type == LILV_VALUE_BLANK);
+ return (value && value->type == LILV_VALUE_BLANK);
}
const char*
lilv_node_as_blank(const LilvNode* value)
{
- return (lilv_node_is_blank(value)
- ? (const char*)sord_node_get_string(value->node)
- : NULL);
+ return (lilv_node_is_blank(value)
+ ? (const char*)sord_node_get_string(value->node)
+ : NULL);
}
bool
lilv_node_is_literal(const LilvNode* value)
{
- if (!value) {
- return false;
- }
-
- switch (value->type) {
- case LILV_VALUE_STRING:
- case LILV_VALUE_INT:
- case LILV_VALUE_FLOAT:
- case LILV_VALUE_BLOB:
- return true;
- default:
- return false;
- }
+ if (!value) {
+ return false;
+ }
+
+ switch (value->type) {
+ case LILV_VALUE_STRING:
+ case LILV_VALUE_INT:
+ case LILV_VALUE_FLOAT:
+ case LILV_VALUE_BLOB:
+ return true;
+ default:
+ return false;
+ }
}
bool
lilv_node_is_string(const LilvNode* value)
{
- return (value && value->type == LILV_VALUE_STRING);
+ return (value && value->type == LILV_VALUE_STRING);
}
const char*
lilv_node_as_string(const LilvNode* value)
{
- return value ? (const char*)sord_node_get_string(value->node) : NULL;
+ return value ? (const char*)sord_node_get_string(value->node) : NULL;
}
bool
lilv_node_is_int(const LilvNode* value)
{
- return (value && value->type == LILV_VALUE_INT);
+ return (value && value->type == LILV_VALUE_INT);
}
int
lilv_node_as_int(const LilvNode* value)
{
- return lilv_node_is_int(value) ? value->val.int_val : 0;
+ return lilv_node_is_int(value) ? value->val.int_val : 0;
}
bool
lilv_node_is_float(const LilvNode* value)
{
- return (value && value->type == LILV_VALUE_FLOAT);
+ return (value && value->type == LILV_VALUE_FLOAT);
}
float
lilv_node_as_float(const LilvNode* value)
{
- if (lilv_node_is_float(value)) {
- return value->val.float_val;
- } else if (lilv_node_is_int(value)) {
- return (float)value->val.int_val;
- }
- return NAN;
+ if (lilv_node_is_float(value)) {
+ return value->val.float_val;
+ }
+
+ if (lilv_node_is_int(value)) {
+ return (float)value->val.int_val;
+ }
+
+ return NAN;
}
bool
lilv_node_is_bool(const LilvNode* value)
{
- return (value && value->type == LILV_VALUE_BOOL);
+ return (value && value->type == LILV_VALUE_BOOL);
}
bool
lilv_node_as_bool(const LilvNode* value)
{
- return lilv_node_is_bool(value) ? value->val.bool_val : false;
+ return lilv_node_is_bool(value) ? value->val.bool_val : false;
}
char*
lilv_node_get_path(const LilvNode* value, char** hostname)
{
- if (lilv_node_is_uri(value)) {
- return lilv_file_uri_parse(lilv_node_as_uri(value), hostname);
- }
- return NULL;
+ if (lilv_node_is_uri(value)) {
+ return lilv_file_uri_parse(lilv_node_as_uri(value), hostname);
+ }
+ return NULL;
}
diff --git a/src/plugin.c b/src/plugin.c
index 9e9eba1..f191eda 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -25,7 +12,7 @@
#include "lv2/ui/ui.h"
#ifdef LILV_DYN_MANIFEST
-# include "lv2/dynmanifest/dynmanifest.h"
+# include "lv2/dynmanifest/dynmanifest.h"
#endif
#include <math.h>
@@ -42,79 +29,79 @@
static void
lilv_plugin_init(LilvPlugin* plugin, LilvNode* bundle_uri)
{
- plugin->bundle_uri = bundle_uri;
- plugin->binary_uri = NULL;
+ plugin->bundle_uri = bundle_uri;
+ plugin->binary_uri = NULL;
#ifdef LILV_DYN_MANIFEST
- plugin->dynmanifest = NULL;
+ plugin->dynmanifest = NULL;
#endif
- plugin->plugin_class = NULL;
- plugin->data_uris = lilv_nodes_new();
- plugin->ports = NULL;
- plugin->num_ports = 0;
- plugin->loaded = false;
- plugin->parse_errors = false;
- plugin->replaced = false;
+ plugin->plugin_class = NULL;
+ plugin->data_uris = lilv_nodes_new();
+ plugin->ports = NULL;
+ plugin->num_ports = 0;
+ plugin->loaded = false;
+ plugin->parse_errors = false;
+ plugin->replaced = false;
}
/** Ownership of `uri` and `bundle` is taken */
LilvPlugin*
lilv_plugin_new(LilvWorld* world, LilvNode* uri, LilvNode* bundle_uri)
{
- LilvPlugin* plugin = (LilvPlugin*)malloc(sizeof(LilvPlugin));
+ LilvPlugin* plugin = (LilvPlugin*)malloc(sizeof(LilvPlugin));
- plugin->world = world;
- plugin->plugin_uri = uri;
+ plugin->world = world;
+ plugin->plugin_uri = uri;
- lilv_plugin_init(plugin, bundle_uri);
- return plugin;
+ lilv_plugin_init(plugin, bundle_uri);
+ return plugin;
}
void
lilv_plugin_clear(LilvPlugin* plugin, LilvNode* bundle_uri)
{
- lilv_node_free(plugin->bundle_uri);
- lilv_node_free(plugin->binary_uri);
- lilv_nodes_free(plugin->data_uris);
- lilv_plugin_init(plugin, bundle_uri);
+ lilv_node_free(plugin->bundle_uri);
+ lilv_node_free(plugin->binary_uri);
+ lilv_nodes_free(plugin->data_uris);
+ lilv_plugin_init(plugin, bundle_uri);
}
static void
lilv_plugin_free_ports(LilvPlugin* plugin)
{
- if (plugin->ports) {
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- lilv_port_free(plugin, plugin->ports[i]);
- }
- free(plugin->ports);
- plugin->num_ports = 0;
- plugin->ports = NULL;
- }
+ if (plugin->ports) {
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ lilv_port_free(plugin, plugin->ports[i]);
+ }
+ free(plugin->ports);
+ plugin->num_ports = 0;
+ plugin->ports = NULL;
+ }
}
void
lilv_plugin_free(LilvPlugin* plugin)
{
#ifdef LILV_DYN_MANIFEST
- if (plugin->dynmanifest && --plugin->dynmanifest->refs == 0) {
- lilv_dynmanifest_free(plugin->dynmanifest);
- }
+ if (plugin->dynmanifest && --plugin->dynmanifest->refs == 0) {
+ lilv_dynmanifest_free(plugin->dynmanifest);
+ }
#endif
- lilv_node_free(plugin->plugin_uri);
- plugin->plugin_uri = NULL;
+ lilv_node_free(plugin->plugin_uri);
+ plugin->plugin_uri = NULL;
- lilv_node_free(plugin->bundle_uri);
- plugin->bundle_uri = NULL;
+ lilv_node_free(plugin->bundle_uri);
+ plugin->bundle_uri = NULL;
- lilv_node_free(plugin->binary_uri);
- plugin->binary_uri = NULL;
+ lilv_node_free(plugin->binary_uri);
+ plugin->binary_uri = NULL;
- lilv_plugin_free_ports(plugin);
+ lilv_plugin_free_ports(plugin);
- lilv_nodes_free(plugin->data_uris);
- plugin->data_uris = NULL;
+ lilv_nodes_free(plugin->data_uris);
+ plugin->data_uris = NULL;
- free(plugin);
+ free(plugin);
}
static LilvNode*
@@ -122,22 +109,22 @@ lilv_plugin_get_one(const LilvPlugin* plugin,
const SordNode* subject,
const SordNode* predicate)
{
- /* TODO: This is slower than it could be in some cases, but it's simpler to
- use the existing i18n code. */
+ /* TODO: This is slower than it could be in some cases, but it's simpler to
+ use the existing i18n code. */
- SordIter* stream =
- lilv_world_query_internal(plugin->world, subject, predicate, NULL);
+ SordIter* stream =
+ lilv_world_query_internal(plugin->world, subject, predicate, NULL);
- LilvNodes* nodes = lilv_nodes_from_stream_objects(
- plugin->world, stream, SORD_OBJECT);
+ LilvNodes* nodes =
+ lilv_nodes_from_stream_objects(plugin->world, stream, SORD_OBJECT);
- if (nodes) {
- LilvNode* value = lilv_node_duplicate(lilv_nodes_get_first(nodes));
- lilv_nodes_free(nodes);
- return value;
- }
+ if (nodes) {
+ LilvNode* value = lilv_node_duplicate(lilv_nodes_get_first(nodes));
+ lilv_nodes_free(nodes);
+ return value;
+ }
- return NULL;
+ return NULL;
}
LilvNode*
@@ -145,394 +132,391 @@ lilv_plugin_get_unique(const LilvPlugin* plugin,
const SordNode* subject,
const SordNode* predicate)
{
- LilvNode* ret = lilv_plugin_get_one(plugin, subject, predicate);
- if (!ret) {
- LILV_ERRORF("No value found for (%s %s ...) property\n",
- sord_node_get_string(subject),
- sord_node_get_string(predicate));
- }
- return ret;
+ LilvNode* ret = lilv_plugin_get_one(plugin, subject, predicate);
+ if (!ret) {
+ LILV_ERRORF("No value found for (%s %s ...) property\n",
+ sord_node_get_string(subject),
+ sord_node_get_string(predicate));
+ }
+ return ret;
}
static void
lilv_plugin_load(LilvPlugin* plugin)
{
- SordNode* bundle_uri_node = plugin->bundle_uri->node;
- const SerdNode* bundle_uri_snode = sord_node_to_serd_node(bundle_uri_node);
-
- SerdEnv* env = serd_env_new(bundle_uri_snode);
- SerdReader* reader = sord_new_reader(plugin->world->model, env, SERD_TURTLE,
- bundle_uri_node);
-
- SordModel* prots = lilv_world_filter_model(
- plugin->world,
- plugin->world->model,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_prototype,
- NULL, NULL);
- SordModel* skel = sord_new(plugin->world->world, SORD_SPO, false);
- SordIter* iter = sord_begin(prots);
- for (; !sord_iter_end(iter); sord_iter_next(iter)) {
- const SordNode* t = sord_iter_get_node(iter, SORD_OBJECT);
- LilvNode* prototype = lilv_node_new_from_node(plugin->world, t);
-
- lilv_world_load_resource(plugin->world, prototype);
-
- SordIter* statements = sord_search(
- plugin->world->model, prototype->node, NULL, NULL, NULL);
- FOREACH_MATCH(statements) {
- SordQuad quad;
- sord_iter_get(statements, quad);
- quad[0] = plugin->plugin_uri->node;
- sord_add(skel, quad);
- }
-
- sord_iter_free(statements);
- lilv_node_free(prototype);
- }
- sord_iter_free(iter);
-
- for (iter = sord_begin(skel); !sord_iter_end(iter); sord_iter_next(iter)) {
- SordQuad quad;
- sord_iter_get(iter, quad);
- sord_add(plugin->world->model, quad);
- }
- sord_iter_free(iter);
- sord_free(skel);
- sord_free(prots);
-
- // Parse all the plugin's data files into RDF model
- SerdStatus st = SERD_SUCCESS;
- LILV_FOREACH(nodes, i, plugin->data_uris) {
- const LilvNode* data_uri = lilv_nodes_get(plugin->data_uris, i);
-
- serd_env_set_base_uri(env, sord_node_to_serd_node(data_uri->node));
- st = lilv_world_load_file(plugin->world, reader, data_uri);
- if (st > SERD_FAILURE) {
- break;
- }
- }
-
- if (st > SERD_FAILURE) {
- plugin->loaded = true;
- plugin->parse_errors = true;
- serd_reader_free(reader);
- serd_env_free(env);
- return;
- }
+ SordNode* bundle_uri_node = plugin->bundle_uri->node;
+ const SerdNode* bundle_uri_snode = sord_node_to_serd_node(bundle_uri_node);
+
+ SerdEnv* env = serd_env_new(bundle_uri_snode);
+ SerdReader* reader =
+ sord_new_reader(plugin->world->model, env, SERD_TURTLE, bundle_uri_node);
+
+ SordModel* prots = lilv_world_filter_model(plugin->world,
+ plugin->world->model,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_prototype,
+ NULL,
+ NULL);
+ SordModel* skel = sord_new(plugin->world->world, SORD_SPO, false);
+ SordIter* iter = sord_begin(prots);
+ for (; !sord_iter_end(iter); sord_iter_next(iter)) {
+ const SordNode* t = sord_iter_get_node(iter, SORD_OBJECT);
+ LilvNode* prototype = lilv_node_new_from_node(plugin->world, t);
+
+ lilv_world_load_resource(plugin->world, prototype);
+
+ SordIter* statements =
+ sord_search(plugin->world->model, prototype->node, NULL, NULL, NULL);
+ FOREACH_MATCH (statements) {
+ SordQuad quad;
+ sord_iter_get(statements, quad);
+ quad[0] = plugin->plugin_uri->node;
+ sord_add(skel, quad);
+ }
+
+ sord_iter_free(statements);
+ lilv_node_free(prototype);
+ }
+ sord_iter_free(iter);
+
+ for (iter = sord_begin(skel); !sord_iter_end(iter); sord_iter_next(iter)) {
+ SordQuad quad;
+ sord_iter_get(iter, quad);
+ sord_add(plugin->world->model, quad);
+ }
+ sord_iter_free(iter);
+ sord_free(skel);
+ sord_free(prots);
+
+ // Parse all the plugin's data files into RDF model
+ SerdStatus st = SERD_SUCCESS;
+ LILV_FOREACH (nodes, i, plugin->data_uris) {
+ const LilvNode* data_uri = lilv_nodes_get(plugin->data_uris, i);
+
+ serd_env_set_base_uri(env, sord_node_to_serd_node(data_uri->node));
+ st = lilv_world_load_file(plugin->world, reader, data_uri);
+ if (st > SERD_FAILURE) {
+ break;
+ }
+ }
+
+ if (st > SERD_FAILURE) {
+ plugin->loaded = true;
+ plugin->parse_errors = true;
+ serd_reader_free(reader);
+ serd_env_free(env);
+ return;
+ }
#ifdef LILV_DYN_MANIFEST
- // Load and parse dynamic manifest data, if this is a library
- if (plugin->dynmanifest) {
- typedef int (*GetDataFunc)(LV2_Dyn_Manifest_Handle handle,
- FILE* fp,
- const char* uri);
- GetDataFunc get_data_func = (GetDataFunc)lilv_dlfunc(
- plugin->dynmanifest->lib, "lv2_dyn_manifest_get_data");
- if (get_data_func) {
- const SordNode* bundle = plugin->dynmanifest->bundle->node;
- serd_env_set_base_uri(env, sord_node_to_serd_node(bundle));
- FILE* fd = tmpfile();
- get_data_func(plugin->dynmanifest->handle, fd,
- lilv_node_as_string(plugin->plugin_uri));
- rewind(fd);
- serd_reader_add_blank_prefix(
- reader, lilv_world_blank_node_prefix(plugin->world));
- serd_reader_read_file_handle(
- reader, fd, (const uint8_t*)"(dyn-manifest)");
- fclose(fd);
- }
- }
+ // Load and parse dynamic manifest data, if this is a library
+ if (plugin->dynmanifest) {
+ typedef int (*GetDataFunc)(
+ LV2_Dyn_Manifest_Handle handle, FILE * fp, const char* uri);
+ GetDataFunc get_data_func = (GetDataFunc)lilv_dlfunc(
+ plugin->dynmanifest->lib, "lv2_dyn_manifest_get_data");
+ if (get_data_func) {
+ const SordNode* bundle = plugin->dynmanifest->bundle->node;
+ serd_env_set_base_uri(env, sord_node_to_serd_node(bundle));
+ FILE* fd = tmpfile();
+ get_data_func(plugin->dynmanifest->handle,
+ fd,
+ lilv_node_as_string(plugin->plugin_uri));
+ rewind(fd);
+ serd_reader_add_blank_prefix(reader,
+ lilv_world_blank_node_prefix(plugin->world));
+ serd_reader_read_file_handle(
+ reader, fd, (const uint8_t*)"(dyn-manifest)");
+ fclose(fd);
+ }
+ }
#endif
- serd_reader_free(reader);
- serd_env_free(env);
+ serd_reader_free(reader);
+ serd_env_free(env);
- plugin->loaded = true;
+ plugin->loaded = true;
}
static bool
is_symbol(const char* str)
{
- for (const char* s = str; *s; ++s) {
- if (!((*s >= 'a' && *s <= 'z') ||
- (*s >= 'A' && *s <= 'Z') ||
- (s > str && *s >= '0' && *s <= '9') ||
- *s == '_')) {
- return false;
- }
- }
- return true;
+ for (const char* s = str; *s; ++s) {
+ if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
+ (s > str && *s >= '0' && *s <= '9') || *s == '_')) {
+ return false;
+ }
+ }
+ return true;
}
static void
lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_plugin)
{
- LilvPlugin* plugin = (LilvPlugin*)const_plugin;
-
- lilv_plugin_load_if_necessary(plugin);
-
- if (!plugin->ports) {
- plugin->ports = (LilvPort**)malloc(sizeof(LilvPort*));
- plugin->ports[0] = NULL;
-
- SordIter* ports = lilv_world_query_internal(
- plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_port,
- NULL);
-
- FOREACH_MATCH(ports) {
- const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
- LilvNode* index = lilv_plugin_get_unique(
- plugin, port, plugin->world->uris.lv2_index);
- LilvNode* symbol = lilv_plugin_get_unique(
- plugin, port, plugin->world->uris.lv2_symbol);
-
- if (!lilv_node_is_string(symbol) ||
- !is_symbol((const char*)sord_node_get_string(symbol->node))) {
- LILV_ERRORF("Plugin <%s> port symbol `%s' is invalid\n",
- lilv_node_as_uri(plugin->plugin_uri),
- lilv_node_as_string(symbol));
- lilv_node_free(symbol);
- lilv_node_free(index);
- lilv_plugin_free_ports(plugin);
- break;
- }
-
- if (!lilv_node_is_int(index)) {
- LILV_ERRORF("Plugin <%s> port index is not an integer\n",
- lilv_node_as_uri(plugin->plugin_uri));
- lilv_node_free(symbol);
- lilv_node_free(index);
- lilv_plugin_free_ports(plugin);
- break;
- }
-
- uint32_t this_index = lilv_node_as_int(index);
- LilvPort* this_port = NULL;
- if (plugin->num_ports > this_index) {
- this_port = plugin->ports[this_index];
- } else {
- plugin->ports = (LilvPort**)realloc(
- plugin->ports, (this_index + 1) * sizeof(LilvPort*));
- memset(plugin->ports + plugin->num_ports, '\0',
- (this_index - plugin->num_ports) * sizeof(LilvPort*));
- plugin->num_ports = this_index + 1;
- }
-
- // Havn't seen this port yet, add it to array
- if (!this_port) {
- this_port = lilv_port_new(plugin->world,
- port,
- this_index,
- lilv_node_as_string(symbol));
- plugin->ports[this_index] = this_port;
- }
-
- SordIter* types = lilv_world_query_internal(
- plugin->world, port, plugin->world->uris.rdf_a, NULL);
- FOREACH_MATCH(types) {
- const SordNode* type = sord_iter_get_node(types, SORD_OBJECT);
- if (sord_node_get_type(type) == SORD_URI) {
- zix_tree_insert(
- (ZixTree*)this_port->classes,
- lilv_node_new_from_node(plugin->world, type), NULL);
- } else {
- LILV_WARNF("Plugin <%s> port type is not a URI\n",
- lilv_node_as_uri(plugin->plugin_uri));
- }
- }
- sord_iter_free(types);
-
- lilv_node_free(symbol);
- lilv_node_free(index);
- }
- sord_iter_free(ports);
-
- // Check sanity
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- if (!plugin->ports[i]) {
- LILV_ERRORF("Plugin <%s> is missing port %u/%u\n",
- lilv_node_as_uri(plugin->plugin_uri), i, plugin->num_ports);
- lilv_plugin_free_ports(plugin);
- break;
- }
- }
- }
+ LilvPlugin* plugin = (LilvPlugin*)const_plugin;
+
+ lilv_plugin_load_if_necessary(plugin);
+
+ if (!plugin->ports) {
+ plugin->ports = (LilvPort**)malloc(sizeof(LilvPort*));
+ plugin->ports[0] = NULL;
+
+ SordIter* ports = lilv_world_query_internal(plugin->world,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_port,
+ NULL);
+
+ FOREACH_MATCH (ports) {
+ const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
+
+ LilvNode* index =
+ lilv_plugin_get_unique(plugin, port, plugin->world->uris.lv2_index);
+
+ LilvNode* symbol =
+ lilv_plugin_get_unique(plugin, port, plugin->world->uris.lv2_symbol);
+
+ if (!lilv_node_is_string(symbol) ||
+ !is_symbol((const char*)sord_node_get_string(symbol->node))) {
+ LILV_ERRORF("Plugin <%s> port symbol `%s' is invalid\n",
+ lilv_node_as_uri(plugin->plugin_uri),
+ lilv_node_as_string(symbol));
+ lilv_node_free(symbol);
+ lilv_node_free(index);
+ lilv_plugin_free_ports(plugin);
+ break;
+ }
+
+ if (!lilv_node_is_int(index)) {
+ LILV_ERRORF("Plugin <%s> port index is not an integer\n",
+ lilv_node_as_uri(plugin->plugin_uri));
+ lilv_node_free(symbol);
+ lilv_node_free(index);
+ lilv_plugin_free_ports(plugin);
+ break;
+ }
+
+ uint32_t this_index = lilv_node_as_int(index);
+ LilvPort* this_port = NULL;
+ if (plugin->num_ports > this_index) {
+ this_port = plugin->ports[this_index];
+ } else {
+ plugin->ports = (LilvPort**)realloc(
+ plugin->ports, (this_index + 1) * sizeof(LilvPort*));
+ memset(plugin->ports + plugin->num_ports,
+ '\0',
+ (this_index - plugin->num_ports) * sizeof(LilvPort*));
+ plugin->num_ports = this_index + 1;
+ }
+
+ // Havn't seen this port yet, add it to array
+ if (!this_port) {
+ this_port = lilv_port_new(
+ plugin->world, port, this_index, lilv_node_as_string(symbol));
+ plugin->ports[this_index] = this_port;
+ }
+
+ SordIter* types = lilv_world_query_internal(
+ plugin->world, port, plugin->world->uris.rdf_a, NULL);
+ FOREACH_MATCH (types) {
+ const SordNode* type = sord_iter_get_node(types, SORD_OBJECT);
+ if (sord_node_get_type(type) == SORD_URI) {
+ zix_tree_insert((ZixTree*)this_port->classes,
+ lilv_node_new_from_node(plugin->world, type),
+ NULL);
+ } else {
+ LILV_WARNF("Plugin <%s> port type is not a URI\n",
+ lilv_node_as_uri(plugin->plugin_uri));
+ }
+ }
+ sord_iter_free(types);
+
+ lilv_node_free(symbol);
+ lilv_node_free(index);
+ }
+ sord_iter_free(ports);
+
+ // Check sanity
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ if (!plugin->ports[i]) {
+ LILV_ERRORF("Plugin <%s> is missing port %u/%u\n",
+ lilv_node_as_uri(plugin->plugin_uri),
+ i,
+ plugin->num_ports);
+ lilv_plugin_free_ports(plugin);
+ break;
+ }
+ }
+ }
}
void
lilv_plugin_load_if_necessary(const LilvPlugin* plugin)
{
- if (!plugin->loaded) {
- lilv_plugin_load((LilvPlugin*)plugin);
- }
+ if (!plugin->loaded) {
+ lilv_plugin_load((LilvPlugin*)plugin);
+ }
}
const LilvNode*
lilv_plugin_get_uri(const LilvPlugin* plugin)
{
- return plugin->plugin_uri;
+ return plugin->plugin_uri;
}
const LilvNode*
lilv_plugin_get_bundle_uri(const LilvPlugin* plugin)
{
- return plugin->bundle_uri;
+ return plugin->bundle_uri;
}
const LilvNode*
lilv_plugin_get_library_uri(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary((LilvPlugin*)plugin);
- if (!plugin->binary_uri) {
- // <plugin> lv2:binary ?binary
- SordIter* i = lilv_world_query_internal(plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_binary,
- NULL);
- FOREACH_MATCH(i) {
- const SordNode* binary_node = sord_iter_get_node(i, SORD_OBJECT);
- if (sord_node_get_type(binary_node) == SORD_URI) {
- ((LilvPlugin*)plugin)->binary_uri =
- lilv_node_new_from_node(plugin->world, binary_node);
- break;
- }
- }
- sord_iter_free(i);
- }
- if (!plugin->binary_uri) {
- LILV_WARNF("Plugin <%s> has no lv2:binary\n",
- lilv_node_as_uri(lilv_plugin_get_uri(plugin)));
- }
- return plugin->binary_uri;
+ lilv_plugin_load_if_necessary((LilvPlugin*)plugin);
+ if (!plugin->binary_uri) {
+ // <plugin> lv2:binary ?binary
+ SordIter* i = lilv_world_query_internal(plugin->world,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_binary,
+ NULL);
+ FOREACH_MATCH (i) {
+ const SordNode* binary_node = sord_iter_get_node(i, SORD_OBJECT);
+ if (sord_node_get_type(binary_node) == SORD_URI) {
+ ((LilvPlugin*)plugin)->binary_uri =
+ lilv_node_new_from_node(plugin->world, binary_node);
+ break;
+ }
+ }
+ sord_iter_free(i);
+ }
+ if (!plugin->binary_uri) {
+ LILV_WARNF("Plugin <%s> has no lv2:binary\n",
+ lilv_node_as_uri(lilv_plugin_get_uri(plugin)));
+ }
+ return plugin->binary_uri;
}
const LilvNodes*
lilv_plugin_get_data_uris(const LilvPlugin* plugin)
{
- return plugin->data_uris;
+ return plugin->data_uris;
}
const LilvPluginClass*
lilv_plugin_get_class(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary((LilvPlugin*)plugin);
- if (!plugin->plugin_class) {
- // <plugin> a ?class
- SordIter* c = lilv_world_query_internal(plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.rdf_a,
- NULL);
- FOREACH_MATCH(c) {
- const SordNode* class_node = sord_iter_get_node(c, SORD_OBJECT);
- if (sord_node_get_type(class_node) != SORD_URI) {
- continue;
- }
-
- LilvNode* klass = lilv_node_new_from_node(plugin->world, class_node);
- if (!lilv_node_equals(klass, plugin->world->lv2_plugin_class->uri)) {
- const LilvPluginClass* pclass = lilv_plugin_classes_get_by_uri(
- plugin->world->plugin_classes, klass);
-
- if (pclass) {
- ((LilvPlugin*)plugin)->plugin_class = pclass;
- lilv_node_free(klass);
- break;
- }
- }
-
- lilv_node_free(klass);
- }
- sord_iter_free(c);
-
- if (plugin->plugin_class == NULL) {
- ((LilvPlugin*)plugin)->plugin_class =
- plugin->world->lv2_plugin_class;
- }
- }
- return plugin->plugin_class;
+ lilv_plugin_load_if_necessary((LilvPlugin*)plugin);
+ if (!plugin->plugin_class) {
+ // <plugin> a ?class
+ SordIter* c = lilv_world_query_internal(
+ plugin->world, plugin->plugin_uri->node, plugin->world->uris.rdf_a, NULL);
+ FOREACH_MATCH (c) {
+ const SordNode* class_node = sord_iter_get_node(c, SORD_OBJECT);
+ if (sord_node_get_type(class_node) != SORD_URI) {
+ continue;
+ }
+
+ LilvNode* klass = lilv_node_new_from_node(plugin->world, class_node);
+ if (!lilv_node_equals(klass, plugin->world->lv2_plugin_class->uri)) {
+ const LilvPluginClass* pclass =
+ lilv_plugin_classes_get_by_uri(plugin->world->plugin_classes, klass);
+
+ if (pclass) {
+ ((LilvPlugin*)plugin)->plugin_class = pclass;
+ lilv_node_free(klass);
+ break;
+ }
+ }
+
+ lilv_node_free(klass);
+ }
+ sord_iter_free(c);
+
+ if (plugin->plugin_class == NULL) {
+ ((LilvPlugin*)plugin)->plugin_class = plugin->world->lv2_plugin_class;
+ }
+ }
+ return plugin->plugin_class;
}
static LilvNodes*
lilv_plugin_get_value_internal(const LilvPlugin* plugin,
const SordNode* predicate)
{
- lilv_plugin_load_if_necessary(plugin);
- return lilv_world_find_nodes_internal(
- plugin->world, plugin->plugin_uri->node, predicate, NULL);
+ lilv_plugin_load_if_necessary(plugin);
+ return lilv_world_find_nodes_internal(
+ plugin->world, plugin->plugin_uri->node, predicate, NULL);
}
bool
lilv_plugin_verify(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
- if (plugin->parse_errors) {
- return false;
- }
-
- LilvNode* rdf_type = lilv_new_uri(plugin->world, LILV_NS_RDF "type");
- LilvNodes* results = lilv_plugin_get_value(plugin, rdf_type);
- lilv_node_free(rdf_type);
- if (!results) {
- return false;
- }
-
- lilv_nodes_free(results);
- results = lilv_plugin_get_value_internal(plugin,
- plugin->world->uris.doap_name);
- if (!results) {
- return false;
- }
-
- lilv_nodes_free(results);
- LilvNode* lv2_port = lilv_new_uri(plugin->world, LV2_CORE__port);
- results = lilv_plugin_get_value(plugin, lv2_port);
- lilv_node_free(lv2_port);
- if (!results) {
- return false;
- }
-
- lilv_nodes_free(results);
- return true;
+ lilv_plugin_load_if_necessary(plugin);
+ if (plugin->parse_errors) {
+ return false;
+ }
+
+ LilvNode* rdf_type = lilv_new_uri(plugin->world, LILV_NS_RDF "type");
+ LilvNodes* results = lilv_plugin_get_value(plugin, rdf_type);
+ lilv_node_free(rdf_type);
+ if (!results) {
+ return false;
+ }
+
+ lilv_nodes_free(results);
+ results =
+ lilv_plugin_get_value_internal(plugin, plugin->world->uris.doap_name);
+ if (!results) {
+ return false;
+ }
+
+ lilv_nodes_free(results);
+ LilvNode* lv2_port = lilv_new_uri(plugin->world, LV2_CORE__port);
+ results = lilv_plugin_get_value(plugin, lv2_port);
+ lilv_node_free(lv2_port);
+ if (!results) {
+ return false;
+ }
+
+ lilv_nodes_free(results);
+ return true;
}
LilvNode*
lilv_plugin_get_name(const LilvPlugin* plugin)
{
- LilvNodes* results = lilv_plugin_get_value_internal(
- plugin, plugin->world->uris.doap_name);
-
- LilvNode* ret = NULL;
- if (results) {
- LilvNode* val = lilv_nodes_get_first(results);
- if (lilv_node_is_string(val)) {
- ret = lilv_node_duplicate(val);
- }
- lilv_nodes_free(results);
- }
-
- if (!ret) {
- LILV_WARNF("Plugin <%s> has no (mandatory) doap:name\n",
- lilv_node_as_string(lilv_plugin_get_uri(plugin)));
- }
-
- return ret;
+ LilvNodes* results =
+ lilv_plugin_get_value_internal(plugin, plugin->world->uris.doap_name);
+
+ LilvNode* ret = NULL;
+ if (results) {
+ LilvNode* val = lilv_nodes_get_first(results);
+ if (lilv_node_is_string(val)) {
+ ret = lilv_node_duplicate(val);
+ }
+ lilv_nodes_free(results);
+ }
+
+ if (!ret) {
+ LILV_WARNF("Plugin <%s> has no (mandatory) doap:name\n",
+ lilv_node_as_string(lilv_plugin_get_uri(plugin)));
+ }
+
+ return ret;
}
LilvNodes*
-lilv_plugin_get_value(const LilvPlugin* plugin,
- const LilvNode* predicate)
+lilv_plugin_get_value(const LilvPlugin* plugin, const LilvNode* predicate)
{
- lilv_plugin_load_if_necessary(plugin);
- return lilv_world_find_nodes(plugin->world, plugin->plugin_uri, predicate, NULL);
+ lilv_plugin_load_if_necessary(plugin);
+ return lilv_world_find_nodes(
+ plugin->world, plugin->plugin_uri, predicate, NULL);
}
uint32_t
lilv_plugin_get_num_ports(const LilvPlugin* plugin)
{
- lilv_plugin_load_ports_if_necessary(plugin);
- return plugin->num_ports;
+ lilv_plugin_load_ports_if_necessary(plugin);
+ return plugin->num_ports;
}
void
@@ -541,158 +525,163 @@ lilv_plugin_get_port_ranges_float(const LilvPlugin* plugin,
float* max_values,
float* def_values)
{
- lilv_plugin_load_ports_if_necessary(plugin);
- LilvNode* min = NULL;
- LilvNode* max = NULL;
- LilvNode* def = NULL;
- LilvNode** minptr = min_values ? &min : NULL;
- LilvNode** maxptr = max_values ? &max : NULL;
- LilvNode** defptr = def_values ? &def : NULL;
-
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- lilv_port_get_range(plugin, plugin->ports[i], defptr, minptr, maxptr);
-
- if (min_values) {
- if (lilv_node_is_float(min) || lilv_node_is_int(min)) {
- min_values[i] = lilv_node_as_float(min);
- } else {
- min_values[i] = NAN;
- }
- }
-
- if (max_values) {
- if (lilv_node_is_float(max) || lilv_node_is_int(max)) {
- max_values[i] = lilv_node_as_float(max);
- } else {
- max_values[i] = NAN;
- }
- }
-
- if (def_values) {
- if (lilv_node_is_float(def) || lilv_node_is_int(def)) {
- def_values[i] = lilv_node_as_float(def);
- } else {
- def_values[i] = NAN;
- }
- }
-
- lilv_node_free(def);
- lilv_node_free(min);
- lilv_node_free(max);
- }
+ lilv_plugin_load_ports_if_necessary(plugin);
+ LilvNode* min = NULL;
+ LilvNode* max = NULL;
+ LilvNode* def = NULL;
+ LilvNode** minptr = min_values ? &min : NULL;
+ LilvNode** maxptr = max_values ? &max : NULL;
+ LilvNode** defptr = def_values ? &def : NULL;
+
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ lilv_port_get_range(plugin, plugin->ports[i], defptr, minptr, maxptr);
+
+ if (min_values) {
+ if (lilv_node_is_float(min) || lilv_node_is_int(min)) {
+ min_values[i] = lilv_node_as_float(min);
+ } else {
+ min_values[i] = NAN;
+ }
+ }
+
+ if (max_values) {
+ if (lilv_node_is_float(max) || lilv_node_is_int(max)) {
+ max_values[i] = lilv_node_as_float(max);
+ } else {
+ max_values[i] = NAN;
+ }
+ }
+
+ if (def_values) {
+ if (lilv_node_is_float(def) || lilv_node_is_int(def)) {
+ def_values[i] = lilv_node_as_float(def);
+ } else {
+ def_values[i] = NAN;
+ }
+ }
+
+ lilv_node_free(def);
+ lilv_node_free(min);
+ lilv_node_free(max);
+ }
}
uint32_t
-lilv_plugin_get_num_ports_of_class_va(const LilvPlugin* plugin,
- const LilvNode* class_1,
- va_list args)
+lilv_plugin_get_num_ports_of_class_va(
+ const LilvPlugin* plugin,
+ const LilvNode* class_1,
+ va_list args // NOLINT(readability-non-const-parameter)
+)
{
- lilv_plugin_load_ports_if_necessary(plugin);
-
- uint32_t count = 0;
-
- // Build array of classes from args so we can walk it several times
- size_t n_classes = 0;
- const LilvNode** classes = NULL;
- for (LilvNode* c = NULL; (c = va_arg(args, LilvNode*)); ) {
- classes = (const LilvNode**)realloc(
- classes, ++n_classes * sizeof(LilvNode*));
- classes[n_classes - 1] = c;
- }
-
- // Check each port against every type
- for (unsigned i = 0; i < plugin->num_ports; ++i) {
- LilvPort* port = plugin->ports[i];
- if (port && lilv_port_is_a(plugin, port, class_1)) {
- bool matches = true;
- for (size_t j = 0; j < n_classes; ++j) {
- if (!lilv_port_is_a(plugin, port, classes[j])) {
- matches = false;
- break;
- }
- }
-
- if (matches) {
- ++count;
- }
- }
- }
-
- free(classes);
- return count;
+ lilv_plugin_load_ports_if_necessary(plugin);
+
+ uint32_t count = 0;
+
+ // Build array of classes from args so we can walk it several times
+ size_t n_classes = 0;
+ const LilvNode** classes = NULL;
+ for (LilvNode* c = NULL; (c = va_arg(args, LilvNode*));) {
+ classes =
+ (const LilvNode**)realloc(classes, ++n_classes * sizeof(LilvNode*));
+ classes[n_classes - 1] = c;
+ }
+
+ // Check each port against every type
+ for (unsigned i = 0; i < plugin->num_ports; ++i) {
+ LilvPort* port = plugin->ports[i];
+ if (port && lilv_port_is_a(plugin, port, class_1)) {
+ bool matches = true;
+ for (size_t j = 0; j < n_classes; ++j) {
+ if (!lilv_port_is_a(plugin, port, classes[j])) {
+ matches = false;
+ break;
+ }
+ }
+
+ if (matches) {
+ ++count;
+ }
+ }
+ }
+
+ free(classes);
+ return count;
}
uint32_t
lilv_plugin_get_num_ports_of_class(const LilvPlugin* plugin,
- const LilvNode* class_1, ...)
+ const LilvNode* class_1,
+ ...)
{
- va_list args;
- va_start(args, class_1);
+ va_list args; // NOLINT(cppcoreguidelines-init-variables)
+ va_start(args, class_1);
- uint32_t count = lilv_plugin_get_num_ports_of_class_va(plugin, class_1, args);
+ uint32_t count = lilv_plugin_get_num_ports_of_class_va(plugin, class_1, args);
- va_end(args);
- return count;
+ va_end(args);
+ return count;
}
bool
lilv_plugin_has_latency(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
- SordIter* ports = lilv_world_query_internal(
- plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_port,
- NULL);
-
- bool ret = false;
- FOREACH_MATCH(ports) {
- const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
- SordIter* prop = lilv_world_query_internal(
- plugin->world,
- port,
- plugin->world->uris.lv2_portProperty,
- plugin->world->uris.lv2_reportsLatency);
- SordIter* des = lilv_world_query_internal(
- plugin->world,
- port,
- plugin->world->uris.lv2_designation,
- plugin->world->uris.lv2_latency);
- const bool latent = !sord_iter_end(prop) || !sord_iter_end(des);
- sord_iter_free(prop);
- sord_iter_free(des);
- if (latent) {
- ret = true;
- break;
- }
- }
- sord_iter_free(ports);
-
- return ret;
+ lilv_plugin_load_if_necessary(plugin);
+ SordIter* ports = lilv_world_query_internal(plugin->world,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_port,
+ NULL);
+
+ bool ret = false;
+ FOREACH_MATCH (ports) {
+ const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
+
+ SordIter* prop =
+ lilv_world_query_internal(plugin->world,
+ port,
+ plugin->world->uris.lv2_portProperty,
+ plugin->world->uris.lv2_reportsLatency);
+
+ SordIter* des =
+ lilv_world_query_internal(plugin->world,
+ port,
+ plugin->world->uris.lv2_designation,
+ plugin->world->uris.lv2_latency);
+
+ const bool latent = !sord_iter_end(prop) || !sord_iter_end(des);
+ sord_iter_free(prop);
+ sord_iter_free(des);
+ if (latent) {
+ ret = true;
+ break;
+ }
+ }
+ sord_iter_free(ports);
+
+ return ret;
}
static const LilvPort*
lilv_plugin_get_port_by_property(const LilvPlugin* plugin,
const SordNode* port_property)
{
- lilv_plugin_load_ports_if_necessary(plugin);
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- LilvPort* port = plugin->ports[i];
- SordIter* iter = lilv_world_query_internal(
- plugin->world,
- port->node->node,
- plugin->world->uris.lv2_portProperty,
- port_property);
-
- const bool found = !sord_iter_end(iter);
- sord_iter_free(iter);
-
- if (found) {
- return port;
- }
- }
-
- return NULL;
+ lilv_plugin_load_ports_if_necessary(plugin);
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ LilvPort* port = plugin->ports[i];
+ SordIter* iter =
+ lilv_world_query_internal(plugin->world,
+ port->node->node,
+ plugin->world->uris.lv2_portProperty,
+ port_property);
+
+ const bool found = !sord_iter_end(iter);
+ sord_iter_free(iter);
+
+ if (found) {
+ return port;
+ }
+ }
+
+ return NULL;
}
const LilvPort*
@@ -700,375 +689,353 @@ lilv_plugin_get_port_by_designation(const LilvPlugin* plugin,
const LilvNode* port_class,
const LilvNode* designation)
{
- LilvWorld* world = plugin->world;
- lilv_plugin_load_ports_if_necessary(plugin);
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- LilvPort* port = plugin->ports[i];
- SordIter* iter = lilv_world_query_internal(
- world,
- port->node->node,
- world->uris.lv2_designation,
- designation->node);
-
- const bool found = !sord_iter_end(iter) &&
- (!port_class || lilv_port_is_a(plugin, port, port_class));
- sord_iter_free(iter);
-
- if (found) {
- return port;
- }
- }
-
- return NULL;
+ LilvWorld* world = plugin->world;
+ lilv_plugin_load_ports_if_necessary(plugin);
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ LilvPort* port = plugin->ports[i];
+ SordIter* iter = lilv_world_query_internal(
+ world, port->node->node, world->uris.lv2_designation, designation->node);
+
+ const bool found =
+ !sord_iter_end(iter) &&
+ (!port_class || lilv_port_is_a(plugin, port, port_class));
+ sord_iter_free(iter);
+
+ if (found) {
+ return port;
+ }
+ }
+
+ return NULL;
}
uint32_t
lilv_plugin_get_latency_port_index(const LilvPlugin* plugin)
{
- LilvNode* lv2_OutputPort =
- lilv_new_uri(plugin->world, LV2_CORE__OutputPort);
- LilvNode* lv2_latency =
- lilv_new_uri(plugin->world, LV2_CORE__latency);
-
- const LilvPort* prop_port = lilv_plugin_get_port_by_property(
- plugin, plugin->world->uris.lv2_reportsLatency);
- const LilvPort* des_port = lilv_plugin_get_port_by_designation(
- plugin, lv2_OutputPort, lv2_latency);
-
- lilv_node_free(lv2_latency);
- lilv_node_free(lv2_OutputPort);
-
- if (prop_port) {
- return prop_port->index;
- } else if (des_port) {
- return des_port->index;
- } else {
- return (uint32_t)-1;
- }
+ LilvNode* lv2_OutputPort = lilv_new_uri(plugin->world, LV2_CORE__OutputPort);
+ LilvNode* lv2_latency = lilv_new_uri(plugin->world, LV2_CORE__latency);
+
+ const LilvPort* prop_port = lilv_plugin_get_port_by_property(
+ plugin, plugin->world->uris.lv2_reportsLatency);
+ const LilvPort* des_port =
+ lilv_plugin_get_port_by_designation(plugin, lv2_OutputPort, lv2_latency);
+
+ lilv_node_free(lv2_latency);
+ lilv_node_free(lv2_OutputPort);
+
+ if (prop_port) {
+ return prop_port->index;
+ }
+
+ if (des_port) {
+ return des_port->index;
+ }
+
+ return (uint32_t)-1;
}
bool
-lilv_plugin_has_feature(const LilvPlugin* plugin,
- const LilvNode* feature)
+lilv_plugin_has_feature(const LilvPlugin* plugin, const LilvNode* feature)
{
- lilv_plugin_load_if_necessary(plugin);
- const SordNode* predicates[] = { plugin->world->uris.lv2_requiredFeature,
- plugin->world->uris.lv2_optionalFeature,
- NULL };
-
- for (const SordNode** pred = predicates; *pred; ++pred) {
- if (lilv_world_ask_internal(
- plugin->world, plugin->plugin_uri->node, *pred, feature->node)) {
- return true;
- }
- }
- return false;
+ lilv_plugin_load_if_necessary(plugin);
+ const SordNode* predicates[] = {plugin->world->uris.lv2_requiredFeature,
+ plugin->world->uris.lv2_optionalFeature,
+ NULL};
+
+ for (const SordNode** pred = predicates; *pred; ++pred) {
+ if (lilv_world_ask_internal(
+ plugin->world, plugin->plugin_uri->node, *pred, feature->node)) {
+ return true;
+ }
+ }
+ return false;
}
LilvNodes*
lilv_plugin_get_supported_features(const LilvPlugin* plugin)
{
- LilvNodes* optional = lilv_plugin_get_optional_features(plugin);
- LilvNodes* required = lilv_plugin_get_required_features(plugin);
- LilvNodes* result = lilv_nodes_merge(optional, required);
- lilv_nodes_free(optional);
- lilv_nodes_free(required);
- return result;
+ LilvNodes* optional = lilv_plugin_get_optional_features(plugin);
+ LilvNodes* required = lilv_plugin_get_required_features(plugin);
+ LilvNodes* result = lilv_nodes_merge(optional, required);
+ lilv_nodes_free(optional);
+ lilv_nodes_free(required);
+ return result;
}
LilvNodes*
lilv_plugin_get_optional_features(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
- return lilv_world_find_nodes_internal(plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_optionalFeature,
- NULL);
+ lilv_plugin_load_if_necessary(plugin);
+ return lilv_world_find_nodes_internal(plugin->world,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_optionalFeature,
+ NULL);
}
LilvNodes*
lilv_plugin_get_required_features(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
- return lilv_world_find_nodes_internal(plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_requiredFeature,
- NULL);
+ lilv_plugin_load_if_necessary(plugin);
+ return lilv_world_find_nodes_internal(plugin->world,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_requiredFeature,
+ NULL);
}
bool
-lilv_plugin_has_extension_data(const LilvPlugin* plugin,
- const LilvNode* uri)
+lilv_plugin_has_extension_data(const LilvPlugin* plugin, const LilvNode* uri)
{
- if (!lilv_node_is_uri(uri)) {
- LILV_ERRORF("Extension data `%s' is not a URI\n",
- sord_node_get_string(uri->node));
- return false;
- }
-
- lilv_plugin_load_if_necessary(plugin);
- return lilv_world_ask_internal(
- plugin->world,
- plugin->plugin_uri->node,
- plugin->world->uris.lv2_extensionData,
- uri->node);
+ if (!lilv_node_is_uri(uri)) {
+ LILV_ERRORF("Extension data `%s' is not a URI\n",
+ sord_node_get_string(uri->node));
+ return false;
+ }
+
+ lilv_plugin_load_if_necessary(plugin);
+ return lilv_world_ask_internal(plugin->world,
+ plugin->plugin_uri->node,
+ plugin->world->uris.lv2_extensionData,
+ uri->node);
}
LilvNodes*
lilv_plugin_get_extension_data(const LilvPlugin* plugin)
{
- return lilv_plugin_get_value_internal(plugin, plugin->world->uris.lv2_extensionData);
+ return lilv_plugin_get_value_internal(plugin,
+ plugin->world->uris.lv2_extensionData);
}
const LilvPort*
-lilv_plugin_get_port_by_index(const LilvPlugin* plugin,
- uint32_t index)
+lilv_plugin_get_port_by_index(const LilvPlugin* plugin, uint32_t index)
{
- lilv_plugin_load_ports_if_necessary(plugin);
- if (index < plugin->num_ports) {
- return plugin->ports[index];
- } else {
- return NULL;
- }
+ lilv_plugin_load_ports_if_necessary(plugin);
+ if (index < plugin->num_ports) {
+ return plugin->ports[index];
+ }
+
+ return NULL;
}
const LilvPort*
-lilv_plugin_get_port_by_symbol(const LilvPlugin* plugin,
- const LilvNode* symbol)
+lilv_plugin_get_port_by_symbol(const LilvPlugin* plugin, const LilvNode* symbol)
{
- lilv_plugin_load_ports_if_necessary(plugin);
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- LilvPort* port = plugin->ports[i];
- if (lilv_node_equals(port->symbol, symbol)) {
- return port;
- }
- }
-
- return NULL;
+ lilv_plugin_load_ports_if_necessary(plugin);
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ LilvPort* port = plugin->ports[i];
+ if (lilv_node_equals(port->symbol, symbol)) {
+ return port;
+ }
+ }
+
+ return NULL;
}
LilvNode*
lilv_plugin_get_project(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
+ lilv_plugin_load_if_necessary(plugin);
- SordNode* lv2_project = sord_new_uri(plugin->world->world,
- (const uint8_t*)LV2_CORE__project);
+ SordNode* lv2_project =
+ sord_new_uri(plugin->world->world, (const uint8_t*)LV2_CORE__project);
- SordIter* projects = lilv_world_query_internal(plugin->world,
- plugin->plugin_uri->node,
- lv2_project,
- NULL);
+ SordIter* projects = lilv_world_query_internal(
+ plugin->world, plugin->plugin_uri->node, lv2_project, NULL);
- sord_node_free(plugin->world->world, lv2_project);
+ sord_node_free(plugin->world->world, lv2_project);
- if (sord_iter_end(projects)) {
- sord_iter_free(projects);
- return NULL;
- }
+ if (sord_iter_end(projects)) {
+ sord_iter_free(projects);
+ return NULL;
+ }
- const SordNode* project = sord_iter_get_node(projects, SORD_OBJECT);
+ const SordNode* project = sord_iter_get_node(projects, SORD_OBJECT);
- sord_iter_free(projects);
- return lilv_node_new_from_node(plugin->world, project);
+ sord_iter_free(projects);
+ return lilv_node_new_from_node(plugin->world, project);
}
static const SordNode*
lilv_plugin_get_author(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
+ lilv_plugin_load_if_necessary(plugin);
- SordNode* doap_maintainer = sord_new_uri(
- plugin->world->world, NS_DOAP "maintainer");
+ SordNode* doap_maintainer =
+ sord_new_uri(plugin->world->world, NS_DOAP "maintainer");
- SordIter* maintainers = lilv_world_query_internal(
- plugin->world,
- plugin->plugin_uri->node,
- doap_maintainer,
- NULL);
+ SordIter* maintainers = lilv_world_query_internal(
+ plugin->world, plugin->plugin_uri->node, doap_maintainer, NULL);
- if (sord_iter_end(maintainers)) {
- sord_iter_free(maintainers);
+ if (sord_iter_end(maintainers)) {
+ sord_iter_free(maintainers);
- LilvNode* project = lilv_plugin_get_project(plugin);
- if (!project) {
- sord_node_free(plugin->world->world, doap_maintainer);
- return NULL;
- }
+ LilvNode* project = lilv_plugin_get_project(plugin);
+ if (!project) {
+ sord_node_free(plugin->world->world, doap_maintainer);
+ return NULL;
+ }
- maintainers = lilv_world_query_internal(
- plugin->world,
- project->node,
- doap_maintainer,
- NULL);
+ maintainers = lilv_world_query_internal(
+ plugin->world, project->node, doap_maintainer, NULL);
- lilv_node_free(project);
- }
+ lilv_node_free(project);
+ }
- sord_node_free(plugin->world->world, doap_maintainer);
+ sord_node_free(plugin->world->world, doap_maintainer);
- if (sord_iter_end(maintainers)) {
- sord_iter_free(maintainers);
- return NULL;
- }
+ if (sord_iter_end(maintainers)) {
+ sord_iter_free(maintainers);
+ return NULL;
+ }
- const SordNode* author = sord_iter_get_node(maintainers, SORD_OBJECT);
+ const SordNode* author = sord_iter_get_node(maintainers, SORD_OBJECT);
- sord_iter_free(maintainers);
- return author;
+ sord_iter_free(maintainers);
+ return author;
}
static LilvNode*
lilv_plugin_get_author_property(const LilvPlugin* plugin, const uint8_t* uri)
{
- const SordNode* author = lilv_plugin_get_author(plugin);
- if (author) {
- SordWorld* sworld = plugin->world->world;
- SordNode* pred = sord_new_uri(sworld, uri);
- LilvNode* ret = lilv_plugin_get_one(plugin, author, pred);
- sord_node_free(sworld, pred);
- return ret;
- }
- return NULL;
+ const SordNode* author = lilv_plugin_get_author(plugin);
+ if (author) {
+ SordWorld* sworld = plugin->world->world;
+ SordNode* pred = sord_new_uri(sworld, uri);
+ LilvNode* ret = lilv_plugin_get_one(plugin, author, pred);
+ sord_node_free(sworld, pred);
+ return ret;
+ }
+ return NULL;
}
LilvNode*
lilv_plugin_get_author_name(const LilvPlugin* plugin)
{
- return lilv_plugin_get_author_property(plugin, NS_FOAF "name");
+ return lilv_plugin_get_author_property(plugin, NS_FOAF "name");
}
LilvNode*
lilv_plugin_get_author_email(const LilvPlugin* plugin)
{
- return lilv_plugin_get_author_property(plugin, NS_FOAF "mbox");
+ return lilv_plugin_get_author_property(plugin, NS_FOAF "mbox");
}
LilvNode*
lilv_plugin_get_author_homepage(const LilvPlugin* plugin)
{
- return lilv_plugin_get_author_property(plugin, NS_FOAF "homepage");
+ return lilv_plugin_get_author_property(plugin, NS_FOAF "homepage");
}
bool
lilv_plugin_is_replaced(const LilvPlugin* plugin)
{
- return plugin->replaced;
+ return plugin->replaced;
}
LilvUIs*
lilv_plugin_get_uis(const LilvPlugin* plugin)
{
- lilv_plugin_load_if_necessary(plugin);
-
- SordNode* ui_ui_node = sord_new_uri(plugin->world->world,
- (const uint8_t*)LV2_UI__ui);
- SordNode* ui_binary_node = sord_new_uri(plugin->world->world,
- (const uint8_t*)LV2_UI__binary);
-
- LilvUIs* result = lilv_uis_new();
- SordIter* uis = lilv_world_query_internal(plugin->world,
- plugin->plugin_uri->node,
- ui_ui_node,
- NULL);
-
- FOREACH_MATCH(uis) {
- const SordNode* ui = sord_iter_get_node(uis, SORD_OBJECT);
-
- LilvNode* type = lilv_plugin_get_unique(plugin, ui, plugin->world->uris.rdf_a);
- LilvNode* binary = lilv_plugin_get_one(plugin, ui, plugin->world->uris.lv2_binary);
- if (!binary) {
- binary = lilv_plugin_get_unique(plugin, ui, ui_binary_node);
- }
-
- if (sord_node_get_type(ui) != SORD_URI
- || !lilv_node_is_uri(type)
- || !lilv_node_is_uri(binary)) {
- lilv_node_free(binary);
- lilv_node_free(type);
- LILV_ERRORF("Corrupt UI <%s>\n", sord_node_get_string(ui));
- continue;
- }
-
- LilvUI* lilv_ui = lilv_ui_new(
- plugin->world,
- lilv_node_new_from_node(plugin->world, ui),
- type,
- binary);
-
- zix_tree_insert((ZixTree*)result, lilv_ui, NULL);
- }
- sord_iter_free(uis);
-
- sord_node_free(plugin->world->world, ui_binary_node);
- sord_node_free(plugin->world->world, ui_ui_node);
-
- if (lilv_uis_size(result) > 0) {
- return result;
- } else {
- lilv_uis_free(result);
- return NULL;
- }
+ lilv_plugin_load_if_necessary(plugin);
+
+ SordNode* ui_ui_node =
+ sord_new_uri(plugin->world->world, (const uint8_t*)LV2_UI__ui);
+ SordNode* ui_binary_node =
+ sord_new_uri(plugin->world->world, (const uint8_t*)LV2_UI__binary);
+
+ LilvUIs* result = lilv_uis_new();
+ SordIter* uis = lilv_world_query_internal(
+ plugin->world, plugin->plugin_uri->node, ui_ui_node, NULL);
+
+ FOREACH_MATCH (uis) {
+ const SordNode* ui = sord_iter_get_node(uis, SORD_OBJECT);
+
+ LilvNode* type =
+ lilv_plugin_get_unique(plugin, ui, plugin->world->uris.rdf_a);
+ LilvNode* binary =
+ lilv_plugin_get_one(plugin, ui, plugin->world->uris.lv2_binary);
+ if (!binary) {
+ binary = lilv_plugin_get_unique(plugin, ui, ui_binary_node);
+ }
+
+ if (sord_node_get_type(ui) != SORD_URI || !lilv_node_is_uri(type) ||
+ !lilv_node_is_uri(binary)) {
+ lilv_node_free(binary);
+ lilv_node_free(type);
+ LILV_ERRORF("Corrupt UI <%s>\n", sord_node_get_string(ui));
+ continue;
+ }
+
+ LilvUI* lilv_ui = lilv_ui_new(
+ plugin->world, lilv_node_new_from_node(plugin->world, ui), type, binary);
+
+ zix_tree_insert((ZixTree*)result, lilv_ui, NULL);
+ }
+ sord_iter_free(uis);
+
+ sord_node_free(plugin->world->world, ui_binary_node);
+ sord_node_free(plugin->world->world, ui_ui_node);
+
+ if (lilv_uis_size(result) > 0) {
+ return result;
+ }
+
+ lilv_uis_free(result);
+ return NULL;
}
LilvNodes*
lilv_plugin_get_related(const LilvPlugin* plugin, const LilvNode* type)
{
- lilv_plugin_load_if_necessary(plugin);
-
- LilvWorld* const world = plugin->world;
- LilvNodes* const related = lilv_world_find_nodes_internal(
- world,
- NULL,
- world->uris.lv2_appliesTo,
- lilv_plugin_get_uri(plugin)->node);
-
- if (!type) {
- return related;
- }
-
- LilvNodes* matches = lilv_nodes_new();
- LILV_FOREACH(nodes, i, related) {
- LilvNode* node = (LilvNode*)lilv_collection_get((ZixTree*)related, i);
- if (lilv_world_ask_internal(
- world, node->node, world->uris.rdf_a, type->node)) {
- zix_tree_insert((ZixTree*)matches,
- lilv_node_new_from_node(world, node->node),
- NULL);
- }
- }
-
- lilv_nodes_free(related);
- return matches;
+ lilv_plugin_load_if_necessary(plugin);
+
+ LilvWorld* const world = plugin->world;
+ LilvNodes* const related = lilv_world_find_nodes_internal(
+ world, NULL, world->uris.lv2_appliesTo, lilv_plugin_get_uri(plugin)->node);
+
+ if (!type) {
+ return related;
+ }
+
+ LilvNodes* matches = lilv_nodes_new();
+ LILV_FOREACH (nodes, i, related) {
+ LilvNode* node = (LilvNode*)lilv_collection_get((ZixTree*)related, i);
+ if (lilv_world_ask_internal(
+ world, node->node, world->uris.rdf_a, type->node)) {
+ zix_tree_insert(
+ (ZixTree*)matches, lilv_node_new_from_node(world, node->node), NULL);
+ }
+ }
+
+ lilv_nodes_free(related);
+ return matches;
}
static SerdEnv*
new_lv2_env(const SerdNode* base)
{
- SerdEnv* env = serd_env_new(base);
+ SerdEnv* env = serd_env_new(base);
#define USTR(s) ((const uint8_t*)(s))
- serd_env_set_prefix_from_strings(env, USTR("doap"), USTR(LILV_NS_DOAP));
- serd_env_set_prefix_from_strings(env, USTR("foaf"), USTR(LILV_NS_FOAF));
- serd_env_set_prefix_from_strings(env, USTR("lv2"), USTR(LILV_NS_LV2));
- serd_env_set_prefix_from_strings(env, USTR("owl"), USTR(LILV_NS_OWL));
- serd_env_set_prefix_from_strings(env, USTR("rdf"), USTR(LILV_NS_RDF));
- serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(LILV_NS_RDFS));
- serd_env_set_prefix_from_strings(env, USTR("xsd"), USTR(LILV_NS_XSD));
-
- return env;
+
+ serd_env_set_prefix_from_strings(env, USTR("doap"), USTR(LILV_NS_DOAP));
+ serd_env_set_prefix_from_strings(env, USTR("foaf"), USTR(LILV_NS_FOAF));
+ serd_env_set_prefix_from_strings(env, USTR("lv2"), USTR(LILV_NS_LV2));
+ serd_env_set_prefix_from_strings(env, USTR("owl"), USTR(LILV_NS_OWL));
+ serd_env_set_prefix_from_strings(env, USTR("rdf"), USTR(LILV_NS_RDF));
+ serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(LILV_NS_RDFS));
+ serd_env_set_prefix_from_strings(env, USTR("xsd"), USTR(LILV_NS_XSD));
+
+ return env;
}
static void
maybe_write_prefixes(SerdWriter* writer, SerdEnv* env, FILE* file)
{
- fseek(file, 0, SEEK_END);
- if (ftell(file) == 0) {
- serd_env_foreach(
- env, (SerdPrefixSink)serd_writer_set_prefix, writer);
- } else {
- fprintf(file, "\n");
- }
+ fseek(file, 0, SEEK_END);
+ if (ftell(file) == 0) {
+ serd_env_foreach(env, (SerdPrefixSink)serd_writer_set_prefix, writer);
+ } else {
+ fprintf(file, "\n");
+ }
}
void
@@ -1077,37 +1044,37 @@ lilv_plugin_write_description(LilvWorld* world,
const LilvNode* base_uri,
FILE* plugin_file)
{
- const LilvNode* subject = lilv_plugin_get_uri(plugin);
- const uint32_t num_ports = lilv_plugin_get_num_ports(plugin);
- const SerdNode* base = sord_node_to_serd_node(base_uri->node);
- SerdEnv* env = new_lv2_env(base);
-
- SerdWriter* writer = serd_writer_new(
- SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
- env,
- NULL,
- serd_file_sink,
- plugin_file);
-
- // Write prefixes if this is a new file
- maybe_write_prefixes(writer, env, plugin_file);
-
- // Write plugin description
- SordIter* plug_iter = lilv_world_query_internal(
- world, subject->node, NULL, NULL);
- sord_write_iter(plug_iter, writer);
-
- // Write port descriptions
- for (uint32_t i = 0; i < num_ports; ++i) {
- const LilvPort* port = plugin->ports[i];
- SordIter* port_iter = lilv_world_query_internal(
- world, port->node->node, NULL, NULL);
- sord_write_iter(port_iter, writer);
- }
-
- serd_writer_free(writer);
- serd_env_free(env);
+ const LilvNode* subject = lilv_plugin_get_uri(plugin);
+ const uint32_t num_ports = lilv_plugin_get_num_ports(plugin);
+ const SerdNode* base = sord_node_to_serd_node(base_uri->node);
+ SerdEnv* env = new_lv2_env(base);
+
+ SerdWriter* writer =
+ serd_writer_new(SERD_TURTLE,
+ (SerdStyle)(SERD_STYLE_ABBREVIATED | SERD_STYLE_CURIED),
+ env,
+ NULL,
+ serd_file_sink,
+ plugin_file);
+
+ // Write prefixes if this is a new file
+ maybe_write_prefixes(writer, env, plugin_file);
+
+ // Write plugin description
+ SordIter* plug_iter =
+ lilv_world_query_internal(world, subject->node, NULL, NULL);
+ sord_write_iter(plug_iter, writer);
+
+ // Write port descriptions
+ for (uint32_t i = 0; i < num_ports; ++i) {
+ const LilvPort* port = plugin->ports[i];
+ SordIter* port_iter =
+ lilv_world_query_internal(world, port->node->node, NULL, NULL);
+ sord_write_iter(port_iter, writer);
+ }
+
+ serd_writer_free(writer);
+ serd_env_free(env);
}
void
@@ -1117,36 +1084,46 @@ lilv_plugin_write_manifest_entry(LilvWorld* world,
FILE* manifest_file,
const char* plugin_file_path)
{
- const LilvNode* subject = lilv_plugin_get_uri(plugin);
- const SerdNode* base = sord_node_to_serd_node(base_uri->node);
- SerdEnv* env = new_lv2_env(base);
-
- SerdWriter* writer = serd_writer_new(
- SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
- env,
- NULL,
- serd_file_sink,
- manifest_file);
-
- // Write prefixes if this is a new file
- maybe_write_prefixes(writer, env, manifest_file);
-
- // Write manifest entry
- serd_writer_write_statement(
- writer, 0, NULL,
- sord_node_to_serd_node(subject->node),
- sord_node_to_serd_node(plugin->world->uris.rdf_a),
- sord_node_to_serd_node(plugin->world->uris.lv2_Plugin), 0, 0);
-
- const SerdNode file_node = serd_node_from_string(
- SERD_URI, (const uint8_t*)plugin_file_path);
- serd_writer_write_statement(
- writer, 0, NULL,
- sord_node_to_serd_node(subject->node),
- sord_node_to_serd_node(plugin->world->uris.rdfs_seeAlso),
- &file_node, 0, 0);
-
- serd_writer_free(writer);
- serd_env_free(env);
+ (void)world;
+
+ const LilvNode* subject = lilv_plugin_get_uri(plugin);
+ const SerdNode* base = sord_node_to_serd_node(base_uri->node);
+ SerdEnv* env = new_lv2_env(base);
+
+ SerdWriter* writer =
+ serd_writer_new(SERD_TURTLE,
+ (SerdStyle)(SERD_STYLE_ABBREVIATED | SERD_STYLE_CURIED),
+ env,
+ NULL,
+ serd_file_sink,
+ manifest_file);
+
+ // Write prefixes if this is a new file
+ maybe_write_prefixes(writer, env, manifest_file);
+
+ // Write manifest entry
+ serd_writer_write_statement(
+ writer,
+ 0,
+ NULL,
+ sord_node_to_serd_node(subject->node),
+ sord_node_to_serd_node(plugin->world->uris.rdf_a),
+ sord_node_to_serd_node(plugin->world->uris.lv2_Plugin),
+ 0,
+ 0);
+
+ const SerdNode file_node =
+ serd_node_from_string(SERD_URI, (const uint8_t*)plugin_file_path);
+ serd_writer_write_statement(
+ writer,
+ 0,
+ NULL,
+ sord_node_to_serd_node(subject->node),
+ sord_node_to_serd_node(plugin->world->uris.rdfs_seeAlso),
+ &file_node,
+ 0,
+ 0);
+
+ serd_writer_free(writer);
+ serd_env_free(env);
}
diff --git a/src/pluginclass.c b/src/pluginclass.c
index 538722f..18109f3 100644
--- a/src/pluginclass.c
+++ b/src/pluginclass.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -29,64 +16,64 @@ lilv_plugin_class_new(LilvWorld* world,
const SordNode* uri,
const char* label)
{
- LilvPluginClass* pc = (LilvPluginClass*)malloc(sizeof(LilvPluginClass));
- pc->world = world;
- pc->uri = lilv_node_new_from_node(world, uri);
- pc->label = lilv_node_new(world, LILV_VALUE_STRING, label);
- pc->parent_uri = (parent_node
- ? lilv_node_new_from_node(world, parent_node)
- : NULL);
- return pc;
+ LilvPluginClass* pc = (LilvPluginClass*)malloc(sizeof(LilvPluginClass));
+ pc->world = world;
+ pc->uri = lilv_node_new_from_node(world, uri);
+ pc->label = lilv_node_new(world, LILV_VALUE_STRING, label);
+ pc->parent_uri =
+ (parent_node ? lilv_node_new_from_node(world, parent_node) : NULL);
+ return pc;
}
void
lilv_plugin_class_free(LilvPluginClass* plugin_class)
{
- if (!plugin_class) {
- return;
- }
+ if (!plugin_class) {
+ return;
+ }
- lilv_node_free(plugin_class->uri);
- lilv_node_free(plugin_class->parent_uri);
- lilv_node_free(plugin_class->label);
- free(plugin_class);
+ lilv_node_free(plugin_class->uri);
+ lilv_node_free(plugin_class->parent_uri);
+ lilv_node_free(plugin_class->label);
+ free(plugin_class);
}
const LilvNode*
lilv_plugin_class_get_parent_uri(const LilvPluginClass* plugin_class)
{
- return plugin_class->parent_uri ? plugin_class->parent_uri : NULL;
+ return plugin_class->parent_uri ? plugin_class->parent_uri : NULL;
}
const LilvNode*
lilv_plugin_class_get_uri(const LilvPluginClass* plugin_class)
{
- return plugin_class->uri;
+ return plugin_class->uri;
}
const LilvNode*
lilv_plugin_class_get_label(const LilvPluginClass* plugin_class)
{
- return plugin_class->label;
+ return plugin_class->label;
}
LilvPluginClasses*
lilv_plugin_class_get_children(const LilvPluginClass* plugin_class)
{
- // Returned list doesn't own categories
- LilvPluginClasses* all = plugin_class->world->plugin_classes;
- LilvPluginClasses* result = zix_tree_new(false, lilv_ptr_cmp, NULL, NULL);
+ // Returned list doesn't own categories
+ LilvPluginClasses* all = plugin_class->world->plugin_classes;
+ LilvPluginClasses* result =
+ zix_tree_new(NULL, false, lilv_header_compare_by_uri, NULL, NULL, NULL);
- for (ZixTreeIter* i = zix_tree_begin((ZixTree*)all);
- i != zix_tree_end((ZixTree*)all);
- i = zix_tree_iter_next(i)) {
- const LilvPluginClass* c = (LilvPluginClass*)zix_tree_get(i);
- const LilvNode* parent = lilv_plugin_class_get_parent_uri(c);
- if (parent && lilv_node_equals(lilv_plugin_class_get_uri(plugin_class),
- parent)) {
- zix_tree_insert((ZixTree*)result, (LilvPluginClass*)c, NULL);
- }
- }
+ for (ZixTreeIter* i = zix_tree_begin((ZixTree*)all);
+ i != zix_tree_end((ZixTree*)all);
+ i = zix_tree_iter_next(i)) {
+ const LilvPluginClass* c = (LilvPluginClass*)zix_tree_get(i);
+ const LilvNode* parent = lilv_plugin_class_get_parent_uri(c);
+ if (parent &&
+ lilv_node_equals(lilv_plugin_class_get_uri(plugin_class), parent)) {
+ zix_tree_insert((ZixTree*)result, (LilvPluginClass*)c, NULL);
+ }
+ }
- return result;
+ return result;
}
diff --git a/src/port.c b/src/port.c
index be555fb..55641e7 100644
--- a/src/port.c
+++ b/src/port.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -36,23 +23,25 @@ lilv_port_new(LilvWorld* world,
uint32_t index,
const char* symbol)
{
- LilvPort* port = (LilvPort*)malloc(sizeof(LilvPort));
- port->node = lilv_node_new_from_node(world, node);
- port->index = index;
- port->symbol = lilv_node_new(world, LILV_VALUE_STRING, symbol);
- port->classes = lilv_nodes_new();
- return port;
+ LilvPort* port = (LilvPort*)malloc(sizeof(LilvPort));
+ port->node = lilv_node_new_from_node(world, node);
+ port->index = index;
+ port->symbol = lilv_node_new(world, LILV_VALUE_STRING, symbol);
+ port->classes = lilv_nodes_new();
+ return port;
}
void
lilv_port_free(const LilvPlugin* plugin, LilvPort* port)
{
- if (port) {
- lilv_node_free(port->node);
- lilv_nodes_free(port->classes);
- lilv_node_free(port->symbol);
- free(port);
- }
+ (void)plugin;
+
+ if (port) {
+ lilv_node_free(port->node);
+ lilv_nodes_free(port->classes);
+ lilv_node_free(port->symbol);
+ free(port);
+ }
}
bool
@@ -60,13 +49,15 @@ lilv_port_is_a(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* port_class)
{
- LILV_FOREACH(nodes, i, port->classes) {
- if (lilv_node_equals(lilv_nodes_get(port->classes, i), port_class)) {
- return true;
- }
- }
+ (void)plugin;
- return false;
+ LILV_FOREACH (nodes, i, port->classes) {
+ if (lilv_node_equals(lilv_nodes_get(port->classes, i), port_class)) {
+ return true;
+ }
+ }
+
+ return false;
}
bool
@@ -74,10 +65,10 @@ lilv_port_has_property(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* property)
{
- return lilv_world_ask_internal(plugin->world,
- port->node->node,
- plugin->world->uris.lv2_portProperty,
- property->node);
+ return lilv_world_ask_internal(plugin->world,
+ port->node->node,
+ plugin->world->uris.lv2_portProperty,
+ property->node);
}
bool
@@ -85,19 +76,19 @@ lilv_port_supports_event(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* event_type)
{
- const uint8_t* predicates[] = { (const uint8_t*)LV2_EVENT__supportsEvent,
- (const uint8_t*)LV2_ATOM__supports,
- NULL };
-
- for (const uint8_t** pred = predicates; *pred; ++pred) {
- if (lilv_world_ask_internal(plugin->world,
- port->node->node,
- sord_new_uri(plugin->world->world, *pred),
- event_type->node)) {
- return true;
- }
- }
- return false;
+ const uint8_t* predicates[] = {(const uint8_t*)LV2_EVENT__supportsEvent,
+ (const uint8_t*)LV2_ATOM__supports,
+ NULL};
+
+ for (const uint8_t** pred = predicates; *pred; ++pred) {
+ if (lilv_world_ask_internal(plugin->world,
+ port->node->node,
+ sord_new_uri(plugin->world->world, *pred),
+ event_type->node)) {
+ return true;
+ }
+ }
+ return false;
}
static LilvNodes*
@@ -105,17 +96,16 @@ lilv_port_get_value_by_node(const LilvPlugin* plugin,
const LilvPort* port,
const SordNode* predicate)
{
- return lilv_world_find_nodes_internal(plugin->world,
- port->node->node,
- predicate,
- NULL);
+ return lilv_world_find_nodes_internal(
+ plugin->world, port->node->node, predicate, NULL);
}
const LilvNode*
-lilv_port_get_node(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_node(const LilvPlugin* plugin, const LilvPort* port)
{
- return port->node;
+ (void)plugin;
+
+ return port->node;
}
LilvNodes*
@@ -123,13 +113,13 @@ lilv_port_get_value(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* predicate)
{
- if (!lilv_node_is_uri(predicate)) {
- LILV_ERRORF("Predicate `%s' is not a URI\n",
- sord_node_get_string(predicate->node));
- return NULL;
- }
+ if (!lilv_node_is_uri(predicate)) {
+ LILV_ERRORF("Predicate `%s' is not a URI\n",
+ sord_node_get_string(predicate->node));
+ return NULL;
+ }
- return lilv_port_get_value_by_node(plugin, port, predicate->node);
+ return lilv_port_get_value_by_node(plugin, port, predicate->node);
}
LilvNode*
@@ -137,58 +127,60 @@ lilv_port_get(const LilvPlugin* plugin,
const LilvPort* port,
const LilvNode* predicate)
{
- LilvNodes* values = lilv_port_get_value(plugin, port, predicate);
+ LilvNodes* values = lilv_port_get_value(plugin, port, predicate);
- LilvNode* value = lilv_node_duplicate(
- values ? lilv_nodes_get_first(values) : NULL);
+ LilvNode* value =
+ lilv_node_duplicate(values ? lilv_nodes_get_first(values) : NULL);
- lilv_nodes_free(values);
- return value;
+ lilv_nodes_free(values);
+ return value;
}
uint32_t
-lilv_port_get_index(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_index(const LilvPlugin* plugin, const LilvPort* port)
{
- return port->index;
+ (void)plugin;
+
+ return port->index;
}
const LilvNode*
-lilv_port_get_symbol(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_symbol(const LilvPlugin* plugin, const LilvPort* port)
{
- return port->symbol;
+ (void)plugin;
+
+ return port->symbol;
}
LilvNode*
-lilv_port_get_name(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_name(const LilvPlugin* plugin, const LilvPort* port)
{
- LilvNodes* results = lilv_port_get_value_by_node(
- plugin, port, plugin->world->uris.lv2_name);
-
- LilvNode* ret = NULL;
- if (results) {
- LilvNode* val = lilv_nodes_get_first(results);
- if (lilv_node_is_string(val)) {
- ret = lilv_node_duplicate(val);
- }
- lilv_nodes_free(results);
- }
-
- if (!ret) {
- LILV_WARNF("Plugin <%s> port has no (mandatory) doap:name\n",
- lilv_node_as_string(lilv_plugin_get_uri(plugin)));
- }
-
- return ret;
+ LilvNodes* results =
+ lilv_port_get_value_by_node(plugin, port, plugin->world->uris.lv2_name);
+
+ LilvNode* ret = NULL;
+ if (results) {
+ LilvNode* val = lilv_nodes_get_first(results);
+ if (lilv_node_is_string(val)) {
+ ret = lilv_node_duplicate(val);
+ }
+ lilv_nodes_free(results);
+ }
+
+ if (!ret) {
+ LILV_WARNF("Plugin <%s> port has no (mandatory) doap:name\n",
+ lilv_node_as_string(lilv_plugin_get_uri(plugin)));
+ }
+
+ return ret;
}
const LilvNodes*
-lilv_port_get_classes(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_classes(const LilvPlugin* plugin, const LilvPort* port)
{
- return port->classes;
+ (void)plugin;
+
+ return port->classes;
}
void
@@ -198,76 +190,71 @@ lilv_port_get_range(const LilvPlugin* plugin,
LilvNode** min,
LilvNode** max)
{
- if (def) {
- LilvNodes* defaults = lilv_port_get_value_by_node(
- plugin, port, plugin->world->uris.lv2_default);
- *def = defaults
- ? lilv_node_duplicate(lilv_nodes_get_first(defaults))
- : NULL;
- lilv_nodes_free(defaults);
- }
- if (min) {
- LilvNodes* minimums = lilv_port_get_value_by_node(
- plugin, port, plugin->world->uris.lv2_minimum);
- *min = minimums
- ? lilv_node_duplicate(lilv_nodes_get_first(minimums))
- : NULL;
- lilv_nodes_free(minimums);
- }
- if (max) {
- LilvNodes* maximums = lilv_port_get_value_by_node(
- plugin, port, plugin->world->uris.lv2_maximum);
- *max = maximums
- ? lilv_node_duplicate(lilv_nodes_get_first(maximums))
- : NULL;
- lilv_nodes_free(maximums);
- }
+ if (def) {
+ LilvNodes* defaults = lilv_port_get_value_by_node(
+ plugin, port, plugin->world->uris.lv2_default);
+ *def =
+ defaults ? lilv_node_duplicate(lilv_nodes_get_first(defaults)) : NULL;
+ lilv_nodes_free(defaults);
+ }
+
+ if (min) {
+ LilvNodes* minimums = lilv_port_get_value_by_node(
+ plugin, port, plugin->world->uris.lv2_minimum);
+ *min =
+ minimums ? lilv_node_duplicate(lilv_nodes_get_first(minimums)) : NULL;
+ lilv_nodes_free(minimums);
+ }
+
+ if (max) {
+ LilvNodes* maximums = lilv_port_get_value_by_node(
+ plugin, port, plugin->world->uris.lv2_maximum);
+ *max =
+ maximums ? lilv_node_duplicate(lilv_nodes_get_first(maximums)) : NULL;
+ lilv_nodes_free(maximums);
+ }
}
LilvScalePoints*
-lilv_port_get_scale_points(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_scale_points(const LilvPlugin* plugin, const LilvPort* port)
{
- SordIter* points = lilv_world_query_internal(
- plugin->world,
- port->node->node,
- sord_new_uri(plugin->world->world, (const uint8_t*)LV2_CORE__scalePoint),
- NULL);
-
- LilvScalePoints* ret = NULL;
- if (!sord_iter_end(points)) {
- ret = lilv_scale_points_new();
- }
-
- FOREACH_MATCH(points) {
- const SordNode* point = sord_iter_get_node(points, SORD_OBJECT);
-
- LilvNode* value = lilv_plugin_get_unique(plugin,
- point,
- plugin->world->uris.rdf_value);
-
- LilvNode* label = lilv_plugin_get_unique(plugin,
- point,
- plugin->world->uris.rdfs_label);
-
- if (value && label) {
- zix_tree_insert(
- (ZixTree*)ret, lilv_scale_point_new(value, label), NULL);
- }
- }
- sord_iter_free(points);
-
- assert(!ret || lilv_nodes_size(ret) > 0);
- return ret;
+ SordIter* points = lilv_world_query_internal(
+ plugin->world,
+ port->node->node,
+ sord_new_uri(plugin->world->world, (const uint8_t*)LV2_CORE__scalePoint),
+ NULL);
+
+ if (sord_iter_end(points)) {
+ return NULL;
+ }
+
+ LilvScalePoints* ret = lilv_scale_points_new();
+
+ FOREACH_MATCH (points) {
+ const SordNode* point = sord_iter_get_node(points, SORD_OBJECT);
+
+ LilvNode* value =
+ lilv_plugin_get_unique(plugin, point, plugin->world->uris.rdf_value);
+
+ LilvNode* label =
+ lilv_plugin_get_unique(plugin, point, plugin->world->uris.rdfs_label);
+
+ if (value && label) {
+ zix_tree_insert((ZixTree*)ret, lilv_scale_point_new(value, label), NULL);
+ }
+ }
+ sord_iter_free(points);
+
+ assert(lilv_nodes_size(ret) > 0);
+ return ret;
}
LilvNodes*
-lilv_port_get_properties(const LilvPlugin* plugin,
- const LilvPort* port)
+lilv_port_get_properties(const LilvPlugin* plugin, const LilvPort* port)
{
- LilvNode* pred = lilv_node_new_from_node(
- plugin->world, plugin->world->uris.lv2_portProperty);
- LilvNodes* ret = lilv_port_get_value(plugin, port, pred);
- lilv_node_free(pred);
- return ret;
+ LilvNode* pred = lilv_node_new_from_node(
+ plugin->world, plugin->world->uris.lv2_portProperty);
+ LilvNodes* ret = lilv_port_get_value(plugin, port, pred);
+ lilv_node_free(pred);
+ return ret;
}
diff --git a/src/query.c b/src/query.c
index cf5e44f..3dd8eca 100644
--- a/src/query.c
+++ b/src/query.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -24,30 +11,32 @@
#include <string.h>
typedef enum {
- LILV_LANG_MATCH_NONE, ///< Language does not match at all
- LILV_LANG_MATCH_PARTIAL, ///< Partial (language, but not country) match
- LILV_LANG_MATCH_EXACT ///< Exact (language and country) match
+ LILV_LANG_MATCH_NONE, ///< Language does not match at all
+ LILV_LANG_MATCH_PARTIAL, ///< Partial (language, but not country) match
+ LILV_LANG_MATCH_EXACT ///< Exact (language and country) match
} LilvLangMatch;
static LilvLangMatch
lilv_lang_matches(const char* a, const char* b)
{
- if (!a || !b) {
- return LILV_LANG_MATCH_NONE;
- } else if (!strcmp(a, b)) {
- return LILV_LANG_MATCH_EXACT;
- }
-
- const char* a_dash = strchr(a, '-');
- const size_t a_lang_len = a_dash ? (size_t)(a_dash - a) : strlen(a);
- const char* b_dash = strchr(b, '-');
- const size_t b_lang_len = b_dash ? (size_t)(b_dash - b) : strlen(b);
-
- if (a_lang_len == b_lang_len && !strncmp(a, b, a_lang_len)) {
- return LILV_LANG_MATCH_PARTIAL;
- }
-
- return LILV_LANG_MATCH_NONE;
+ if (!a || !b) {
+ return LILV_LANG_MATCH_NONE;
+ }
+
+ if (!strcmp(a, b)) {
+ return LILV_LANG_MATCH_EXACT;
+ }
+
+ const char* a_dash = strchr(a, '-');
+ const size_t a_lang_len = a_dash ? (size_t)(a_dash - a) : strlen(a);
+ const char* b_dash = strchr(b, '-');
+ const size_t b_lang_len = b_dash ? (size_t)(b_dash - b) : strlen(b);
+
+ if (a_lang_len == b_lang_len && !strncmp(a, b, a_lang_len)) {
+ return LILV_LANG_MATCH_PARTIAL;
+ }
+
+ return LILV_LANG_MATCH_NONE;
}
static LilvNodes*
@@ -55,66 +44,59 @@ lilv_nodes_from_stream_objects_i18n(LilvWorld* world,
SordIter* stream,
SordQuadIndex field)
{
- LilvNodes* values = lilv_nodes_new();
- const SordNode* nolang = NULL; // Untranslated value
- const SordNode* partial = NULL; // Partial language match
- char* syslang = lilv_get_lang();
- FOREACH_MATCH(stream) {
- const SordNode* value = sord_iter_get_node(stream, field);
- if (sord_node_get_type(value) == SORD_LITERAL) {
- const char* lang = sord_node_get_language(value);
-
- if (!lang) {
- nolang = value;
- } else {
- switch (lilv_lang_matches(lang, syslang)) {
- case LILV_LANG_MATCH_EXACT:
- // Exact language match, add to results
- zix_tree_insert((ZixTree*)values,
- lilv_node_new_from_node(world, value),
- NULL);
- break;
- case LILV_LANG_MATCH_PARTIAL:
- // Partial language match, save in case we find no exact
- partial = value;
- break;
- case LILV_LANG_MATCH_NONE:
- break;
- }
- }
- } else {
- zix_tree_insert((ZixTree*)values,
- lilv_node_new_from_node(world, value),
- NULL);
- }
- }
- sord_iter_free(stream);
- free(syslang);
-
- if (lilv_nodes_size(values) > 0) {
- return values;
- }
-
- const SordNode* best = nolang;
- if (syslang && partial) {
- // Partial language match for system language
- best = partial;
- } else if (!best) {
- // No languages matches at all, and no untranslated value
- // Use any value, if possible
- best = partial;
- }
-
- if (best) {
- zix_tree_insert(
- (ZixTree*)values, lilv_node_new_from_node(world, best), NULL);
- } else {
- // No matches whatsoever
- lilv_nodes_free(values);
- values = NULL;
- }
-
- return values;
+ LilvNodes* values = lilv_nodes_new();
+ const SordNode* nolang = NULL; // Untranslated value
+ const SordNode* partial = NULL; // Partial language match
+ char* syslang = lilv_get_lang();
+ FOREACH_MATCH (stream) {
+ const SordNode* value = sord_iter_get_node(stream, field);
+ if (sord_node_get_type(value) == SORD_LITERAL) {
+ const char* lang = sord_node_get_language(value);
+
+ if (!lang) {
+ nolang = value;
+ } else {
+ switch (lilv_lang_matches(lang, syslang)) {
+ case LILV_LANG_MATCH_EXACT:
+ // Exact language match, add to results
+ zix_tree_insert(
+ (ZixTree*)values, lilv_node_new_from_node(world, value), NULL);
+ break;
+ case LILV_LANG_MATCH_PARTIAL:
+ // Partial language match, save in case we find no exact
+ partial = value;
+ break;
+ case LILV_LANG_MATCH_NONE:
+ break;
+ }
+ }
+ } else {
+ zix_tree_insert(
+ (ZixTree*)values, lilv_node_new_from_node(world, value), NULL);
+ }
+ }
+ sord_iter_free(stream);
+ free(syslang);
+
+ if (lilv_nodes_size(values) > 0) {
+ return values;
+ }
+
+ const SordNode* best = nolang;
+ if ((syslang && partial) || !best) {
+ best = partial;
+ }
+
+ if (best) {
+ zix_tree_insert(
+ (ZixTree*)values, lilv_node_new_from_node(world, best), NULL);
+ } else {
+ // No matches whatsoever
+ lilv_nodes_free(values);
+ values = NULL;
+ }
+
+ return values;
}
LilvNodes*
@@ -122,21 +104,23 @@ lilv_nodes_from_stream_objects(LilvWorld* world,
SordIter* stream,
SordQuadIndex field)
{
- if (sord_iter_end(stream)) {
- sord_iter_free(stream);
- return NULL;
- } else if (world->opt.filter_language) {
- return lilv_nodes_from_stream_objects_i18n(world, stream, field);
- } else {
- LilvNodes* values = lilv_nodes_new();
- FOREACH_MATCH(stream) {
- const SordNode* value = sord_iter_get_node(stream, field);
- LilvNode* node = lilv_node_new_from_node(world, value);
- if (node) {
- zix_tree_insert((ZixTree*)values, node, NULL);
- }
- }
- sord_iter_free(stream);
- return values;
- }
+ if (sord_iter_end(stream)) {
+ sord_iter_free(stream);
+ return NULL;
+ }
+
+ if (world->opt.filter_language) {
+ return lilv_nodes_from_stream_objects_i18n(world, stream, field);
+ }
+
+ LilvNodes* values = lilv_nodes_new();
+ FOREACH_MATCH (stream) {
+ const SordNode* value = sord_iter_get_node(stream, field);
+ LilvNode* node = lilv_node_new_from_node(world, value);
+ if (node) {
+ zix_tree_insert((ZixTree*)values, node, NULL);
+ }
+ }
+ sord_iter_free(stream);
+ return values;
}
diff --git a/src/scalepoint.c b/src/scalepoint.c
index 31e33c2..60cc905 100644
--- a/src/scalepoint.c
+++ b/src/scalepoint.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -24,30 +11,30 @@
LilvScalePoint*
lilv_scale_point_new(LilvNode* value, LilvNode* label)
{
- LilvScalePoint* point = (LilvScalePoint*)malloc(sizeof(LilvScalePoint));
- point->value = value;
- point->label = label;
- return point;
+ LilvScalePoint* point = (LilvScalePoint*)malloc(sizeof(LilvScalePoint));
+ point->value = value;
+ point->label = label;
+ return point;
}
void
lilv_scale_point_free(LilvScalePoint* point)
{
- if (point) {
- lilv_node_free(point->value);
- lilv_node_free(point->label);
- free(point);
- }
+ if (point) {
+ lilv_node_free(point->value);
+ lilv_node_free(point->label);
+ free(point);
+ }
}
const LilvNode*
lilv_scale_point_get_value(const LilvScalePoint* point)
{
- return point->value;
+ return point->value;
}
const LilvNode*
lilv_scale_point_get_label(const LilvScalePoint* point)
{
- return point->label;
+ return point->label;
}
diff --git a/src/state.c b/src/state.c
index a1c5d3c..0ed5715 100644
--- a/src/state.c
+++ b/src/state.c
@@ -1,26 +1,17 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "filesystem.h"
+// Copyright 2007-2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
#include "sord/sord.h"
#include "sratom/sratom.h"
+#include "zix/allocator.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
+#include "zix/status.h"
+#include "zix/string_view.h"
#include "zix/tree.h"
#include "lv2/atom/atom.h"
@@ -41,85 +32,91 @@
#define USTR(s) ((const uint8_t*)(s))
typedef struct {
- void* value; ///< Value/Object
- size_t size; ///< Size of value
- uint32_t key; ///< Key/Predicate (URID)
- uint32_t type; ///< Type of value (URID)
- uint32_t flags; ///< State flags (POD, etc)
+ void* value; ///< Value/Object
+ size_t size; ///< Size of value
+ uint32_t key; ///< Key/Predicate (URID)
+ uint32_t type; ///< Type of value (URID)
+ uint32_t flags; ///< State flags (POD, etc)
} Property;
typedef struct {
- char* symbol; ///< Symbol of port
- LV2_Atom* atom; ///< Value in port
+ char* symbol; ///< Symbol of port
+ LV2_Atom* atom; ///< Value in port
} PortValue;
typedef struct {
- char* abs; ///< Absolute path of actual file
- char* rel; ///< Abstract path (relative path in state dir)
+ char* abs; ///< Absolute path of actual file
+ char* rel; ///< Abstract path (relative path in state dir)
} PathMap;
typedef struct {
- size_t n;
- Property* props;
+ size_t n;
+ Property* props;
} PropertyArray;
struct LilvStateImpl {
- LilvNode* plugin_uri; ///< Plugin URI
- LilvNode* uri; ///< State/preset URI
- char* dir; ///< Save directory (if saved)
- char* scratch_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
+ LilvNode* plugin_uri; ///< Plugin URI
+ LilvNode* uri; ///< State/preset URI
+ char* dir; ///< Save directory (if saved)
+ char* scratch_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
-abs_cmp(const void* a, const void* b, void* user_data)
+abs_cmp(const void* a, const void* b, const void* user_data)
{
- return strcmp(((const PathMap*)a)->abs, ((const PathMap*)b)->abs);
+ (void)user_data;
+
+ return strcmp(((const PathMap*)a)->abs, ((const PathMap*)b)->abs);
}
static int
-rel_cmp(const void* a, const void* b, void* user_data)
+rel_cmp(const void* a, const void* b, const void* user_data)
{
- return strcmp(((const PathMap*)a)->rel, ((const PathMap*)b)->rel);
+ (void)user_data;
+
+ return strcmp(((const PathMap*)a)->rel, ((const PathMap*)b)->rel);
}
static int
property_cmp(const void* a, const void* b)
{
- const uint32_t a_key = ((const Property*)a)->key;
- const uint32_t b_key = ((const Property*)b)->key;
+ const uint32_t a_key = ((const Property*)a)->key;
+ const uint32_t b_key = ((const Property*)b)->key;
+
+ if (a_key < b_key) {
+ return -1;
+ }
- if (a_key < b_key) {
- return -1;
- } else if (b_key < a_key) {
- return 1;
- }
+ if (b_key < a_key) {
+ return 1;
+ }
- return 0;
+ return 0;
}
static int
value_cmp(const void* a, const void* b)
{
- return strcmp(((const PortValue*)a)->symbol,
- ((const PortValue*)b)->symbol);
+ return strcmp(((const PortValue*)a)->symbol, ((const PortValue*)b)->symbol);
}
static void
-path_rel_free(void* ptr)
+map_free(void* ptr, const void* user_data)
{
- free(((PathMap*)ptr)->abs);
- free(((PathMap*)ptr)->rel);
- free(ptr);
+ (void)user_data;
+ free(((PathMap*)ptr)->abs);
+ free(((PathMap*)ptr)->rel);
+ free(ptr);
}
static PortValue*
@@ -129,30 +126,30 @@ append_port_value(LilvState* state,
uint32_t size,
uint32_t type)
{
- PortValue* pv = NULL;
- if (value) {
- state->values = (PortValue*)realloc(
- state->values, (++state->n_values) * sizeof(PortValue));
-
- pv = &state->values[state->n_values - 1];
- pv->symbol = lilv_strdup(port_symbol);
- pv->atom = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size);
- pv->atom->size = size;
- pv->atom->type = type;
- memcpy(pv->atom + 1, value, size);
- }
- return pv;
+ PortValue* pv = NULL;
+ if (value) {
+ state->values = (PortValue*)realloc(
+ state->values, (++state->n_values) * sizeof(PortValue));
+
+ pv = &state->values[state->n_values - 1];
+ pv->symbol = lilv_strdup(port_symbol);
+ pv->atom = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size);
+ pv->atom->size = size;
+ pv->atom->type = type;
+ memcpy(pv->atom + 1, value, size);
+ }
+ return pv;
}
static const char*
lilv_state_rel2abs(const LilvState* state, const char* path)
{
- ZixTreeIter* iter = NULL;
- const PathMap key = { NULL, (char*)path };
- if (state->rel2abs && !zix_tree_find(state->rel2abs, &key, &iter)) {
- return ((const PathMap*)zix_tree_get(iter))->abs;
- }
- return path;
+ ZixTreeIter* iter = NULL;
+ const PathMap key = {NULL, (char*)path};
+ if (state->rel2abs && !zix_tree_find(state->rel2abs, &key, &iter)) {
+ return ((const PathMap*)zix_tree_get(iter))->abs;
+ }
+ return path;
}
static void
@@ -164,37 +161,37 @@ append_property(LilvState* state,
uint32_t type,
uint32_t flags)
{
- array->props = (Property*)realloc(
- array->props, (++array->n) * sizeof(Property));
-
- Property* const prop = &array->props[array->n - 1];
- if ((flags & LV2_STATE_IS_POD) || type == state->atom_Path) {
- prop->value = malloc(size);
- memcpy(prop->value, value, size);
- } else {
- prop->value = (void*)value;
- }
-
- prop->size = size;
- prop->key = key;
- prop->type = type;
- prop->flags = flags;
+ array->props =
+ (Property*)realloc(array->props, (++array->n) * sizeof(Property));
+
+ Property* const prop = &array->props[array->n - 1];
+ if ((flags & LV2_STATE_IS_POD) || type == state->atom_Path) {
+ prop->value = malloc(size);
+ memcpy(prop->value, value, size);
+ } else {
+ prop->value = (void*)value;
+ }
+
+ prop->size = size;
+ prop->key = key;
+ prop->type = type;
+ prop->flags = flags;
}
static const Property*
find_property(const LilvState* const state, const uint32_t key)
{
- if (!state->props.props) {
- return NULL;
- }
+ if (!state->props.props) {
+ return NULL;
+ }
- const Property search_key = {NULL, 0, key, 0, 0};
+ const Property search_key = {NULL, 0, key, 0, 0};
- return (const Property*)bsearch(&search_key,
- state->props.props,
- state->props.n,
- sizeof(Property),
- property_cmp);
+ return (const Property*)bsearch(&search_key,
+ state->props.props,
+ state->props.n,
+ sizeof(Property),
+ property_cmp);
}
static LV2_State_Status
@@ -205,18 +202,18 @@ store_callback(LV2_State_Handle handle,
uint32_t type,
uint32_t flags)
{
- LilvState* const state = (LilvState*)handle;
+ LilvState* const state = (LilvState*)handle;
- if (!key) {
- return LV2_STATE_ERR_UNKNOWN; // TODO: Add status for bad arguments
- }
+ if (!key) {
+ return LV2_STATE_ERR_UNKNOWN; // TODO: Add status for bad arguments
+ }
- if (find_property((const LilvState*)handle, key)) {
- return LV2_STATE_ERR_UNKNOWN; // TODO: Add status for duplicate keys
- }
+ if (find_property((const LilvState*)handle, key)) {
+ return LV2_STATE_ERR_UNKNOWN; // TODO: Add status for duplicate keys
+ }
- append_property(state, &state->props, key, value, size, type, flags);
- return LV2_STATE_SUCCESS;
+ append_property(state, &state->props, key, value, size, type, flags);
+ return LV2_STATE_SUCCESS;
}
static const void*
@@ -226,125 +223,150 @@ retrieve_callback(LV2_State_Handle handle,
uint32_t* type,
uint32_t* flags)
{
- const Property* const prop = find_property((const LilvState*)handle, key);
-
- if (prop) {
- *size = prop->size;
- *type = prop->type;
- *flags = prop->flags;
- return prop->value;
- }
- return NULL;
+ const Property* const prop = find_property((const LilvState*)handle, key);
+
+ if (prop) {
+ if (size) {
+ *size = prop->size;
+ }
+ if (type) {
+ *type = prop->type;
+ }
+ if (flags) {
+ *flags = prop->flags;
+ }
+ return prop->value;
+ }
+ return NULL;
}
static bool
path_exists(const char* path, const void* ignored)
{
- return lilv_path_exists(path);
+ (void)ignored;
+
+ return zix_file_type(path) != ZIX_FILE_TYPE_NONE;
}
static bool
lilv_state_has_path(const char* path, const void* state)
{
- return lilv_state_rel2abs((const LilvState*)state, path) != path;
+ return lilv_state_rel2abs((const LilvState*)state, path) != path;
}
static char*
make_path(LV2_State_Make_Path_Handle handle, const char* path)
{
- LilvState* state = (LilvState*)handle;
- lilv_create_directories(state->dir);
+ LilvState* state = (LilvState*)handle;
+ zix_create_directories(NULL, state->dir);
- return lilv_path_join(state->dir, path);
+ return zix_path_join(NULL, state->dir, path);
+}
+
+static bool
+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;
}
static char*
-abstract_path(LV2_State_Map_Path_Handle handle,
- const char* abs_path)
+abstract_path(LV2_State_Map_Path_Handle handle, const char* abs_path)
{
- LilvState* state = (LilvState*)handle;
- char* path = NULL;
- char* real_path = lilv_path_canonical(abs_path);
- const PathMap key = { real_path, NULL };
- ZixTreeIter* iter = NULL;
-
- if (abs_path[0] == '\0') {
- return lilv_strdup(abs_path);
- } else if (!zix_tree_find(state->abs2rel, &key, &iter)) {
- // Already mapped path in a previous call
- PathMap* pm = (PathMap*)zix_tree_get(iter);
- free(real_path);
- return lilv_strdup(pm->rel);
- } else if (lilv_path_is_child(real_path, state->dir)) {
- // File in state directory (loaded, or created by plugin during save)
- path = lilv_path_relative_to(real_path, state->dir);
- } else if (lilv_path_is_child(real_path, state->scratch_dir)) {
- // File created by plugin earlier
- path = lilv_path_relative_to(real_path, state->scratch_dir);
- if (state->copy_dir) {
- int st = lilv_create_directories(state->copy_dir);
- if (st) {
- LILV_ERRORF("Error creating directory %s (%s)\n",
- state->copy_dir, strerror(st));
- }
-
- char* cpath = lilv_path_join(state->copy_dir, path);
- char* copy = lilv_get_latest_copy(real_path, cpath);
- if (!copy || !lilv_file_equals(real_path, copy)) {
- // No recent enough copy, make a new one
- free(copy);
- copy = lilv_find_free_path(cpath, path_exists, NULL);
- if ((st = lilv_copy_file(real_path, copy))) {
- LILV_ERRORF("Error copying state file %s (%s)\n",
- copy, strerror(st));
- }
- }
- free(real_path);
- free(cpath);
-
- // Refer to the latest copy in plugin state
- real_path = copy;
- }
- } else if (state->link_dir) {
- // New path outside state directory, make a link
- const char* slash = strrchr(real_path, '/');
- const char* name = slash ? (slash + 1) : real_path;
-
- // Find a free name in the (virtual) state directory
- path = lilv_find_free_path(name, lilv_state_has_path, state);
- } else {
- // No link directory, preserve absolute path
- path = lilv_strdup(abs_path);
- }
-
- // Add record to path mapping
- PathMap* pm = (PathMap*)malloc(sizeof(PathMap));
- pm->abs = real_path;
- pm->rel = lilv_strdup(path);
- zix_tree_insert(state->abs2rel, pm, NULL);
- zix_tree_insert(state->rel2abs, pm, NULL);
-
- return path;
+ LilvState* state = (LilvState*)handle;
+ char* path = NULL;
+ char* real_path = zix_canonical_path(NULL, abs_path);
+ if (!real_path) {
+ real_path = zix_path_lexically_normal(NULL, abs_path);
+ }
+
+ const PathMap key = {real_path, NULL};
+ ZixTreeIter* iter = NULL;
+
+ if (abs_path[0] == '\0') {
+ return lilv_strdup(abs_path);
+ }
+
+ if (!zix_tree_find(state->abs2rel, &key, &iter)) {
+ // Already mapped path in a previous call
+ PathMap* pm = (PathMap*)zix_tree_get(iter);
+ zix_free(NULL, real_path);
+ return lilv_strdup(pm->rel);
+ }
+
+ if (path_is_child(real_path, state->dir)) {
+ // File in state directory (loaded, or created by plugin during save)
+ path = zix_path_lexically_relative(NULL, real_path, state->dir);
+ } else if (path_is_child(real_path, state->scratch_dir)) {
+ // File created by plugin earlier
+ path = zix_path_lexically_relative(NULL, real_path, state->scratch_dir);
+ if (state->copy_dir) {
+ ZixStatus st = zix_create_directories(NULL, state->copy_dir);
+ if (st) {
+ LILV_ERRORF("Error creating directory %s (%s)\n",
+ state->copy_dir,
+ zix_strerror(st));
+ }
+
+ char* cpath = zix_path_join(NULL, state->copy_dir, path);
+ char* copy = lilv_get_latest_copy(real_path, cpath);
+ if (!copy || !zix_file_equals(NULL, real_path, copy)) {
+ // No recent enough copy, make a new one
+ free(copy);
+ copy = lilv_find_free_path(cpath, path_exists, NULL);
+ if ((st = zix_copy_file(NULL, real_path, copy, 0U))) {
+ LILV_ERRORF(
+ "Error copying state file %s (%s)\n", copy, zix_strerror(st));
+ }
+ }
+ zix_free(NULL, real_path);
+ zix_free(NULL, cpath);
+
+ // Refer to the latest copy in plugin state
+ real_path = copy;
+ }
+ } else if (state->link_dir) {
+ // New path outside state directory, make a link
+ const ZixStringView name = zix_path_filename(real_path);
+
+ // Find a free name in the (virtual) state directory
+ path = lilv_find_free_path(name.data, lilv_state_has_path, state);
+ } else {
+ // No link directory, preserve absolute path
+ path = lilv_strdup(abs_path);
+ }
+
+ // Add record to path mapping
+ PathMap* pm = (PathMap*)malloc(sizeof(PathMap));
+ pm->abs = real_path;
+ pm->rel = lilv_strdup(path);
+ zix_tree_insert(state->abs2rel, pm, NULL);
+ zix_tree_insert(state->rel2abs, pm, NULL);
+
+ return path;
}
static char*
-absolute_path(LV2_State_Map_Path_Handle handle,
- const char* state_path)
+absolute_path(LV2_State_Map_Path_Handle handle, const char* state_path)
{
- LilvState* state = (LilvState*)handle;
- char* path = NULL;
- if (lilv_path_is_absolute(state_path)) {
- // Absolute path, return identical path
- path = lilv_strdup(state_path);
- } else if (state->dir) {
- // Relative path inside state directory
- path = lilv_path_join(state->dir, state_path);
- } else {
- // State has not been saved, unmap
- path = lilv_strdup(lilv_state_rel2abs(state, state_path));
- }
-
- return path;
+ LilvState* state = (LilvState*)handle;
+ char* path = NULL;
+ if (zix_path_is_absolute(state_path)) {
+ // Absolute path, return identical path
+ path = lilv_strdup(state_path);
+ } else if (state->dir) {
+ // Relative path inside state directory
+ path = zix_path_join(NULL, state->dir, state_path);
+ } else {
+ // State has not been saved, unmap
+ path = lilv_strdup(lilv_state_rel2abs(state, state_path));
+ }
+
+ return path;
}
/** Return a new features array with built-in features added to `features`. */
@@ -354,138 +376,157 @@ add_features(const LV2_Feature* const* features,
const LV2_Feature* make,
const LV2_Feature* free)
{
- size_t n_features = 0;
- for (; features && features[n_features]; ++n_features) {}
-
- const LV2_Feature** ret = (const LV2_Feature**)calloc(
- n_features + 4, sizeof(LV2_Feature*));
-
- if (features) {
- memcpy(ret, features, n_features * sizeof(LV2_Feature*));
- }
-
- size_t i = n_features;
- if (map) {
- ret[i++] = map;
- }
- if (make) {
- ret[i++] = make;
- }
- if (free) {
- ret[i++] = free;
- }
-
- return ret;
+ size_t n_features = 0;
+ for (; features && features[n_features]; ++n_features) {
+ if (!strcmp(features[n_features]->URI, LV2_STATE__mapPath)) {
+ map = NULL;
+ }
+ if (!strcmp(features[n_features]->URI, LV2_STATE__makePath)) {
+ make = NULL;
+ }
+ if (!strcmp(features[n_features]->URI, LV2_STATE__freePath)) {
+ free = NULL;
+ }
+ }
+
+ const LV2_Feature** ret =
+ (const LV2_Feature**)calloc(n_features + 4, sizeof(LV2_Feature*));
+
+ if (features) {
+ memcpy(ret, features, n_features * sizeof(LV2_Feature*));
+ }
+
+ size_t i = n_features;
+ if (map) {
+ ret[i++] = map;
+ }
+ if (make) {
+ ret[i++] = make;
+ }
+ if (free) {
+ ret[i++] = free;
+ }
+
+ return ret;
}
-/// Return the canonical path for a directory with a trailing separator
+/// Return a normal path for a directory with a trailing separator
static char*
-real_dir(const char* path)
+normal_dir(const char* path)
{
- char* abs_path = lilv_path_canonical(path);
- char* base = lilv_path_join(abs_path, NULL);
- free(abs_path);
- return base;
+ char* const normal_path = zix_path_lexically_normal(NULL, path);
+ char* const base_path = zix_path_join(NULL, normal_path, NULL);
+
+ zix_free(NULL, normal_path);
+ return base_path;
}
static const char*
state_strerror(LV2_State_Status st)
{
- switch (st) {
- case LV2_STATE_SUCCESS: return "Completed successfully";
- case LV2_STATE_ERR_BAD_TYPE: return "Unsupported type";
- case LV2_STATE_ERR_BAD_FLAGS: return "Unsupported flags";
- case LV2_STATE_ERR_NO_FEATURE: return "Missing features";
- case LV2_STATE_ERR_NO_PROPERTY: return "Missing property";
- default: return "Unknown error";
- }
+ switch (st) {
+ case LV2_STATE_SUCCESS:
+ return "Completed successfully";
+ case LV2_STATE_ERR_BAD_TYPE:
+ return "Unsupported type";
+ case LV2_STATE_ERR_BAD_FLAGS:
+ return "Unsupported flags";
+ case LV2_STATE_ERR_NO_FEATURE:
+ return "Missing features";
+ case LV2_STATE_ERR_NO_PROPERTY:
+ return "Missing property";
+ default:
+ return "Unknown error";
+ }
}
static void
lilv_free_path(LV2_State_Free_Path_Handle handle, char* path)
{
- lilv_free(path);
+ (void)handle;
+
+ lilv_free(path);
}
LilvState*
-lilv_state_new_from_instance(const LilvPlugin* plugin,
- LilvInstance* instance,
- LV2_URID_Map* map,
- const char* scratch_dir,
- const char* copy_dir,
- const char* link_dir,
- const char* save_dir,
- LilvGetPortValueFunc get_value,
- void* user_data,
- uint32_t flags,
- const LV2_Feature *const * features)
+lilv_state_new_from_instance(const LilvPlugin* plugin,
+ LilvInstance* instance,
+ LV2_URID_Map* map,
+ const char* scratch_dir,
+ const char* copy_dir,
+ const char* link_dir,
+ const char* save_dir,
+ LilvGetPortValueFunc get_value,
+ void* user_data,
+ uint32_t flags,
+ const LV2_Feature* const* features)
{
- const LV2_Feature** sfeatures = NULL;
- LilvWorld* const world = plugin->world;
- LilvState* const state = (LilvState*)calloc(1, sizeof(LilvState));
- state->plugin_uri = lilv_node_duplicate(lilv_plugin_get_uri(plugin));
- state->abs2rel = zix_tree_new(false, abs_cmp, NULL, path_rel_free);
- state->rel2abs = zix_tree_new(false, rel_cmp, NULL, NULL);
- state->scratch_dir = scratch_dir ? real_dir(scratch_dir) : NULL;
- state->copy_dir = copy_dir ? real_dir(copy_dir) : NULL;
- state->link_dir = link_dir ? real_dir(link_dir) : NULL;
- state->dir = save_dir ? real_dir(save_dir) : NULL;
- state->atom_Path = map->map(map->handle, LV2_ATOM__Path);
-
- LV2_State_Map_Path pmap = { state, abstract_path, absolute_path };
- LV2_Feature pmap_feature = { LV2_STATE__mapPath, &pmap };
- LV2_State_Make_Path pmake = { state, make_path };
- LV2_Feature pmake_feature = { LV2_STATE__makePath, &pmake };
- LV2_State_Free_Path pfree = { NULL, lilv_free_path };
- LV2_Feature pfree_feature = { LV2_STATE__freePath, &pfree };
- features = sfeatures = add_features(features, &pmap_feature,
- save_dir ? &pmake_feature : NULL,
- &pfree_feature);
-
- // Store port values
- if (get_value) {
- LilvNode* lv2_ControlPort = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
- LilvNode* lv2_InputPort = lilv_new_uri(world, LILV_URI_INPUT_PORT);
- for (uint32_t i = 0; i < plugin->num_ports; ++i) {
- const LilvPort* const port = plugin->ports[i];
- if (lilv_port_is_a(plugin, port, lv2_ControlPort)
- && lilv_port_is_a(plugin, port, lv2_InputPort)) {
- uint32_t size = 0;
- uint32_t type = 0;
- const char* sym = lilv_node_as_string(port->symbol);
- const void* value = get_value(sym, user_data, &size, &type);
- append_port_value(state, sym, value, size, type);
- }
- }
- lilv_node_free(lv2_ControlPort);
- lilv_node_free(lv2_InputPort);
- }
-
- // Store properties
- const LV2_Descriptor* desc = instance->lv2_descriptor;
- const LV2_State_Interface* iface = (desc->extension_data)
- ? (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface)
- : NULL;
-
- if (iface) {
- LV2_State_Status st = iface->save(
- instance->lv2_handle, store_callback, state, flags, features);
- if (st) {
- LILV_ERRORF("Error saving plugin state: %s\n", state_strerror(st));
- free(state->props.props);
- state->props.props = NULL;
- state->props.n = 0;
- } else {
- qsort(state->props.props, state->props.n, sizeof(Property), property_cmp);
- }
- }
-
- if (state->values) {
- qsort(state->values, state->n_values, sizeof(PortValue), value_cmp);
- }
-
- free(sfeatures);
- return state;
+ const LV2_Feature** sfeatures = NULL;
+ LilvWorld* const world = plugin->world;
+ LilvState* const state = (LilvState*)calloc(1, sizeof(LilvState));
+ state->plugin_uri = lilv_node_duplicate(lilv_plugin_get_uri(plugin));
+ state->abs2rel = zix_tree_new(NULL, false, abs_cmp, NULL, map_free, NULL);
+ state->rel2abs = zix_tree_new(NULL, false, rel_cmp, NULL, NULL, NULL);
+ state->scratch_dir = scratch_dir ? normal_dir(scratch_dir) : NULL;
+ state->copy_dir = copy_dir ? normal_dir(copy_dir) : NULL;
+ state->link_dir = link_dir ? normal_dir(link_dir) : NULL;
+ state->dir = save_dir ? normal_dir(save_dir) : NULL;
+ state->atom_Path = map->map(map->handle, LV2_ATOM__Path);
+
+ LV2_State_Map_Path pmap = {state, abstract_path, absolute_path};
+ LV2_Feature pmap_feature = {LV2_STATE__mapPath, &pmap};
+ LV2_State_Make_Path pmake = {state, make_path};
+ LV2_Feature pmake_feature = {LV2_STATE__makePath, &pmake};
+ LV2_State_Free_Path pfree = {NULL, lilv_free_path};
+ LV2_Feature pfree_feature = {LV2_STATE__freePath, &pfree};
+ features = sfeatures = add_features(
+ features, &pmap_feature, save_dir ? &pmake_feature : NULL, &pfree_feature);
+
+ // Store port values
+ if (get_value) {
+ LilvNode* lv2_ControlPort = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
+ LilvNode* lv2_InputPort = lilv_new_uri(world, LILV_URI_INPUT_PORT);
+ for (uint32_t i = 0; i < plugin->num_ports; ++i) {
+ const LilvPort* const port = plugin->ports[i];
+ if (lilv_port_is_a(plugin, port, lv2_ControlPort) &&
+ lilv_port_is_a(plugin, port, lv2_InputPort)) {
+ uint32_t size = 0;
+ uint32_t type = 0;
+ const char* sym = lilv_node_as_string(port->symbol);
+ const void* value = get_value(sym, user_data, &size, &type);
+ append_port_value(state, sym, value, size, type);
+ }
+ }
+ lilv_node_free(lv2_ControlPort);
+ lilv_node_free(lv2_InputPort);
+ }
+
+ // Store properties
+ const LV2_Descriptor* desc = instance->lv2_descriptor;
+ const LV2_State_Interface* iface =
+ (desc->extension_data)
+ ? (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface)
+ : NULL;
+
+ if (iface) {
+ LV2_State_Status st =
+ iface->save(instance->lv2_handle, store_callback, state, flags, features);
+ if (st) {
+ LILV_ERRORF("Error saving plugin state: %s\n", state_strerror(st));
+ free(state->props.props);
+ state->props.props = NULL;
+ state->props.n = 0;
+ } else {
+ qsort(state->props.props, state->props.n, sizeof(Property), property_cmp);
+ }
+ }
+
+ if (state->values) {
+ qsort(state->values, state->n_values, sizeof(PortValue), value_cmp);
+ }
+
+ free(sfeatures);
+ return state;
}
void
@@ -493,209 +534,209 @@ lilv_state_emit_port_values(const LilvState* state,
LilvSetPortValueFunc set_value,
void* user_data)
{
- for (uint32_t i = 0; i < state->n_values; ++i) {
- const PortValue* value = &state->values[i];
- const LV2_Atom* atom = value->atom;
- set_value(value->symbol, user_data, atom + 1, atom->size, atom->type);
- }
+ for (uint32_t i = 0; i < state->n_values; ++i) {
+ const PortValue* value = &state->values[i];
+ const LV2_Atom* atom = value->atom;
+ set_value(value->symbol, user_data, atom + 1, atom->size, atom->type);
+ }
}
void
-lilv_state_restore(const LilvState* state,
- LilvInstance* instance,
- LilvSetPortValueFunc set_value,
- void* user_data,
- uint32_t flags,
- const LV2_Feature *const * features)
+lilv_state_restore(const LilvState* state,
+ LilvInstance* instance,
+ 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 };
-
- LV2_State_Free_Path free_path = { NULL, lilv_free_path };
- LV2_Feature free_feature = { LV2_STATE__freePath, &free_path };
-
- if (instance) {
- const LV2_Descriptor* desc = instance->lv2_descriptor;
- if (desc->extension_data) {
- const LV2_State_Interface* iface = (const LV2_State_Interface*)
- desc->extension_data(LV2_STATE__interface);
-
- if (iface && iface->restore) {
- const LV2_Feature** sfeatures = add_features(
- features, &map_feature, NULL, &free_feature);
-
- iface->restore(instance->lv2_handle, retrieve_callback,
- (LV2_State_Handle)state, flags, sfeatures);
-
- free(sfeatures);
- }
- }
- }
-
-
- if (set_value) {
- lilv_state_emit_port_values(state, set_value, user_data);
- }
+ 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};
+
+ LV2_State_Free_Path free_path = {NULL, lilv_free_path};
+ LV2_Feature free_feature = {LV2_STATE__freePath, &free_path};
+
+ if (instance) {
+ const LV2_Descriptor* desc = instance->lv2_descriptor;
+ if (desc->extension_data) {
+ const LV2_State_Interface* iface =
+ (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface);
+
+ if (iface && iface->restore) {
+ const LV2_Feature** sfeatures =
+ add_features(features, &map_feature, NULL, &free_feature);
+
+ iface->restore(instance->lv2_handle,
+ retrieve_callback,
+ (LV2_State_Handle)state,
+ flags,
+ sfeatures);
+
+ free(sfeatures);
+ }
+ }
+ }
+
+ if (set_value) {
+ lilv_state_emit_port_values(state, set_value, user_data);
+ }
}
static void
set_state_dir_from_model(LilvState* state, const SordNode* graph)
{
- if (!state->dir && graph) {
- const char* uri = (const char*)sord_node_get_string(graph);
- char* path = lilv_file_uri_parse(uri, NULL);
-
- state->dir = lilv_path_join(path, NULL);
- free(path);
- }
- assert(!state->dir || lilv_path_is_absolute(state->dir));
+ if (!state->dir && graph) {
+ const char* uri = (const char*)sord_node_get_string(graph);
+ char* path = lilv_file_uri_parse(uri, NULL);
+
+ state->dir = zix_path_join(NULL, path, NULL);
+ free(path);
+ }
+ assert(!state->dir || zix_path_is_absolute(state->dir));
}
static LilvState*
-new_state_from_model(LilvWorld* world,
- LV2_URID_Map* map,
- SordModel* model,
- const SordNode* node,
- const char* dir)
+new_state_from_model(LilvWorld* world,
+ LV2_URID_Map* map,
+ SordModel* model,
+ const SordNode* node,
+ const char* dir)
{
- // Check that we know at least something about this state subject
- if (!sord_ask(model, node, 0, 0, 0)) {
- return NULL;
- }
-
- // Allocate state
- LilvState* const state = (LilvState*)calloc(1, sizeof(LilvState));
- state->dir = lilv_path_join(dir, NULL);
- state->atom_Path = map->map(map->handle, LV2_ATOM__Path);
- state->uri = lilv_node_new_from_node(world, node);
-
- // Get the plugin URI this state applies to
- SordIter* i = sord_search(model, node, world->uris.lv2_appliesTo, 0, 0);
- if (i) {
- const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
- const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH);
- state->plugin_uri = lilv_node_new_from_node(world, object);
- set_state_dir_from_model(state, graph);
- sord_iter_free(i);
- } else if (sord_ask(model,
- node,
- world->uris.rdf_a,
- world->uris.lv2_Plugin, 0)) {
- // Loading plugin description as state (default state)
- state->plugin_uri = lilv_node_new_from_node(world, node);
- } else {
- LILV_ERRORF("State %s missing lv2:appliesTo property\n",
- sord_node_get_string(node));
- }
-
- // Get the state label
- i = sord_search(model, node, world->uris.rdfs_label, NULL, NULL);
- if (i) {
- const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
- const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH);
- state->label = lilv_strdup((const char*)sord_node_get_string(object));
- set_state_dir_from_model(state, graph);
- sord_iter_free(i);
- }
-
- Sratom* sratom = sratom_new(map);
- SerdChunk chunk = { NULL, 0 };
- LV2_Atom_Forge forge;
- lv2_atom_forge_init(&forge, map);
- lv2_atom_forge_set_sink(
- &forge, sratom_forge_sink, sratom_forge_deref, &chunk);
-
- // Get port values
- SordIter* ports = sord_search(model, node, world->uris.lv2_port, 0, 0);
- FOREACH_MATCH(ports) {
- const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
-
- SordNode* label = sord_get(model, port, world->uris.rdfs_label, 0, 0);
- SordNode* symbol = sord_get(model, port, world->uris.lv2_symbol, 0, 0);
- SordNode* value = sord_get(model, port, world->uris.pset_value, 0, 0);
- if (!value) {
- value = sord_get(model, port, world->uris.lv2_default, 0, 0);
- }
- if (!symbol) {
- LILV_ERRORF("State `%s' port missing symbol.\n",
- sord_node_get_string(node));
- } else if (value) {
- chunk.len = 0;
- sratom_read(sratom, &forge, world->world, model, value);
- const LV2_Atom* atom = (const LV2_Atom*)chunk.buf;
-
- append_port_value(state,
- (const char*)sord_node_get_string(symbol),
- LV2_ATOM_BODY_CONST(atom),
- atom->size, atom->type);
-
- if (label) {
- lilv_state_set_label(state,
- (const char*)sord_node_get_string(label));
- }
- }
- sord_node_free(world->world, value);
- sord_node_free(world->world, symbol);
- sord_node_free(world->world, label);
- }
- sord_iter_free(ports);
-
- // Get properties
- SordNode* statep = sord_new_uri(world->world, USTR(LV2_STATE__state));
- SordNode* state_node = sord_get(model, node, statep, NULL, NULL);
- if (state_node) {
- SordIter* props = sord_search(model, state_node, 0, 0, 0);
- FOREACH_MATCH(props) {
- const SordNode* p = sord_iter_get_node(props, SORD_PREDICATE);
- const SordNode* o = sord_iter_get_node(props, SORD_OBJECT);
- const char* key = (const char*)sord_node_get_string(p);
-
- chunk.len = 0;
- lv2_atom_forge_set_sink(
- &forge, sratom_forge_sink, sratom_forge_deref, &chunk);
-
- sratom_read(sratom, &forge, world->world, model, o);
- const LV2_Atom* atom = (const LV2_Atom*)chunk.buf;
- uint32_t flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE;
- Property prop = { NULL, 0, 0, 0, flags };
-
- prop.key = map->map(map->handle, key);
- prop.type = atom->type;
- prop.size = atom->size;
- prop.value = malloc(atom->size);
- memcpy(prop.value, LV2_ATOM_BODY_CONST(atom), atom->size);
- if (atom->type == forge.Path) {
- prop.flags = LV2_STATE_IS_POD;
- }
-
- if (prop.value) {
- 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_node_free(world->world, state_node);
- sord_node_free(world->world, statep);
-
- serd_free((void*)chunk.buf);
- sratom_free(sratom);
-
- 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;
+ // Check that we know at least something about this state subject
+ if (!sord_ask(model, node, 0, 0, 0)) {
+ return NULL;
+ }
+
+ // Allocate state
+ LilvState* const state = (LilvState*)calloc(1, sizeof(LilvState));
+ state->dir = dir ? zix_path_join(NULL, dir, NULL) : NULL;
+ state->atom_Path = map->map(map->handle, LV2_ATOM__Path);
+ state->uri = lilv_node_new_from_node(world, node);
+
+ // Get the plugin URI this state applies to
+ SordIter* i = sord_search(model, node, world->uris.lv2_appliesTo, 0, 0);
+ if (i) {
+ const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
+ const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH);
+ state->plugin_uri = lilv_node_new_from_node(world, object);
+ set_state_dir_from_model(state, graph);
+ sord_iter_free(i);
+ } else if (sord_ask(
+ model, node, world->uris.rdf_a, world->uris.lv2_Plugin, 0)) {
+ // Loading plugin description as state (default state)
+ state->plugin_uri = lilv_node_new_from_node(world, node);
+ } else {
+ LILV_ERRORF("State %s missing lv2:appliesTo property\n",
+ sord_node_get_string(node));
+ }
+
+ // Get the state label
+ i = sord_search(model, node, world->uris.rdfs_label, NULL, NULL);
+ if (i) {
+ const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
+ const SordNode* graph = sord_iter_get_node(i, SORD_GRAPH);
+ state->label = lilv_strdup((const char*)sord_node_get_string(object));
+ set_state_dir_from_model(state, graph);
+ sord_iter_free(i);
+ }
+
+ Sratom* sratom = sratom_new(map);
+ SerdChunk chunk = {NULL, 0};
+ LV2_Atom_Forge forge;
+ lv2_atom_forge_init(&forge, map);
+ lv2_atom_forge_set_sink(
+ &forge, sratom_forge_sink, sratom_forge_deref, &chunk);
+
+ // Get port values
+ SordIter* ports = sord_search(model, node, world->uris.lv2_port, 0, 0);
+ FOREACH_MATCH (ports) {
+ const SordNode* port = sord_iter_get_node(ports, SORD_OBJECT);
+
+ SordNode* label = sord_get(model, port, world->uris.rdfs_label, 0, 0);
+ SordNode* symbol = sord_get(model, port, world->uris.lv2_symbol, 0, 0);
+ SordNode* value = sord_get(model, port, world->uris.pset_value, 0, 0);
+ if (!value) {
+ value = sord_get(model, port, world->uris.lv2_default, 0, 0);
+ }
+ if (!symbol) {
+ LILV_ERRORF("State `%s' port missing symbol.\n",
+ sord_node_get_string(node));
+ } else if (value) {
+ chunk.len = 0;
+ sratom_read(sratom, &forge, world->world, model, value);
+ const LV2_Atom* atom = (const LV2_Atom*)chunk.buf;
+
+ append_port_value(state,
+ (const char*)sord_node_get_string(symbol),
+ LV2_ATOM_BODY_CONST(atom),
+ atom->size,
+ atom->type);
+
+ if (label) {
+ lilv_state_set_label(state, (const char*)sord_node_get_string(label));
+ }
+ }
+ sord_node_free(world->world, value);
+ sord_node_free(world->world, symbol);
+ sord_node_free(world->world, label);
+ }
+ sord_iter_free(ports);
+
+ // Get properties
+ SordNode* statep = sord_new_uri(world->world, USTR(LV2_STATE__state));
+ SordNode* state_node = sord_get(model, node, statep, NULL, NULL);
+ if (state_node) {
+ SordIter* props = sord_search(model, state_node, 0, 0, 0);
+ FOREACH_MATCH (props) {
+ const SordNode* p = sord_iter_get_node(props, SORD_PREDICATE);
+ const SordNode* o = sord_iter_get_node(props, SORD_OBJECT);
+ const char* key = (const char*)sord_node_get_string(p);
+
+ chunk.len = 0;
+ lv2_atom_forge_set_sink(
+ &forge, sratom_forge_sink, sratom_forge_deref, &chunk);
+
+ sratom_read(sratom, &forge, world->world, model, o);
+ const LV2_Atom* atom = (const LV2_Atom*)chunk.buf;
+ uint32_t flags = LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE;
+ Property prop = {NULL, 0, 0, 0, flags};
+
+ prop.key = map->map(map->handle, key);
+ prop.type = atom->type;
+ prop.size = atom->size;
+ prop.value = malloc(atom->size);
+ memcpy(prop.value, LV2_ATOM_BODY_CONST(atom), atom->size);
+ if (atom->type == forge.Path) {
+ prop.flags = LV2_STATE_IS_POD;
+ }
+
+ if (prop.value) {
+ 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_node_free(world->world, state_node);
+ sord_node_free(world->world, statep);
+
+ serd_free((void*)chunk.buf);
+ sratom_free(sratom);
+
+ 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;
}
LilvState*
@@ -703,13 +744,13 @@ lilv_state_new_from_world(LilvWorld* world,
LV2_URID_Map* map,
const LilvNode* node)
{
- if (!lilv_node_is_uri(node) && !lilv_node_is_blank(node)) {
- LILV_ERRORF("Subject `%s' is not a URI or blank node.\n",
- lilv_node_as_string(node));
- return NULL;
- }
+ if (!lilv_node_is_uri(node) && !lilv_node_is_blank(node)) {
+ LILV_ERRORF("Subject `%s' is not a URI or blank node.\n",
+ lilv_node_as_string(node));
+ return NULL;
+ }
- return new_state_from_model(world, map, world->model, node->node, NULL);
+ return new_state_from_model(world, map, world->model, node->node, NULL);
}
LilvState*
@@ -718,127 +759,128 @@ lilv_state_new_from_file(LilvWorld* world,
const LilvNode* subject,
const char* path)
{
- if (subject && !lilv_node_is_uri(subject)
- && !lilv_node_is_blank(subject)) {
- LILV_ERRORF("Subject `%s' is not a URI or blank node.\n",
- lilv_node_as_string(subject));
- return NULL;
- }
-
- uint8_t* abs_path = (uint8_t*)lilv_path_absolute(path);
- SerdNode node = serd_node_new_file_uri(abs_path, NULL, NULL, true);
- SerdEnv* env = serd_env_new(&node);
- SordModel* model = sord_new(world->world, SORD_SPO, false);
- SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
-
- serd_reader_read_file(reader, node.buf);
-
- SordNode* subject_node = (subject)
- ? subject->node
- : sord_node_from_serd_node(world->world, env, &node, NULL, NULL);
-
- char* dirname = lilv_path_parent(path);
- char* real_path = lilv_path_canonical(dirname);
- char* dir_path = lilv_path_join(real_path, NULL);
- LilvState* state =
- new_state_from_model(world, map, model, subject_node, dir_path);
- free(dir_path);
- free(real_path);
- free(dirname);
-
- serd_node_free(&node);
- free(abs_path);
- serd_reader_free(reader);
- sord_free(model);
- serd_env_free(env);
- return state;
+ if (subject && !lilv_node_is_uri(subject) && !lilv_node_is_blank(subject)) {
+ LILV_ERRORF("Subject `%s' is not a URI or blank node.\n",
+ lilv_node_as_string(subject));
+ return NULL;
+ }
+
+ uint8_t* const abs_path = (uint8_t*)zix_canonical_path(NULL, path);
+ if (!abs_path) {
+ return NULL;
+ }
+
+ SerdNode node = serd_node_new_file_uri(abs_path, NULL, NULL, true);
+ SerdEnv* env = serd_env_new(&node);
+ SordModel* model = sord_new(world->world, SORD_SPO, false);
+ SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
+
+ serd_reader_read_file(reader, (const uint8_t*)node.buf);
+
+ SordNode* subject_node =
+ (subject) ? subject->node
+ : sord_node_from_serd_node(world->world, env, &node, NULL, NULL);
+
+ const ZixStringView dirname = zix_path_parent_path(path);
+ char* const real_path = zix_canonical_path(NULL, dirname.data);
+ char* const dir_path = zix_path_join(NULL, real_path, NULL);
+
+ LilvState* const state =
+ new_state_from_model(world, map, model, subject_node, dir_path);
+
+ zix_free(NULL, dir_path);
+ zix_free(NULL, real_path);
+
+ serd_node_free(&node);
+ zix_free(NULL, abs_path);
+ serd_reader_free(reader);
+ sord_free(model);
+ serd_env_free(env);
+ return state;
}
static void
set_prefixes(SerdEnv* env)
{
#define SET_PSET(e, p, u) serd_env_set_prefix_from_strings(e, p, u)
- SET_PSET(env, USTR("atom"), USTR(LV2_ATOM_PREFIX));
- SET_PSET(env, USTR("lv2"), USTR(LV2_CORE_PREFIX));
- SET_PSET(env, USTR("pset"), USTR(LV2_PRESETS_PREFIX));
- SET_PSET(env, USTR("rdf"), USTR(LILV_NS_RDF));
- SET_PSET(env, USTR("rdfs"), USTR(LILV_NS_RDFS));
- SET_PSET(env, USTR("state"), USTR(LV2_STATE_PREFIX));
- SET_PSET(env, USTR("xsd"), USTR(LILV_NS_XSD));
+ SET_PSET(env, USTR("atom"), USTR(LV2_ATOM_PREFIX));
+ SET_PSET(env, USTR("lv2"), USTR(LV2_CORE_PREFIX));
+ SET_PSET(env, USTR("pset"), USTR(LV2_PRESETS_PREFIX));
+ SET_PSET(env, USTR("rdf"), USTR(LILV_NS_RDF));
+ SET_PSET(env, USTR("rdfs"), USTR(LILV_NS_RDFS));
+ SET_PSET(env, USTR("state"), USTR(LV2_STATE_PREFIX));
+ SET_PSET(env, USTR("xsd"), USTR(LILV_NS_XSD));
}
LilvState*
-lilv_state_new_from_string(LilvWorld* world,
- LV2_URID_Map* map,
- const char* str)
+lilv_state_new_from_string(LilvWorld* world, LV2_URID_Map* map, const char* str)
{
- if (!str) {
- return NULL;
- }
+ if (!str) {
+ return NULL;
+ }
- SerdNode base = SERD_NODE_NULL;
- SerdEnv* env = serd_env_new(&base);
- SordModel* model = sord_new(world->world, SORD_SPO|SORD_OPS, false);
- SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
+ SerdNode base = SERD_NODE_NULL;
+ SerdEnv* env = serd_env_new(&base);
+ SordModel* model = sord_new(world->world, SORD_SPO | SORD_OPS, false);
+ SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
- set_prefixes(env);
- serd_reader_read_string(reader, USTR(str));
+ set_prefixes(env);
+ serd_reader_read_string(reader, USTR(str));
- SordNode* o = sord_new_uri(world->world, USTR(LV2_PRESETS__Preset));
- SordNode* s = sord_get(model, NULL, world->uris.rdf_a, o, NULL);
+ SordNode* o = sord_new_uri(world->world, USTR(LV2_PRESETS__Preset));
+ SordNode* s = sord_get(model, NULL, world->uris.rdf_a, o, NULL);
- LilvState* state = new_state_from_model(world, map, model, s, NULL);
+ LilvState* state = new_state_from_model(world, map, model, s, NULL);
- sord_node_free(world->world, s);
- sord_node_free(world->world, o);
- serd_reader_free(reader);
- sord_free(model);
- serd_env_free(env);
+ sord_node_free(world->world, s);
+ sord_node_free(world->world, o);
+ serd_reader_free(reader);
+ sord_free(model);
+ serd_env_free(env);
- return state;
+ return state;
}
static SerdWriter*
ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env)
{
- SerdURI base_uri = SERD_URI_NULL;
- if (base && base->buf) {
- serd_uri_parse(base->buf, &base_uri);
- }
-
- SerdEnv* env = *new_env ? *new_env : serd_env_new(base);
- set_prefixes(env);
-
- SerdWriter* writer = serd_writer_new(
- SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_RESOLVED |
- SERD_STYLE_ABBREVIATED|
- SERD_STYLE_CURIED),
- env,
- &base_uri,
- sink,
- stream);
-
- if (!*new_env) {
- *new_env = env;
- }
-
- return writer;
+ SerdURI base_uri = SERD_URI_NULL;
+ if (base && base->buf) {
+ serd_uri_parse((const uint8_t*)base->buf, &base_uri);
+ }
+
+ SerdEnv* env = *new_env ? *new_env : serd_env_new(base);
+ set_prefixes(env);
+
+ SerdWriter* writer =
+ serd_writer_new(SERD_TURTLE,
+ (SerdStyle)(SERD_STYLE_RESOLVED | SERD_STYLE_ABBREVIATED |
+ SERD_STYLE_CURIED),
+ env,
+ &base_uri,
+ sink,
+ stream);
+
+ if (!*new_env) {
+ *new_env = env;
+ }
+
+ return writer;
}
static SerdWriter*
ttl_file_writer(FILE* fd, const SerdNode* node, SerdEnv** env)
{
- SerdWriter* writer = ttl_writer(serd_file_sink, fd, node, env);
+ SerdWriter* writer = ttl_writer(serd_file_sink, fd, node, env);
- fseek(fd, 0, SEEK_END);
- if (ftell(fd) == 0) {
- serd_env_foreach(*env, (SerdPrefixSink)serd_writer_set_prefix, writer);
- } else {
- fprintf(fd, "\n");
- }
+ fseek(fd, 0, SEEK_END);
+ if (ftell(fd) == 0) {
+ serd_env_foreach(*env, (SerdPrefixSink)serd_writer_set_prefix, writer);
+ } else {
+ fprintf(fd, "\n");
+ }
- return writer;
+ return writer;
}
static void
@@ -849,28 +891,28 @@ add_to_model(SordWorld* world,
const SerdNode p,
const SerdNode o)
{
- SordNode* ss = sord_node_from_serd_node(world, env, &s, NULL, NULL);
- SordNode* sp = sord_node_from_serd_node(world, env, &p, NULL, NULL);
- SordNode* so = sord_node_from_serd_node(world, env, &o, NULL, NULL);
+ SordNode* ss = sord_node_from_serd_node(world, env, &s, NULL, NULL);
+ SordNode* sp = sord_node_from_serd_node(world, env, &p, NULL, NULL);
+ SordNode* so = sord_node_from_serd_node(world, env, &o, NULL, NULL);
- SordQuad quad = { ss, sp, so, NULL };
- sord_add(model, quad);
+ SordQuad quad = {ss, sp, so, NULL};
+ sord_add(model, quad);
- sord_node_free(world, ss);
- sord_node_free(world, sp);
- sord_node_free(world, so);
+ sord_node_free(world, ss);
+ sord_node_free(world, sp);
+ sord_node_free(world, so);
}
static void
remove_manifest_entry(SordWorld* world, SordModel* model, const char* subject)
{
- SordNode* s = sord_new_uri(world, USTR(subject));
- SordIter* i = sord_search(model, s, NULL, NULL, NULL);
- while (!sord_iter_end(i)) {
- sord_erase(model, i);
- }
- sord_iter_free(i);
- sord_node_free(world, s);
+ SordNode* s = sord_new_uri(world, USTR(subject));
+ SordIter* i = sord_search(model, s, NULL, NULL, NULL);
+ while (!sord_iter_end(i)) {
+ sord_erase(model, i);
+ }
+ sord_iter_free(i);
+ sord_node_free(world, s);
}
static int
@@ -879,22 +921,24 @@ write_manifest(LilvWorld* world,
SordModel* model,
const SerdNode* file_uri)
{
- char* const path = (char*)serd_file_uri_parse(file_uri->buf, NULL);
- FILE* const wfd = fopen(path, "w");
- if (!wfd) {
- LILV_ERRORF("Failed to open %s for writing (%s)\n",
- path, strerror(errno));
-
- serd_free(path);
- return 1;
- }
-
- SerdWriter* writer = ttl_file_writer(wfd, file_uri, &env);
- sord_write(model, writer, NULL);
- serd_writer_free(writer);
- fclose(wfd);
- serd_free(path);
- return 0;
+ (void)world;
+
+ char* const path =
+ (char*)serd_file_uri_parse((const uint8_t*)file_uri->buf, NULL);
+
+ FILE* const wfd = path ? fopen(path, "w") : NULL;
+ if (!wfd) {
+ LILV_ERRORF("Failed to open %s for writing (%s)\n", path, strerror(errno));
+ serd_free(path);
+ return 1;
+ }
+
+ SerdWriter* writer = ttl_file_writer(wfd, file_uri, &env);
+ sord_write(model, writer, NULL);
+ serd_writer_free(writer);
+ fclose(wfd);
+ serd_free(path);
+ return 0;
}
static int
@@ -904,102 +948,133 @@ add_state_to_manifest(LilvWorld* lworld,
const char* state_uri,
const char* state_path)
{
- SordWorld* world = lworld->world;
- SerdNode manifest = serd_node_new_file_uri(USTR(manifest_path), 0, 0, 1);
- SerdNode file = serd_node_new_file_uri(USTR(state_path), 0, 0, 1);
- SerdEnv* env = serd_env_new(&manifest);
- SordModel* model = sord_new(world, SORD_SPO, false);
-
- FILE* rfd = fopen(manifest_path, "r");
- if (rfd) {
- // Read manifest into model
- SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
- lilv_flock(rfd, true, true);
- serd_reader_read_file_handle(reader, rfd, manifest.buf);
- serd_reader_free(reader);
- }
-
- // Choose state URI (use file URI if not given)
- if (!state_uri) {
- state_uri = (const char*)file.buf;
- }
-
- // Remove any existing manifest entries for this state
- remove_manifest_entry(world, model, state_uri);
-
- // Add manifest entry for this state to model
- SerdNode s = serd_node_from_string(SERD_URI, USTR(state_uri));
-
- // <state> a pset:Preset
- add_to_model(world, env, model,
- s,
- serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")),
- serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset)));
-
- // <state> a pset:Preset
- add_to_model(world, env, model,
- s,
- serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")),
- serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset)));
-
- // <state> rdfs:seeAlso <file>
- add_to_model(world, env, model,
- s,
- serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "seeAlso")),
- file);
-
- // <state> lv2:appliesTo <plugin>
- add_to_model(world, env, model,
- s,
- serd_node_from_string(SERD_URI, USTR(LV2_CORE__appliesTo)),
- serd_node_from_string(SERD_URI,
- USTR(lilv_node_as_string(plugin_uri))));
-
- // Write manifest model to file
- write_manifest(lworld, env, model, &manifest);
-
- sord_free(model);
- serd_node_free(&file);
- serd_node_free(&manifest);
- serd_env_free(env);
-
- if (rfd) {
- lilv_flock(rfd, false, true);
- fclose(rfd);
- }
-
- return 0;
+ SordWorld* world = lworld->world;
+ SerdNode manifest = serd_node_new_file_uri(USTR(manifest_path), 0, 0, 1);
+ SerdNode file = serd_node_new_file_uri(USTR(state_path), 0, 0, 1);
+ SerdEnv* env = serd_env_new(&manifest);
+ SordModel* model = sord_new(world, SORD_SPO, false);
+
+ const uint8_t* const manifest_uri = manifest.buf;
+ if (manifest_uri && zix_file_type(manifest_path) == ZIX_FILE_TYPE_REGULAR) {
+ // Read manifest into model
+ SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
+ SerdStatus st = serd_reader_read_file(reader, manifest_uri);
+ if (st) {
+ LILV_WARNF("Failed to read manifest (%s)\n", serd_strerror(st));
+ }
+ serd_reader_free(reader);
+ }
+
+ // Choose state URI (use file URI if not given)
+ if (!state_uri) {
+ state_uri = (const char*)file.buf;
+ }
+
+ // Remove any existing manifest entries for this state
+ remove_manifest_entry(world, model, state_uri);
+
+ // Add manifest entry for this state to model
+ SerdNode s = serd_node_from_string(SERD_URI, USTR(state_uri));
+
+ // <state> a pset:Preset
+ add_to_model(world,
+ env,
+ model,
+ s,
+ serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")),
+ serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset)));
+
+ // <state> a pset:Preset
+ add_to_model(world,
+ env,
+ model,
+ s,
+ serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")),
+ serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset)));
+
+ // <state> rdfs:seeAlso <file>
+ add_to_model(world,
+ env,
+ model,
+ s,
+ serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "seeAlso")),
+ file);
+
+ // <state> lv2:appliesTo <plugin>
+ add_to_model(
+ world,
+ env,
+ model,
+ s,
+ serd_node_from_string(SERD_URI, USTR(LV2_CORE__appliesTo)),
+ serd_node_from_string(SERD_URI, USTR(lilv_node_as_string(plugin_uri))));
+
+ /* Re-open manifest for locked writing. We need to do this because it may
+ need to be truncated, and the file can only be open once on Windows. */
+
+ FILE* wfd = fopen(manifest_path, "wb");
+ int r = 0;
+ if (!wfd) {
+ LILV_ERRORF(
+ "Failed to open %s for writing (%s)\n", manifest_path, strerror(errno));
+ r = 1;
+ } else {
+ SerdWriter* writer = ttl_file_writer(wfd, &manifest, &env);
+ zix_file_lock(wfd, ZIX_FILE_LOCK_BLOCK);
+ sord_write(model, writer, NULL);
+ zix_file_unlock(wfd, ZIX_FILE_LOCK_BLOCK);
+ serd_writer_free(writer);
+ fclose(wfd);
+ }
+
+ sord_free(model);
+ serd_node_free(&file);
+ serd_node_free(&manifest);
+ serd_env_free(env);
+
+ return r;
}
static bool
link_exists(const char* path, const void* data)
{
- const char* target = (const char*)data;
- if (!lilv_path_exists(path)) {
- return false;
- }
- char* real_path = lilv_path_canonical(path);
- bool matches = !strcmp(real_path, target);
- free(real_path);
- return !matches;
+ const char* target = (const char*)data;
+ if (zix_file_type(path) == ZIX_FILE_TYPE_NONE) {
+ return false;
+ }
+
+ char* const real_path = zix_canonical_path(NULL, path);
+ const bool matches = real_path && !strcmp(real_path, target);
+ zix_free(NULL, real_path);
+ return !matches;
}
-static int
+static ZixStatus
+create_link(const char* oldpath, const char* newpath)
+{
+ const ZixStringView parent_path = zix_path_parent_path(newpath);
+ char* const parent = zix_string_view_copy(NULL, parent_path);
+
+ char* const relpath = zix_path_lexically_relative(NULL, oldpath, parent);
+
+ ZixStatus st = ZIX_STATUS_SUCCESS;
+ if ((st = zix_create_symlink(relpath, newpath))) {
+ if ((st = zix_create_hard_link(oldpath, newpath))) {
+ LILV_ERRORF(
+ "Failed to link %s => %s (%s)\n", newpath, oldpath, zix_strerror(st));
+ }
+ }
+
+ zix_free(NULL, relpath);
+ zix_free(NULL, parent);
+ return st;
+}
+
+static ZixStatus
maybe_symlink(const char* oldpath, const char* newpath)
{
- if (link_exists(newpath, oldpath)) {
- return 0;
- }
-
- const int st = lilv_symlink(oldpath, newpath);
- if (st) {
- LILV_ERRORF("Failed to link %s => %s (%s)\n",
- newpath,
- oldpath,
- strerror(errno));
- }
-
- return st;
+ return link_exists(newpath, oldpath) ? ZIX_STATUS_SUCCESS
+ : create_link(oldpath, newpath);
}
static void
@@ -1011,26 +1086,31 @@ write_property_array(const LilvState* state,
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);
- }
- }
+ 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
@@ -1042,139 +1122,143 @@ lilv_state_write(LilvWorld* world,
const char* uri,
const char* dir)
{
- SerdNode lv2_appliesTo = serd_node_from_string(
- SERD_CURIE, USTR("lv2:appliesTo"));
-
- const SerdNode* plugin_uri = sord_node_to_serd_node(
- state->plugin_uri->node);
-
- SerdNode subject = serd_node_from_string(SERD_URI, USTR(uri ? uri : ""));
-
- // <subject> a pset:Preset
- SerdNode p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type"));
- SerdNode o = serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset));
- serd_writer_write_statement(writer, 0, NULL,
- &subject, &p, &o, NULL, NULL);
-
- // <subject> lv2:appliesTo <http://example.org/plugin>
- serd_writer_write_statement(writer, 0, NULL,
- &subject,
- &lv2_appliesTo,
- plugin_uri, NULL, NULL);
-
- // <subject> rdfs:label label
- if (state->label) {
- p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "label"));
- o = serd_node_from_string(SERD_LITERAL, USTR(state->label));
- serd_writer_write_statement(writer, 0,
- NULL, &subject, &p, &o, NULL, NULL);
- }
-
- SerdEnv* env = serd_writer_get_env(writer);
- const SerdNode* base = serd_env_get_base_uri(env, NULL);
-
- Sratom* sratom = sratom_new(map);
- sratom_set_sink(sratom, (const char*)base->buf,
- (SerdStatementSink)serd_writer_write_statement,
- (SerdEndSink)serd_writer_end_anon,
- writer);
-
- // 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
- sratom_set_pretty_numbers(sratom, true); // Use pretty numbers
- for (uint32_t i = 0; i < state->n_values; ++i) {
- PortValue* const value = &state->values[i];
-
- const SerdNode port = serd_node_from_string(
- SERD_BLANK, USTR(value->symbol));
-
- // <> lv2:port _:symbol
- p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__port));
- serd_writer_write_statement(writer, SERD_ANON_O_BEGIN,
- NULL, &subject, &p, &port, NULL, NULL);
-
- // _:symbol lv2:symbol "symbol"
- p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__symbol));
- o = serd_node_from_string(SERD_LITERAL, USTR(value->symbol));
- serd_writer_write_statement(writer, SERD_ANON_CONT,
- NULL, &port, &p, &o, NULL, NULL);
-
- // _:symbol pset:value value
- p = serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__value));
- sratom_write(sratom, unmap, SERD_ANON_CONT, &port, &p,
- value->atom->type, value->atom->size, value->atom + 1);
-
- serd_writer_end_anon(writer, &port);
- }
-
- // Write properties
- const SerdNode body = serd_node_from_string(SERD_BLANK, USTR("body"));
- if (state->props.n > 0) {
- p = serd_node_from_string(SERD_URI, USTR(LV2_STATE__state));
- serd_writer_write_statement(writer, SERD_ANON_O_BEGIN, NULL,
- &subject, &p, &body, NULL, NULL);
- }
- sratom_set_pretty_numbers(sratom, false); // Use precise types
- write_property_array(state, &state->props, sratom, SERD_ANON_CONT,
- &body, unmap, dir);
-
- if (state->props.n > 0) {
- serd_writer_end_anon(writer, &body);
- }
-
- sratom_free(sratom);
- return 0;
+ (void)world;
+
+ SerdNode lv2_appliesTo =
+ serd_node_from_string(SERD_CURIE, USTR("lv2:appliesTo"));
+
+ const SerdNode* plugin_uri = sord_node_to_serd_node(state->plugin_uri->node);
+
+ SerdNode subject = serd_node_from_string(SERD_URI, USTR(uri ? uri : ""));
+
+ // <subject> a pset:Preset
+ SerdNode p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type"));
+ SerdNode o = serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__Preset));
+ serd_writer_write_statement(writer, 0, NULL, &subject, &p, &o, NULL, NULL);
+
+ // <subject> lv2:appliesTo <http://example.org/plugin>
+ serd_writer_write_statement(
+ writer, 0, NULL, &subject, &lv2_appliesTo, plugin_uri, NULL, NULL);
+
+ // <subject> rdfs:label label
+ if (state->label) {
+ p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "label"));
+ o = serd_node_from_string(SERD_LITERAL, USTR(state->label));
+ serd_writer_write_statement(writer, 0, NULL, &subject, &p, &o, NULL, NULL);
+ }
+
+ SerdEnv* env = serd_writer_get_env(writer);
+ const SerdNode* base = serd_env_get_base_uri(env, NULL);
+
+ Sratom* sratom = sratom_new(map);
+ sratom_set_sink(sratom,
+ (const char*)base->buf,
+ (SerdStatementSink)serd_writer_write_statement,
+ (SerdEndSink)serd_writer_end_anon,
+ writer);
+
+ // 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
+ sratom_set_pretty_numbers(sratom, true); // Use pretty numbers
+ for (uint32_t i = 0; i < state->n_values; ++i) {
+ PortValue* const value = &state->values[i];
+
+ const SerdNode port =
+ serd_node_from_string(SERD_BLANK, USTR(value->symbol));
+
+ // <> lv2:port _:symbol
+ p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__port));
+ serd_writer_write_statement(
+ writer, SERD_ANON_O_BEGIN, NULL, &subject, &p, &port, NULL, NULL);
+
+ // _:symbol lv2:symbol "symbol"
+ p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__symbol));
+ o = serd_node_from_string(SERD_LITERAL, USTR(value->symbol));
+ serd_writer_write_statement(
+ writer, SERD_ANON_CONT, NULL, &port, &p, &o, NULL, NULL);
+
+ // _:symbol pset:value value
+ p = serd_node_from_string(SERD_URI, USTR(LV2_PRESETS__value));
+ sratom_write(sratom,
+ unmap,
+ SERD_ANON_CONT,
+ &port,
+ &p,
+ value->atom->type,
+ value->atom->size,
+ value->atom + 1);
+
+ serd_writer_end_anon(writer, &port);
+ }
+
+ // Write properties
+ const SerdNode body = serd_node_from_string(SERD_BLANK, USTR("body"));
+ if (state->props.n > 0) {
+ p = serd_node_from_string(SERD_URI, USTR(LV2_STATE__state));
+ serd_writer_write_statement(
+ writer, SERD_ANON_O_BEGIN, NULL, &subject, &p, &body, NULL, NULL);
+ }
+ sratom_set_pretty_numbers(sratom, false); // Use precise types
+ write_property_array(
+ state, &state->props, sratom, SERD_ANON_CONT, &body, unmap, dir);
+
+ if (state->props.n > 0) {
+ serd_writer_end_anon(writer, &body);
+ }
+
+ sratom_free(sratom);
+ return 0;
}
static void
lilv_state_make_links(const LilvState* state, const char* dir)
{
- // Create symlinks to files
- for (ZixTreeIter* i = zix_tree_begin(state->abs2rel);
- i != zix_tree_end(state->abs2rel);
- i = zix_tree_iter_next(i)) {
- const PathMap* pm = (const PathMap*)zix_tree_get(i);
-
- char* path = lilv_path_join(dir, pm->rel);
- if (lilv_path_is_child(pm->abs, state->copy_dir)
- && strcmp(state->copy_dir, dir)) {
- // Link directly to snapshot in the copy directory
- char* target = lilv_path_relative_to(pm->abs, dir);
- maybe_symlink(target, path);
- free(target);
- } else if (!lilv_path_is_child(pm->abs, dir)) {
- const char* link_dir = state->link_dir ? state->link_dir : dir;
- char* pat = lilv_path_join(link_dir, pm->rel);
- if (!strcmp(dir, link_dir)) {
- // Link directory is save directory, make link at exact path
- remove(pat);
- maybe_symlink(pm->abs, pat);
- } else {
- // Make a link in the link directory to external file
- char* lpath = lilv_find_free_path(pat, link_exists, pm->abs);
- if (!lilv_path_exists(lpath)) {
- if (lilv_symlink(pm->abs, lpath)) {
- LILV_ERRORF("Failed to link %s => %s (%s)\n",
- pm->abs,
- lpath,
- strerror(errno));
- }
- }
-
- // Make a link in the save directory to the external link
- char* target = lilv_path_relative_to(lpath, dir);
- maybe_symlink(target, path);
- free(target);
- free(lpath);
- }
- free(pat);
- }
- free(path);
- }
+ // Create symlinks to files
+ for (ZixTreeIter* i = zix_tree_begin(state->abs2rel);
+ i != zix_tree_end(state->abs2rel);
+ i = zix_tree_iter_next(i)) {
+ const PathMap* const pm = (const PathMap*)zix_tree_get(i);
+ char* const path = zix_path_join(NULL, dir, pm->rel);
+
+ if (state->copy_dir && path_is_child(pm->abs, state->copy_dir) &&
+ !!strcmp(state->copy_dir, dir)) {
+ // Link directly to snapshot in the copy directory
+ maybe_symlink(pm->abs, path);
+ } else if (!path_is_child(pm->abs, dir)) {
+ const char* link_dir = state->link_dir ? state->link_dir : dir;
+ char* pat = zix_path_join(NULL, link_dir, pm->rel);
+
+ if (!strcmp(dir, link_dir)) {
+ // Link directory is save directory, make link at exact path
+ remove(pat);
+ maybe_symlink(pm->abs, pat);
+ } else {
+ // Make a link in the link directory to external file
+ char* lpath = lilv_find_free_path(pat, link_exists, pm->abs);
+ if (zix_file_type(lpath) == ZIX_FILE_TYPE_NONE) {
+ const ZixStatus st = create_link(pm->abs, lpath);
+ if (st) {
+ LILV_ERRORF("Failed to link %s => %s (%s)\n",
+ pm->abs,
+ lpath,
+ zix_strerror(st));
+ }
+ }
+
+ // Make a link in the save directory to the external link
+ char* target = zix_path_lexically_relative(NULL, lpath, dir);
+ maybe_symlink(lpath, path);
+ free(target);
+ free(lpath);
+ }
+ free(pat);
+ }
+ free(path);
+ }
}
int
@@ -1186,50 +1270,58 @@ lilv_state_save(LilvWorld* world,
const char* dir,
const char* filename)
{
- if (!filename || !dir || lilv_create_directories(dir)) {
- return 1;
- }
-
- char* abs_dir = real_dir(dir);
- char* const path = lilv_path_join(abs_dir, filename);
- FILE* fd = fopen(path, "w");
- if (!fd) {
- LILV_ERRORF("Failed to open %s (%s)\n", path, strerror(errno));
- free(abs_dir);
- free(path);
- return 4;
- }
-
- // Create symlinks to files if necessary
- lilv_state_make_links(state, abs_dir);
-
- // Write state to Turtle file
- SerdNode file = serd_node_new_file_uri(USTR(path), NULL, NULL, true);
- SerdNode node = uri ? serd_node_from_string(SERD_URI, USTR(uri)) : file;
- SerdEnv* env = NULL;
- SerdWriter* ttl = ttl_file_writer(fd, &file, &env);
- int ret = lilv_state_write(
- world, map, unmap, state, ttl, (const char*)node.buf, dir);
-
- // Set saved dir and uri (FIXME: const violation)
- free(state->dir);
- lilv_node_free(state->uri);
- ((LilvState*)state)->dir = lilv_strdup(abs_dir);
- ((LilvState*)state)->uri = lilv_new_uri(world, (const char*)node.buf);
-
- serd_node_free(&file);
- serd_writer_free(ttl);
- serd_env_free(env);
- fclose(fd);
-
- // Add entry to manifest
- char* const manifest = lilv_path_join(abs_dir, "manifest.ttl");
- add_state_to_manifest(world, state->plugin_uri, manifest, uri, path);
-
- free(manifest);
- free(abs_dir);
- free(path);
- return ret;
+ if (!filename || !dir || zix_create_directories(NULL, dir)) {
+ return 1;
+ }
+
+ char* const abs_dir = zix_canonical_path(NULL, dir);
+ if (!abs_dir) {
+ return 2;
+ }
+
+ char* const path = zix_path_join(NULL, abs_dir, filename);
+ FILE* fd = path ? fopen(path, "w") : NULL;
+ if (!fd) {
+ LILV_ERRORF("Failed to open %s (%s)\n", path, strerror(errno));
+ zix_free(NULL, abs_dir);
+ zix_free(NULL, path);
+ return 4;
+ }
+
+ // Create symlinks to files if necessary
+ lilv_state_make_links(state, abs_dir);
+
+ // Write state to Turtle file
+ SerdNode file = serd_node_new_file_uri(USTR(path), NULL, NULL, true);
+ SerdNode node = uri ? serd_node_from_string(SERD_URI, USTR(uri)) : file;
+ SerdEnv* env = NULL;
+ SerdWriter* ttl = ttl_file_writer(fd, &file, &env);
+ int ret =
+ lilv_state_write(world, map, unmap, state, ttl, (const char*)node.buf, dir);
+
+ // Set saved dir and uri (FIXME: const violation)
+ zix_free(NULL, state->dir);
+ lilv_node_free(state->uri);
+ ((LilvState*)state)->dir = zix_path_join(NULL, abs_dir, "");
+ ((LilvState*)state)->uri = lilv_new_uri(world, (const char*)node.buf);
+
+ serd_node_free(&file);
+ serd_writer_free(ttl);
+ serd_env_free(env);
+ fclose(fd);
+
+ // Add entry to manifest
+ if (!ret) {
+ char* const manifest = zix_path_join(NULL, abs_dir, "manifest.ttl");
+
+ ret = add_state_to_manifest(world, state->plugin_uri, manifest, uri, path);
+
+ zix_free(NULL, manifest);
+ }
+
+ zix_free(NULL, abs_dir);
+ zix_free(NULL, path);
+ return ret;
}
char*
@@ -1240,240 +1332,252 @@ lilv_state_to_string(LilvWorld* world,
const char* uri,
const char* base_uri)
{
- if (!uri) {
- LILV_ERROR("Attempt to serialise state with no URI\n");
- return NULL;
- }
-
- SerdChunk chunk = { NULL, 0 };
- SerdEnv* env = NULL;
- SerdNode base = serd_node_from_string(SERD_URI, USTR(base_uri));
- SerdWriter* writer = ttl_writer(serd_chunk_sink, &chunk, &base, &env);
-
- lilv_state_write(world, map, unmap, state, writer, uri, NULL);
-
- serd_writer_free(writer);
- serd_env_free(env);
- char* str = (char*)serd_chunk_sink_finish(&chunk);
- char* result = lilv_strdup(str);
- serd_free(str);
- return result;
+ if (!uri) {
+ LILV_ERROR("Attempt to serialise state with no URI\n");
+ return NULL;
+ }
+
+ SerdChunk chunk = {NULL, 0};
+ SerdEnv* env = NULL;
+ SerdNode base = serd_node_from_string(SERD_URI, USTR(base_uri));
+ SerdWriter* writer = ttl_writer(serd_chunk_sink, &chunk, &base, &env);
+
+ lilv_state_write(world, map, unmap, state, writer, uri, NULL);
+
+ serd_writer_free(writer);
+ serd_env_free(env);
+ char* str = (char*)serd_chunk_sink_finish(&chunk);
+ char* result = lilv_strdup(str);
+ serd_free(str);
+ return result;
}
static void
try_unlink(const char* state_dir, const char* path)
{
- if (!strncmp(state_dir, path, strlen(state_dir))) {
- if (lilv_path_exists(path) && lilv_remove(path)) {
- LILV_ERRORF("Failed to remove %s (%s)\n", path, strerror(errno));
- }
- }
+ if (!strncmp(state_dir, path, strlen(state_dir))) {
+ if (zix_file_type(path) != ZIX_FILE_TYPE_NONE && zix_remove(path)) {
+ LILV_ERRORF("Failed to remove %s (%s)\n", path, strerror(errno));
+ }
+ }
+}
+
+static char*
+get_canonical_path(const LilvNode* const node)
+{
+ char* const path = lilv_node_get_path(node, NULL);
+ char* const real_path = zix_canonical_path(NULL, path);
+
+ free(path);
+ return real_path;
}
int
-lilv_state_delete(LilvWorld* world,
- const LilvState* state)
+lilv_state_delete(LilvWorld* world, const LilvState* state)
{
- if (!state->dir) {
- LILV_ERROR("Attempt to delete unsaved state\n");
- return -1;
- }
-
- LilvNode* bundle = lilv_new_file_uri(world, NULL, state->dir);
- LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle);
- char* manifest_path = lilv_node_get_path(manifest, NULL);
- const bool has_manifest = lilv_path_exists(manifest_path);
- SordModel* model = sord_new(world->world, SORD_SPO, false);
-
- if (has_manifest) {
- // Read manifest into temporary local model
- SerdEnv* env = serd_env_new(sord_node_to_serd_node(manifest->node));
- SerdReader* ttl = sord_new_reader(model, env, SERD_TURTLE, NULL);
- serd_reader_read_file(ttl, USTR(manifest_path));
- serd_reader_free(ttl);
- serd_env_free(env);
- }
-
- if (state->uri) {
- SordNode* file = sord_get(
- model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL);
- if (file) {
- // Remove state file
- const uint8_t* uri = sord_node_get_string(file);
- char* path = (char*)serd_file_uri_parse(uri, NULL);
- try_unlink(state->dir, path);
- serd_free(path);
- }
-
- // Remove any existing manifest entries for this state
- const char* state_uri_str = lilv_node_as_string(state->uri);
- remove_manifest_entry(world->world, model, state_uri_str);
- remove_manifest_entry(world->world, world->model, state_uri_str);
- }
-
- // Drop bundle from model
- lilv_world_unload_bundle(world, bundle);
-
- if (sord_num_quads(model) == 0) {
- // Manifest is empty, attempt to remove bundle entirely
- if (has_manifest) {
- try_unlink(state->dir, manifest_path);
- }
-
- // Remove all known files from state bundle
- if (state->abs2rel) {
- // State created from instance, get paths from map
- for (ZixTreeIter* i = zix_tree_begin(state->abs2rel);
- i != zix_tree_end(state->abs2rel);
- i = zix_tree_iter_next(i)) {
- const PathMap* pm = (const PathMap*)zix_tree_get(i);
- char* path = lilv_path_join(state->dir, pm->rel);
- try_unlink(state->dir, path);
- free(path);
- }
- } else {
- // State loaded from model, get paths from loaded properties
- for (uint32_t i = 0; i < state->props.n; ++i) {
- const Property* const p = &state->props.props[i];
- if (p->type == state->atom_Path) {
- try_unlink(state->dir, (const char*)p->value);
- }
- }
- }
-
- if (lilv_remove(state->dir)) {
- LILV_ERRORF("Failed to remove directory %s (%s)\n",
- state->dir, strerror(errno));
- }
- } else {
- // Still something in the manifest, update and reload bundle
- const SerdNode* manifest_node = sord_node_to_serd_node(manifest->node);
- SerdEnv* env = serd_env_new(manifest_node);
-
- write_manifest(world, env, model, manifest_node);
- lilv_world_load_bundle(world, bundle);
- serd_env_free(env);
- }
-
- sord_free(model);
- lilv_free(manifest_path);
- lilv_node_free(manifest);
- lilv_node_free(bundle);
-
- return 0;
+ if (!state->dir) {
+ LILV_ERROR("Attempt to delete unsaved state\n");
+ return -1;
+ }
+
+ LilvNode* bundle = lilv_new_file_uri(world, NULL, state->dir);
+ LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle);
+ char* manifest_path = get_canonical_path(manifest);
+ const bool has_manifest =
+ manifest_path && zix_file_type(manifest_path) == ZIX_FILE_TYPE_REGULAR;
+
+ SordModel* model = sord_new(world->world, SORD_SPO, false);
+
+ if (has_manifest) {
+ // Read manifest into temporary local model
+ SerdEnv* env = serd_env_new(sord_node_to_serd_node(manifest->node));
+ SerdReader* ttl = sord_new_reader(model, env, SERD_TURTLE, NULL);
+ serd_reader_read_file(ttl, USTR(manifest_path));
+ serd_reader_free(ttl);
+ serd_env_free(env);
+ }
+
+ if (state->uri) {
+ SordNode* file =
+ sord_get(model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL);
+ if (file) {
+ // Remove state file
+ const uint8_t* uri = sord_node_get_string(file);
+ char* path = (char*)serd_file_uri_parse(uri, NULL);
+ char* real_path = zix_canonical_path(NULL, path);
+ if (real_path) {
+ try_unlink(state->dir, real_path);
+ }
+ zix_free(NULL, real_path);
+ serd_free(path);
+ }
+
+ // Remove any existing manifest entries for this state
+ const char* state_uri_str = lilv_node_as_string(state->uri);
+ remove_manifest_entry(world->world, model, state_uri_str);
+ remove_manifest_entry(world->world, world->model, state_uri_str);
+ }
+
+ // Drop bundle from model
+ lilv_world_unload_bundle(world, bundle);
+
+ if (sord_num_quads(model) == 0) {
+ // Manifest is empty, attempt to remove bundle entirely
+ if (has_manifest) {
+ try_unlink(state->dir, manifest_path);
+ }
+
+ // Remove all known files from state bundle
+ if (state->abs2rel) {
+ // State created from instance, get paths from map
+ for (ZixTreeIter* i = zix_tree_begin(state->abs2rel);
+ i != zix_tree_end(state->abs2rel);
+ i = zix_tree_iter_next(i)) {
+ const PathMap* pm = (const PathMap*)zix_tree_get(i);
+ char* path = zix_path_join(NULL, state->dir, pm->rel);
+ try_unlink(state->dir, path);
+ zix_free(NULL, path);
+ }
+ } else {
+ // State loaded from model, get paths from loaded properties
+ for (uint32_t i = 0; i < state->props.n; ++i) {
+ const Property* const p = &state->props.props[i];
+ if (p->type == state->atom_Path) {
+ try_unlink(state->dir, (const char*)p->value);
+ }
+ }
+ }
+
+ if (zix_remove(state->dir)) {
+ LILV_ERRORF(
+ "Failed to remove directory %s (%s)\n", state->dir, strerror(errno));
+ }
+ } else {
+ // Still something in the manifest, update and reload bundle
+ const SerdNode* manifest_node = sord_node_to_serd_node(manifest->node);
+ SerdEnv* env = serd_env_new(manifest_node);
+
+ write_manifest(world, env, model, manifest_node);
+ lilv_world_load_bundle(world, bundle);
+ serd_env_free(env);
+ }
+
+ sord_free(model);
+ zix_free(NULL, manifest_path);
+ lilv_node_free(manifest);
+ lilv_node_free(bundle);
+
+ 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);
+ 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);
}
void
lilv_state_free(LilvState* state)
{
- if (state) {
- 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].atom);
- free(state->values[i].symbol);
- }
- lilv_node_free(state->plugin_uri);
- lilv_node_free(state->uri);
- zix_tree_free(state->abs2rel);
- zix_tree_free(state->rel2abs);
- free(state->values);
- free(state->label);
- free(state->dir);
- free(state->scratch_dir);
- free(state->copy_dir);
- free(state->link_dir);
- free(state);
- }
+ if (state) {
+ 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].atom);
+ free(state->values[i].symbol);
+ }
+ lilv_node_free(state->plugin_uri);
+ lilv_node_free(state->uri);
+ zix_tree_free(state->abs2rel);
+ zix_tree_free(state->rel2abs);
+ free(state->values);
+ free(state->label);
+ free(state->dir);
+ free(state->scratch_dir);
+ free(state->copy_dir);
+ free(state->link_dir);
+ free(state);
+ }
}
bool
lilv_state_equals(const LilvState* a, const LilvState* b)
{
- if (!lilv_node_equals(a->plugin_uri, b->plugin_uri)
- || (a->label && !b->label)
- || (b->label && !a->label)
- || (a->label && b->label && strcmp(a->label, b->label))
- || a->props.n != b->props.n
- || a->n_values != b->n_values) {
- return false;
- }
-
- for (uint32_t i = 0; i < a->n_values; ++i) {
- PortValue* const av = &a->values[i];
- PortValue* const bv = &b->values[i];
- if (av->atom->size != bv->atom->size ||
- av->atom->type != bv->atom->type ||
- strcmp(av->symbol, bv->symbol) ||
- memcmp(av->atom + 1, bv->atom + 1, av->atom->size)) {
- return false;
- }
- }
-
- for (uint32_t i = 0; i < a->props.n; ++i) {
- Property* const ap = &a->props.props[i];
- Property* const bp = &b->props.props[i];
- if (ap->key != bp->key
- || ap->type != bp->type
- || ap->flags != bp->flags) {
- return false;
- } else if (ap->type == a->atom_Path) {
- if (!lilv_file_equals(lilv_state_rel2abs(a, (char*)ap->value),
- lilv_state_rel2abs(b, (char*)bp->value))) {
- return false;
- }
- } else if (ap->size != bp->size
- || memcmp(ap->value, bp->value, ap->size)) {
- return false;
- }
- }
-
- return true;
+ if (!lilv_node_equals(a->plugin_uri, b->plugin_uri) ||
+ (a->label && !b->label) || (b->label && !a->label) ||
+ (a->label && b->label && !!strcmp(a->label, b->label)) ||
+ a->props.n != b->props.n || a->n_values != b->n_values) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < a->n_values; ++i) {
+ PortValue* const av = &a->values[i];
+ PortValue* const bv = &b->values[i];
+ if (av->atom->size != bv->atom->size || av->atom->type != bv->atom->type ||
+ !!strcmp(av->symbol, bv->symbol) ||
+ !!memcmp(av->atom + 1, bv->atom + 1, av->atom->size)) {
+ return false;
+ }
+ }
+
+ for (uint32_t i = 0; i < a->props.n; ++i) {
+ Property* const ap = &a->props.props[i];
+ Property* const bp = &b->props.props[i];
+ if (ap->key != bp->key || ap->type != bp->type || ap->flags != bp->flags) {
+ return false;
+ }
+
+ if (ap->type == a->atom_Path) {
+ if (!zix_file_equals(NULL,
+ lilv_state_rel2abs(a, (char*)ap->value),
+ lilv_state_rel2abs(b, (char*)bp->value))) {
+ return false;
+ }
+ } else if (ap->size != bp->size ||
+ !!memcmp(ap->value, bp->value, ap->size)) {
+ return false;
+ }
+ }
+
+ return true;
}
unsigned
lilv_state_get_num_properties(const LilvState* state)
{
- return state->props.n;
+ return state->props.n;
}
const LilvNode*
lilv_state_get_plugin_uri(const LilvState* state)
{
- return state->plugin_uri;
+ return state->plugin_uri;
}
const LilvNode*
lilv_state_get_uri(const LilvState* state)
{
- return state->uri;
+ return state->uri;
}
const char*
lilv_state_get_label(const LilvState* state)
{
- return state->label;
+ return state->label;
}
void
lilv_state_set_label(LilvState* state, const char* label)
{
- const size_t len = strlen(label);
- state->label = (char*)realloc(state->label, len + 1);
- memcpy(state->label, label, len + 1);
+ const size_t len = strlen(label);
+ state->label = (char*)realloc(state->label, len + 1);
+ memcpy(state->label, label, len + 1);
}
int
@@ -1484,6 +1588,6 @@ lilv_state_set_metadata(LilvState* state,
uint32_t type,
uint32_t flags)
{
- append_property(state, &state->metadata, key, value, size, type, flags);
- return LV2_STATE_SUCCESS;
+ append_property(state, &state->metadata, key, value, size, type, flags);
+ return LV2_STATE_SUCCESS;
}
diff --git a/src/ui.c b/src/ui.c
index cfe788e..2be49ec 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2019 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.
-*/
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_internal.h"
@@ -26,46 +13,46 @@
LilvUI*
lilv_ui_new(LilvWorld* world,
- LilvNode* uri,
- LilvNode* type_uri,
- LilvNode* binary_uri)
+ LilvNode* uri,
+ LilvNode* type_uri,
+ LilvNode* binary_uri)
{
- assert(uri);
- assert(type_uri);
- assert(binary_uri);
-
- LilvUI* ui = (LilvUI*)malloc(sizeof(LilvUI));
- ui->world = world;
- ui->uri = uri;
- ui->binary_uri = binary_uri;
-
- // FIXME: kludge
- char* bundle = lilv_strdup(lilv_node_as_string(ui->binary_uri));
- char* last_slash = strrchr(bundle, '/') + 1;
- *last_slash = '\0';
- ui->bundle_uri = lilv_new_uri(world, bundle);
- free(bundle);
-
- ui->classes = lilv_nodes_new();
- zix_tree_insert((ZixTree*)ui->classes, type_uri, NULL);
-
- return ui;
+ assert(uri);
+ assert(type_uri);
+ assert(binary_uri);
+
+ LilvUI* ui = (LilvUI*)malloc(sizeof(LilvUI));
+ ui->world = world;
+ ui->uri = uri;
+ ui->binary_uri = binary_uri;
+
+ // FIXME: kludge
+ char* bundle = lilv_strdup(lilv_node_as_string(ui->binary_uri));
+ char* last_slash = strrchr(bundle, '/') + 1;
+ *last_slash = '\0';
+ ui->bundle_uri = lilv_new_uri(world, bundle);
+ free(bundle);
+
+ ui->classes = lilv_nodes_new();
+ zix_tree_insert((ZixTree*)ui->classes, type_uri, NULL);
+
+ return ui;
}
void
lilv_ui_free(LilvUI* ui)
{
- lilv_node_free(ui->uri);
- lilv_node_free(ui->bundle_uri);
- lilv_node_free(ui->binary_uri);
- lilv_nodes_free(ui->classes);
- free(ui);
+ lilv_node_free(ui->uri);
+ lilv_node_free(ui->bundle_uri);
+ lilv_node_free(ui->binary_uri);
+ lilv_nodes_free(ui->classes);
+ free(ui);
}
const LilvNode*
lilv_ui_get_uri(const LilvUI* ui)
{
- return ui->uri;
+ return ui->uri;
}
unsigned
@@ -74,42 +61,42 @@ lilv_ui_is_supported(const LilvUI* ui,
const LilvNode* container_type,
const LilvNode** ui_type)
{
- const LilvNodes* classes = lilv_ui_get_classes(ui);
- LILV_FOREACH(nodes, c, classes) {
- const LilvNode* type = lilv_nodes_get(classes, c);
- const unsigned q = supported_func(lilv_node_as_uri(container_type),
- lilv_node_as_uri(type));
- if (q) {
- if (ui_type) {
- *ui_type = type;
- }
- return q;
- }
- }
-
- return 0;
+ const LilvNodes* classes = lilv_ui_get_classes(ui);
+ LILV_FOREACH (nodes, c, classes) {
+ const LilvNode* type = lilv_nodes_get(classes, c);
+ const unsigned q =
+ supported_func(lilv_node_as_uri(container_type), lilv_node_as_uri(type));
+ if (q) {
+ if (ui_type) {
+ *ui_type = type;
+ }
+ return q;
+ }
+ }
+
+ return 0;
}
const LilvNodes*
lilv_ui_get_classes(const LilvUI* ui)
{
- return ui->classes;
+ return ui->classes;
}
bool
lilv_ui_is_a(const LilvUI* ui, const LilvNode* class_uri)
{
- return lilv_nodes_contains(ui->classes, class_uri);
+ return lilv_nodes_contains(ui->classes, class_uri);
}
const LilvNode*
lilv_ui_get_bundle_uri(const LilvUI* ui)
{
- return ui->bundle_uri;
+ return ui->bundle_uri;
}
const LilvNode*
lilv_ui_get_binary_uri(const LilvUI* ui)
{
- return ui->binary_uri;
+ return ui->binary_uri;
}
diff --git a/src/util.c b/src/util.c
index 6d80975..c0047d9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,111 +1,100 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "filesystem.h"
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
+#include "zix/allocator.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
+#include "zix/string_view.h"
#include <sys/stat.h>
-#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h> // IWYU pragma: keep
void
lilv_free(void* ptr)
{
- free(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) {
- va_end(args);
- free(result);
- return NULL;
- }
-
- result = new_result;
- memcpy(result + len, s, this_len);
- len += this_len;
- }
- va_end(args);
-
- result[len] = '\0';
-
- return result;
+ size_t len = strlen(first);
+ char* result = (char*)malloc(len + 1);
+
+ memcpy(result, first, len);
+
+ va_list args; // NOLINT(cppcoreguidelines-init-variables)
+ 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) {
+ va_end(args);
+ 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;
+ 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)
{
-#ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#if defined(__GNUC__) && __GNUC__ > 4
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
- return (const char*)serd_uri_to_path((const uint8_t*)uri);
+ return (const char*)serd_uri_to_path((const uint8_t*)uri);
-#ifdef __GNUC__
-# pragma GCC diagnostic pop
+#if defined(__GNUC__) && __GNUC__ > 4
+# pragma GCC diagnostic pop
#endif
}
char*
lilv_file_uri_parse(const char* uri, char** hostname)
{
- return (char*)serd_file_uri_parse((const uint8_t*)uri, (uint8_t**)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.
@@ -114,35 +103,34 @@ lilv_file_uri_parse(const char* uri, char** hostname)
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;
+ 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') ||
+ (env_lang[i] >= '0' && env_lang[i] <= '9')) {
+ lang[i] = env_lang[i]; // Lowercase letter or 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;
}
#ifndef _WIN32
@@ -151,24 +139,24 @@ lilv_get_lang(void)
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;
+ 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));
- }
+ // Get value from environment
+ const char* val = getenv(var);
+ if (val) { // Value found, append it
+ return strappend(dst, dst_len, val, strlen(val));
+ }
+
+ // No value found, append variable reference as-is
+ return strappend(strappend(dst, dst_len, "$", 1), dst_len, var, strlen(var));
}
#endif
@@ -178,48 +166,48 @@ char*
lilv_expand(const char* path)
{
#ifdef _WIN32
- char* out = (char*)malloc(MAX_PATH);
- ExpandEnvironmentStrings(path, out, MAX_PATH);
+ 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));
- }
+ 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;
+ return out;
}
char*
@@ -227,66 +215,66 @@ lilv_find_free_path(const char* in_path,
bool (*exists)(const char*, const void*),
const 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 (unsigned i = 2; i < 1000000u; ++i) {
- if (!exists(path, user_data)) {
- return path;
- }
- snprintf(path, in_path_len + 7, "%s.%u", in_path, i);
- }
-
- return NULL;
+ 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 (unsigned i = 2U; i < 1000000U; ++i) {
+ if (!exists(path, user_data)) {
+ return path;
+ }
+ snprintf(path, in_path_len + 7, "%s.%u", in_path, i);
+ }
+
+ return NULL;
}
typedef struct {
- char* pattern;
- time_t time;
- char* latest;
+ 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 = 0;
- 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);
- }
+ Latest* latest = (Latest*)data;
+ char* entry_path = zix_path_join(NULL, path, name);
+ unsigned num = 0;
+ if (sscanf(entry_path, latest->pattern, &num) == 1) {
+ struct stat st;
+ if (!stat(entry_path, &st)) {
+ if (st.st_mtime >= latest->time) {
+ zix_free(NULL, latest->latest);
+ latest->latest = entry_path;
+ }
+ } else {
+ LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno));
+ }
+ }
+ if (entry_path != latest->latest) {
+ zix_free(NULL, 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_path_parent(copy_path);
- Latest latest = { lilv_strjoin(copy_path, ".%u", NULL), 0, NULL };
+ char* copy_dir = zix_string_view_copy(NULL, zix_path_parent_path(copy_path));
- struct stat st;
- if (!stat(path, &st)) {
- latest.time = st.st_mtime;
- } else {
- LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno));
- }
+ Latest latest = {lilv_strjoin(copy_path, ".%u", NULL), 0, NULL};
- lilv_dir_for_each(copy_dir, &latest, update_latest);
+ struct stat st;
+ if (!stat(path, &st)) {
+ latest.time = st.st_mtime;
+ } else {
+ LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno));
+ }
- free(latest.pattern);
- free(copy_dir);
- return latest.latest;
-}
+ zix_dir_for_each(copy_dir, &latest, update_latest);
+ free(latest.pattern);
+ zix_free(NULL, copy_dir);
+ return latest.latest;
+}
diff --git a/src/world.c b/src/world.c
index 7095a6e..b0ef24d 100644
--- a/src/world.c
+++ b/src/world.c
@@ -1,35 +1,20 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "filesystem.h"
-#include "lilv_config.h"
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lilv_config.h" // IWYU pragma: keep
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
#include "sord/sord.h"
-#include "zix/common.h"
+#include "zix/filesystem.h"
#include "zix/tree.h"
#include "lv2/core/lv2.h"
#include "lv2/presets/presets.h"
#ifdef LILV_DYN_MANIFEST
-# include "lv2/dynmanifest/dynmanifest.h"
-# include <dlfcn.h>
+# include "lv2/dynmanifest/dynmanifest.h"
#endif
#include <assert.h>
@@ -42,169 +27,178 @@
static int
lilv_world_drop_graph(LilvWorld* world, const SordNode* graph);
+static int
+lilv_lib_compare(const void* a, const void* b, const void* user_data);
+
+static void
+destroy_node(void* const ptr, const void* const user_data)
+{
+ (void)user_data;
+ lilv_node_free((LilvNode*)ptr);
+}
+
LilvWorld*
lilv_world_new(void)
{
- LilvWorld* world = (LilvWorld*)calloc(1, sizeof(LilvWorld));
+ LilvWorld* world = (LilvWorld*)calloc(1, sizeof(LilvWorld));
+
+ world->world = sord_world_new();
+ if (!world->world) {
+ goto fail;
+ }
- world->world = sord_world_new();
- if (!world->world) {
- goto fail;
- }
+ world->model = sord_new(world->world, SORD_SPO | SORD_OPS, true);
+ if (!world->model) {
+ goto fail;
+ }
- world->model = sord_new(world->world, SORD_SPO|SORD_OPS, true);
- if (!world->model) {
- goto fail;
- }
+ world->specs = NULL;
+ world->plugin_classes = lilv_plugin_classes_new();
+ world->plugins = lilv_plugins_new();
+ world->zombies = lilv_plugins_new();
- world->specs = NULL;
- world->plugin_classes = lilv_plugin_classes_new();
- world->plugins = lilv_plugins_new();
- world->zombies = lilv_plugins_new();
- world->loaded_files = zix_tree_new(
- false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free);
+ world->loaded_files =
+ zix_tree_new(NULL, false, lilv_resource_node_cmp, NULL, destroy_node, NULL);
- world->libs = zix_tree_new(false, lilv_lib_compare, NULL, NULL);
+ world->libs = zix_tree_new(NULL, false, lilv_lib_compare, NULL, NULL, NULL);
#define NS_DCTERMS "http://purl.org/dc/terms/"
-#define NS_DYNMAN "http://lv2plug.in/ns/ext/dynmanifest#"
-#define NS_OWL "http://www.w3.org/2002/07/owl#"
+#define NS_DYNMAN "http://lv2plug.in/ns/ext/dynmanifest#"
+#define NS_OWL "http://www.w3.org/2002/07/owl#"
#define NEW_URI(uri) sord_new_uri(world->world, (const uint8_t*)(uri))
- world->uris.dc_replaces = NEW_URI(NS_DCTERMS "replaces");
- world->uris.dman_DynManifest = NEW_URI(NS_DYNMAN "DynManifest");
- world->uris.doap_name = NEW_URI(LILV_NS_DOAP "name");
- world->uris.lv2_Plugin = NEW_URI(LV2_CORE__Plugin);
- world->uris.lv2_Specification = NEW_URI(LV2_CORE__Specification);
- world->uris.lv2_appliesTo = NEW_URI(LV2_CORE__appliesTo);
- world->uris.lv2_binary = NEW_URI(LV2_CORE__binary);
- world->uris.lv2_default = NEW_URI(LV2_CORE__default);
- world->uris.lv2_designation = NEW_URI(LV2_CORE__designation);
- world->uris.lv2_extensionData = NEW_URI(LV2_CORE__extensionData);
- world->uris.lv2_index = NEW_URI(LV2_CORE__index);
- world->uris.lv2_latency = NEW_URI(LV2_CORE__latency);
- world->uris.lv2_maximum = NEW_URI(LV2_CORE__maximum);
- world->uris.lv2_microVersion = NEW_URI(LV2_CORE__microVersion);
- world->uris.lv2_minimum = NEW_URI(LV2_CORE__minimum);
- world->uris.lv2_minorVersion = NEW_URI(LV2_CORE__minorVersion);
- world->uris.lv2_name = NEW_URI(LV2_CORE__name);
- world->uris.lv2_optionalFeature = NEW_URI(LV2_CORE__optionalFeature);
- world->uris.lv2_port = NEW_URI(LV2_CORE__port);
- world->uris.lv2_portProperty = NEW_URI(LV2_CORE__portProperty);
- world->uris.lv2_reportsLatency = NEW_URI(LV2_CORE__reportsLatency);
- world->uris.lv2_requiredFeature = NEW_URI(LV2_CORE__requiredFeature);
- world->uris.lv2_symbol = NEW_URI(LV2_CORE__symbol);
- world->uris.lv2_prototype = NEW_URI(LV2_CORE__prototype);
- world->uris.owl_Ontology = NEW_URI(NS_OWL "Ontology");
- world->uris.pset_value = NEW_URI(LV2_PRESETS__value);
- world->uris.rdf_a = NEW_URI(LILV_NS_RDF "type");
- world->uris.rdf_value = NEW_URI(LILV_NS_RDF "value");
- world->uris.rdfs_Class = NEW_URI(LILV_NS_RDFS "Class");
- world->uris.rdfs_label = NEW_URI(LILV_NS_RDFS "label");
- world->uris.rdfs_seeAlso = NEW_URI(LILV_NS_RDFS "seeAlso");
- world->uris.rdfs_subClassOf = NEW_URI(LILV_NS_RDFS "subClassOf");
- world->uris.xsd_base64Binary = NEW_URI(LILV_NS_XSD "base64Binary");
- world->uris.xsd_boolean = NEW_URI(LILV_NS_XSD "boolean");
- world->uris.xsd_decimal = NEW_URI(LILV_NS_XSD "decimal");
- world->uris.xsd_double = NEW_URI(LILV_NS_XSD "double");
- world->uris.xsd_integer = NEW_URI(LILV_NS_XSD "integer");
- world->uris.null_uri = NULL;
-
- world->lv2_plugin_class = lilv_plugin_class_new(
- world, NULL, world->uris.lv2_Plugin, "Plugin");
- assert(world->lv2_plugin_class);
-
- world->n_read_files = 0;
- world->opt.filter_language = true;
- world->opt.dyn_manifest = true;
-
- return world;
+ world->uris.dc_replaces = NEW_URI(NS_DCTERMS "replaces");
+ world->uris.dman_DynManifest = NEW_URI(NS_DYNMAN "DynManifest");
+ world->uris.doap_name = NEW_URI(LILV_NS_DOAP "name");
+ world->uris.lv2_Plugin = NEW_URI(LV2_CORE__Plugin);
+ world->uris.lv2_Specification = NEW_URI(LV2_CORE__Specification);
+ world->uris.lv2_appliesTo = NEW_URI(LV2_CORE__appliesTo);
+ world->uris.lv2_binary = NEW_URI(LV2_CORE__binary);
+ world->uris.lv2_default = NEW_URI(LV2_CORE__default);
+ world->uris.lv2_designation = NEW_URI(LV2_CORE__designation);
+ world->uris.lv2_extensionData = NEW_URI(LV2_CORE__extensionData);
+ world->uris.lv2_index = NEW_URI(LV2_CORE__index);
+ world->uris.lv2_latency = NEW_URI(LV2_CORE__latency);
+ world->uris.lv2_maximum = NEW_URI(LV2_CORE__maximum);
+ world->uris.lv2_microVersion = NEW_URI(LV2_CORE__microVersion);
+ world->uris.lv2_minimum = NEW_URI(LV2_CORE__minimum);
+ world->uris.lv2_minorVersion = NEW_URI(LV2_CORE__minorVersion);
+ world->uris.lv2_name = NEW_URI(LV2_CORE__name);
+ world->uris.lv2_optionalFeature = NEW_URI(LV2_CORE__optionalFeature);
+ world->uris.lv2_port = NEW_URI(LV2_CORE__port);
+ world->uris.lv2_portProperty = NEW_URI(LV2_CORE__portProperty);
+ world->uris.lv2_reportsLatency = NEW_URI(LV2_CORE__reportsLatency);
+ world->uris.lv2_requiredFeature = NEW_URI(LV2_CORE__requiredFeature);
+ world->uris.lv2_symbol = NEW_URI(LV2_CORE__symbol);
+ world->uris.lv2_prototype = NEW_URI(LV2_CORE__prototype);
+ world->uris.owl_Ontology = NEW_URI(NS_OWL "Ontology");
+ world->uris.pset_value = NEW_URI(LV2_PRESETS__value);
+ world->uris.rdf_a = NEW_URI(LILV_NS_RDF "type");
+ world->uris.rdf_value = NEW_URI(LILV_NS_RDF "value");
+ world->uris.rdfs_Class = NEW_URI(LILV_NS_RDFS "Class");
+ world->uris.rdfs_label = NEW_URI(LILV_NS_RDFS "label");
+ world->uris.rdfs_seeAlso = NEW_URI(LILV_NS_RDFS "seeAlso");
+ world->uris.rdfs_subClassOf = NEW_URI(LILV_NS_RDFS "subClassOf");
+ world->uris.xsd_base64Binary = NEW_URI(LILV_NS_XSD "base64Binary");
+ world->uris.xsd_boolean = NEW_URI(LILV_NS_XSD "boolean");
+ world->uris.xsd_decimal = NEW_URI(LILV_NS_XSD "decimal");
+ world->uris.xsd_double = NEW_URI(LILV_NS_XSD "double");
+ world->uris.xsd_integer = NEW_URI(LILV_NS_XSD "integer");
+ world->uris.null_uri = NULL;
+
+ world->lv2_plugin_class =
+ lilv_plugin_class_new(world, NULL, world->uris.lv2_Plugin, "Plugin");
+ assert(world->lv2_plugin_class);
+
+ world->n_read_files = 0;
+ world->opt.filter_language = true;
+ world->opt.dyn_manifest = true;
+
+ return world;
fail:
- /* keep on rockin' in the */ free(world);
- return NULL;
+ /* keep on rockin' in the */ free(world);
+ return NULL;
}
void
lilv_world_free(LilvWorld* world)
{
- if (!world) {
- return;
- }
-
- lilv_plugin_class_free(world->lv2_plugin_class);
- world->lv2_plugin_class = NULL;
-
- for (SordNode** n = (SordNode**)&world->uris; *n; ++n) {
- sord_node_free(world->world, *n);
- }
-
- for (LilvSpec* spec = world->specs; spec;) {
- LilvSpec* next = spec->next;
- sord_node_free(world->world, spec->spec);
- sord_node_free(world->world, spec->bundle);
- lilv_nodes_free(spec->data_uris);
- free(spec);
- spec = next;
- }
- world->specs = NULL;
-
- LILV_FOREACH(plugins, i, world->plugins) {
- const LilvPlugin* p = lilv_plugins_get(world->plugins, i);
- lilv_plugin_free((LilvPlugin*)p);
- }
- zix_tree_free((ZixTree*)world->plugins);
- world->plugins = NULL;
-
- LILV_FOREACH(plugins, i, world->zombies) {
- const LilvPlugin* p = lilv_plugins_get(world->zombies, i);
- lilv_plugin_free((LilvPlugin*)p);
- }
- zix_tree_free((ZixTree*)world->zombies);
- world->zombies = NULL;
-
- zix_tree_free((ZixTree*)world->loaded_files);
- world->loaded_files = NULL;
-
- zix_tree_free(world->libs);
- world->libs = NULL;
-
- zix_tree_free((ZixTree*)world->plugin_classes);
- world->plugin_classes = NULL;
-
- sord_free(world->model);
- world->model = NULL;
-
- sord_world_free(world->world);
- world->world = NULL;
-
- free(world->opt.lv2_path);
- free(world);
+ if (!world) {
+ return;
+ }
+
+ lilv_plugin_class_free(world->lv2_plugin_class);
+ world->lv2_plugin_class = NULL;
+
+ for (SordNode** n = (SordNode**)&world->uris; *n; ++n) {
+ sord_node_free(world->world, *n);
+ }
+
+ for (LilvSpec* spec = world->specs; spec;) {
+ LilvSpec* next = spec->next;
+ sord_node_free(world->world, spec->spec);
+ sord_node_free(world->world, spec->bundle);
+ lilv_nodes_free(spec->data_uris);
+ free(spec);
+ spec = next;
+ }
+ world->specs = NULL;
+
+ LILV_FOREACH (plugins, i, world->plugins) {
+ const LilvPlugin* p = lilv_plugins_get(world->plugins, i);
+ lilv_plugin_free((LilvPlugin*)p);
+ }
+ zix_tree_free((ZixTree*)world->plugins);
+ world->plugins = NULL;
+
+ LILV_FOREACH (plugins, i, world->zombies) {
+ const LilvPlugin* p = lilv_plugins_get(world->zombies, i);
+ lilv_plugin_free((LilvPlugin*)p);
+ }
+ zix_tree_free((ZixTree*)world->zombies);
+ world->zombies = NULL;
+
+ zix_tree_free((ZixTree*)world->loaded_files);
+ world->loaded_files = NULL;
+
+ zix_tree_free(world->libs);
+ world->libs = NULL;
+
+ zix_tree_free((ZixTree*)world->plugin_classes);
+ world->plugin_classes = NULL;
+
+ sord_free(world->model);
+ world->model = NULL;
+
+ sord_world_free(world->world);
+ world->world = NULL;
+
+ free(world->opt.lv2_path);
+ free(world);
}
void
-lilv_world_set_option(LilvWorld* world,
- const char* uri,
- const LilvNode* value)
+lilv_world_set_option(LilvWorld* world, const char* uri, const LilvNode* value)
{
- if (!strcmp(uri, LILV_OPTION_DYN_MANIFEST)) {
- if (lilv_node_is_bool(value)) {
- world->opt.dyn_manifest = lilv_node_as_bool(value);
- return;
- }
- } else if (!strcmp(uri, LILV_OPTION_FILTER_LANG)) {
- if (lilv_node_is_bool(value)) {
- world->opt.filter_language = lilv_node_as_bool(value);
- return;
- }
- } else if (!strcmp(uri, LILV_OPTION_LV2_PATH)) {
- if (lilv_node_is_string(value)) {
- world->opt.lv2_path = lilv_strdup(lilv_node_as_string(value));
- return;
- }
- }
- LILV_WARNF("Unrecognized or invalid option `%s'\n", uri);
+ if (!strcmp(uri, LILV_OPTION_DYN_MANIFEST)) {
+ if (lilv_node_is_bool(value)) {
+ world->opt.dyn_manifest = lilv_node_as_bool(value);
+ return;
+ }
+ } else if (!strcmp(uri, LILV_OPTION_FILTER_LANG)) {
+ if (lilv_node_is_bool(value)) {
+ world->opt.filter_language = lilv_node_as_bool(value);
+ return;
+ }
+ } else if (!strcmp(uri, LILV_OPTION_LV2_PATH)) {
+ if (lilv_node_is_string(value)) {
+ world->opt.lv2_path = lilv_strdup(lilv_node_as_string(value));
+ return;
+ }
+ }
+ LILV_WARNF("Unrecognized or invalid option `%s'\n", uri);
}
LilvNodes*
@@ -213,26 +207,32 @@ lilv_world_find_nodes(LilvWorld* world,
const LilvNode* predicate,
const LilvNode* object)
{
- if (subject && !lilv_node_is_uri(subject) && !lilv_node_is_blank(subject)) {
- LILV_ERRORF("Subject `%s' is not a resource\n",
- sord_node_get_string(subject->node));
- return NULL;
- } else if (!predicate) {
- LILV_ERROR("Missing required predicate\n");
- return NULL;
- } else if (!lilv_node_is_uri(predicate)) {
- LILV_ERRORF("Predicate `%s' is not a URI\n",
- sord_node_get_string(predicate->node));
- return NULL;
- } else if (!subject && !object) {
- LILV_ERROR("Both subject and object are NULL\n");
- return NULL;
- }
-
- return lilv_world_find_nodes_internal(world,
- subject ? subject->node : NULL,
- predicate->node,
- object ? object->node : NULL);
+ if (subject && !lilv_node_is_uri(subject) && !lilv_node_is_blank(subject)) {
+ LILV_ERRORF("Subject `%s' is not a resource\n",
+ sord_node_get_string(subject->node));
+ return NULL;
+ }
+
+ if (!predicate) {
+ LILV_ERROR("Missing required predicate\n");
+ return NULL;
+ }
+
+ if (!lilv_node_is_uri(predicate)) {
+ LILV_ERRORF("Predicate `%s' is not a URI\n",
+ sord_node_get_string(predicate->node));
+ return NULL;
+ }
+
+ if (!subject && !object) {
+ LILV_ERROR("Both subject and object are NULL\n");
+ return NULL;
+ }
+
+ return lilv_world_find_nodes_internal(world,
+ subject ? subject->node : NULL,
+ predicate->node,
+ object ? object->node : NULL);
}
LilvNode*
@@ -241,34 +241,34 @@ lilv_world_get(LilvWorld* world,
const LilvNode* predicate,
const LilvNode* object)
{
- if (!object) {
- // TODO: Improve performance (see lilv_plugin_get_one)
- SordIter* stream = sord_search(world->model,
- subject ? subject->node : NULL,
- predicate ? predicate->node : NULL,
- NULL,
- NULL);
-
- LilvNodes* nodes =
- lilv_nodes_from_stream_objects(world, stream, SORD_OBJECT);
-
- if (nodes) {
- LilvNode* value = lilv_node_duplicate(lilv_nodes_get_first(nodes));
- lilv_nodes_free(nodes);
- return value;
- }
-
- return NULL;
- }
-
- SordNode* snode = sord_get(world->model,
- subject ? subject->node : NULL,
- predicate ? predicate->node : NULL,
- object ? object->node : NULL,
- NULL);
- LilvNode* lnode = lilv_node_new_from_node(world, snode);
- sord_node_free(world->world, snode);
- return lnode;
+ if (!object) {
+ // TODO: Improve performance (see lilv_plugin_get_one)
+ SordIter* stream = sord_search(world->model,
+ subject ? subject->node : NULL,
+ predicate ? predicate->node : NULL,
+ NULL,
+ NULL);
+
+ LilvNodes* nodes =
+ lilv_nodes_from_stream_objects(world, stream, SORD_OBJECT);
+
+ if (nodes) {
+ LilvNode* value = lilv_node_duplicate(lilv_nodes_get_first(nodes));
+ lilv_nodes_free(nodes);
+ return value;
+ }
+
+ return NULL;
+ }
+
+ SordNode* snode = sord_get(world->model,
+ subject ? subject->node : NULL,
+ predicate ? predicate->node : NULL,
+ object ? object->node : NULL,
+ NULL);
+ LilvNode* lnode = lilv_node_new_from_node(world, snode);
+ sord_node_free(world->world, snode);
+ return lnode;
}
SordIter*
@@ -277,7 +277,7 @@ lilv_world_query_internal(LilvWorld* world,
const SordNode* predicate,
const SordNode* object)
{
- return sord_search(world->model, subject, predicate, object, NULL);
+ return sord_search(world->model, subject, predicate, object, NULL);
}
bool
@@ -286,7 +286,7 @@ lilv_world_ask_internal(LilvWorld* world,
const SordNode* predicate,
const SordNode* object)
{
- return sord_ask(world->model, subject, predicate, object, NULL);
+ return sord_ask(world->model, subject, predicate, object, NULL);
}
bool
@@ -295,11 +295,11 @@ lilv_world_ask(LilvWorld* world,
const LilvNode* predicate,
const LilvNode* object)
{
- return sord_ask(world->model,
- subject ? subject->node : NULL,
- predicate ? predicate->node : NULL,
- object ? object->node : NULL,
- NULL);
+ return sord_ask(world->model,
+ subject ? subject->node : NULL,
+ predicate ? predicate->node : NULL,
+ object ? object->node : NULL,
+ NULL);
}
SordModel*
@@ -310,15 +310,15 @@ lilv_world_filter_model(LilvWorld* world,
const SordNode* object,
const SordNode* graph)
{
- SordModel* results = sord_new(world->world, SORD_SPO, false);
- SordIter* i = sord_search(model, subject, predicate, object, graph);
- for (; !sord_iter_end(i); sord_iter_next(i)) {
- SordQuad quad;
- sord_iter_get(i, quad);
- sord_add(results, quad);
- }
- sord_iter_free(i);
- return results;
+ SordModel* results = sord_new(world->world, SORD_SPO, false);
+ SordIter* i = sord_search(model, subject, predicate, object, graph);
+ for (; !sord_iter_end(i); sord_iter_next(i)) {
+ SordQuad quad;
+ sord_iter_get(i, quad);
+ sord_add(results, quad);
+ }
+ sord_iter_free(i);
+ return results;
}
LilvNodes*
@@ -327,37 +327,31 @@ lilv_world_find_nodes_internal(LilvWorld* world,
const SordNode* predicate,
const SordNode* object)
{
- return lilv_nodes_from_stream_objects(
- world,
- lilv_world_query_internal(world, subject, predicate, object),
- (object == NULL) ? SORD_OBJECT : SORD_SUBJECT);
-}
-
-static SerdNode
-lilv_new_uri_relative_to_base(const uint8_t* uri_str,
- const uint8_t* base_uri_str)
-{
- SerdURI base_uri;
- serd_uri_parse(base_uri_str, &base_uri);
- return serd_node_new_uri_from_string(uri_str, &base_uri, NULL);
+ return lilv_nodes_from_stream_objects(
+ world,
+ lilv_world_query_internal(world, subject, predicate, object),
+ (object == NULL) ? SORD_OBJECT : SORD_SUBJECT);
}
const uint8_t*
lilv_world_blank_node_prefix(LilvWorld* world)
{
- static char str[32];
- snprintf(str, sizeof(str), "%u", world->n_read_files++);
- return (const uint8_t*)str;
+ static char str[32];
+ snprintf(str, sizeof(str), "%u", world->n_read_files++);
+ return (const uint8_t*)str;
}
/** Comparator for sequences (e.g. world->plugins). */
int
-lilv_header_compare_by_uri(const void* a, const void* b, void* user_data)
+lilv_header_compare_by_uri(const void* a, const void* b, const void* user_data)
{
- const struct LilvHeader* const header_a = (const struct LilvHeader*)a;
- const struct LilvHeader* const header_b = (const struct LilvHeader*)b;
- return strcmp(lilv_node_as_uri(header_a->uri),
- lilv_node_as_uri(header_b->uri));
+ (void)user_data;
+
+ const struct LilvHeader* const header_a = (const struct LilvHeader*)a;
+ const struct LilvHeader* const header_b = (const struct LilvHeader*)b;
+
+ return strcmp(lilv_node_as_uri(header_a->uri),
+ lilv_node_as_uri(header_b->uri));
}
/**
@@ -367,35 +361,39 @@ lilv_header_compare_by_uri(const void* a, const void* b, void* user_data)
handle the case where the same library is loaded with different bundles, and
consequently different contents (mainly plugins).
*/
-int
-lilv_lib_compare(const void* a, const void* b, void* user_data)
+static int
+lilv_lib_compare(const void* a, const void* b, const void* user_data)
{
- const LilvLib* const lib_a = (const LilvLib*)a;
- const LilvLib* const lib_b = (const LilvLib*)b;
- int cmp = strcmp(lilv_node_as_uri(lib_a->uri),
- lilv_node_as_uri(lib_b->uri));
- return cmp ? cmp : strcmp(lib_a->bundle_path, lib_b->bundle_path);
+ (void)user_data;
+
+ const LilvLib* const lib_a = (const LilvLib*)a;
+ const LilvLib* const lib_b = (const LilvLib*)b;
+
+ const int cmp =
+ strcmp(lilv_node_as_uri(lib_a->uri), lilv_node_as_uri(lib_b->uri));
+
+ return cmp ? cmp : strcmp(lib_a->bundle_path, lib_b->bundle_path);
}
/** Get an element of a collection of any object with an LilvHeader by URI. */
static ZixTreeIter*
lilv_collection_find_by_uri(const ZixTree* seq, const LilvNode* uri)
{
- ZixTreeIter* i = NULL;
- if (lilv_node_is_uri(uri)) {
- struct LilvHeader key = { NULL, (LilvNode*)uri };
- zix_tree_find(seq, &key, &i);
- }
- return i;
+ ZixTreeIter* i = NULL;
+ if (lilv_node_is_uri(uri)) {
+ struct LilvHeader key = {NULL, (LilvNode*)uri};
+ zix_tree_find(seq, &key, &i);
+ }
+ return 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);
+ ZixTreeIter* const i = lilv_collection_find_by_uri(seq, uri);
- return i ? (struct LilvHeader*)zix_tree_get(i) : NULL;
+ return i ? (struct LilvHeader*)zix_tree_get(i) : NULL;
}
static void
@@ -403,28 +401,25 @@ lilv_world_add_spec(LilvWorld* world,
const SordNode* specification_node,
const SordNode* bundle_node)
{
- LilvSpec* spec = (LilvSpec*)malloc(sizeof(LilvSpec));
- spec->spec = sord_node_copy(specification_node);
- spec->bundle = sord_node_copy(bundle_node);
- spec->data_uris = lilv_nodes_new();
-
- // Add all data files (rdfs:seeAlso)
- SordIter* files = sord_search(world->model,
- specification_node,
- world->uris.rdfs_seeAlso,
- NULL,
- NULL);
- FOREACH_MATCH(files) {
- const SordNode* file_node = sord_iter_get_node(files, SORD_OBJECT);
- zix_tree_insert((ZixTree*)spec->data_uris,
- lilv_node_new_from_node(world, file_node),
- NULL);
- }
- sord_iter_free(files);
-
- // Add specification to world specification list
- spec->next = world->specs;
- world->specs = spec;
+ LilvSpec* spec = (LilvSpec*)malloc(sizeof(LilvSpec));
+ spec->spec = sord_node_copy(specification_node);
+ spec->bundle = sord_node_copy(bundle_node);
+ spec->data_uris = lilv_nodes_new();
+
+ // Add all data files (rdfs:seeAlso)
+ SordIter* files = sord_search(
+ world->model, specification_node, world->uris.rdfs_seeAlso, NULL, NULL);
+ FOREACH_MATCH (files) {
+ const SordNode* file_node = sord_iter_get_node(files, SORD_OBJECT);
+ zix_tree_insert((ZixTree*)spec->data_uris,
+ lilv_node_new_from_node(world, file_node),
+ NULL);
+ }
+ sord_iter_free(files);
+
+ // Add specification to world specification list
+ spec->next = world->specs;
+ world->specs = spec;
}
static void
@@ -434,86 +429,82 @@ lilv_world_add_plugin(LilvWorld* world,
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_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));
-
- // 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);
- }
-
+ (void)dynmanifest;
+
+ 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_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));
+
+ // 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);
+ }
#ifdef LILV_DYN_MANIFEST
- // Set dynamic manifest library URI, if applicable
- if (dynmanifest) {
- plugin->dynmanifest = (LilvDynManifest*)dynmanifest;
- ++((LilvDynManifest*)dynmanifest)->refs;
- }
+ // Set dynamic manifest library URI, if applicable
+ if (dynmanifest) {
+ plugin->dynmanifest = (LilvDynManifest*)dynmanifest;
+ ++((LilvDynManifest*)dynmanifest)->refs;
+ }
#endif
- // Add all plugin data files (rdfs:seeAlso)
- SordIter* files = sord_search(world->model,
- plugin_node,
- world->uris.rdfs_seeAlso,
- NULL,
- NULL);
- FOREACH_MATCH(files) {
- const SordNode* file_node = sord_iter_get_node(files, SORD_OBJECT);
- zix_tree_insert((ZixTree*)plugin->data_uris,
- lilv_node_new_from_node(world, file_node),
- NULL);
- }
- sord_iter_free(files);
+ // Add all plugin data files (rdfs:seeAlso)
+ SordIter* files = sord_search(
+ world->model, plugin_node, world->uris.rdfs_seeAlso, NULL, NULL);
+ FOREACH_MATCH (files) {
+ const SordNode* file_node = sord_iter_get_node(files, SORD_OBJECT);
+ zix_tree_insert((ZixTree*)plugin->data_uris,
+ lilv_node_new_from_node(world, file_node),
+ NULL);
+ }
+ sord_iter_free(files);
}
-SerdStatus
+static SerdStatus
lilv_world_load_graph(LilvWorld* world, SordNode* graph, const LilvNode* uri)
{
- const SerdNode* base = sord_node_to_serd_node(uri->node);
- SerdEnv* env = serd_env_new(base);
- SerdReader* reader = sord_new_reader(
- world->model, env, SERD_TURTLE, graph);
+ const SerdNode* base = sord_node_to_serd_node(uri->node);
+ SerdEnv* env = serd_env_new(base);
+ SerdReader* reader = sord_new_reader(world->model, env, SERD_TURTLE, graph);
- const SerdStatus st = lilv_world_load_file(world, reader, uri);
+ const SerdStatus st = lilv_world_load_file(world, reader, uri);
- serd_env_free(env);
- serd_reader_free(reader);
- return st;
+ serd_env_free(env);
+ serd_reader_free(reader);
+ return st;
}
static void
@@ -522,161 +513,173 @@ lilv_world_load_dyn_manifest(LilvWorld* world,
const LilvNode* manifest)
{
#ifdef LILV_DYN_MANIFEST
- if (!world->opt.dyn_manifest) {
- return;
- }
-
- LV2_Dyn_Manifest_Handle handle = NULL;
-
- // ?dman a dynman:DynManifest bundle_node
- SordModel* model = lilv_world_filter_model(world,
- world->model,
- NULL,
- world->uris.rdf_a,
- world->uris.dman_DynManifest,
- bundle_node);
- SordIter* iter = sord_begin(model);
- for (; !sord_iter_end(iter); sord_iter_next(iter)) {
- const SordNode* dmanifest = sord_iter_get_node(iter, SORD_SUBJECT);
-
- // ?dman lv2:binary ?binary
- SordIter* binaries = sord_search(world->model,
- dmanifest,
- world->uris.lv2_binary,
- NULL,
- bundle_node);
- if (sord_iter_end(binaries)) {
- sord_iter_free(binaries);
- LILV_ERRORF("Dynamic manifest in <%s> has no binaries, ignored\n",
- sord_node_get_string(bundle_node));
- continue;
- }
-
- // Get binary path
- const SordNode* binary = sord_iter_get_node(binaries, SORD_OBJECT);
- const uint8_t* lib_uri = sord_node_get_string(binary);
- char* lib_path = lilv_file_uri_parse((const char*)lib_uri, 0);
- if (!lib_path) {
- LILV_ERROR("No dynamic manifest library path\n");
- sord_iter_free(binaries);
- continue;
- }
-
- // Open library
- dlerror();
- void* lib = dlopen(lib_path, RTLD_LAZY);
- if (!lib) {
- LILV_ERRORF("Failed to open dynmanifest library `%s' (%s)\n",
- lib_path, dlerror());
- sord_iter_free(binaries);
- lilv_free(lib_path);
- continue;
- }
-
- // Open dynamic manifest
- typedef int (*OpenFunc)(LV2_Dyn_Manifest_Handle*,
- const LV2_Feature *const *);
- OpenFunc dmopen = (OpenFunc)lilv_dlfunc(lib, "lv2_dyn_manifest_open");
- if (!dmopen || dmopen(&handle, &dman_features)) {
- LILV_ERRORF("No `lv2_dyn_manifest_open' in `%s'\n", lib_path);
- sord_iter_free(binaries);
- dlclose(lib);
- lilv_free(lib_path);
- continue;
- }
-
- // Get subjects (the data that would be in manifest.ttl)
- typedef int (*GetSubjectsFunc)(LV2_Dyn_Manifest_Handle, FILE*);
- GetSubjectsFunc get_subjects_func = (GetSubjectsFunc)lilv_dlfunc(
- lib, "lv2_dyn_manifest_get_subjects");
- if (!get_subjects_func) {
- LILV_ERRORF("No `lv2_dyn_manifest_get_subjects' in `%s'\n",
- lib_path);
- sord_iter_free(binaries);
- dlclose(lib);
- lilv_free(lib_path);
- continue;
- }
-
- LilvDynManifest* desc = (LilvDynManifest*)malloc(sizeof(LilvDynManifest));
- desc->bundle = lilv_node_new_from_node(world, bundle_node);
- desc->lib = lib;
- desc->handle = handle;
- desc->refs = 0;
-
- sord_iter_free(binaries);
-
- // Generate data file
- FILE* fd = tmpfile();
- get_subjects_func(handle, fd);
- rewind(fd);
-
- // Parse generated data file into temporary model
- // FIXME
- const SerdNode* base = sord_node_to_serd_node(dmanifest);
- SerdEnv* env = serd_env_new(base);
- SerdReader* reader = sord_new_reader(
- world->model, env, SERD_TURTLE, sord_node_copy(dmanifest));
- serd_reader_add_blank_prefix(reader,
- lilv_world_blank_node_prefix(world));
- serd_reader_read_file_handle(reader, fd,
- (const uint8_t*)"(dyn-manifest)");
- serd_reader_free(reader);
- serd_env_free(env);
-
- // Close (and automatically delete) temporary data file
- fclose(fd);
-
- // ?plugin a lv2:Plugin
- SordModel* plugins = lilv_world_filter_model(world,
- world->model,
- NULL,
- world->uris.rdf_a,
- world->uris.lv2_Plugin,
- dmanifest);
- SordIter* p = sord_begin(plugins);
- FOREACH_MATCH(p) {
- const SordNode* plug = sord_iter_get_node(p, SORD_SUBJECT);
- lilv_world_add_plugin(world, plug, manifest, desc, bundle_node);
- }
- if (desc->refs == 0) {
- lilv_dynmanifest_free(desc);
- }
- sord_iter_free(p);
- sord_free(plugins);
- lilv_free(lib_path);
- }
- sord_iter_free(iter);
- sord_free(model);
-#endif // LILV_DYN_MANIFEST
+ if (!world->opt.dyn_manifest) {
+ return;
+ }
+
+ LV2_Dyn_Manifest_Handle handle = NULL;
+
+ // ?dman a dynman:DynManifest bundle_node
+ SordModel* model = lilv_world_filter_model(world,
+ world->model,
+ NULL,
+ world->uris.rdf_a,
+ world->uris.dman_DynManifest,
+ bundle_node);
+ SordIter* iter = sord_begin(model);
+ for (; !sord_iter_end(iter); sord_iter_next(iter)) {
+ const SordNode* dmanifest = sord_iter_get_node(iter, SORD_SUBJECT);
+
+ // ?dman lv2:binary ?binary
+ SordIter* binaries = sord_search(
+ world->model, dmanifest, world->uris.lv2_binary, NULL, bundle_node);
+ if (sord_iter_end(binaries)) {
+ sord_iter_free(binaries);
+ LILV_ERRORF("Dynamic manifest in <%s> has no binaries, ignored\n",
+ sord_node_get_string(bundle_node));
+ continue;
+ }
+
+ // Get binary path
+ const SordNode* binary = sord_iter_get_node(binaries, SORD_OBJECT);
+ const uint8_t* lib_uri = sord_node_get_string(binary);
+ char* lib_path = lilv_file_uri_parse((const char*)lib_uri, 0);
+ if (!lib_path) {
+ LILV_ERROR("No dynamic manifest library path\n");
+ sord_iter_free(binaries);
+ continue;
+ }
+
+ // Open library
+ dlerror();
+ void* lib = dlopen(lib_path, RTLD_LAZY);
+ if (!lib) {
+ LILV_ERRORF(
+ "Failed to open dynmanifest library `%s' (%s)\n", lib_path, dlerror());
+ sord_iter_free(binaries);
+ lilv_free(lib_path);
+ continue;
+ }
+
+ // Open dynamic manifest
+ typedef int (*OpenFunc)(LV2_Dyn_Manifest_Handle*,
+ const LV2_Feature* const*);
+ OpenFunc dmopen = (OpenFunc)lilv_dlfunc(lib, "lv2_dyn_manifest_open");
+ if (!dmopen || dmopen(&handle, &dman_features)) {
+ LILV_ERRORF("No `lv2_dyn_manifest_open' in `%s'\n", lib_path);
+ sord_iter_free(binaries);
+ dlclose(lib);
+ lilv_free(lib_path);
+ continue;
+ }
+
+ // Get subjects (the data that would be in manifest.ttl)
+ typedef int (*GetSubjectsFunc)(LV2_Dyn_Manifest_Handle, FILE*);
+ GetSubjectsFunc get_subjects_func =
+ (GetSubjectsFunc)lilv_dlfunc(lib, "lv2_dyn_manifest_get_subjects");
+ if (!get_subjects_func) {
+ LILV_ERRORF("No `lv2_dyn_manifest_get_subjects' in `%s'\n", lib_path);
+ sord_iter_free(binaries);
+ dlclose(lib);
+ lilv_free(lib_path);
+ continue;
+ }
+
+ LilvDynManifest* desc = (LilvDynManifest*)malloc(sizeof(LilvDynManifest));
+ desc->bundle = lilv_node_new_from_node(world, bundle_node);
+ desc->lib = lib;
+ desc->handle = handle;
+ desc->refs = 0;
+
+ sord_iter_free(binaries);
+
+ // Generate data file
+ FILE* fd = tmpfile();
+ get_subjects_func(handle, fd);
+ rewind(fd);
+
+ // Parse generated data file into temporary model
+ // FIXME
+ const SerdNode* base = sord_node_to_serd_node(dmanifest);
+ SerdEnv* env = serd_env_new(base);
+ SerdReader* reader = sord_new_reader(
+ world->model, env, SERD_TURTLE, sord_node_copy(dmanifest));
+ serd_reader_add_blank_prefix(reader, lilv_world_blank_node_prefix(world));
+ serd_reader_read_file_handle(reader, fd, (const uint8_t*)"(dyn-manifest)");
+ serd_reader_free(reader);
+ serd_env_free(env);
+
+ // Close (and automatically delete) temporary data file
+ fclose(fd);
+
+ // ?plugin a lv2:Plugin
+ SordModel* plugins = lilv_world_filter_model(world,
+ world->model,
+ NULL,
+ world->uris.rdf_a,
+ world->uris.lv2_Plugin,
+ dmanifest);
+ SordIter* p = sord_begin(plugins);
+ FOREACH_MATCH (p) {
+ const SordNode* plug = sord_iter_get_node(p, SORD_SUBJECT);
+ lilv_world_add_plugin(world, plug, manifest, desc, bundle_node);
+ }
+ if (desc->refs == 0) {
+ lilv_dynmanifest_free(desc);
+ }
+ sord_iter_free(p);
+ sord_free(plugins);
+ lilv_free(lib_path);
+ }
+ sord_iter_free(iter);
+ sord_free(model);
+
+#else // LILV_DYN_MANIFEST
+ (void)world;
+ (void)bundle_node;
+ (void)manifest;
+#endif
}
#ifdef LILV_DYN_MANIFEST
void
lilv_dynmanifest_free(LilvDynManifest* dynmanifest)
{
- typedef int (*CloseFunc)(LV2_Dyn_Manifest_Handle);
- CloseFunc close_func = (CloseFunc)lilv_dlfunc(dynmanifest->lib,
- "lv2_dyn_manifest_close");
- if (close_func) {
- close_func(dynmanifest->handle);
- }
-
- dlclose(dynmanifest->lib);
- lilv_node_free(dynmanifest->bundle);
- free(dynmanifest);
+ typedef int (*CloseFunc)(LV2_Dyn_Manifest_Handle);
+ CloseFunc close_func =
+ (CloseFunc)lilv_dlfunc(dynmanifest->lib, "lv2_dyn_manifest_close");
+ if (close_func) {
+ close_func(dynmanifest->handle);
+ }
+
+ dlclose(dynmanifest->lib);
+ lilv_node_free(dynmanifest->bundle);
+ free(dynmanifest);
}
-#endif // LILV_DYN_MANIFEST
+#endif // LILV_DYN_MANIFEST
LilvNode*
lilv_world_get_manifest_uri(LilvWorld* world, const LilvNode* bundle_uri)
{
- SerdNode manifest_uri = lilv_new_uri_relative_to_base(
- (const uint8_t*)"manifest.ttl",
- sord_node_get_string(bundle_uri->node));
- LilvNode* manifest = lilv_new_uri(world, (const char*)manifest_uri.buf);
- serd_node_free(&manifest_uri);
- return manifest;
+ // Get the string and length of the given bundle URI
+ size_t bundle_uri_length = 0U;
+ const char* const bundle_uri_string =
+ (const char*)sord_node_get_string_counted(bundle_uri->node,
+ &bundle_uri_length);
+ if (!bundle_uri_length) {
+ return NULL;
+ }
+
+ // Build the manifest URI by inserting a separating "/" if necessary
+ const char last = bundle_uri_string[bundle_uri_length - 1U];
+ char* const manifest_uri_string =
+ (last == '/') ? lilv_strjoin(bundle_uri_string, "manifest.ttl", NULL)
+ : lilv_strjoin(bundle_uri_string, "/", "manifest.ttl", NULL);
+
+ // Make a node from the manifeset URI to return
+ LilvNode* const manifest = lilv_new_uri(world, manifest_uri_string);
+ free(manifest_uri_string);
+ return manifest;
}
static SordModel*
@@ -684,308 +687,301 @@ 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;
+ // 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;
+ 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;
}
void
lilv_world_load_bundle(LilvWorld* world, const LilvNode* bundle_uri)
{
- if (!lilv_node_is_uri(bundle_uri)) {
- LILV_ERRORF("Bundle URI `%s' is not a URI\n",
- sord_node_get_string(bundle_uri->node));
- return;
- }
-
- SordNode* bundle_node = bundle_uri->node;
- LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri);
-
- // Read manifest into model with graph = bundle_node
- SerdStatus st = lilv_world_load_graph(world, bundle_node, manifest);
- if (st > SERD_FAILURE) {
- LILV_ERRORF("Error reading %s\n", lilv_node_as_string(manifest));
- lilv_node_free(manifest);
- return;
- }
-
- // ?plugin a lv2:Plugin
- SordIter* plug_results = sord_search(world->model,
- NULL,
- world->uris.rdf_a,
- world->uris.lv2_Plugin,
- bundle_node);
-
- // Find any loaded plugins that will be replaced with a newer version
- LilvNodes* unload_uris = lilv_nodes_new();
- FOREACH_MATCH(plug_results) {
- const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT);
-
- LilvNode* plugin_uri = lilv_node_new_from_node(world, plug);
- const LilvPlugin* plugin = lilv_plugins_get_by_uri(world->plugins, plugin_uri);
- const LilvNode* last_bundle = plugin ? lilv_plugin_get_bundle_uri(plugin) : NULL;
- if (!plugin || sord_node_equals(bundle_node, last_bundle->node)) {
- // No previously loaded version, or it's from the same bundle
- lilv_node_free(plugin_uri);
- continue;
- }
-
- // Compare versions
- SordModel* this_model = load_plugin_model(world, bundle_uri, plugin_uri);
- LilvVersion this_version = get_version(world, this_model, plugin_uri);
- SordModel* last_model = load_plugin_model(world, last_bundle, plugin_uri);
- LilvVersion last_version = get_version(world, last_model, plugin_uri);
- sord_free(this_model);
- sord_free(last_model);
- const int cmp = lilv_version_cmp(&this_version, &last_version);
- if (cmp > 0) {
- zix_tree_insert((ZixTree*)unload_uris,
- lilv_node_duplicate(plugin_uri),
- NULL);
- LILV_WARNF("Replacing version %d.%d of <%s> from <%s>\n",
- last_version.minor, last_version.micro,
- sord_node_get_string(plug),
- sord_node_get_string(last_bundle->node));
- LILV_NOTEF("New version %d.%d found in <%s>\n",
- this_version.minor, this_version.micro,
- sord_node_get_string(bundle_node));
- } else if (cmp < 0) {
- LILV_WARNF("Ignoring bundle <%s>\n",
- sord_node_get_string(bundle_node));
- LILV_NOTEF("Newer version of <%s> loaded from <%s>\n",
- sord_node_get_string(plug),
- sord_node_get_string(last_bundle->node));
- lilv_node_free(plugin_uri);
- sord_iter_free(plug_results);
- lilv_world_drop_graph(world, bundle_node);
- lilv_node_free(manifest);
- lilv_nodes_free(unload_uris);
- return;
- }
- lilv_node_free(plugin_uri);
- }
-
- sord_iter_free(plug_results);
-
- // Unload any old conflicting plugins
- LilvNodes* unload_bundles = lilv_nodes_new();
- LILV_FOREACH(nodes, i, unload_uris) {
- const LilvNode* uri = lilv_nodes_get(unload_uris, i);
- const LilvPlugin* plugin = lilv_plugins_get_by_uri(world->plugins, uri);
- const LilvNode* bundle = lilv_plugin_get_bundle_uri(plugin);
-
- // Unload plugin and record bundle for later unloading
- lilv_world_unload_resource(world, uri);
- zix_tree_insert((ZixTree*)unload_bundles,
- lilv_node_duplicate(bundle),
- NULL);
-
- }
- lilv_nodes_free(unload_uris);
-
- // Now unload the associated bundles
- // This must be done last since several plugins could be in the same bundle
- LILV_FOREACH(nodes, i, unload_bundles) {
- lilv_world_unload_bundle(world, lilv_nodes_get(unload_bundles, i));
- }
- lilv_nodes_free(unload_bundles);
-
- // Re-search for plugin results now that old plugins are gone
- plug_results = sord_search(world->model,
- NULL,
- world->uris.rdf_a,
- world->uris.lv2_Plugin,
- bundle_node);
-
- FOREACH_MATCH(plug_results) {
- const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT);
- lilv_world_add_plugin(world, plug, manifest, NULL, bundle_node);
- }
- sord_iter_free(plug_results);
-
- lilv_world_load_dyn_manifest(world, bundle_node, manifest);
-
- // ?spec a lv2:Specification
- // ?spec a owl:Ontology
- const SordNode* spec_preds[] = { world->uris.lv2_Specification,
- world->uris.owl_Ontology,
- NULL };
- for (const SordNode** p = spec_preds; *p; ++p) {
- SordIter* i = sord_search(
- world->model, NULL, world->uris.rdf_a, *p, bundle_node);
- FOREACH_MATCH(i) {
- const SordNode* spec = sord_iter_get_node(i, SORD_SUBJECT);
- lilv_world_add_spec(world, spec, bundle_node);
- }
- sord_iter_free(i);
- }
-
- lilv_node_free(manifest);
+ if (!lilv_node_is_uri(bundle_uri)) {
+ LILV_ERRORF("Bundle URI `%s' is not a URI\n",
+ sord_node_get_string(bundle_uri->node));
+ return;
+ }
+
+ SordNode* bundle_node = bundle_uri->node;
+ LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri);
+ if (!manifest) {
+ return;
+ }
+
+ // Read manifest into model with graph = bundle_node
+ SerdStatus st = lilv_world_load_graph(world, bundle_node, manifest);
+ if (st > SERD_FAILURE) {
+ LILV_ERRORF("Error reading %s\n", lilv_node_as_string(manifest));
+ lilv_node_free(manifest);
+ return;
+ }
+
+ // ?plugin a lv2:Plugin
+ SordIter* plug_results = sord_search(
+ world->model, NULL, world->uris.rdf_a, world->uris.lv2_Plugin, bundle_node);
+
+ // Find any loaded plugins that will be replaced with a newer version
+ LilvNodes* unload_uris = lilv_nodes_new();
+ FOREACH_MATCH (plug_results) {
+ const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT);
+
+ LilvNode* plugin_uri = lilv_node_new_from_node(world, plug);
+ const LilvPlugin* plugin =
+ lilv_plugins_get_by_uri(world->plugins, plugin_uri);
+ const LilvNode* last_bundle =
+ plugin ? lilv_plugin_get_bundle_uri(plugin) : NULL;
+ if (!plugin || sord_node_equals(bundle_node, last_bundle->node)) {
+ // No previously loaded version, or it's from the same bundle
+ lilv_node_free(plugin_uri);
+ continue;
+ }
+
+ // Compare versions
+ SordModel* this_model = load_plugin_model(world, bundle_uri, plugin_uri);
+ LilvVersion this_version = get_version(world, this_model, plugin_uri);
+ SordModel* last_model = load_plugin_model(world, last_bundle, plugin_uri);
+ LilvVersion last_version = get_version(world, last_model, plugin_uri);
+ sord_free(this_model);
+ sord_free(last_model);
+ const int cmp = lilv_version_cmp(&this_version, &last_version);
+ if (cmp > 0) {
+ zix_tree_insert(
+ (ZixTree*)unload_uris, lilv_node_duplicate(plugin_uri), NULL);
+ LILV_WARNF("Replacing version %d.%d of <%s> from <%s>\n",
+ last_version.minor,
+ last_version.micro,
+ sord_node_get_string(plug),
+ sord_node_get_string(last_bundle->node));
+ LILV_NOTEF("New version %d.%d found in <%s>\n",
+ this_version.minor,
+ this_version.micro,
+ sord_node_get_string(bundle_node));
+ } else if (cmp < 0) {
+ LILV_WARNF("Ignoring bundle <%s>\n", sord_node_get_string(bundle_node));
+ LILV_NOTEF("Newer version of <%s> loaded from <%s>\n",
+ sord_node_get_string(plug),
+ sord_node_get_string(last_bundle->node));
+ lilv_node_free(plugin_uri);
+ sord_iter_free(plug_results);
+ lilv_world_drop_graph(world, bundle_node);
+ lilv_node_free(manifest);
+ lilv_nodes_free(unload_uris);
+ return;
+ }
+ lilv_node_free(plugin_uri);
+ }
+
+ sord_iter_free(plug_results);
+
+ // Unload any old conflicting plugins
+ LilvNodes* unload_bundles = lilv_nodes_new();
+ LILV_FOREACH (nodes, i, unload_uris) {
+ const LilvNode* uri = lilv_nodes_get(unload_uris, i);
+ const LilvPlugin* plugin = lilv_plugins_get_by_uri(world->plugins, uri);
+ const LilvNode* bundle = lilv_plugin_get_bundle_uri(plugin);
+
+ // Unload plugin and record bundle for later unloading
+ lilv_world_unload_resource(world, uri);
+ zix_tree_insert(
+ (ZixTree*)unload_bundles, lilv_node_duplicate(bundle), NULL);
+ }
+ lilv_nodes_free(unload_uris);
+
+ // Now unload the associated bundles
+ // This must be done last since several plugins could be in the same bundle
+ LILV_FOREACH (nodes, i, unload_bundles) {
+ lilv_world_unload_bundle(world, lilv_nodes_get(unload_bundles, i));
+ }
+ lilv_nodes_free(unload_bundles);
+
+ // Re-search for plugin results now that old plugins are gone
+ plug_results = sord_search(
+ world->model, NULL, world->uris.rdf_a, world->uris.lv2_Plugin, bundle_node);
+
+ FOREACH_MATCH (plug_results) {
+ const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT);
+ lilv_world_add_plugin(world, plug, manifest, NULL, bundle_node);
+ }
+ sord_iter_free(plug_results);
+
+ lilv_world_load_dyn_manifest(world, bundle_node, manifest);
+
+ // ?spec a lv2:Specification
+ // ?spec a owl:Ontology
+ const SordNode* spec_preds[] = {
+ world->uris.lv2_Specification, world->uris.owl_Ontology, NULL};
+ for (const SordNode** p = spec_preds; *p; ++p) {
+ SordIter* i =
+ sord_search(world->model, NULL, world->uris.rdf_a, *p, bundle_node);
+ FOREACH_MATCH (i) {
+ const SordNode* spec = sord_iter_get_node(i, SORD_SUBJECT);
+ lilv_world_add_spec(world, spec, bundle_node);
+ }
+ sord_iter_free(i);
+ }
+
+ lilv_node_free(manifest);
}
static int
lilv_world_drop_graph(LilvWorld* world, const SordNode* graph)
{
- SordIter* i = sord_search(world->model, NULL, NULL, NULL, graph);
- while (!sord_iter_end(i)) {
- const SerdStatus st = sord_erase(world->model, i);
- if (st) {
- LILV_ERRORF("Error removing statement from <%s> (%s)\n",
- sord_node_get_string(graph), serd_strerror(st));
- return st;
- }
- }
- sord_iter_free(i);
-
- return 0;
+ SordIter* i = sord_search(world->model, NULL, NULL, NULL, graph);
+ while (!sord_iter_end(i)) {
+ const SerdStatus st = sord_erase(world->model, i);
+ if (st) {
+ LILV_ERRORF("Error removing statement from <%s> (%s)\n",
+ sord_node_get_string(graph),
+ serd_strerror(st));
+ return st;
+ }
+ }
+ sord_iter_free(i);
+
+ return 0;
}
/** Remove loaded_files entry so file will be reloaded if requested. */
static int
lilv_world_unload_file(LilvWorld* world, const LilvNode* file)
{
- ZixTreeIter* iter = NULL;
- if (!zix_tree_find((ZixTree*)world->loaded_files, file, &iter)) {
- zix_tree_remove((ZixTree*)world->loaded_files, iter);
- return 0;
- }
- return 1;
+ ZixTreeIter* iter = NULL;
+ if (!zix_tree_find((ZixTree*)world->loaded_files, file, &iter)) {
+ zix_tree_remove((ZixTree*)world->loaded_files, iter);
+ return 0;
+ }
+ return 1;
}
int
lilv_world_unload_bundle(LilvWorld* world, const LilvNode* bundle_uri)
{
- if (!bundle_uri) {
- return 0;
- }
-
- // Find all loaded files that are inside the bundle
- LilvNodes* files = lilv_nodes_new();
- LILV_FOREACH(nodes, i, world->loaded_files) {
- const LilvNode* file = lilv_nodes_get(world->loaded_files, i);
- if (!strncmp(lilv_node_as_string(file),
- lilv_node_as_string(bundle_uri),
- strlen(lilv_node_as_string(bundle_uri)))) {
- zix_tree_insert((ZixTree*)files,
- lilv_node_duplicate(file),
- NULL);
- }
- }
-
- // Unload all loaded files in the bundle
- LILV_FOREACH(nodes, i, files) {
- const LilvNode* file = lilv_nodes_get(world->plugins, i);
- lilv_world_unload_file(world, file);
- }
-
- lilv_nodes_free(files);
-
- /* Remove any plugins in the bundle from the plugin list. Since the
- application may still have a pointer to the LilvPlugin, it can not be
- destroyed here. Instead, we move it to the zombie plugin list, so it
- will not be in the list returned by lilv_world_get_all_plugins() but can
- still be used.
- */
- ZixTreeIter* i = zix_tree_begin((ZixTree*)world->plugins);
- while (i != zix_tree_end((ZixTree*)world->plugins)) {
- LilvPlugin* p = (LilvPlugin*)zix_tree_get(i);
- ZixTreeIter* next = zix_tree_iter_next(i);
-
- if (lilv_node_equals(lilv_plugin_get_bundle_uri(p), bundle_uri)) {
- zix_tree_remove((ZixTree*)world->plugins, i);
- zix_tree_insert((ZixTree*)world->zombies, p, NULL);
- }
-
- i = next;
- }
-
- // Drop everything in bundle graph
- return lilv_world_drop_graph(world, bundle_uri->node);
+ if (!bundle_uri) {
+ return 0;
+ }
+
+ // 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 && i != zix_tree_end((ZixTree*)world->plugins)) {
+ LilvPlugin* p = (LilvPlugin*)zix_tree_get(i);
+ ZixTreeIter* next = zix_tree_iter_next(i);
+
+ if (lilv_node_equals(lilv_plugin_get_bundle_uri(p), bundle_uri)) {
+ zix_tree_remove((ZixTree*)world->plugins, i);
+ zix_tree_insert((ZixTree*)world->zombies, p, NULL);
+ }
+
+ i = next;
+ }
+
+ // Drop everything in bundle graph
+ return lilv_world_drop_graph(world, bundle_uri->node);
}
static void
load_dir_entry(const char* dir, const char* name, void* data)
{
- LilvWorld* world = (LilvWorld*)data;
- char* path = lilv_strjoin(dir, "/", name, "/", NULL);
- SerdNode suri = serd_node_new_file_uri((const uint8_t*)path, 0, 0, true);
- LilvNode* node = lilv_new_uri(world, (const char*)suri.buf);
-
- lilv_world_load_bundle(world, node);
- lilv_node_free(node);
- serd_node_free(&suri);
- free(path);
+ LilvWorld* world = (LilvWorld*)data;
+ char* path = lilv_strjoin(dir, "/", name, "/", NULL);
+ SerdNode suri = serd_node_new_file_uri((const uint8_t*)path, 0, 0, true);
+ LilvNode* node = lilv_new_uri(world, (const char*)suri.buf);
+
+ lilv_world_load_bundle(world, node);
+ lilv_node_free(node);
+ serd_node_free(&suri);
+ free(path);
}
/** Load all bundles in the directory at `dir_path`. */
static void
lilv_world_load_directory(LilvWorld* world, const char* dir_path)
{
- char* path = lilv_expand(dir_path);
- if (path) {
- lilv_dir_for_each(path, world, load_dir_entry);
- free(path);
- }
+ char* path = lilv_expand(dir_path);
+ if (path) {
+ zix_dir_for_each(path, world, load_dir_entry);
+ free(path);
+ }
}
static const char*
first_path_sep(const char* path)
{
- for (const char* p = path; *p != '\0'; ++p) {
- if (*p == LILV_PATH_SEP[0]) {
- return p;
- }
- }
- return NULL;
+ for (const char* p = path; *p != '\0'; ++p) {
+ if (*p == LILV_PATH_SEP[0]) {
+ return p;
+ }
+ }
+ return NULL;
}
/** Load all bundles found in `lv2_path`.
@@ -994,277 +990,265 @@ first_path_sep(const char* path)
* parent directories of bundles, not a list of bundle directories).
*/
static void
-lilv_world_load_path(LilvWorld* world,
- const char* lv2_path)
+lilv_world_load_path(LilvWorld* world, const char* lv2_path)
{
- while (lv2_path[0] != '\0') {
- const char* const sep = first_path_sep(lv2_path);
- if (sep) {
- const size_t dir_len = sep - lv2_path;
- char* const dir = (char*)malloc(dir_len + 1);
- memcpy(dir, lv2_path, dir_len);
- dir[dir_len] = '\0';
- lilv_world_load_directory(world, dir);
- free(dir);
- lv2_path += dir_len + 1;
- } else {
- lilv_world_load_directory(world, lv2_path);
- lv2_path = "\0";
- }
- }
+ while (lv2_path[0] != '\0') {
+ const char* const sep = first_path_sep(lv2_path);
+ if (sep) {
+ const size_t dir_len = sep - lv2_path;
+ char* const dir = (char*)malloc(dir_len + 1);
+ memcpy(dir, lv2_path, dir_len);
+ dir[dir_len] = '\0';
+ lilv_world_load_directory(world, dir);
+ free(dir);
+ lv2_path += dir_len + 1;
+ } else {
+ lilv_world_load_directory(world, lv2_path);
+ lv2_path = "\0";
+ }
+ }
}
void
lilv_world_load_specifications(LilvWorld* world)
{
- for (LilvSpec* spec = world->specs; spec; spec = spec->next) {
- LILV_FOREACH(nodes, f, spec->data_uris) {
- LilvNode* file = (LilvNode*)lilv_collection_get(spec->data_uris, f);
- lilv_world_load_graph(world, NULL, file);
- }
- }
+ for (LilvSpec* spec = world->specs; spec; spec = spec->next) {
+ LILV_FOREACH (nodes, f, spec->data_uris) {
+ LilvNode* file = (LilvNode*)lilv_collection_get(spec->data_uris, f);
+ lilv_world_load_graph(world, NULL, file);
+ }
+ }
}
void
lilv_world_load_plugin_classes(LilvWorld* world)
{
- /* FIXME: This loads all classes, not just lv2:Plugin subclasses.
- However, if the host gets all the classes via lilv_plugin_class_get_children
- starting with lv2:Plugin as the root (which is e.g. how a host would build
- a menu), they won't be seen anyway...
- */
-
- SordIter* classes = sord_search(world->model,
- NULL,
- world->uris.rdf_a,
- world->uris.rdfs_Class,
- NULL);
- FOREACH_MATCH(classes) {
- const SordNode* class_node = sord_iter_get_node(classes, SORD_SUBJECT);
-
- SordNode* parent = sord_get(
- world->model, class_node, world->uris.rdfs_subClassOf, NULL, NULL);
- if (!parent || sord_node_get_type(parent) != SORD_URI) {
- continue;
- }
-
- SordNode* label = sord_get(
- world->model, class_node, world->uris.rdfs_label, NULL, NULL);
- if (!label) {
- sord_node_free(world->world, parent);
- continue;
- }
-
- LilvPluginClass* pclass = lilv_plugin_class_new(
- world, parent, class_node,
- (const char*)sord_node_get_string(label));
- if (pclass) {
- zix_tree_insert((ZixTree*)world->plugin_classes, pclass, NULL);
- }
-
- sord_node_free(world->world, label);
- sord_node_free(world->world, parent);
- }
- sord_iter_free(classes);
+ /* FIXME: This loads all classes, not just lv2:Plugin subclasses.
+ However, if the host gets all the classes via
+ lilv_plugin_class_get_children starting with lv2:Plugin as the root (which
+ is e.g. how a host would build a menu), they won't be seen anyway...
+ */
+
+ SordIter* classes = sord_search(
+ world->model, NULL, world->uris.rdf_a, world->uris.rdfs_Class, NULL);
+ FOREACH_MATCH (classes) {
+ const SordNode* class_node = sord_iter_get_node(classes, SORD_SUBJECT);
+
+ SordNode* parent = sord_get(
+ world->model, class_node, world->uris.rdfs_subClassOf, NULL, NULL);
+ if (!parent || sord_node_get_type(parent) != SORD_URI) {
+ continue;
+ }
+
+ SordNode* label =
+ sord_get(world->model, class_node, world->uris.rdfs_label, NULL, NULL);
+ if (!label) {
+ sord_node_free(world->world, parent);
+ continue;
+ }
+
+ LilvPluginClass* pclass = lilv_plugin_class_new(
+ world, parent, class_node, (const char*)sord_node_get_string(label));
+ if (pclass) {
+ zix_tree_insert((ZixTree*)world->plugin_classes, pclass, NULL);
+ }
+
+ sord_node_free(world->world, label);
+ sord_node_free(world->world, parent);
+ }
+ sord_iter_free(classes);
}
void
lilv_world_load_all(LilvWorld* world)
{
- const char* lv2_path = world->opt.lv2_path;
- if (!lv2_path) {
- lv2_path = getenv("LV2_PATH");
- }
- if (!lv2_path) {
- lv2_path = LILV_DEFAULT_LV2_PATH;
- }
-
- // Discover bundles and read all manifest files into model
- lilv_world_load_path(world, lv2_path);
-
- LILV_FOREACH(plugins, p, world->plugins) {
- const LilvPlugin* plugin = (const LilvPlugin*)lilv_collection_get(
- (ZixTree*)world->plugins, p);
-
- // ?new dc:replaces plugin
- if (sord_ask(world->model,
- NULL,
- world->uris.dc_replaces,
- lilv_plugin_get_uri(plugin)->node,
- NULL)) {
- // TODO: Check if replacement is a known plugin? (expensive)
- ((LilvPlugin*)plugin)->replaced = true;
- }
- }
-
- // Query out things to cache
- lilv_world_load_specifications(world);
- lilv_world_load_plugin_classes(world);
+ const char* lv2_path = world->opt.lv2_path;
+ if (!lv2_path) {
+ lv2_path = getenv("LV2_PATH");
+ }
+ if (!lv2_path) {
+ lv2_path = LILV_DEFAULT_LV2_PATH;
+ }
+
+ // Discover bundles and read all manifest files into model
+ lilv_world_load_path(world, lv2_path);
+
+ LILV_FOREACH (plugins, p, world->plugins) {
+ const LilvPlugin* plugin =
+ (const LilvPlugin*)lilv_collection_get((ZixTree*)world->plugins, p);
+
+ // ?new dc:replaces plugin
+ if (sord_ask(world->model,
+ NULL,
+ world->uris.dc_replaces,
+ lilv_plugin_get_uri(plugin)->node,
+ NULL)) {
+ // TODO: Check if replacement is a known plugin? (expensive)
+ ((LilvPlugin*)plugin)->replaced = true;
+ }
+ }
+
+ // Query out things to cache
+ lilv_world_load_specifications(world);
+ lilv_world_load_plugin_classes(world);
}
SerdStatus
lilv_world_load_file(LilvWorld* world, SerdReader* reader, const LilvNode* uri)
{
- ZixTreeIter* iter = NULL;
- if (!zix_tree_find((ZixTree*)world->loaded_files, uri, &iter)) {
- return SERD_FAILURE; // File has already been loaded
- }
-
- size_t uri_len = 0;
- const uint8_t* const uri_str = sord_node_get_string_counted(
- uri->node, &uri_len);
- if (strncmp((const char*)uri_str, "file:", 5)) {
- return SERD_FAILURE; // Not a local file
- } else if (strcmp((const char*)uri_str + uri_len - 4, ".ttl")) {
- return SERD_FAILURE; // Not a Turtle file
- }
-
- serd_reader_add_blank_prefix(reader, lilv_world_blank_node_prefix(world));
- const SerdStatus st = serd_reader_read_file(reader, uri_str);
- if (st) {
- LILV_ERRORF("Error loading file `%s'\n", lilv_node_as_string(uri));
- return st;
- }
-
- zix_tree_insert((ZixTree*)world->loaded_files,
- lilv_node_duplicate(uri),
- NULL);
- return SERD_SUCCESS;
+ ZixTreeIter* iter = NULL;
+ if (!zix_tree_find((ZixTree*)world->loaded_files, uri, &iter)) {
+ return SERD_FAILURE; // File has already been loaded
+ }
+
+ size_t uri_len = 0;
+ const uint8_t* const uri_str =
+ sord_node_get_string_counted(uri->node, &uri_len);
+ if (!!strncmp((const char*)uri_str, "file:", 5)) {
+ return SERD_FAILURE; // Not a local file
+ }
+
+ if (!!strcmp((const char*)uri_str + uri_len - 4, ".ttl")) {
+ return SERD_FAILURE; // Not a Turtle file
+ }
+
+ serd_reader_add_blank_prefix(reader, lilv_world_blank_node_prefix(world));
+ const SerdStatus st = serd_reader_read_file(reader, uri_str);
+ if (st) {
+ LILV_ERRORF("Error loading file `%s'\n", lilv_node_as_string(uri));
+ return st;
+ }
+
+ zix_tree_insert(
+ (ZixTree*)world->loaded_files, lilv_node_duplicate(uri), NULL);
+ return SERD_SUCCESS;
}
int
-lilv_world_load_resource(LilvWorld* world,
- const LilvNode* resource)
+lilv_world_load_resource(LilvWorld* world, const LilvNode* resource)
{
- if (!lilv_node_is_uri(resource) && !lilv_node_is_blank(resource)) {
- LILV_ERRORF("Node `%s' is not a resource\n",
- sord_node_get_string(resource->node));
- return -1;
- }
-
- SordModel* files = lilv_world_filter_model(world,
- world->model,
- resource->node,
- world->uris.rdfs_seeAlso,
- NULL, NULL);
-
- SordIter* f = sord_begin(files);
- int n_read = 0;
- FOREACH_MATCH(f) {
- const SordNode* file = sord_iter_get_node(f, SORD_OBJECT);
- const uint8_t* file_str = sord_node_get_string(file);
- LilvNode* file_node = lilv_node_new_from_node(world, file);
- if (sord_node_get_type(file) != SORD_URI) {
- LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", file_str);
- } else if (!lilv_world_load_graph(world, (SordNode*)file, file_node)) {
- ++n_read;
- }
- lilv_node_free(file_node);
- }
- sord_iter_free(f);
-
- sord_free(files);
- return n_read;
+ if (!lilv_node_is_uri(resource) && !lilv_node_is_blank(resource)) {
+ LILV_ERRORF("Node `%s' is not a resource\n",
+ sord_node_get_string(resource->node));
+ return -1;
+ }
+
+ SordModel* files = lilv_world_filter_model(
+ world, world->model, resource->node, world->uris.rdfs_seeAlso, NULL, NULL);
+
+ SordIter* f = sord_begin(files);
+ int n_read = 0;
+ FOREACH_MATCH (f) {
+ const SordNode* file = sord_iter_get_node(f, SORD_OBJECT);
+ const uint8_t* file_str = sord_node_get_string(file);
+ LilvNode* file_node = lilv_node_new_from_node(world, file);
+ if (sord_node_get_type(file) != SORD_URI) {
+ LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n", file_str);
+ } else if (!lilv_world_load_graph(world, (SordNode*)file, file_node)) {
+ ++n_read;
+ }
+ lilv_node_free(file_node);
+ }
+ sord_iter_free(f);
+
+ sord_free(files);
+ return n_read;
}
int
-lilv_world_unload_resource(LilvWorld* world,
- const LilvNode* resource)
+lilv_world_unload_resource(LilvWorld* world, const LilvNode* resource)
{
- if (!lilv_node_is_uri(resource) && !lilv_node_is_blank(resource)) {
- LILV_ERRORF("Node `%s' is not a resource\n",
- sord_node_get_string(resource->node));
- return -1;
- }
-
- SordModel* files = lilv_world_filter_model(world,
- world->model,
- resource->node,
- world->uris.rdfs_seeAlso,
- NULL, NULL);
-
- SordIter* f = sord_begin(files);
- int n_dropped = 0;
- FOREACH_MATCH(f) {
- const SordNode* file = sord_iter_get_node(f, SORD_OBJECT);
- LilvNode* file_node = lilv_node_new_from_node(world, file);
- if (sord_node_get_type(file) != SORD_URI) {
- LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n",
- sord_node_get_string(file));
- } else if (!lilv_world_drop_graph(world, file_node->node)) {
- lilv_world_unload_file(world, file_node);
- ++n_dropped;
- }
- lilv_node_free(file_node);
- }
- sord_iter_free(f);
-
- sord_free(files);
- return n_dropped;
+ if (!lilv_node_is_uri(resource) && !lilv_node_is_blank(resource)) {
+ LILV_ERRORF("Node `%s' is not a resource\n",
+ sord_node_get_string(resource->node));
+ return -1;
+ }
+
+ SordModel* files = lilv_world_filter_model(
+ world, world->model, resource->node, world->uris.rdfs_seeAlso, NULL, NULL);
+
+ SordIter* f = sord_begin(files);
+ int n_dropped = 0;
+ FOREACH_MATCH (f) {
+ const SordNode* file = sord_iter_get_node(f, SORD_OBJECT);
+ LilvNode* file_node = lilv_node_new_from_node(world, file);
+ if (sord_node_get_type(file) != SORD_URI) {
+ LILV_ERRORF("rdfs:seeAlso node `%s' is not a URI\n",
+ sord_node_get_string(file));
+ } else if (!lilv_world_drop_graph(world, file_node->node)) {
+ lilv_world_unload_file(world, file_node);
+ ++n_dropped;
+ }
+ lilv_node_free(file_node);
+ }
+ sord_iter_free(f);
+
+ sord_free(files);
+ return n_dropped;
}
const LilvPluginClass*
lilv_world_get_plugin_class(const LilvWorld* world)
{
- return world->lv2_plugin_class;
+ return world->lv2_plugin_class;
}
const LilvPluginClasses*
lilv_world_get_plugin_classes(const LilvWorld* world)
{
- return world->plugin_classes;
+ return world->plugin_classes;
}
const LilvPlugins*
lilv_world_get_all_plugins(const LilvWorld* world)
{
- return world->plugins;
+ return world->plugins;
}
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;
+ // 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;
}
diff --git a/src/zix/common.h b/src/zix/common.h
deleted file mode 100644
index 32019e9..0000000
--- a/src/zix/common.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- Copyright 2016 David Robillard <http://drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- 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.
-*/
-
-#ifndef ZIX_COMMON_H
-#define ZIX_COMMON_H
-
-/**
- @addtogroup zix
- @{
-*/
-
-/** @cond */
-#ifdef ZIX_SHARED
-# ifdef _WIN32
-# define ZIX_LIB_IMPORT __declspec(dllimport)
-# define ZIX_LIB_EXPORT __declspec(dllexport)
-# else
-# define ZIX_LIB_IMPORT __attribute__((visibility("default")))
-# define ZIX_LIB_EXPORT __attribute__((visibility("default")))
-# endif
-# ifdef ZIX_INTERNAL
-# define ZIX_API ZIX_LIB_EXPORT
-# else
-# define ZIX_API ZIX_LIB_IMPORT
-# endif
-# define ZIX_PRIVATE static
-#elif defined(ZIX_INLINE)
-# define ZIX_API static inline
-# define ZIX_PRIVATE static inline
-#else
-# define ZIX_API
-# define ZIX_PRIVATE static
-#endif
-/** @endcond */
-
-#ifdef __cplusplus
-extern "C" {
-#else
-# include <stdbool.h>
-#endif
-
-typedef enum {
- ZIX_STATUS_SUCCESS,
- ZIX_STATUS_ERROR,
- ZIX_STATUS_NO_MEM,
- ZIX_STATUS_NOT_FOUND,
- ZIX_STATUS_EXISTS,
- ZIX_STATUS_BAD_ARG,
- ZIX_STATUS_BAD_PERMS
-} ZixStatus;
-
-/**
- Function for comparing two elements.
-*/
-typedef int (*ZixComparator)(const void* a, const void* b, void* user_data);
-
-/**
- Function for testing equality of two elements.
-*/
-typedef bool (*ZixEqualFunc)(const void* a, const void* b);
-
-/**
- Function to destroy an element.
-*/
-typedef void (*ZixDestroyFunc)(void* ptr);
-
-/**
- @}
-*/
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ZIX_COMMON_H */
diff --git a/src/zix/tree.c b/src/zix/tree.c
deleted file mode 100644
index 55d39dc..0000000
--- a/src/zix/tree.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- Copyright 2011-2019 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.
-*/
-
-#include "zix/common.h"
-#include "zix/tree.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-typedef struct ZixTreeNodeImpl ZixTreeNode;
-
-struct ZixTreeImpl {
- ZixTreeNode* root;
- ZixDestroyFunc destroy;
- ZixComparator cmp;
- void* cmp_data;
- size_t size;
- bool allow_duplicates;
-};
-
-struct ZixTreeNodeImpl {
- void* data;
- struct ZixTreeNodeImpl* left;
- struct ZixTreeNodeImpl* right;
- struct ZixTreeNodeImpl* parent;
- int_fast8_t balance;
-};
-
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-
-// Uncomment these for debugging features
-// #define ZIX_TREE_DUMP 1
-// #define ZIX_TREE_VERIFY 1
-// #define ZIX_TREE_HYPER_VERIFY 1
-
-#if defined(ZIX_TREE_VERIFY) || defined(ZIX_TREE_HYPER_VERIFY)
-# include "tree_debug.h"
-# define ASSERT_BALANCE(n) assert(verify_balance(n))
-#else
-# define ASSERT_BALANCE(n)
-#endif
-
-#ifdef ZIX_TREE_DUMP
-# include "tree_debug.h"
-# define DUMP(t) zix_tree_print(t->root, 0)
-# define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
-#else
-# define DUMP(t)
-# define DEBUG_PRINTF(fmt, ...)
-#endif
-
-ZIX_API ZixTree*
-zix_tree_new(bool allow_duplicates,
- ZixComparator cmp,
- void* cmp_data,
- ZixDestroyFunc destroy)
-{
- ZixTree* t = (ZixTree*)malloc(sizeof(ZixTree));
- t->root = NULL;
- t->destroy = destroy;
- t->cmp = cmp;
- t->cmp_data = cmp_data;
- t->size = 0;
- t->allow_duplicates = allow_duplicates;
- return t;
-}
-
-ZIX_PRIVATE void
-zix_tree_free_rec(ZixTree* t, ZixTreeNode* n)
-{
- if (n) {
- zix_tree_free_rec(t, n->left);
- zix_tree_free_rec(t, n->right);
- if (t->destroy) {
- t->destroy(n->data);
- }
- free(n);
- }
-}
-
-ZIX_API void
-zix_tree_free(ZixTree* t)
-{
- if (t) {
- zix_tree_free_rec(t, t->root);
- free(t);
- }
-}
-
-ZIX_API size_t
-zix_tree_size(const ZixTree* t)
-{
- return t->size;
-}
-
-ZIX_PRIVATE void
-rotate(ZixTreeNode* p, ZixTreeNode* q)
-{
- assert(q->parent == p);
- assert(p->left == q || p->right == q);
-
- q->parent = p->parent;
- if (q->parent) {
- if (q->parent->left == p) {
- q->parent->left = q;
- } else {
- q->parent->right = q;
- }
- }
-
- if (p->right == q) {
- // Rotate left
- p->right = q->left;
- q->left = p;
- if (p->right) {
- p->right->parent = p;
- }
- } else {
- // Rotate right
- assert(p->left == q);
- p->left = q->right;
- q->right = p;
- if (p->left) {
- p->left->parent = p;
- }
- }
-
- p->parent = q;
-}
-
-/**
- * Rotate left about `p`.
- *
- * p q
- * / \ / \
- * A q => p C
- * / \ / \
- * B C A B
- */
-ZIX_PRIVATE ZixTreeNode*
-rotate_left(ZixTreeNode* p, int* height_change)
-{
- ZixTreeNode* const q = p->right;
- *height_change = (q->balance == 0) ? 0 : -1;
-
- DEBUG_PRINTF("LL %ld\n", (intptr_t)p->data);
-
- assert(p->balance == 2);
- assert(q->balance == 0 || q->balance == 1);
-
- rotate(p, q);
-
- // p->balance -= 1 + MAX(0, q->balance);
- // q->balance -= 1 - MIN(0, p->balance);
- --q->balance;
- p->balance = -(q->balance);
-
- ASSERT_BALANCE(p);
- ASSERT_BALANCE(q);
- return q;
-}
-
-/**
- * Rotate right about `p`.
- *
- * p q
- * / \ / \
- * q C => A p
- * / \ / \
- * A B B C
- *
- */
-ZIX_PRIVATE ZixTreeNode*
-rotate_right(ZixTreeNode* p, int* height_change)
-{
- ZixTreeNode* const q = p->left;
- *height_change = (q->balance == 0) ? 0 : -1;
-
- DEBUG_PRINTF("RR %ld\n", (intptr_t)p->data);
-
- assert(p->balance == -2);
- assert(q->balance == 0 || q->balance == -1);
-
- rotate(p, q);
-
- // p->balance += 1 - MIN(0, q->balance);
- // q->balance += 1 + MAX(0, p->balance);
- ++q->balance;
- p->balance = -(q->balance);
-
- ASSERT_BALANCE(p);
- ASSERT_BALANCE(q);
- return q;
-}
-
-/**
- * Rotate left about `p->left` then right about `p`.
- *
- * p r
- * / \ / \
- * q D => q p
- * / \ / \ / \
- * A r A B C D
- * / \
- * B C
- *
- */
-ZIX_PRIVATE ZixTreeNode*
-rotate_left_right(ZixTreeNode* p, int* height_change)
-{
- ZixTreeNode* const q = p->left;
- ZixTreeNode* const r = q->right;
-
- assert(p->balance == -2);
- assert(q->balance == 1);
- assert(r->balance == -1 || r->balance == 0 || r->balance == 1);
-
- DEBUG_PRINTF("LR %ld P: %2d Q: %2d R: %2d\n",
- (intptr_t)p->data, p->balance, q->balance, r->balance);
-
- rotate(q, r);
- rotate(p, r);
-
- q->balance -= 1 + MAX(0, r->balance);
- p->balance += 1 - MIN(MIN(0, r->balance) - 1, r->balance + q->balance);
- // r->balance += MAX(0, p->balance) + MIN(0, q->balance);
-
- // p->balance = (p->left && p->right) ? -MIN(r->balance, 0) : 0;
- // q->balance = - MAX(r->balance, 0);
- r->balance = 0;
-
- *height_change = -1;
-
- ASSERT_BALANCE(p);
- ASSERT_BALANCE(q);
- ASSERT_BALANCE(r);
- return r;
-}
-
-/**
- * Rotate right about `p->right` then right about `p`.
- *
- * p r
- * / \ / \
- * A q => p q
- * / \ / \ / \
- * r D A B C D
- * / \
- * B C
- *
- */
-ZIX_PRIVATE ZixTreeNode*
-rotate_right_left(ZixTreeNode* p, int* height_change)
-{
- ZixTreeNode* const q = p->right;
- ZixTreeNode* const r = q->left;
-
- assert(p->balance == 2);
- assert(q->balance == -1);
- assert(r->balance == -1 || r->balance == 0 || r->balance == 1);
-
- DEBUG_PRINTF("RL %ld P: %2d Q: %2d R: %2d\n",
- (intptr_t)p->data, p->balance, q->balance, r->balance);
-
- rotate(q, r);
- rotate(p, r);
-
- q->balance += 1 - MIN(0, r->balance);
- p->balance -= 1 + MAX(MAX(0, r->balance) + 1, r->balance + q->balance);
- // r->balance += MAX(0, q->balance) + MIN(0, p->balance);
-
- // p->balance = (p->left && p->right) ? -MAX(r->balance, 0) : 0;
- // q->balance = - MIN(r->balance, 0);
- r->balance = 0;
- // assert(r->balance == 0);
-
- *height_change = -1;
-
- ASSERT_BALANCE(p);
- ASSERT_BALANCE(q);
- ASSERT_BALANCE(r);
- return r;
-}
-
-ZIX_PRIVATE ZixTreeNode*
-zix_tree_rebalance(ZixTree* t, ZixTreeNode* node, int* height_change)
-{
-#ifdef ZIX_TREE_HYPER_VERIFY
- const size_t old_height = height(node);
-#endif
- DEBUG_PRINTF("REBALANCE %ld (%d)\n", (intptr_t)node->data, node->balance);
- *height_change = 0;
- const bool is_root = !node->parent;
- assert((is_root && t->root == node) || (!is_root && t->root != node));
- ZixTreeNode* replacement = node;
- if (node->balance == -2) {
- assert(node->left);
- if (node->left->balance == 1) {
- replacement = rotate_left_right(node, height_change);
- } else {
- replacement = rotate_right(node, height_change);
- }
- } else if (node->balance == 2) {
- assert(node->right);
- if (node->right->balance == -1) {
- replacement = rotate_right_left(node, height_change);
- } else {
- replacement = rotate_left(node, height_change);
- }
- }
- if (is_root) {
- assert(!replacement->parent);
- t->root = replacement;
- }
- DUMP(t);
-#ifdef ZIX_TREE_HYPER_VERIFY
- assert(old_height + *height_change == height(replacement));
-#endif
- return replacement;
-}
-
-ZIX_API ZixStatus
-zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti)
-{
- DEBUG_PRINTF("**** INSERT %ld\n", (intptr_t)e);
- int cmp = 0;
- ZixTreeNode* n = t->root;
- ZixTreeNode* p = NULL;
-
- // Find the parent p of e
- while (n) {
- p = n;
- cmp = t->cmp(e, n->data, t->cmp_data);
- if (cmp < 0) {
- n = n->left;
- } else if (cmp > 0) {
- n = n->right;
- } else if (t->allow_duplicates) {
- n = n->right;
- } else {
- if (ti) {
- *ti = n;
- }
- DEBUG_PRINTF("%ld EXISTS!\n", (intptr_t)e);
- return ZIX_STATUS_EXISTS;
- }
- }
-
- // Allocate a new node n
- if (!(n = (ZixTreeNode*)malloc(sizeof(ZixTreeNode)))) {
- return ZIX_STATUS_NO_MEM;
- }
- memset(n, '\0', sizeof(ZixTreeNode));
- n->data = e;
- n->balance = 0;
- if (ti) {
- *ti = n;
- }
-
- bool p_height_increased = false;
-
- // Make p the parent of n
- n->parent = p;
- if (!p) {
- t->root = n;
- } else {
- if (cmp < 0) {
- assert(!p->left);
- assert(p->balance == 0 || p->balance == 1);
- p->left = n;
- --p->balance;
- p_height_increased = !p->right;
- } else {
- assert(!p->right);
- assert(p->balance == 0 || p->balance == -1);
- p->right = n;
- ++p->balance;
- p_height_increased = !p->left;
- }
- }
-
- DUMP(t);
-
- // Rebalance if necessary (at most 1 rotation)
- assert(!p || p->balance == -1 || p->balance == 0 || p->balance == 1);
- if (p && p_height_increased) {
- int height_change = 0;
- for (ZixTreeNode* i = p; i && i->parent; i = i->parent) {
- if (i == i->parent->left) {
- if (--i->parent->balance == -2) {
- zix_tree_rebalance(t, i->parent, &height_change);
- break;
- }
- } else {
- assert(i == i->parent->right);
- if (++i->parent->balance == 2) {
- zix_tree_rebalance(t, i->parent, &height_change);
- break;
- }
- }
-
- if (i->parent->balance == 0) {
- break;
- }
- }
- }
-
- DUMP(t);
-
- ++t->size;
-
-#ifdef ZIX_TREE_VERIFY
- if (!verify(t, t->root)) {
- return ZIX_STATUS_ERROR;
- }
-#endif
-
- return ZIX_STATUS_SUCCESS;
-}
-
-ZIX_API ZixStatus
-zix_tree_remove(ZixTree* t, ZixTreeIter* ti)
-{
- ZixTreeNode* const n = ti;
- ZixTreeNode** pp = NULL; // parent pointer
- ZixTreeNode* to_balance = n->parent; // lowest node to balance
- int8_t d_balance = 0; // delta(balance) for n->parent
-
- DEBUG_PRINTF("*** REMOVE %ld\n", (intptr_t)n->data);
-
- if ((n == t->root) && !n->left && !n->right) {
- t->root = NULL;
- if (t->destroy) {
- t->destroy(n->data);
- }
- free(n);
- --t->size;
- assert(t->size == 0);
- return ZIX_STATUS_SUCCESS;
- }
-
- // Set pp to the parent pointer to n, if applicable
- if (n->parent) {
- assert(n->parent->left == n || n->parent->right == n);
- if (n->parent->left == n) { // n is left child
- pp = &n->parent->left;
- d_balance = 1;
- } else { // n is right child
- assert(n->parent->right == n);
- pp = &n->parent->right;
- d_balance = -1;
- }
- }
-
- assert(!pp || *pp == n);
-
- int height_change = 0;
- if (!n->left && !n->right) {
- // n is a leaf, just remove it
- if (pp) {
- *pp = NULL;
- to_balance = n->parent;
- height_change = (!n->parent->left && !n->parent->right) ? -1 : 0;
- }
- } else if (!n->left) {
- // Replace n with right (only) child
- if (pp) {
- *pp = n->right;
- to_balance = n->parent;
- } else {
- t->root = n->right;
- }
- n->right->parent = n->parent;
- height_change = -1;
- } else if (!n->right) {
- // Replace n with left (only) child
- if (pp) {
- *pp = n->left;
- to_balance = n->parent;
- } else {
- t->root = n->left;
- }
- n->left->parent = n->parent;
- height_change = -1;
- } else {
- // Replace n with in-order successor (leftmost child of right subtree)
- ZixTreeNode* replace = n->right;
- while (replace->left) {
- assert(replace->left->parent == replace);
- replace = replace->left;
- }
-
- // Remove replace from parent (replace_p)
- if (replace->parent->left == replace) {
- height_change = replace->parent->right ? 0 : -1;
- d_balance = 1;
- to_balance = replace->parent;
- replace->parent->left = replace->right;
- } else {
- assert(replace->parent == n);
- height_change = replace->parent->left ? 0 : -1;
- d_balance = -1;
- to_balance = replace->parent;
- replace->parent->right = replace->right;
- }
-
- if (to_balance == n) {
- to_balance = replace;
- }
-
- if (replace->right) {
- replace->right->parent = replace->parent;
- }
-
- replace->balance = n->balance;
-
- // Swap node to delete with replace
- if (pp) {
- *pp = replace;
- } else {
- assert(t->root == n);
- t->root = replace;
- }
- replace->parent = n->parent;
- replace->left = n->left;
- n->left->parent = replace;
- replace->right = n->right;
- if (n->right) {
- n->right->parent = replace;
- }
-
- assert(!replace->parent
- || replace->parent->left == replace
- || replace->parent->right == replace);
- }
-
- // Rebalance starting at to_balance upwards.
- for (ZixTreeNode* i = to_balance; i; i = i->parent) {
- i->balance += d_balance;
- if (d_balance == 0 || i->balance == -1 || i->balance == 1) {
- break;
- }
-
- assert(i != n);
- i = zix_tree_rebalance(t, i, &height_change);
- if (i->balance == 0) {
- height_change = -1;
- }
-
- if (i->parent) {
- if (i == i->parent->left) {
- d_balance = height_change * -1;
- } else {
- assert(i == i->parent->right);
- d_balance = height_change;
- }
- }
- }
-
- DUMP(t);
-
- if (t->destroy) {
- t->destroy(n->data);
- }
- free(n);
-
- --t->size;
-
-#ifdef ZIX_TREE_VERIFY
- if (!verify(t, t->root)) {
- return ZIX_STATUS_ERROR;
- }
-#endif
-
- return ZIX_STATUS_SUCCESS;
-}
-
-ZIX_API ZixStatus
-zix_tree_find(const ZixTree* t, const void* e, ZixTreeIter** ti)
-{
- ZixTreeNode* n = t->root;
- while (n) {
- const int cmp = t->cmp(e, n->data, t->cmp_data);
- if (cmp == 0) {
- break;
- } else if (cmp < 0) {
- n = n->left;
- } else {
- n = n->right;
- }
- }
-
- *ti = n;
- return (n) ? ZIX_STATUS_SUCCESS : ZIX_STATUS_NOT_FOUND;
-}
-
-ZIX_API void*
-zix_tree_get(const ZixTreeIter* ti)
-{
- return ti ? ti->data : NULL;
-}
-
-ZIX_API ZixTreeIter*
-zix_tree_begin(ZixTree* t)
-{
- if (!t->root) {
- return NULL;
- }
-
- ZixTreeNode* n = t->root;
- while (n->left) {
- n = n->left;
- }
- return n;
-}
-
-ZIX_API ZixTreeIter*
-zix_tree_end(ZixTree* t)
-{
- return NULL;
-}
-
-ZIX_API ZixTreeIter*
-zix_tree_rbegin(ZixTree* t)
-{
- if (!t->root) {
- return NULL;
- }
-
- ZixTreeNode* n = t->root;
- while (n->right) {
- n = n->right;
- }
- return n;
-}
-
-ZIX_API ZixTreeIter*
-zix_tree_rend(ZixTree* t)
-{
- return NULL;
-}
-
-ZIX_API bool
-zix_tree_iter_is_end(const ZixTreeIter* i)
-{
- return !i;
-}
-
-ZIX_API bool
-zix_tree_iter_is_rend(const ZixTreeIter* i)
-{
- return !i;
-}
-
-ZIX_API ZixTreeIter*
-zix_tree_iter_next(ZixTreeIter* i)
-{
- if (!i) {
- return NULL;
- }
-
- if (i->right) {
- i = i->right;
- while (i->left) {
- i = i->left;
- }
- } else {
- while (i->parent && i->parent->right == i) { // i is a right child
- i = i->parent;
- }
-
- i = i->parent;
- }
-
- return i;
-}
-
-ZIX_API ZixTreeIter*
-zix_tree_iter_prev(ZixTreeIter* i)
-{
- if (!i) {
- return NULL;
- }
-
- if (i->left) {
- i = i->left;
- while (i->right) {
- i = i->right;
- }
- } else {
- while (i->parent && i->parent->left == i) { // i is a left child
- i = i->parent;
- }
-
- i = i->parent;
- }
-
- return i;
-}
diff --git a/src/zix/tree.h b/src/zix/tree.h
deleted file mode 100644
index 983c0ea..0000000
--- a/src/zix/tree.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- Copyright 2011-2019 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.
-*/
-
-#ifndef ZIX_TREE_H
-#define ZIX_TREE_H
-
-#include "zix/common.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- @addtogroup zix
- @{
- @name Tree
- @{
-*/
-
-/**
- A balanced binary search tree.
-*/
-typedef struct ZixTreeImpl ZixTree;
-
-/**
- An iterator over a ZixTree.
-*/
-typedef struct ZixTreeNodeImpl ZixTreeIter;
-
-/**
- Create a new (empty) tree.
-*/
-ZIX_API ZixTree*
-zix_tree_new(bool allow_duplicates,
- ZixComparator cmp,
- void* cmp_data,
- ZixDestroyFunc destroy);
-
-/**
- Free `t`.
-*/
-ZIX_API void
-zix_tree_free(ZixTree* t);
-
-/**
- Return the number of elements in `t`.
-*/
-ZIX_API size_t
-zix_tree_size(const ZixTree* t);
-
-/**
- Insert the element `e` into `t` and point `ti` at the new element.
-*/
-ZIX_API ZixStatus
-zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti);
-
-/**
- Remove the item pointed at by `ti` from `t`.
-*/
-ZIX_API ZixStatus
-zix_tree_remove(ZixTree* t, ZixTreeIter* ti);
-
-/**
- Set `ti` to an element equal to `e` in `t`.
- If no such item exists, `ti` is set to NULL.
-*/
-ZIX_API ZixStatus
-zix_tree_find(const ZixTree* t, const void* e, ZixTreeIter** ti);
-
-/**
- Return the data associated with the given tree item.
-*/
-ZIX_API void*
-zix_tree_get(const ZixTreeIter* ti);
-
-/**
- Return an iterator to the first (smallest) element in `t`.
-*/
-ZIX_API ZixTreeIter*
-zix_tree_begin(ZixTree* t);
-
-/**
- Return an iterator the the element one past the last element in `t`.
-*/
-ZIX_API ZixTreeIter*
-zix_tree_end(ZixTree* t);
-
-/**
- Return true iff `i` is an iterator to the end of its tree.
-*/
-ZIX_API bool
-zix_tree_iter_is_end(const ZixTreeIter* i);
-
-/**
- Return an iterator to the last (largest) element in `t`.
-*/
-ZIX_API ZixTreeIter*
-zix_tree_rbegin(ZixTree* t);
-
-/**
- Return an iterator the the element one before the first element in `t`.
-*/
-ZIX_API ZixTreeIter*
-zix_tree_rend(ZixTree* t);
-
-/**
- Return true iff `i` is an iterator to the reverse end of its tree.
-*/
-ZIX_API bool
-zix_tree_iter_is_rend(const ZixTreeIter* i);
-
-/**
- Return an iterator that points to the element one past `i`.
-*/
-ZIX_API ZixTreeIter*
-zix_tree_iter_next(ZixTreeIter* i);
-
-/**
- Return an iterator that points to the element one before `i`.
-*/
-ZIX_API ZixTreeIter*
-zix_tree_iter_prev(ZixTreeIter* i);
-
-/**
- @}
- @}
-*/
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* ZIX_TREE_H */
diff --git a/subprojects/sphinxygen.wrap b/subprojects/sphinxygen.wrap
new file mode 100644
index 0000000..9707d1a
--- /dev/null
+++ b/subprojects/sphinxygen.wrap
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+[wrap-file]
+directory = sphinxygen-1.0.4
+source_url = https://download.drobilla.net/sphinxygen-1.0.4.tar.gz
+source_filename = sphinxygen-1.0.4.tar.gz
+source_hash = 12fa9f18ed9fca608f272520072257ba61fd9eff25613f86d83d4fce14fc01f5
+
+# [wrap-git]
+# url = https://gitlab.com/drobilla/sphinxygen.git
+# push-url = ssh://git@gitlab.com:drobilla/sphinxygen.git
+# revision = v1.0.4
+# depth = 1
diff --git a/test/.clang-tidy b/test/.clang-tidy
new file mode 100644
index 0000000..f6f74ab
--- /dev/null
+++ b/test/.clang-tidy
@@ -0,0 +1,19 @@
+# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+Checks: >
+ -*-magic-numbers,
+ -android-cloexec-fopen,
+ -bugprone-branch-clone,
+ -bugprone-narrowing-conversions,
+ -cert-err33-c,
+ -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
+ -concurrency-mt-unsafe,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-narrowing-conversions,
+ -hicpp-multiway-paths-covered,
+ -hicpp-signed-bitwise,
+ -llvm-header-guard,
+ -readability-function-cognitive-complexity,
+ -readability-suspicious-call-argument,
+InheritParentConfig: true
diff --git a/test/bad_syntax.lv2/bad_syntax.c b/test/bad_syntax.lv2/bad_syntax.c
index fc4a210..b1b52e7 100644
--- a/test/bad_syntax.lv2/bad_syntax.c
+++ b/test/bad_syntax.lv2/bad_syntax.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Bad syntax in plugin data file
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/bad-syntax"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,35 +43,43 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
- return (LV2_Handle)test;
+ 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;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/bad_syntax.lv2/meson.build b/test/bad_syntax.lv2/meson.build
new file mode 100644
index 0000000..dbda502
--- /dev/null
+++ b/test/bad_syntax.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'bad_syntax',
+ files('bad_syntax.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'bad_syntax.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ configuration: config,
+ input: files(f + '.in'),
+ output: f,
+ )
+endforeach
+
+test(
+ 'bad_syntax',
+ executable(
+ 'test_bad_syntax',
+ files('test_bad_syntax.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/bad_syntax.lv2/test_bad_syntax.c b/test/bad_syntax.lv2/test_bad_syntax.c
index e7afcfc..39729d4 100644
--- a/test/bad_syntax.lv2/test_bad_syntax.c
+++ b/test/bad_syntax.lv2/test_bad_syntax.c
@@ -1,48 +1,40 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/bad-syntax"
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);
-
- assert(!lilv_plugin_get_name(plugin));
- assert(!lilv_plugin_instantiate(plugin, 48000, NULL));
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+
+ assert(!lilv_plugin_get_name(plugin));
+ assert(!lilv_plugin_instantiate(plugin, 48000, NULL));
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/cpp/.clang-tidy b/test/cpp/.clang-tidy
new file mode 100644
index 0000000..5d20fa0
--- /dev/null
+++ b/test/cpp/.clang-tidy
@@ -0,0 +1,19 @@
+# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+Checks: >
+ -cert-dcl50-cpp,
+ -cppcoreguidelines-macro-usage,
+ -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
+ -fuchsia-overloaded-operator,
+ -google-explicit-constructor,
+ -google-readability-todo,
+ -hicpp-explicit-conversions,
+ -hicpp-no-array-decay,
+ -misc-non-private-member-variables-in-classes,
+ -modernize-return-braced-init-list,
+ -modernize-use-nodiscard,
+ -modernize-use-trailing-return-type,
+ -readability-implicit-bool-conversion,
+HeaderFilterRegex: '.*/lilvmm\.hpp'
+InheritParentConfig: true
diff --git a/test/cpp/meson.build b/test/cpp/meson.build
new file mode 100644
index 0000000..5b8169c
--- /dev/null
+++ b/test/cpp/meson.build
@@ -0,0 +1,37 @@
+# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+cpp_suppressions = []
+if cpp.get_id() == 'gcc'
+ cpp_suppressions += [
+ '-Wno-cast-align',
+ '-Wno-padded',
+ ]
+elif cpp.get_id() == 'clang'
+ cpp_suppressions += [
+ '-Wno-c++98-compat',
+ '-Wno-cast-align',
+ '-Wno-cast-qual',
+ '-Wno-documentation-unknown-command',
+ '-Wno-padded',
+ '-Wno-poison-system-directories',
+ '-Wno-reserved-id-macro',
+ ]
+elif cpp.get_id() == 'msvc'
+ cpp_suppressions += [
+ '/wd4514', # unreferenced inline function has been removed
+ '/wd4820', # padding added after construct
+ ]
+endif
+
+test(
+ 'lilv_hpp',
+ executable(
+ 'test_lilv_hpp',
+ files('test_lilv_hpp.cpp'),
+ cpp_args: test_args + cpp_suppressions,
+ dependencies: [lv2_dep, lilv_static_dep],
+ include_directories: include_directories('../../src'),
+ ),
+ suite: 'unit',
+)
diff --git a/test/cpp/test_lilv_hpp.cpp b/test/cpp/test_lilv_hpp.cpp
new file mode 100644
index 0000000..7e6de72
--- /dev/null
+++ b/test/cpp/test_lilv_hpp.cpp
@@ -0,0 +1,12 @@
+// Copyright 2017-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lilv/lilvmm.hpp"
+
+int
+main()
+{
+ const Lilv::World world{};
+
+ return 0;
+}
diff --git a/test/failed_instantiation.lv2/failed_instantiation.c b/test/failed_instantiation.lv2/failed_instantiation.c
index 30ae0ca..2d75c1a 100644
--- a/test/failed_instantiation.lv2/failed_instantiation.c
+++ b/test/failed_instantiation.lv2/failed_instantiation.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Failed instantiation
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,23 +8,26 @@
#define PLUGIN_URI "http://example.org/failed-instantiation"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
-{}
+{
+ (void)instance;
+}
static void
connect_port(LV2_Handle instance, uint32_t port, void* data)
-{}
+{
+ (void)instance;
+ (void)port;
+ (void)data;
+}
static LV2_Handle
instantiate(const LV2_Descriptor* descriptor,
@@ -46,26 +35,35 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- return NULL;
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
+
+ return NULL;
}
static void
run(LV2_Handle instance, uint32_t sample_count)
-{}
+{
+ (void)instance;
+ (void)sample_count;
+}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/failed_instantiation.lv2/meson.build b/test/failed_instantiation.lv2/meson.build
new file mode 100644
index 0000000..966eed0
--- /dev/null
+++ b/test/failed_instantiation.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'failed_instantiation',
+ files('failed_instantiation.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'failed_instantiation.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ configuration: config,
+ input: files(f + '.in'),
+ output: f,
+ )
+endforeach
+
+test(
+ 'failed_instantiation',
+ executable(
+ 'test_failed_instantiation',
+ files('test_failed_instantiation.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/failed_instantiation.lv2/test_failed_instantiation.c b/test/failed_instantiation.lv2/test_failed_instantiation.c
index 7fb2714..ed46d5a 100644
--- a/test/failed_instantiation.lv2/test_failed_instantiation.c
+++ b/test/failed_instantiation.lv2/test_failed_instantiation.c
@@ -1,48 +1,40 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
#include "lilv/lilv.h"
-#include "serd/serd.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/failed-instantiation"
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);
- assert(plugin);
-
- assert(!lilv_plugin_instantiate(plugin, 48000, NULL));
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ assert(!lilv_plugin_instantiate(plugin, 48000, NULL));
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/failed_lib_descriptor.lv2/failed_lib_descriptor.c b/test/failed_lib_descriptor.lv2/failed_lib_descriptor.c
index e24c8d9..2d0baee 100644
--- a/test/failed_lib_descriptor.lv2/failed_lib_descriptor.c
+++ b/test/failed_lib_descriptor.lv2/failed_lib_descriptor.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Failed lib descriptor
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -21,8 +7,10 @@
LV2_SYMBOL_EXPORT
const LV2_Lib_Descriptor*
-lv2_lib_descriptor(const char* bundle_path,
- const LV2_Feature*const* features)
+lv2_lib_descriptor(const char* bundle_path, const LV2_Feature* const* features)
{
- return NULL;
+ (void)bundle_path;
+ (void)features;
+
+ return NULL;
}
diff --git a/test/failed_lib_descriptor.lv2/meson.build b/test/failed_lib_descriptor.lv2/meson.build
new file mode 100644
index 0000000..61de196
--- /dev/null
+++ b/test/failed_lib_descriptor.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'failed_lib_descriptor',
+ files('failed_lib_descriptor.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'failed_lib_descriptor.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'failed_lib_descriptor',
+ executable(
+ 'test_failed_lib_descriptor',
+ files('test_failed_lib_descriptor.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/failed_lib_descriptor.lv2/test_failed_lib_descriptor.c b/test/failed_lib_descriptor.lv2/test_failed_lib_descriptor.c
index 5347ade..9a9641b 100644
--- a/test/failed_lib_descriptor.lv2/test_failed_lib_descriptor.c
+++ b/test/failed_lib_descriptor.lv2/test_failed_lib_descriptor.c
@@ -1,49 +1,41 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/failed-lib-descriptor"
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);
- assert(plugin);
-
- LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
- assert(!instance);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
+ assert(!instance);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/lib_descriptor.lv2/lib_descriptor.c b/test/lib_descriptor.lv2/lib_descriptor.c
index 29176dc..bae1659 100644
--- a/test/lib_descriptor.lv2/lib_descriptor.c
+++ b/test/lib_descriptor.lv2/lib_descriptor.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Missing descriptor
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/lib-descriptor"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,54 +43,59 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
+
+ Test* test = (Test*)calloc(1, sizeof(Test));
+ if (!test) {
+ return NULL;
+ }
- return (LV2_Handle)test;
+ return (LV2_Handle)test;
}
static void
run(LV2_Handle instance, uint32_t sample_count)
{
- Test* test = (Test*)instance;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ PLUGIN_URI,
+ instantiate,
+ connect_port,
+ NULL, // activate,
+ run,
+ NULL, // deactivate,
+ cleanup,
+ NULL // extension_data
};
static const LV2_Descriptor*
get_plugin(LV2_Lib_Handle handle, uint32_t index)
{
- switch (index) {
- case 0:
- return &descriptor;
- default:
- return NULL;
- }
+ (void)handle;
+
+ return index ? NULL : &descriptor;
}
-static const LV2_Lib_Descriptor lib = {
- NULL,
- sizeof(LV2_Lib_Descriptor),
- NULL,
- get_plugin };
+static const LV2_Lib_Descriptor lib = {NULL,
+ sizeof(LV2_Lib_Descriptor),
+ NULL,
+ get_plugin};
LV2_SYMBOL_EXPORT
const LV2_Lib_Descriptor*
-lv2_lib_descriptor(const char* bundle_path,
- const LV2_Feature*const* features)
+lv2_lib_descriptor(const char* bundle_path, const LV2_Feature* const* features)
{
- return &lib;
+ (void)bundle_path;
+ (void)features;
+
+ return &lib;
}
diff --git a/test/lib_descriptor.lv2/meson.build b/test/lib_descriptor.lv2/meson.build
new file mode 100644
index 0000000..ea29b6a
--- /dev/null
+++ b/test/lib_descriptor.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'lib_descriptor',
+ files('lib_descriptor.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'lib_descriptor.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'lib_descriptor',
+ executable(
+ 'test_lib_descriptor',
+ files('test_lib_descriptor.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/lib_descriptor.lv2/test_lib_descriptor.c b/test/lib_descriptor.lv2/test_lib_descriptor.c
index fdc5107..e971662 100644
--- a/test/lib_descriptor.lv2/test_lib_descriptor.c
+++ b/test/lib_descriptor.lv2/test_lib_descriptor.c
@@ -1,62 +1,54 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/lib-descriptor"
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);
- assert(plugin);
-
- LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
- assert(instance);
- lilv_instance_free(instance);
-
- LilvNode* eg_blob = lilv_new_uri(world, "http://example.org/blob");
- LilvNode* blob = lilv_world_get(world, plugin_uri, eg_blob, NULL);
- assert(lilv_node_is_literal(blob));
- lilv_node_free(blob);
- lilv_node_free(eg_blob);
-
- LilvNode* eg_junk = lilv_new_uri(world, "http://example.org/junk");
- LilvNode* junk = lilv_world_get(world, plugin_uri, eg_junk, NULL);
- assert(lilv_node_is_literal(junk));
- lilv_node_free(junk);
- lilv_node_free(eg_junk);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
+ assert(instance);
+ lilv_instance_free(instance);
+
+ LilvNode* eg_blob = lilv_new_uri(world, "http://example.org/blob");
+ LilvNode* blob = lilv_world_get(world, plugin_uri, eg_blob, NULL);
+ assert(lilv_node_is_literal(blob));
+ lilv_node_free(blob);
+ lilv_node_free(eg_blob);
+
+ LilvNode* eg_junk = lilv_new_uri(world, "http://example.org/junk");
+ LilvNode* junk = lilv_world_get(world, plugin_uri, eg_junk, NULL);
+ assert(lilv_node_is_literal(junk));
+ lilv_node_free(junk);
+ lilv_node_free(eg_junk);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
}
-
diff --git a/test/lilv_cxx_test.cpp b/test/lilv_cxx_test.cpp
deleted file mode 100644
index 4ee21ae..0000000
--- a/test/lilv_cxx_test.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- Copyright 2017-2019 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.
-*/
-
-#include "lilv/lilvmm.hpp"
-
-int
-main()
-{
- Lilv::World world;
-
- return 0;
-}
diff --git a/test/lilv_test_uri_map.h b/test/lilv_test_uri_map.h
index d6badc1..b4fba0f 100644
--- a/test/lilv_test_uri_map.h
+++ b/test/lilv_test_uri_map.h
@@ -1,86 +1,71 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#ifndef LILV_TEST_URI_MAP_H
#define LILV_TEST_URI_MAP_H
-#include "lilv_test_utils.h"
-
#include "../src/lilv_internal.h"
+#include "lv2/urid/urid.h"
#include "serd/serd.h"
#include <assert.h>
-#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-typedef struct
-{
- char** uris;
- size_t n_uris;
+typedef struct {
+ char** uris;
+ uint32_t n_uris;
} LilvTestUriMap;
static inline void
lilv_test_uri_map_init(LilvTestUriMap* const map)
{
- map->uris = NULL;
- map->n_uris = 0;
+ map->uris = NULL;
+ map->n_uris = 0;
}
static inline void
lilv_test_uri_map_clear(LilvTestUriMap* const map)
{
- for (size_t i = 0; i < map->n_uris; ++i) {
- free(map->uris[i]);
- }
+ for (uint32_t i = 0; i < map->n_uris; ++i) {
+ free(map->uris[i]);
+ }
- free(map->uris);
- map->uris = NULL;
- map->n_uris = 0;
+ free(map->uris);
+ map->uris = NULL;
+ map->n_uris = 0;
}
static inline LV2_URID
map_uri(LV2_URID_Map_Handle handle, const char* uri)
{
- LilvTestUriMap* map = (LilvTestUriMap*)handle;
+ LilvTestUriMap* map = (LilvTestUriMap*)handle;
- for (size_t i = 0; i < map->n_uris; ++i) {
- if (!strcmp(map->uris[i], uri)) {
- return i + 1;
- }
- }
+ for (uint32_t i = 0; i < map->n_uris; ++i) {
+ if (!strcmp(map->uris[i], uri)) {
+ return i + 1;
+ }
+ }
- assert(serd_uri_string_has_scheme((const uint8_t*)uri));
+ assert(serd_uri_string_has_scheme((const uint8_t*)uri));
- map->uris = (char**)realloc(map->uris, ++map->n_uris * sizeof(char*));
- map->uris[map->n_uris - 1] = lilv_strdup(uri);
- return map->n_uris;
+ map->uris = (char**)realloc(map->uris, ++map->n_uris * sizeof(char*));
+ map->uris[map->n_uris - 1] = lilv_strdup(uri);
+ return map->n_uris;
}
static inline const char*
unmap_uri(LV2_URID_Map_Handle handle, LV2_URID urid)
{
- LilvTestUriMap* map = (LilvTestUriMap*)handle;
+ LilvTestUriMap* map = (LilvTestUriMap*)handle;
- if (urid > 0 && urid <= map->n_uris) {
- return map->uris[urid - 1];
- }
+ if (urid > 0 && urid <= map->n_uris) {
+ return map->uris[urid - 1];
+ }
- return NULL;
+ return NULL;
}
#endif // LILV_TEST_URI_MAP_H
diff --git a/test/lilv_test_utils.c b/test/lilv_test_utils.c
index cfc5c4f..c3c47f0 100644
--- a/test/lilv_test_utils.c
+++ b/test/lilv_test_utils.c
@@ -1,28 +1,13 @@
-/*
- Copyright 2020 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 setenv */
+// Copyright 2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lilv_test_utils.h"
-#include "../src/filesystem.h"
-#include "../src/lilv_internal.h"
-
#include "lilv/lilv.h"
#include "serd/serd.h"
+#include "zix/allocator.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
#include <errno.h>
#include <stdbool.h>
@@ -34,151 +19,173 @@
LilvTestEnv*
lilv_test_env_new(void)
{
- LilvWorld* world = lilv_world_new();
- if (!world) {
- return NULL;
- }
-
- LilvTestEnv* env = (LilvTestEnv*)calloc(1, sizeof(LilvTestEnv));
-
- env->world = world;
- env->plugin1_uri = lilv_new_uri(world, "http://example.org/plug");
- env->plugin2_uri = lilv_new_uri(world, "http://example.org/foobar");
-
- // Set custom LV2_PATH in build directory to only use test data
- char* test_path = lilv_path_canonical(LILV_TEST_DIR);
- char* lv2_path = lilv_strjoin(test_path, "/test_lv2_path", NULL);
- LilvNode* path = lilv_new_string(world, lv2_path);
- lilv_world_set_option(world, LILV_OPTION_LV2_PATH, path);
- free(lv2_path);
- free(test_path);
- lilv_node_free(path);
-
- return env;
+ LilvWorld* world = lilv_world_new();
+ if (!world) {
+ return NULL;
+ }
+
+ LilvTestEnv* env = (LilvTestEnv*)calloc(1, sizeof(LilvTestEnv));
+
+ env->world = world;
+ env->plugin1_uri = lilv_new_uri(world, "http://example.org/plug");
+ env->plugin2_uri = lilv_new_uri(world, "http://example.org/foobar");
+
+ // Set custom LV2_PATH in build directory to only use test data
+ char* test_path = zix_canonical_path(NULL, LILV_TEST_DIR);
+ char* lv2_path = zix_path_join(NULL, test_path, "lv2");
+ LilvNode* path = lilv_new_string(world, lv2_path);
+ lilv_world_set_option(world, LILV_OPTION_LV2_PATH, path);
+ lilv_node_free(path);
+ zix_free(NULL, lv2_path);
+ zix_free(NULL, test_path);
+
+ return env;
}
void
lilv_test_env_free(LilvTestEnv* env)
{
- free(env->test_content_path);
- free(env->test_manifest_path);
- free(env->test_bundle_uri);
- free(env->test_bundle_path);
- lilv_node_free(env->plugin2_uri);
- lilv_node_free(env->plugin1_uri);
- lilv_world_free(env->world);
- free(env);
+ zix_free(NULL, env->test_content_path);
+ zix_free(NULL, env->test_manifest_path);
+ lilv_node_free(env->test_bundle_uri);
+ zix_free(NULL, env->test_bundle_path);
+ lilv_node_free(env->plugin2_uri);
+ lilv_node_free(env->plugin1_uri);
+ lilv_world_free(env->world);
+ free(env);
}
int
-create_bundle(LilvTestEnv* env, const char* manifest, const char* plugin)
+create_bundle(LilvTestEnv* env,
+ const char* name,
+ const char* manifest,
+ const char* plugin)
{
- {
- static const char* const bundle_path = "/test_lv2_path/lilv-test.lv2";
-
- char* const test_path = lilv_path_canonical(LILV_TEST_DIR);
- env->test_bundle_path = lilv_strjoin(test_path, bundle_path, NULL);
- lilv_free(test_path);
- }
-
- if (lilv_create_directories(env->test_bundle_path)) {
- fprintf(stderr,
- "Failed to create directory '%s' (%s)\n",
- env->test_bundle_path,
- strerror(errno));
- return 1;
- }
-
- SerdNode s = serd_node_new_file_uri((const uint8_t*)env->test_bundle_path,
- NULL,
- NULL,
- true);
-
- env->test_bundle_uri = lilv_strjoin((const char*)s.buf, "/", NULL);
- env->test_manifest_path =
- lilv_strjoin(env->test_bundle_path, "/manifest.ttl", NULL);
- env->test_content_path =
- lilv_strjoin(env->test_bundle_path, "/plugin.ttl", NULL);
-
- serd_node_free(&s);
-
- FILE* const manifest_file = fopen(env->test_manifest_path, "w");
- if (!manifest_file) {
- return 2;
- }
-
- FILE* const plugin_file = fopen(env->test_content_path, "w");
- if (!plugin_file) {
- fclose(manifest_file);
- return 3;
- }
-
- const size_t manifest_head_len = strlen(MANIFEST_PREFIXES);
- const size_t manifest_len = strlen(manifest);
- const size_t plugin_head_len = strlen(PLUGIN_PREFIXES);
- const size_t plugin_len = strlen(plugin);
- const size_t n_total =
- manifest_len + plugin_len + manifest_head_len + plugin_head_len;
-
- size_t n_written = 0;
- n_written += fwrite(MANIFEST_PREFIXES, 1, manifest_head_len, manifest_file);
- n_written += fwrite(manifest, 1, manifest_len, manifest_file);
- n_written += fwrite(PLUGIN_PREFIXES, 1, plugin_head_len, plugin_file);
- n_written += fwrite(plugin, 1, plugin_len, plugin_file);
-
- fclose(manifest_file);
- fclose(plugin_file);
- return n_written == n_total ? 0 : 4;
+ {
+ char* const test_dir = zix_canonical_path(NULL, LILV_TEST_DIR);
+ char* const bundle_dir = zix_path_join(NULL, test_dir, name);
+
+ env->test_bundle_path = zix_path_join(NULL, bundle_dir, "");
+
+ zix_free(NULL, bundle_dir);
+ zix_free(NULL, test_dir);
+ }
+
+ if (zix_create_directories(NULL, env->test_bundle_path)) {
+ fprintf(stderr,
+ "Failed to create directory '%s' (%s)\n",
+ env->test_bundle_path,
+ strerror(errno));
+ return 1;
+ }
+
+ SerdNode s = serd_node_new_file_uri(
+ (const uint8_t*)env->test_bundle_path, NULL, NULL, true);
+
+ env->test_bundle_uri = lilv_new_uri(env->world, (const char*)s.buf);
+
+ env->test_manifest_path =
+ zix_path_join(NULL, env->test_bundle_path, "manifest.ttl");
+
+ env->test_content_path =
+ zix_path_join(NULL, env->test_bundle_path, "plugin.ttl");
+
+ serd_node_free(&s);
+
+ FILE* const manifest_file = fopen(env->test_manifest_path, "w");
+ if (!manifest_file) {
+ return 2;
+ }
+
+ FILE* const plugin_file = fopen(env->test_content_path, "w");
+ if (!plugin_file) {
+ fclose(manifest_file);
+ return 3;
+ }
+
+ const size_t manifest_head_len = strlen(MANIFEST_PREFIXES);
+ const size_t manifest_len = strlen(manifest);
+ const size_t plugin_head_len = strlen(PLUGIN_PREFIXES);
+ const size_t plugin_len = strlen(plugin);
+ const size_t n_total =
+ manifest_len + plugin_len + manifest_head_len + plugin_head_len;
+
+ size_t n_written = 0;
+ n_written += fwrite(MANIFEST_PREFIXES, 1, manifest_head_len, manifest_file);
+ n_written += fwrite(manifest, 1, manifest_len, manifest_file);
+ n_written += fwrite(PLUGIN_PREFIXES, 1, plugin_head_len, plugin_file);
+ n_written += fwrite(plugin, 1, plugin_len, plugin_file);
+
+ fclose(manifest_file);
+ fclose(plugin_file);
+ return n_written == n_total ? 0 : 4;
}
int
-start_bundle(LilvTestEnv* env, const char* manifest, const char* content)
+start_bundle(LilvTestEnv* env,
+ const char* name,
+ const char* manifest,
+ const char* plugin)
{
- if (create_bundle(env, manifest, content)) {
- return 1;
- }
+ if (create_bundle(env, name, manifest, plugin)) {
+ return 1;
+ }
+
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- lilv_world_load_all(env->world);
- return 0;
+ return 0;
}
void
delete_bundle(LilvTestEnv* env)
{
- if (env->test_content_path) {
- lilv_remove(env->test_content_path);
- }
-
- if (env->test_manifest_path) {
- lilv_remove(env->test_manifest_path);
- }
-
- if (env->test_bundle_path) {
- remove(env->test_bundle_path);
- }
-
- free(env->test_content_path);
- free(env->test_manifest_path);
- free(env->test_bundle_uri);
- free(env->test_bundle_path);
-
- env->test_content_path = NULL;
- env->test_manifest_path = NULL;
- env->test_bundle_uri = NULL;
- env->test_bundle_path = NULL;
+ if (env->test_content_path) {
+ zix_remove(env->test_content_path);
+ }
+
+ if (env->test_manifest_path) {
+ zix_remove(env->test_manifest_path);
+ }
+
+ if (env->test_bundle_path) {
+ remove(env->test_bundle_path);
+ }
+
+ zix_free(NULL, env->test_content_path);
+ zix_free(NULL, env->test_manifest_path);
+ lilv_node_free(env->test_bundle_uri);
+ zix_free(NULL, env->test_bundle_path);
+
+ env->test_content_path = NULL;
+ env->test_manifest_path = NULL;
+ env->test_bundle_uri = NULL;
+ env->test_bundle_path = NULL;
}
void
set_env(const char* name, const char* value)
{
#ifdef _WIN32
- // setenv on Windows does not modify the current process' environment
- const size_t len = strlen(name) + 1 + strlen(value) + 1;
- char* str = (char*)calloc(1, len);
- snprintf(str, len, "%s=%s", name, value);
- putenv(str);
- free(str);
+ // setenv on Windows does not modify the current process' environment
+ const size_t len = strlen(name) + 1 + strlen(value) + 1;
+ char* str = (char*)calloc(1, len);
+ snprintf(str, len, "%s=%s", name, value);
+ putenv(str);
+ free(str);
#else
- setenv(name, value, 1);
+ setenv(name, value, 1);
#endif
}
+
+char*
+lilv_create_temporary_directory(const char* pattern)
+{
+ char* const tmpdir = zix_temp_directory_path(NULL);
+ char* const path_pattern = zix_path_join(NULL, tmpdir, pattern);
+ char* const result = zix_create_temporary_directory(NULL, path_pattern);
+
+ zix_free(NULL, path_pattern);
+ zix_free(NULL, tmpdir);
+
+ return result;
+}
diff --git a/test/lilv_test_utils.h b/test/lilv_test_utils.h
index 13fd939..f01b5b4 100644
--- a/test/lilv_test_utils.h
+++ b/test/lilv_test_utils.h
@@ -1,18 +1,5 @@
-/*
- Copyright 2020 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.
-*/
+// Copyright 2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#ifndef LILV_TEST_UTILS_H
#define LILV_TEST_UTILS_H
@@ -20,13 +7,13 @@
#include "lilv/lilv.h"
#define MANIFEST_PREFIXES \
- "\
+ "\
@prefix : <http://example.org/> .\n\
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
#define PLUGIN_PREFIXES \
- "\
+ "\
@prefix : <http://example.org/> .\n\
@prefix atom: <http://lv2plug.in/ns/ext/atom#> . \n\
@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
@@ -37,30 +24,29 @@
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
#define SIMPLE_MANIFEST_TTL \
- "\
+ "\
:plug a lv2:Plugin ;\n\
lv2:binary <foo" SHLIB_EXT "> ;\n\
rdfs:seeAlso <plugin.ttl> .\n"
#if defined(__APPLE__)
-# define SHLIB_EXT ".dylib"
+# define SHLIB_EXT ".dylib"
#elif defined(_WIN32)
-# define SHLIB_EXT ".dll"
+# define SHLIB_EXT ".dll"
#else
-# define SHLIB_EXT ".so"
+# define SHLIB_EXT ".so"
#endif
-typedef struct
-{
- LilvWorld* world;
- LilvNode* plugin1_uri;
- LilvNode* plugin2_uri;
- char* test_bundle_path;
- char* test_bundle_uri;
- char* test_manifest_path;
- char* test_content_path;
- int test_count;
- int error_count;
+typedef struct {
+ LilvWorld* world;
+ LilvNode* plugin1_uri;
+ LilvNode* plugin2_uri;
+ char* test_bundle_path;
+ LilvNode* test_bundle_uri;
+ char* test_manifest_path;
+ char* test_content_path;
+ int test_count;
+ int error_count;
} LilvTestEnv;
// Create a new test environment with a world, common values, and test LV2_PATH
@@ -73,11 +59,17 @@ lilv_test_env_free(LilvTestEnv* env);
// Create a bundle with a manifest and plugin files, without loading anything
int
-create_bundle(LilvTestEnv* env, const char* manifest, const char* plugin);
+create_bundle(LilvTestEnv* env,
+ const char* name,
+ const char* manifest,
+ const char* plugin);
// Create a bundle with a manifest and plugin files, then load everything
int
-start_bundle(LilvTestEnv* env, const char* manifest, const char* plugin);
+start_bundle(LilvTestEnv* env,
+ const char* name,
+ const char* manifest,
+ const char* plugin);
// Remove the created bundle from the file system and free its paths in `env`
void
@@ -87,4 +79,8 @@ delete_bundle(LilvTestEnv* env);
void
set_env(const char* name, const char* value);
+// Create a unique temporary directory
+char*
+lilv_create_temporary_directory(const char* pattern);
+
#endif // LILV_TEST_UTILS_H
diff --git a/test/core.lv2/lv2core.ttl b/test/lv2/core.lv2/lv2core.ttl
index 5659487..5659487 100644
--- a/test/core.lv2/lv2core.ttl
+++ b/test/lv2/core.lv2/lv2core.ttl
diff --git a/test/core.lv2/manifest.ttl b/test/lv2/core.lv2/manifest.ttl
index a77ad71..a77ad71 100644
--- a/test/core.lv2/manifest.ttl
+++ b/test/lv2/core.lv2/manifest.ttl
diff --git a/test/lv2/core.lv2/meson.build b/test/lv2/core.lv2/meson.build
new file mode 100644
index 0000000..0d02ae1
--- /dev/null
+++ b/test/lv2/core.lv2/meson.build
@@ -0,0 +1,11 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+ttl_files = files(
+ 'lv2core.ttl',
+ 'manifest.ttl',
+)
+
+foreach file : ttl_files
+ configure_file(copy: true, input: file, output: '@PLAINNAME@')
+endforeach
diff --git a/test/meson.build b/test/meson.build
new file mode 100644
index 0000000..d305dad
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,115 @@
+# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+####################
+# Project Metadata #
+####################
+
+if get_option('warning_level') == 'everything'
+ # Check release metadata
+ if not meson.is_subproject()
+ autoship = find_program('autoship', required: false)
+ if autoship.found()
+ test('autoship', autoship, args: ['test', lilv_src_root], suite: 'data')
+ endif
+ endif
+
+ # Check licensing metadata
+ reuse = find_program('reuse', required: false)
+ if reuse.found()
+ test(
+ 'REUSE',
+ reuse,
+ args: ['--root', lilv_src_root, 'lint'],
+ suite: 'data',
+ )
+ endif
+endif
+
+##############
+# Test Setup #
+##############
+
+test_args = ['-DLILV_STATIC']
+if cc.get_id() == 'msvc'
+ test_args += [
+ '/wd4464', # relative include path contains '..'
+ ]
+endif
+
+subdir('lv2/core.lv2')
+
+################
+# Bundle Tests #
+################
+
+subdir('bad_syntax.lv2')
+subdir('failed_instantiation.lv2')
+subdir('failed_lib_descriptor.lv2')
+subdir('lib_descriptor.lv2')
+subdir('missing_descriptor.lv2')
+subdir('missing_name.lv2')
+subdir('missing_plugin.lv2')
+subdir('missing_port.lv2')
+subdir('missing_port_name.lv2')
+subdir('new_version.lv2')
+subdir('old_version.lv2')
+subdir('test_plugin.lv2')
+
+################
+# C++ Bindings #
+################
+
+if not get_option('bindings_cpp').disabled()
+ subdir('cpp')
+endif
+
+##############
+# Unit Tests #
+##############
+
+unit_tests = [
+ 'bad_port_index',
+ 'bad_port_symbol',
+ 'classes',
+ 'discovery',
+ 'get_symbol',
+ 'no_author',
+ 'no_verify',
+ 'plugin',
+ 'port',
+ 'preset',
+ 'project',
+ 'project_no_author',
+ 'prototype',
+ 'reload_bundle',
+ 'replace_version',
+ 'state',
+ 'string',
+ 'ui',
+ 'util',
+ 'value',
+ 'verify',
+ 'world',
+]
+
+define_args = [
+ '-DLILV_TEST_BUNDLE="@0@/"'.format(
+ meson.current_build_dir() / 'test_plugin.lv2',
+ ),
+ '-DLILV_TEST_DIR="@0@/"'.format(meson.current_build_dir()),
+]
+
+foreach unit : unit_tests
+ test(
+ unit,
+ executable(
+ 'test_@0@'.format(unit),
+ files('lilv_test_utils.c', 'test_@0@.c'.format(unit)),
+ c_args: define_args + test_args + c_suppressions,
+ include_directories: include_directories('../src'),
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ suite: 'unit',
+ )
+endforeach
diff --git a/test/missing_descriptor.lv2/meson.build b/test/missing_descriptor.lv2/meson.build
new file mode 100644
index 0000000..b4ad32f
--- /dev/null
+++ b/test/missing_descriptor.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'missing_descriptor',
+ files('missing_descriptor.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'missing_descriptor.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'missing_descriptor',
+ executable(
+ 'test_missing_descriptor',
+ files('test_missing_descriptor.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/missing_descriptor.lv2/missing_descriptor.c b/test/missing_descriptor.lv2/missing_descriptor.c
index ec1b473..ffcf7d6 100644
--- a/test/missing_descriptor.lv2/missing_descriptor.c
+++ b/test/missing_descriptor.lv2/missing_descriptor.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Missing descriptor
- Copyright 2011-2018 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.
-*/
+// Copyright 2011-2018 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
diff --git a/test/missing_descriptor.lv2/test_missing_descriptor.c b/test/missing_descriptor.lv2/test_missing_descriptor.c
index 023545d..b737048 100644
--- a/test/missing_descriptor.lv2/test_missing_descriptor.c
+++ b/test/missing_descriptor.lv2/test_missing_descriptor.c
@@ -1,49 +1,41 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/missing-descriptor"
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);
- assert(plugin);
-
- LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
- assert(!instance);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
+ assert(!instance);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/missing_name.lv2/meson.build b/test/missing_name.lv2/meson.build
new file mode 100644
index 0000000..c32cbb5
--- /dev/null
+++ b/test/missing_name.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'missing_name',
+ files('missing_name.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'missing_name.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'missing_name',
+ executable(
+ 'test_missing_name',
+ files('test_missing_name.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/missing_name.lv2/missing_name.c b/test/missing_name.lv2/missing_name.c
index 8945c1f..8538e73 100644
--- a/test/missing_name.lv2/missing_name.c
+++ b/test/missing_name.lv2/missing_name.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Missing name
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/missing-name"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,35 +43,43 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
- return (LV2_Handle)test;
+ 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;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/missing_name.lv2/test_missing_name.c b/test/missing_name.lv2/test_missing_name.c
index 416442b..a8df1ab 100644
--- a/test/missing_name.lv2/test_missing_name.c
+++ b/test/missing_name.lv2/test_missing_name.c
@@ -1,50 +1,42 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/missing-name"
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);
- assert(plugin);
-
- LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
- assert(instance);
- lilv_instance_free(instance);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
+ assert(instance);
+ lilv_instance_free(instance);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/missing_plugin.lv2/meson.build b/test/missing_plugin.lv2/meson.build
new file mode 100644
index 0000000..b5819ff
--- /dev/null
+++ b/test/missing_plugin.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'missing_plugin',
+ files('missing_plugin.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'missing_plugin.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'missing_plugin',
+ executable(
+ 'test_missing_plugin',
+ files('test_missing_plugin.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/missing_plugin.lv2/missing_plugin.c b/test/missing_plugin.lv2/missing_plugin.c
index bf45cbe..f496c6d 100644
--- a/test/missing_plugin.lv2/missing_plugin.c
+++ b/test/missing_plugin.lv2/missing_plugin.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Missing plugin
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -21,22 +7,22 @@
#include <stdlib.h>
static const LV2_Descriptor descriptor = {
- "http://example.org/not-the-plugin-you-are-looking-for",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
-};
+ "http://example.org/not-the-plugin-you-are-looking-for",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
LV2_SYMBOL_EXPORT
-const LV2_Descriptor* lv2_descriptor(uint32_t index)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- if (index == 0) {
- return &descriptor;
- }
+ if (index == 0) {
+ return &descriptor;
+ }
- return NULL;
+ return NULL;
}
diff --git a/test/missing_plugin.lv2/test_missing_plugin.c b/test/missing_plugin.lv2/test_missing_plugin.c
index 04daf31..6eb1705 100644
--- a/test/missing_plugin.lv2/test_missing_plugin.c
+++ b/test/missing_plugin.lv2/test_missing_plugin.c
@@ -1,49 +1,41 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/missing-plugin"
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);
- assert(plugin);
-
- LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
- assert(!instance);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL);
+ assert(!instance);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/missing_port.lv2/meson.build b/test/missing_port.lv2/meson.build
new file mode 100644
index 0000000..f6138d8
--- /dev/null
+++ b/test/missing_port.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'missing_port',
+ files('missing_port.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'missing_port.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'missing_port',
+ executable(
+ 'test_missing_port',
+ files('test_missing_port.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/missing_port.lv2/missing_port.c b/test/missing_port.lv2/missing_port.c
index 558eeb0..ce98c30 100644
--- a/test/missing_port.lv2/missing_port.c
+++ b/test/missing_port.lv2/missing_port.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Missing port
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/missing-port"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,35 +43,43 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
- return (LV2_Handle)test;
+ 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;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/missing_port.lv2/test_missing_port.c b/test/missing_port.lv2/test_missing_port.c
index 36b583e..463fd63 100644
--- a/test/missing_port.lv2/test_missing_port.c
+++ b/test/missing_port.lv2/test_missing_port.c
@@ -1,48 +1,40 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/missing-port"
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
- assert(lilv_plugin_get_num_ports(plugin) == 0);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
-}
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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
+ assert(lilv_plugin_get_num_ports(plugin) == 0);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/test/missing_port_name.lv2/meson.build b/test/missing_port_name.lv2/meson.build
new file mode 100644
index 0000000..3bddcee
--- /dev/null
+++ b/test/missing_port_name.lv2/meson.build
@@ -0,0 +1,36 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'missing_port_name',
+ files('missing_port_name.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'missing_port_name.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
+test(
+ 'missing_port_name',
+ executable(
+ 'test_missing_port_name',
+ files('test_missing_port_name.c'),
+ c_args: c_suppressions + test_args,
+ dependencies: [lv2_dep, lilv_static_dep],
+ ),
+ args: [meson.current_build_dir() / ''],
+ suite: 'plugin',
+)
+
diff --git a/test/missing_port_name.lv2/missing_port_name.c b/test/missing_port_name.lv2/missing_port_name.c
index f48203a..d10498f 100644
--- a/test/missing_port_name.lv2/missing_port_name.c
+++ b/test/missing_port_name.lv2/missing_port_name.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Missing port name
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/missing-port-name"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,35 +43,43 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
- return (LV2_Handle)test;
+ 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;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/missing_port_name.lv2/test_missing_port_name.c b/test/missing_port_name.lv2/test_missing_port_name.c
index 9a68b00..58e8120 100644
--- a/test/missing_port_name.lv2/test_missing_port_name.c
+++ b/test/missing_port_name.lv2/test_missing_port_name.c
@@ -1,52 +1,44 @@
-#undef NDEBUG
+// Copyright 2015-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
-#include "../src/filesystem.h"
+#undef NDEBUG
-#include "serd/serd.h"
#include "lilv/lilv.h"
#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#define PLUGIN_URI "http://example.org/missing-port-name"
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);
- assert(plugin);
-
- const LilvPort* port = lilv_plugin_get_port_by_index(plugin, 0);
- assert(port);
- LilvNode* name = lilv_port_get_name(plugin, port);
- assert(!name);
- lilv_node_free(name);
-
- lilv_node_free(plugin_uri);
- lilv_world_free(world);
-
- return 0;
+ 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
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, bundle_path);
+ lilv_world_load_bundle(world, bundle_uri);
+ 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);
+ assert(plugin);
+
+ const LilvPort* port = lilv_plugin_get_port_by_index(plugin, 0);
+ assert(port);
+ LilvNode* name = lilv_port_get_name(plugin, port);
+ assert(!name);
+ lilv_node_free(name);
+
+ lilv_node_free(plugin_uri);
+ lilv_world_free(world);
+
+ return 0;
}
-
diff --git a/test/new_version.lv2/meson.build b/test/new_version.lv2/meson.build
new file mode 100644
index 0000000..bd90443
--- /dev/null
+++ b/test/new_version.lv2/meson.build
@@ -0,0 +1,24 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'new_version',
+ files('new_version.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'new_version.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
diff --git a/test/new_version.lv2/new_version.c b/test/new_version.lv2/new_version.c
index 2669a83..64be4f5 100644
--- a/test/new_version.lv2/new_version.c
+++ b/test/new_version.lv2/new_version.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - New version
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/versioned"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,35 +43,43 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
- return (LV2_Handle)test;
+ 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;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/old_version.lv2/meson.build b/test/old_version.lv2/meson.build
new file mode 100644
index 0000000..09434b1
--- /dev/null
+++ b/test/old_version.lv2/meson.build
@@ -0,0 +1,24 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'old_version',
+ files('old_version.c'),
+ c_args: c_suppressions,
+ dependencies: lv2_dep,
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'old_version.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
diff --git a/test/old_version.lv2/old_version.c b/test/old_version.lv2/old_version.c
index 84d3b2c..64be4f5 100644
--- a/test/old_version.lv2/old_version.c
+++ b/test/old_version.lv2/old_version.c
@@ -1,19 +1,5 @@
-/*
- Lilv Test Plugin - Old version
- Copyright 2011-2019 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.
-*/
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#include "lv2/core/lv2.h"
@@ -22,36 +8,33 @@
#define PLUGIN_URI "http://example.org/versioned"
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1
-};
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1 };
typedef struct {
- float* input;
- float* output;
+ float* input;
+ float* output;
} Test;
static void
cleanup(LV2_Handle instance)
{
- free((Test*)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;
- }
+ 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
@@ -60,35 +43,43 @@ instantiate(const LV2_Descriptor* descriptor,
const char* path,
const LV2_Feature* const* features)
{
- Test* test = (Test*)calloc(1, sizeof(Test));
- if (!test) {
- return NULL;
- }
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+ (void)features;
- return (LV2_Handle)test;
+ 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;
+ (void)sample_count;
+
+ Test* test = (Test*)instance;
- *test->output = *test->input;
+ *test->output = *test->input;
}
static const LV2_Descriptor descriptor = {
- PLUGIN_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- NULL // extension_data
+ 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)
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
{
- return (index == 0) ? &descriptor : NULL;
+ return (index == 0) ? &descriptor : NULL;
}
diff --git a/test/test.lv2/test.c b/test/test.lv2/test.c
deleted file mode 100644
index fa3fb6e..0000000
--- a/test/test.lv2/test.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- Lilv Test Plugin
- Copyright 2011-2019 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.
-*/
-
-#define _POSIX_C_SOURCE 200809L
-
-#include "lv2/atom/atom.h"
-#include "lv2/core/lv2.h"
-#include "lv2/state/state.h"
-#include "lv2/urid/urid.h"
-
-#ifdef _MSC_VER
-# include <io.h>
-# define mkstemp(pat) _mktemp(pat)
-#endif
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define TEST_URI "http://example.org/lilv-test-plugin"
-
-#define TMP_TEMPLATE "lilv_testXXXXXX"
-
-enum {
- TEST_INPUT = 0,
- TEST_OUTPUT = 1,
- TEST_CONTROL = 2
-};
-
-typedef struct {
- LV2_URID_Map* map;
- LV2_State_Free_Path* free_path;
-
- struct {
- LV2_URID atom_Float;
- } uris;
-
- char tmp_file_path[sizeof(TMP_TEMPLATE)];
- char* rec_file_path;
- FILE* rec_file;
-
- float* input;
- float* output;
- unsigned num_runs;
-} Test;
-
-static void
-cleanup(LV2_Handle instance)
-{
- Test* test = (Test*)instance;
- if (test->rec_file) {
- fclose(test->rec_file);
- }
-
- if (test->free_path) {
- test->free_path->free_path(test->free_path->handle,
- test->rec_file_path);
- }
-
- free(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;
- case TEST_CONTROL:
- 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;
- }
-
- strncpy(test->tmp_file_path, TMP_TEMPLATE, strlen(TMP_TEMPLATE) + 1);
- mkstemp(test->tmp_file_path);
-
- LV2_State_Make_Path* make_path = NULL;
-
- for (int i = 0; features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
- test->map = (LV2_URID_Map*)features[i]->data;
- test->uris.atom_Float = test->map->map(
- test->map->handle, LV2_ATOM__Float);
- } else if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
- make_path = (LV2_State_Make_Path*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
- test->free_path = (LV2_State_Free_Path*)features[i]->data;
- }
- }
-
- if (!test->map) {
- fprintf(stderr, "Host does not support urid:map\n");
- free(test);
- return NULL;
- }
-
- if (make_path) {
- if (!test->free_path) {
- fprintf(stderr, "Host provided make_path without free_path\n");
- free(test);
- return NULL;
- }
-
- test->rec_file_path = make_path->path(make_path->handle, "recfile");
- if (!(test->rec_file = fopen(test->rec_file_path, "w"))) {
- fprintf(stderr, "ERROR: Failed to open rec file\n");
- }
- fprintf(test->rec_file, "instantiate\n");
- }
-
- return (LV2_Handle)test;
-}
-
-static void
-run(LV2_Handle instance,
- uint32_t sample_count)
-{
- Test* test = (Test*)instance;
- *test->output = *test->input;
- if (sample_count == 1) {
- ++test->num_runs;
- } else if (sample_count == 2 && test->rec_file) {
- // Append to rec file (changes size)
- fprintf(test->rec_file, "run\n");
- } else if (sample_count == 3 && test->rec_file) {
- // Change the first byte of rec file (doesn't change size)
- fseek(test->rec_file, 0, SEEK_SET);
- fprintf(test->rec_file, "X");
- fseek(test->rec_file, 0, SEEK_END);
- }
-}
-
-static uint32_t
-map_uri(Test* plugin, const char* uri)
-{
- return plugin->map->map(plugin->map->handle, uri);
-}
-
-static LV2_State_Status
-save(LV2_Handle instance,
- LV2_State_Store_Function store,
- void* callback_data,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- Test* plugin = (Test*)instance;
-
- LV2_State_Map_Path* map_path = NULL;
- LV2_State_Make_Path* make_path = NULL;
- LV2_State_Free_Path* free_path = NULL;
- for (int i = 0; features && features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_STATE__mapPath)) {
- map_path = (LV2_State_Map_Path*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
- make_path = (LV2_State_Make_Path*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
- free_path = (LV2_State_Free_Path*)features[i]->data;
- }
- }
-
- if (!map_path || !free_path) {
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- store(callback_data,
- map_uri(plugin, "http://example.org/greeting"),
- "hello",
- strlen("hello") + 1,
- map_uri(plugin, LV2_ATOM__String),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- const uint32_t urid = map_uri(plugin, "http://example.org/urivalue");
- store(callback_data,
- map_uri(plugin, "http://example.org/uri"),
- &urid,
- sizeof(uint32_t),
- map_uri(plugin, LV2_ATOM__URID),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- // Try to store second value for the same property (should fail)
- const uint32_t urid2 = map_uri(plugin, "http://example.org/urivalue2");
- if (!store(callback_data,
- map_uri(plugin, "http://example.org/uri"),
- &urid2,
- sizeof(uint32_t),
- map_uri(plugin, LV2_ATOM__URID),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
- return LV2_STATE_ERR_UNKNOWN;
- }
-
- // Try to store with a null key (should fail)
- if (!store(callback_data,
- 0,
- &urid2,
- sizeof(uint32_t),
- map_uri(plugin, LV2_ATOM__URID),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
- return LV2_STATE_ERR_UNKNOWN;
- }
-
- store(callback_data,
- map_uri(plugin, "http://example.org/num-runs"),
- &plugin->num_runs,
- sizeof(plugin->num_runs),
- map_uri(plugin, LV2_ATOM__Int),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- const float two = 2.0f;
- store(callback_data,
- map_uri(plugin, "http://example.org/two"),
- &two,
- sizeof(two),
- map_uri(plugin, LV2_ATOM__Float),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- const uint32_t affirmative = 1;
- store(callback_data,
- map_uri(plugin, "http://example.org/true"),
- &affirmative,
- sizeof(affirmative),
- map_uri(plugin, LV2_ATOM__Bool),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- const uint32_t negative = 0;
- store(callback_data,
- map_uri(plugin, "http://example.org/false"),
- &negative,
- sizeof(negative),
- map_uri(plugin, LV2_ATOM__Bool),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- const uint8_t blob[] = "I am a blob of arbitrary data.";
- store(callback_data,
- map_uri(plugin, "http://example.org/blob"),
- blob,
- sizeof(blob),
- map_uri(plugin, "http://example.org/SomeUnknownType"),
- LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
-
- if (map_path) {
- FILE* file = fopen(plugin->tmp_file_path, "w");
- fprintf(file, "Hello\n");
- fclose(file);
- char* apath = map_path->abstract_path(map_path->handle,
- plugin->tmp_file_path);
- char* apath2 = map_path->abstract_path(map_path->handle,
- plugin->tmp_file_path);
- if (strcmp(apath, apath2)) {
- fprintf(stderr, "ERROR: Path %s != %s\n", apath, apath2);
- }
-
- store(callback_data,
- map_uri(plugin, "http://example.org/extfile"),
- apath,
- strlen(apath) + 1,
- map_uri(plugin, LV2_ATOM__Path),
- LV2_STATE_IS_POD);
-
- free_path->free_path(free_path->handle, apath);
- free_path->free_path(free_path->handle, apath2);
-
- if (plugin->rec_file) {
- fflush(plugin->rec_file);
- apath = map_path->abstract_path(map_path->handle,
- plugin->rec_file_path);
-
- store(callback_data,
- map_uri(plugin, "http://example.org/recfile"),
- apath,
- strlen(apath) + 1,
- map_uri(plugin, LV2_ATOM__Path),
- LV2_STATE_IS_POD);
-
- free_path->free_path(free_path->handle, apath);
- }
-
- if (make_path) {
- char* spath = make_path->path(make_path->handle, "save");
- FILE* sfile = fopen(spath, "w");
- fprintf(sfile, "save");
- fclose(sfile);
-
- apath = map_path->abstract_path(map_path->handle, spath);
- store(callback_data,
- map_uri(plugin, "http://example.org/save-file"),
- apath,
- strlen(apath) + 1,
- map_uri(plugin, LV2_ATOM__Path),
- LV2_STATE_IS_POD);
- free_path->free_path(free_path->handle, apath);
- free_path->free_path(free_path->handle, spath);
- }
- }
-
- return LV2_STATE_SUCCESS;
-}
-
-static LV2_State_Status
-restore(LV2_Handle instance,
- LV2_State_Retrieve_Function retrieve,
- void* callback_data,
- uint32_t flags,
- const LV2_Feature* const* features)
-{
- Test* plugin = (Test*)instance;
-
- LV2_State_Map_Path* map_path = NULL;
- LV2_State_Free_Path* free_path = NULL;
- for (int i = 0; features && features[i]; ++i) {
- if (!strcmp(features[i]->URI, LV2_STATE__mapPath)) {
- map_path = (LV2_State_Map_Path*)features[i]->data;
- } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
- free_path = (LV2_State_Free_Path*)features[i]->data;
- }
- }
-
- size_t size;
- uint32_t type;
- uint32_t valflags;
-
- plugin->num_runs = *(int32_t*)retrieve(
- callback_data,
- map_uri(plugin, "http://example.org/num-runs"),
- &size, &type, &valflags);
-
- if (!map_path || !free_path) {
- return LV2_STATE_ERR_NO_FEATURE;
- }
-
- char* apath = (char*)retrieve(
- callback_data,
- map_uri(plugin, "http://example.org/extfile"),
- &size, &type, &valflags);
-
- if (valflags != LV2_STATE_IS_POD) {
- fprintf(stderr, "error: Restored bad file flags\n");
- return LV2_STATE_ERR_BAD_FLAGS;
- }
-
- if (apath) {
- char* path = map_path->absolute_path(map_path->handle, apath);
- FILE* f = fopen(path, "r");
- char str[8];
- size_t n_read = fread(str, 1, sizeof(str), f);
- fclose(f);
- if (strncmp(str, "Hello\n", n_read)) {
- fprintf(stderr, "error: Restored bad file contents `%s' != `Hello'\n",
- str);
- }
- free_path->free_path(free_path->handle, path);
- }
-
- apath = (char*)retrieve(
- callback_data,
- map_uri(plugin, "http://example.org/save-file"),
- &size, &type, &valflags);
- if (apath) {
- char* spath = map_path->absolute_path(map_path->handle, apath);
- FILE* sfile = fopen(spath, "r");
- if (!sfile) {
- fprintf(stderr, "error: Failed to open save file %s\n", spath);
- } else {
- fclose(sfile);
- }
- free_path->free_path(free_path->handle, spath);
- } else {
- fprintf(stderr, "error: Failed to restore save file.\n");
- }
-
- return LV2_STATE_SUCCESS;
-}
-
-static const void*
-extension_data(const char* uri)
-{
- static const LV2_State_Interface state = { save, restore };
- if (!strcmp(uri, LV2_STATE__interface)) {
- return &state;
- }
- return NULL;
-}
-
-static const LV2_Descriptor descriptor = {
- TEST_URI,
- instantiate,
- connect_port,
- NULL, // activate,
- run,
- NULL, // deactivate,
- cleanup,
- extension_data
-};
-
-LV2_SYMBOL_EXPORT
-const LV2_Descriptor* lv2_descriptor(uint32_t index)
-{
- switch (index) {
- case 0:
- return &descriptor;
- default:
- return NULL;
- }
-}
diff --git a/test/test_bad_port_index.c b/test/test_bad_port_index.c
index a4d9ad2..99bdfc6 100644
--- a/test/test_bad_port_index.c
+++ b/test/test_bad_port_index.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -38,21 +25,25 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ if (create_bundle(
+ env, "bad_port_index.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- uint32_t n_ports = lilv_plugin_get_num_ports(plug);
- assert(n_ports == 0);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- delete_bundle(env);
- lilv_test_env_free(env);
+ uint32_t n_ports = lilv_plugin_get_num_ports(plug);
+ assert(n_ports == 0);
- return 0;
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_bad_port_symbol.c b/test/test_bad_port_symbol.c
index be00986..2422e15 100644
--- a/test/test_bad_port_symbol.c
+++ b/test/test_bad_port_symbol.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -38,21 +25,25 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ if (create_bundle(
+ env, "bad_port_symbol.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- uint32_t n_ports = lilv_plugin_get_num_ports(plug);
- assert(n_ports == 0);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- delete_bundle(env);
- lilv_test_env_free(env);
+ uint32_t n_ports = lilv_plugin_get_num_ports(plug);
+ assert(n_ports == 0);
- return 0;
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_classes.c b/test/test_classes.c
index 2c74c07..2d33a57 100644
--- a/test/test_classes.c
+++ b/test/test_classes.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -38,38 +25,43 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ lilv_world_load_all(world);
+
+ if (create_bundle(env, "classes.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPluginClass* plugin = lilv_world_get_plugin_class(world);
- const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world);
- LilvPluginClasses* children = lilv_plugin_class_get_children(plugin);
+ const LilvPluginClass* plugin = lilv_world_get_plugin_class(world);
+ const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world);
+ LilvPluginClasses* children = lilv_plugin_class_get_children(plugin);
- assert(lilv_plugin_class_get_parent_uri(plugin) == NULL);
- assert(lilv_plugin_classes_size(classes) >
- lilv_plugin_classes_size(children));
- assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_label(plugin)),
- "Plugin"));
- assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_uri(plugin)),
- "http://lv2plug.in/ns/lv2core#Plugin"));
+ assert(lilv_plugin_class_get_parent_uri(plugin) == NULL);
+ assert(lilv_plugin_classes_size(classes) >
+ lilv_plugin_classes_size(children));
+ assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_label(plugin)),
+ "Plugin"));
+ assert(!strcmp(lilv_node_as_string(lilv_plugin_class_get_uri(plugin)),
+ "http://lv2plug.in/ns/lv2core#Plugin"));
- LILV_FOREACH (plugin_classes, i, children) {
- assert(lilv_node_equals(lilv_plugin_class_get_parent_uri(
- lilv_plugin_classes_get(children, i)),
- lilv_plugin_class_get_uri(plugin)));
- }
+ LILV_FOREACH (plugin_classes, i, children) {
+ assert(lilv_node_equals(
+ lilv_plugin_class_get_parent_uri(lilv_plugin_classes_get(children, i)),
+ lilv_plugin_class_get_uri(plugin)));
+ }
- LilvNode* some_uri = lilv_new_uri(world, "http://example.org/whatever");
- assert(lilv_plugin_classes_get_by_uri(classes, some_uri) == NULL);
- lilv_node_free(some_uri);
+ LilvNode* some_uri = lilv_new_uri(world, "http://example.org/whatever");
+ assert(lilv_plugin_classes_get_by_uri(classes, some_uri) == NULL);
+ lilv_node_free(some_uri);
- lilv_plugin_classes_free(children);
- delete_bundle(env);
- lilv_test_env_free(env);
+ lilv_plugin_classes_free(children);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_discovery.c b/test/test_discovery.c
index 2585959..7d38207 100644
--- a/test/test_discovery.c
+++ b/test/test_discovery.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -39,58 +26,59 @@ static int discovery_plugin_found = 0;
static void
discovery_verify_plugin(const LilvTestEnv* env, const LilvPlugin* plugin)
{
- const LilvNode* value = lilv_plugin_get_uri(plugin);
- if (lilv_node_equals(value, env->plugin1_uri)) {
- const LilvNode* lib_uri = NULL;
- assert(!lilv_node_equals(value, env->plugin2_uri));
- discovery_plugin_found = 1;
- lib_uri = lilv_plugin_get_library_uri(plugin);
- assert(lib_uri);
- assert(lilv_node_is_uri(lib_uri));
- assert(lilv_node_as_uri(lib_uri));
- assert(strstr(lilv_node_as_uri(lib_uri), "foo" SHLIB_EXT));
- assert(lilv_plugin_verify(plugin));
- }
+ const LilvNode* value = lilv_plugin_get_uri(plugin);
+ if (lilv_node_equals(value, env->plugin1_uri)) {
+ const LilvNode* lib_uri = NULL;
+ assert(!lilv_node_equals(value, env->plugin2_uri));
+ discovery_plugin_found = 1;
+ lib_uri = lilv_plugin_get_library_uri(plugin);
+ assert(lib_uri);
+ assert(lilv_node_is_uri(lib_uri));
+ assert(lilv_node_as_uri(lib_uri));
+ assert(strstr(lilv_node_as_uri(lib_uri), "foo" SHLIB_EXT));
+ assert(lilv_plugin_verify(plugin));
+ }
}
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ if (create_bundle(env, "discovery.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- assert(lilv_plugins_size(plugins) > 0);
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPlugin* plug1 =
- lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ assert(lilv_plugins_size(plugins) > 0);
- const LilvPlugin* plug2 =
- lilv_plugins_get_by_uri(plugins, env->plugin2_uri);
+ const LilvPlugin* plug1 = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug1);
- assert(!plug2);
+ const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, env->plugin2_uri);
- {
- LilvNode* name = lilv_plugin_get_name(plug1);
- assert(!strcmp(lilv_node_as_string(name), "Test plugin"));
- lilv_node_free(name);
- }
+ assert(plug1);
+ assert(!plug2);
- discovery_plugin_found = 0;
- LILV_FOREACH (plugins, i, plugins) {
- discovery_verify_plugin(env, lilv_plugins_get(plugins, i));
- }
+ {
+ LilvNode* name = lilv_plugin_get_name(plug1);
+ assert(!strcmp(lilv_node_as_string(name), "Test plugin"));
+ lilv_node_free(name);
+ }
- assert(discovery_plugin_found);
- plugins = NULL;
+ discovery_plugin_found = 0;
+ LILV_FOREACH (plugins, i, plugins) {
+ discovery_verify_plugin(env, lilv_plugins_get(plugins, i));
+ }
- delete_bundle(env);
- lilv_test_env_free(env);
+ assert(discovery_plugin_found);
+ plugins = NULL;
- return 0;
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_filesystem.c b/test/test_filesystem.c
deleted file mode 100644
index 8c7b1ba..0000000
--- a/test/test_filesystem.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- Copyright 2020 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.
-*/
-
-#undef NDEBUG
-
-#include "lilv_internal.h"
-
-#include "../src/filesystem.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static bool
-equals(char* string, const char* expected)
-{
- const bool result = !strcmp(string, expected);
- free(string);
- return result;
-}
-
-static void
-test_temp_directory_path(void)
-{
- char* tmpdir = lilv_temp_directory_path();
-
- assert(lilv_is_directory(tmpdir));
-
- free(tmpdir);
-}
-
-static void
-test_path_is_absolute(void)
-{
- assert(lilv_path_is_absolute("/a/b"));
- assert(lilv_path_is_absolute("/a"));
- assert(lilv_path_is_absolute("/"));
-
- assert(!lilv_path_is_absolute("a/b"));
- assert(!lilv_path_is_absolute("a"));
- assert(!lilv_path_is_absolute("."));
-}
-
-static void
-test_path_is_child(void)
-{
- assert(lilv_path_is_child("/a/b", "/a"));
- assert(lilv_path_is_child("/a/b", "/a/"));
- assert(lilv_path_is_child("/a/b/", "/a"));
- assert(lilv_path_is_child("/a/b/", "/a/"));
-
- assert(!lilv_path_is_child("/a/b", "/a/c"));
- assert(!lilv_path_is_child("/a/b", "/a/c/"));
- assert(!lilv_path_is_child("/a/b/", "/a/c"));
- assert(!lilv_path_is_child("/a/b/", "/a/c/"));
-
- assert(!lilv_path_is_child("/a/b", "/c"));
- assert(!lilv_path_is_child("/a/b", "/c/"));
- assert(!lilv_path_is_child("/a/b/", "/c"));
- assert(!lilv_path_is_child("/a/b/", "/c/"));
-}
-
-static void
-test_path_current(void)
-{
- char* cwd = lilv_path_current();
-
- assert(lilv_is_directory(cwd));
-
- free(cwd);
-}
-
-static void
-test_path_absolute(void)
-{
- const char* const short_path = "a";
- const char* const long_path = "a/b/c";
-
- char* const cwd = lilv_path_current();
- char* const expected_short = lilv_path_join(cwd, short_path);
- char* const expected_long = lilv_path_join(cwd, long_path);
-
- assert(equals(lilv_path_absolute(short_path), expected_short));
- assert(equals(lilv_path_absolute(long_path), expected_long));
-
- free(expected_long);
- free(expected_short);
- free(cwd);
-}
-
-static void
-test_path_relative_to(void)
-{
- assert(equals(lilv_path_relative_to("/a/b", "/a/"), "b"));
- assert(equals(lilv_path_relative_to("/a", "/b/c/"), "/a"));
- assert(equals(lilv_path_relative_to("/a/b/c", "/a/b/d/"), "../c"));
- assert(equals(lilv_path_relative_to("/a/b/c", "/a/b/d/e/"), "../../c"));
-}
-
-static void
-test_path_parent(void)
-{
- assert(equals(lilv_path_parent("/"), "/"));
- assert(equals(lilv_path_parent("//"), "/"));
- assert(equals(lilv_path_parent("/a"), "/"));
- assert(equals(lilv_path_parent("/a/"), "/"));
- assert(equals(lilv_path_parent("/a///b/"), "/a"));
- assert(equals(lilv_path_parent("/a///b//"), "/a"));
- assert(equals(lilv_path_parent("/a/b"), "/a"));
- assert(equals(lilv_path_parent("/a/b/"), "/a"));
- assert(equals(lilv_path_parent("/a/b/c"), "/a/b"));
- assert(equals(lilv_path_parent("/a/b/c/"), "/a/b"));
- assert(equals(lilv_path_parent("a"), "."));
-}
-
-static void
-test_path_join(void)
-{
- assert(lilv_path_join(NULL, NULL) == NULL);
- assert(lilv_path_join(NULL, "") == NULL);
- assert(equals(lilv_path_join("", NULL), "/"));
- assert(equals(lilv_path_join("", ""), "/"));
-
- assert(equals(lilv_path_join("/a", ""), "/a/"));
- assert(equals(lilv_path_join("/a/b", ""), "/a/b/"));
- assert(equals(lilv_path_join("/a/", ""), "/a/"));
- assert(equals(lilv_path_join("/a/b/", ""), "/a/b/"));
- assert(equals(lilv_path_join("a", ""), "a/"));
- assert(equals(lilv_path_join("a/b", ""), "a/b/"));
- assert(equals(lilv_path_join("a/", ""), "a/"));
- assert(equals(lilv_path_join("a/b/", ""), "a/b/"));
-
- assert(equals(lilv_path_join("/a", NULL), "/a/"));
- assert(equals(lilv_path_join("/a/b", NULL), "/a/b/"));
- assert(equals(lilv_path_join("/a/", NULL), "/a/"));
- assert(equals(lilv_path_join("/a/b/", NULL), "/a/b/"));
- assert(equals(lilv_path_join("a", NULL), "a/"));
- assert(equals(lilv_path_join("a/b", NULL), "a/b/"));
- assert(equals(lilv_path_join("a/", NULL), "a/"));
- assert(equals(lilv_path_join("a/b/", NULL), "a/b/"));
-
- assert(equals(lilv_path_join("/a", "b"), "/a/b"));
- assert(equals(lilv_path_join("/a/", "b"), "/a/b"));
- assert(equals(lilv_path_join("a", "b"), "a/b"));
- assert(equals(lilv_path_join("a/", "b"), "a/b"));
-
- assert(equals(lilv_path_join("/a", "b/"), "/a/b/"));
- assert(equals(lilv_path_join("/a/", "b/"), "/a/b/"));
- assert(equals(lilv_path_join("a", "b/"), "a/b/"));
- assert(equals(lilv_path_join("a/", "b/"), "a/b/"));
-}
-
-static void
-test_path_canonical(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const file_path = lilv_path_join(temp_dir, "lilv_test_file");
-
- FILE* f = fopen(file_path, "w");
- fprintf(f, "test\n");
- fclose(f);
-
-#ifndef _WIN32
- // Test symlink resolution
-
- char* const link_path = lilv_path_join(temp_dir, "lilv_test_link");
-
- assert(!lilv_symlink(file_path, link_path));
-
- char* const real_file_path = lilv_path_canonical(file_path);
- char* const real_link_path = lilv_path_canonical(link_path);
-
- assert(!strcmp(real_file_path, real_link_path));
-
- assert(!lilv_remove(link_path));
- free(real_link_path);
- free(real_file_path);
- free(link_path);
-#endif
-
- // Test dot segment resolution
-
- char* const parent_dir_1 = lilv_path_join(temp_dir, "..");
- char* const parent_dir_2 = lilv_path_parent(temp_dir);
- char* const real_parent_dir_1 = lilv_path_canonical(parent_dir_1);
- char* const real_parent_dir_2 = lilv_path_canonical(parent_dir_2);
-
- assert(!strcmp(real_parent_dir_1, real_parent_dir_2));
-
- // Clean everything up
-
- assert(!lilv_remove(file_path));
- assert(!lilv_remove(temp_dir));
-
- free(real_parent_dir_2);
- free(real_parent_dir_1);
- free(parent_dir_2);
- free(parent_dir_1);
- free(file_path);
- free(temp_dir);
-}
-
-static void
-test_path_exists(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const file_path = lilv_path_join(temp_dir, "lilv_test_file");
-
- assert(!lilv_path_exists(file_path));
-
- FILE* f = fopen(file_path, "w");
- fprintf(f, "test\n");
- fclose(f);
-
- assert(lilv_path_exists(file_path));
-
- assert(!lilv_remove(file_path));
- assert(!lilv_remove(temp_dir));
-
- free(file_path);
- free(temp_dir);
-}
-
-static void
-test_is_directory(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const file_path = lilv_path_join(temp_dir, "lilv_test_file");
-
- assert(lilv_is_directory(temp_dir));
- assert(!lilv_is_directory(file_path)); // Nonexistent
-
- FILE* f = fopen(file_path, "w");
- fprintf(f, "test\n");
- fclose(f);
-
- assert(!lilv_is_directory(file_path)); // File
-
- assert(!lilv_remove(file_path));
- assert(!lilv_remove(temp_dir));
-
- free(file_path);
- free(temp_dir);
-}
-
-static void
-test_copy_file(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const file_path = lilv_path_join(temp_dir, "lilv_test_file");
- char* const copy_path = lilv_path_join(temp_dir, "lilv_test_copy");
-
- FILE* f = fopen(file_path, "w");
- fprintf(f, "test\n");
- fclose(f);
-
- assert(!lilv_copy_file(file_path, copy_path));
- assert(lilv_file_equals(file_path, copy_path));
-
- if (lilv_path_exists("/dev/full")) {
- // Copy short file (error after flushing)
- assert(lilv_copy_file(file_path, "/dev/full") == ENOSPC);
-
- // Copy long file (error during writing)
- f = fopen(file_path, "w");
- for (size_t i = 0; i < 4096; ++i) {
- fprintf(f, "test\n");
- }
- fclose(f);
- assert(lilv_copy_file(file_path, "/dev/full") == ENOSPC);
- }
-
- assert(!lilv_remove(copy_path));
- assert(!lilv_remove(file_path));
- assert(!lilv_remove(temp_dir));
-
- free(copy_path);
- free(file_path);
- free(temp_dir);
-}
-
-static void
-test_flock(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const file_path = lilv_path_join(temp_dir, "lilv_test_file");
-
- FILE* const f1 = fopen(file_path, "w");
- FILE* const f2 = fopen(file_path, "w");
-
- assert(!lilv_flock(f1, true, false));
- assert(lilv_flock(f2, true, false));
- assert(!lilv_flock(f1, false, false));
-
- fclose(f2);
- fclose(f1);
- assert(!lilv_remove(file_path));
- assert(!lilv_remove(temp_dir));
- free(file_path);
- free(temp_dir);
-}
-
-typedef struct
-{
- size_t n_names;
- char** names;
-} FileList;
-
-static void
-visit(const char* const path, const char* const name, void* const data)
-{
- FileList* file_list = (FileList*)data;
-
- file_list->names =
- (char**)realloc(file_list->names, sizeof(char*) * ++file_list->n_names);
-
- file_list->names[file_list->n_names - 1] = lilv_strdup(name);
-}
-
-static void
-test_dir_for_each(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const path1 = lilv_path_join(temp_dir, "lilv_test_1");
- char* const path2 = lilv_path_join(temp_dir, "lilv_test_2");
-
- FILE* const f1 = fopen(path1, "w");
- FILE* const f2 = fopen(path2, "w");
- fprintf(f1, "test\n");
- fprintf(f2, "test\n");
- fclose(f2);
- fclose(f1);
-
- FileList file_list = {0, NULL};
- lilv_dir_for_each(temp_dir, &file_list, visit);
-
- assert((!strcmp(file_list.names[0], "lilv_test_1") &&
- !strcmp(file_list.names[1], "lilv_test_2")) ||
- (!strcmp(file_list.names[0], "lilv_test_2") &&
- !strcmp(file_list.names[1], "lilv_test_1")));
-
- assert(!lilv_remove(path2));
- assert(!lilv_remove(path1));
- assert(!lilv_remove(temp_dir));
-
- free(file_list.names[0]);
- free(file_list.names[1]);
- free(file_list.names);
- free(path2);
- free(path1);
- free(temp_dir);
-}
-
-static void
-test_create_temporary_directory(void)
-{
- char* const path1 = lilv_create_temporary_directory("lilvXXXXXX");
-
- assert(lilv_is_directory(path1));
-
- char* const path2 = lilv_create_temporary_directory("lilvXXXXXX");
-
- assert(strcmp(path1, path2));
- assert(lilv_is_directory(path2));
-
- assert(!lilv_remove(path2));
- assert(!lilv_remove(path1));
- free(path2);
- free(path1);
-}
-
-static void
-test_create_directories(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
-
- assert(lilv_is_directory(temp_dir));
-
- char* const child_dir = lilv_path_join(temp_dir, "child");
- char* const grandchild_dir = lilv_path_join(child_dir, "grandchild");
-
- assert(!lilv_create_directories(grandchild_dir));
- assert(lilv_is_directory(grandchild_dir));
- assert(lilv_is_directory(child_dir));
-
- char* const file_path = lilv_path_join(temp_dir, "lilv_test_file");
- FILE* const f = fopen(file_path, "w");
-
- fprintf(f, "test\n");
- fclose(f);
-
- assert(lilv_create_directories(file_path));
-
- assert(!lilv_remove(file_path));
- assert(!lilv_remove(grandchild_dir));
- assert(!lilv_remove(child_dir));
- assert(!lilv_remove(temp_dir));
- free(file_path);
- free(child_dir);
- free(grandchild_dir);
- free(temp_dir);
-}
-
-static void
-test_file_equals(void)
-{
- char* const temp_dir = lilv_create_temporary_directory("lilvXXXXXX");
- char* const path1 = lilv_path_join(temp_dir, "lilv_test_1");
- char* const path2 = lilv_path_join(temp_dir, "lilv_test_2");
-
- FILE* const f1 = fopen(path1, "w");
- FILE* const f2 = fopen(path2, "w");
- fprintf(f1, "test\n");
- fprintf(f2, "test\n");
-
- assert(lilv_file_equals(path1, path2));
-
- fprintf(f2, "diff\n");
- fflush(f2);
-
- assert(!lilv_file_equals(path1, path2));
-
- fclose(f2);
- fclose(f1);
-
- assert(!lilv_remove(path2));
- assert(!lilv_remove(path1));
- assert(!lilv_remove(temp_dir));
-
- free(path2);
- free(path1);
- free(temp_dir);
-}
-
-int
-main(void)
-{
- test_temp_directory_path();
- test_path_is_absolute();
- test_path_is_child();
- test_path_current();
- test_path_absolute();
- test_path_relative_to();
- test_path_parent();
- test_path_join();
- test_path_canonical();
- test_path_exists();
- test_is_directory();
- test_copy_file();
- test_flock();
- test_dir_for_each();
- test_create_temporary_directory();
- test_create_directories();
- test_file_equals();
-
- return 0;
-}
diff --git a/test/test_get_symbol.c b/test/test_get_symbol.c
index 0427447..5dc5898 100644
--- a/test/test_get_symbol.c
+++ b/test/test_get_symbol.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -37,45 +24,48 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "get_symbol.lv2", manifest_ttl, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, manifest_ttl, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- LilvNode* plug_sym = lilv_world_get_symbol(world, env->plugin1_uri);
- 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);
+ LilvNode* plug_sym = lilv_world_get_symbol(world, env->plugin1_uri);
+ 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);
- assert(lilv_world_get_symbol(world, nonuri) == NULL);
- assert(!strcmp(lilv_node_as_string(plug_sym), "plugsym"));
- assert(!strcmp(lilv_node_as_string(path_sym), "foo"));
- assert(!strcmp(lilv_node_as_string(query_sym), "bar_baz"));
- assert(!strcmp(lilv_node_as_string(frag_sym), "bar"));
- assert(!strcmp(lilv_node_as_string(queryfrag_sym), "quux"));
+ assert(lilv_world_get_symbol(world, nonuri) == NULL);
+ assert(!strcmp(lilv_node_as_string(plug_sym), "plugsym"));
+ assert(!strcmp(lilv_node_as_string(path_sym), "foo"));
+ assert(!strcmp(lilv_node_as_string(query_sym), "bar_baz"));
+ assert(!strcmp(lilv_node_as_string(frag_sym), "bar"));
+ 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);
+ 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);
- delete_bundle(env);
- lilv_test_env_free(env);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_no_author.c b/test/test_no_author.c
index 9cceedc..396ae9e 100644
--- a/test/test_no_author.c
+++ b/test/test_no_author.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -60,28 +47,31 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "no_author.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!author_name);
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!author_name);
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!author_email);
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!author_email);
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(!author_homepage);
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(!author_homepage);
- delete_bundle(env);
- lilv_test_env_free(env);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_no_verify.c b/test/test_no_verify.c
index 70812a5..66f81e9 100644
--- a/test/test_no_verify.c
+++ b/test/test_no_verify.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -27,22 +14,24 @@ static const char* const plugin_ttl = ":plug a lv2:Plugin .\n";
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ if (create_bundle(env, "no_verify.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* explug =
- lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- assert(explug);
- assert(!lilv_plugin_verify(explug));
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- delete_bundle(env);
- lilv_test_env_free(env);
+ assert(explug);
+ assert(!lilv_plugin_verify(explug));
- return 0;
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_plugin.c b/test/test_plugin.c
index 6eab638..e2b9b53 100644
--- a/test/test_plugin.c
+++ b/test/test_plugin.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -79,218 +66,218 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
-
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- const LilvPluginClass* klass = lilv_plugin_get_class(plug);
- const LilvNode* klass_uri = lilv_plugin_class_get_uri(klass);
- assert(!strcmp(lilv_node_as_string(klass_uri),
- "http://lv2plug.in/ns/lv2core#CompressorPlugin"));
-
- LilvNode* rdf_type =
- lilv_new_uri(world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
- assert(
- lilv_world_ask(world, lilv_plugin_get_uri(plug), rdf_type, klass_uri));
- lilv_node_free(rdf_type);
-
- assert(!lilv_plugin_is_replaced(plug));
- assert(!lilv_plugin_get_related(plug, NULL));
-
- const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
- assert(!strcmp(lilv_node_as_string(plug_bundle_uri), env->test_bundle_uri));
-
- const LilvNodes* data_uris = lilv_plugin_get_data_uris(plug);
- assert(lilv_nodes_size(data_uris) == 2);
-
- LilvNode* project = lilv_plugin_get_project(plug);
- assert(!project);
-
- char* manifest_uri = lilv_strjoin(lilv_node_as_string(plug_bundle_uri),
- "manifest.ttl",
- NULL);
-
- char* data_uri =
- lilv_strjoin(lilv_node_as_string(plug_bundle_uri), "plugin.ttl", NULL);
-
- LilvNode* manifest_uri_val = lilv_new_uri(world, manifest_uri);
- assert(lilv_nodes_contains(data_uris, manifest_uri_val));
- lilv_node_free(manifest_uri_val);
-
- LilvNode* data_uri_val = lilv_new_uri(world, data_uri);
- assert(lilv_nodes_contains(data_uris, data_uri_val));
- lilv_node_free(data_uri_val);
-
- LilvNode* unknown_uri_val =
- lilv_new_uri(world, "http://example.org/unknown");
- assert(!lilv_nodes_contains(data_uris, unknown_uri_val));
- lilv_node_free(unknown_uri_val);
-
- free(manifest_uri);
- free(data_uri);
-
- float mins[3];
- float maxs[3];
- float defs[3];
- lilv_plugin_get_port_ranges_float(plug, mins, maxs, defs);
- assert(mins[0] == -1.0f);
- assert(maxs[0] == 1.0f);
- assert(defs[0] == 0.5f);
-
- LilvNode* audio_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
- LilvNode* control_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
- LilvNode* in_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
- LilvNode* out_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
-
- assert(lilv_plugin_get_num_ports_of_class(plug, control_class, NULL) == 3);
- assert(lilv_plugin_get_num_ports_of_class(plug, audio_class, NULL) == 0);
- assert(lilv_plugin_get_num_ports_of_class(plug, in_class, NULL) == 2);
- assert(lilv_plugin_get_num_ports_of_class(plug, out_class, NULL) == 1);
- assert(lilv_plugin_get_num_ports_of_class(
- plug, control_class, in_class, NULL) == 2);
- assert(lilv_plugin_get_num_ports_of_class(
- plug, control_class, out_class, NULL) == 1);
- assert(
- lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) ==
- 0);
- assert(lilv_plugin_get_num_ports_of_class(
- plug, audio_class, out_class, NULL) == 0);
-
- assert(lilv_plugin_has_latency(plug));
- assert(lilv_plugin_get_latency_port_index(plug) == 2);
-
- LilvNode* lv2_latency =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#latency");
- const LilvPort* latency_port =
- lilv_plugin_get_port_by_designation(plug, out_class, lv2_latency);
- lilv_node_free(lv2_latency);
-
- assert(latency_port);
- assert(lilv_port_get_index(plug, latency_port) == 2);
- assert(lilv_node_is_blank(lilv_port_get_node(plug, latency_port)));
-
- LilvNode* rt_feature =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#hardRTCapable");
- LilvNode* event_feature =
- lilv_new_uri(world, "http://lv2plug.in/ns/ext/event");
- LilvNode* pretend_feature =
- lilv_new_uri(world, "http://example.org/solvesWorldHunger");
-
- assert(lilv_plugin_has_feature(plug, rt_feature));
- assert(lilv_plugin_has_feature(plug, event_feature));
- assert(!lilv_plugin_has_feature(plug, pretend_feature));
-
- lilv_node_free(rt_feature);
- lilv_node_free(event_feature);
- lilv_node_free(pretend_feature);
-
- LilvNodes* supported = lilv_plugin_get_supported_features(plug);
- LilvNodes* required = lilv_plugin_get_required_features(plug);
- LilvNodes* optional = lilv_plugin_get_optional_features(plug);
- assert(lilv_nodes_size(supported) == 2);
- assert(lilv_nodes_size(required) == 1);
- assert(lilv_nodes_size(optional) == 1);
- lilv_nodes_free(supported);
- lilv_nodes_free(required);
- lilv_nodes_free(optional);
-
- LilvNode* foo_p = lilv_new_uri(world, "http://example.org/foo");
- LilvNodes* foos = lilv_plugin_get_value(plug, foo_p);
- assert(lilv_nodes_size(foos) == 1);
- assert(fabs(lilv_node_as_float(lilv_nodes_get_first(foos)) - 1.6180) <
- FLT_EPSILON);
- lilv_node_free(foo_p);
- lilv_nodes_free(foos);
-
- LilvNode* bar_p = lilv_new_uri(world, "http://example.org/bar");
- LilvNodes* bars = lilv_plugin_get_value(plug, bar_p);
- assert(lilv_nodes_size(bars) == 1);
- assert(lilv_node_as_bool(lilv_nodes_get_first(bars)) == true);
- lilv_node_free(bar_p);
- lilv_nodes_free(bars);
-
- LilvNode* baz_p = lilv_new_uri(world, "http://example.org/baz");
- LilvNodes* bazs = lilv_plugin_get_value(plug, baz_p);
- assert(lilv_nodes_size(bazs) == 1);
- assert(lilv_node_as_bool(lilv_nodes_get_first(bazs)) == false);
- lilv_node_free(baz_p);
- lilv_nodes_free(bazs);
-
- LilvNode* blank_p = lilv_new_uri(world, "http://example.org/blank");
- LilvNodes* blanks = lilv_plugin_get_value(plug, blank_p);
- assert(lilv_nodes_size(blanks) == 1);
- LilvNode* blank = lilv_nodes_get_first(blanks);
- assert(lilv_node_is_blank(blank));
- const char* blank_str = lilv_node_as_blank(blank);
- char* blank_tok = lilv_node_get_turtle_token(blank);
- assert(!strncmp(blank_tok, "_:", 2));
- assert(!strcmp(blank_tok + 2, blank_str));
- lilv_free(blank_tok);
- lilv_node_free(blank_p);
- lilv_nodes_free(blanks);
-
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
- lilv_node_free(author_name);
-
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
- lilv_node_free(author_email);
-
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(
- !strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
- lilv_node_free(author_homepage);
-
- LilvNode* thing_uri = lilv_new_uri(world, "http://example.org/thing");
- LilvNode* name_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name");
- LilvNodes* thing_names =
- lilv_world_find_nodes(world, thing_uri, name_p, NULL);
- assert(lilv_nodes_size(thing_names) == 1);
- LilvNode* thing_name = lilv_nodes_get_first(thing_names);
- assert(thing_name);
- assert(lilv_node_is_string(thing_name));
- assert(!strcmp(lilv_node_as_string(thing_name), "Something else"));
- LilvNode* thing_name2 = lilv_world_get(world, thing_uri, name_p, NULL);
- assert(lilv_node_equals(thing_name, thing_name2));
-
- LilvUIs* uis = lilv_plugin_get_uis(plug);
- assert(lilv_uis_size(uis) == 0);
- lilv_uis_free(uis);
-
- LilvNode* extdata = lilv_new_uri(world, "http://example.org/extdata");
- LilvNode* noextdata = lilv_new_uri(world, "http://example.org/noextdata");
- LilvNodes* extdatas = lilv_plugin_get_extension_data(plug);
- assert(lilv_plugin_has_extension_data(plug, extdata));
- assert(!lilv_plugin_has_extension_data(plug, noextdata));
- assert(lilv_nodes_size(extdatas) == 1);
- assert(lilv_node_equals(lilv_nodes_get_first(extdatas), extdata));
- lilv_node_free(noextdata);
- lilv_node_free(extdata);
- lilv_nodes_free(extdatas);
-
- lilv_nodes_free(thing_names);
- lilv_node_free(thing_uri);
- lilv_node_free(thing_name2);
- lilv_node_free(name_p);
- lilv_node_free(control_class);
- lilv_node_free(audio_class);
- lilv_node_free(in_class);
- lilv_node_free(out_class);
-
- delete_bundle(env);
- lilv_test_env_free(env);
-
- return 0;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ lilv_world_load_all(world);
+
+ if (create_bundle(env, "plugin.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ const LilvPluginClass* klass = lilv_plugin_get_class(plug);
+ const LilvNode* klass_uri = lilv_plugin_class_get_uri(klass);
+ assert(!strcmp(lilv_node_as_string(klass_uri),
+ "http://lv2plug.in/ns/lv2core#CompressorPlugin"));
+
+ LilvNode* rdf_type =
+ lilv_new_uri(world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+ assert(lilv_world_ask(world, lilv_plugin_get_uri(plug), rdf_type, klass_uri));
+ lilv_node_free(rdf_type);
+
+ assert(!lilv_plugin_is_replaced(plug));
+ assert(!lilv_plugin_get_related(plug, NULL));
+
+ const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
+ assert(lilv_node_equals(plug_bundle_uri, env->test_bundle_uri));
+
+ const LilvNodes* data_uris = lilv_plugin_get_data_uris(plug);
+ assert(lilv_nodes_size(data_uris) == 2);
+
+ LilvNode* project = lilv_plugin_get_project(plug);
+ assert(!project);
+
+ char* manifest_uri =
+ lilv_strjoin(lilv_node_as_string(plug_bundle_uri), "manifest.ttl", NULL);
+
+ char* data_uri =
+ lilv_strjoin(lilv_node_as_string(plug_bundle_uri), "plugin.ttl", NULL);
+
+ LilvNode* manifest_uri_val = lilv_new_uri(world, manifest_uri);
+ assert(lilv_nodes_contains(data_uris, manifest_uri_val));
+ lilv_node_free(manifest_uri_val);
+
+ LilvNode* data_uri_val = lilv_new_uri(world, data_uri);
+ assert(lilv_nodes_contains(data_uris, data_uri_val));
+ lilv_node_free(data_uri_val);
+
+ LilvNode* unknown_uri_val = lilv_new_uri(world, "http://example.org/unknown");
+ assert(!lilv_nodes_contains(data_uris, unknown_uri_val));
+ lilv_node_free(unknown_uri_val);
+
+ free(manifest_uri);
+ free(data_uri);
+
+ float mins[3];
+ float maxs[3];
+ float defs[3];
+ lilv_plugin_get_port_ranges_float(plug, mins, maxs, defs);
+ assert(mins[0] == -1.0f);
+ assert(maxs[0] == 1.0f);
+ assert(defs[0] == 0.5f);
+
+ LilvNode* audio_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
+ LilvNode* control_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
+ LilvNode* in_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
+ LilvNode* out_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
+
+ assert(lilv_plugin_get_num_ports_of_class(plug, control_class, NULL) == 3);
+ assert(lilv_plugin_get_num_ports_of_class(plug, audio_class, NULL) == 0);
+ assert(lilv_plugin_get_num_ports_of_class(plug, in_class, NULL) == 2);
+ assert(lilv_plugin_get_num_ports_of_class(plug, out_class, NULL) == 1);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, control_class, in_class, NULL) == 2);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, control_class, out_class, NULL) == 1);
+ assert(
+ lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) == 0);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, audio_class, out_class, NULL) == 0);
+
+ assert(lilv_plugin_has_latency(plug));
+ assert(lilv_plugin_get_latency_port_index(plug) == 2);
+
+ LilvNode* lv2_latency =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#latency");
+ const LilvPort* latency_port =
+ lilv_plugin_get_port_by_designation(plug, out_class, lv2_latency);
+ lilv_node_free(lv2_latency);
+
+ assert(latency_port);
+ assert(lilv_port_get_index(plug, latency_port) == 2);
+ assert(lilv_node_is_blank(lilv_port_get_node(plug, latency_port)));
+
+ LilvNode* rt_feature =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#hardRTCapable");
+ LilvNode* event_feature =
+ lilv_new_uri(world, "http://lv2plug.in/ns/ext/event");
+ LilvNode* pretend_feature =
+ lilv_new_uri(world, "http://example.org/solvesWorldHunger");
+
+ assert(lilv_plugin_has_feature(plug, rt_feature));
+ assert(lilv_plugin_has_feature(plug, event_feature));
+ assert(!lilv_plugin_has_feature(plug, pretend_feature));
+
+ lilv_node_free(rt_feature);
+ lilv_node_free(event_feature);
+ lilv_node_free(pretend_feature);
+
+ LilvNodes* supported = lilv_plugin_get_supported_features(plug);
+ LilvNodes* required = lilv_plugin_get_required_features(plug);
+ LilvNodes* optional = lilv_plugin_get_optional_features(plug);
+ assert(lilv_nodes_size(supported) == 2);
+ assert(lilv_nodes_size(required) == 1);
+ assert(lilv_nodes_size(optional) == 1);
+ lilv_nodes_free(supported);
+ lilv_nodes_free(required);
+ lilv_nodes_free(optional);
+
+ LilvNode* foo_p = lilv_new_uri(world, "http://example.org/foo");
+ LilvNodes* foos = lilv_plugin_get_value(plug, foo_p);
+ assert(lilv_nodes_size(foos) == 1);
+ assert(fabs(lilv_node_as_float(lilv_nodes_get_first(foos)) - 1.6180) <
+ FLT_EPSILON);
+ lilv_node_free(foo_p);
+ lilv_nodes_free(foos);
+
+ LilvNode* bar_p = lilv_new_uri(world, "http://example.org/bar");
+ LilvNodes* bars = lilv_plugin_get_value(plug, bar_p);
+ assert(lilv_nodes_size(bars) == 1);
+ assert(lilv_node_as_bool(lilv_nodes_get_first(bars)) == true);
+ lilv_node_free(bar_p);
+ lilv_nodes_free(bars);
+
+ LilvNode* baz_p = lilv_new_uri(world, "http://example.org/baz");
+ LilvNodes* bazs = lilv_plugin_get_value(plug, baz_p);
+ assert(lilv_nodes_size(bazs) == 1);
+ assert(lilv_node_as_bool(lilv_nodes_get_first(bazs)) == false);
+ lilv_node_free(baz_p);
+ lilv_nodes_free(bazs);
+
+ LilvNode* blank_p = lilv_new_uri(world, "http://example.org/blank");
+ LilvNodes* blanks = lilv_plugin_get_value(plug, blank_p);
+ assert(lilv_nodes_size(blanks) == 1);
+ LilvNode* blank = lilv_nodes_get_first(blanks);
+ assert(lilv_node_is_blank(blank));
+ const char* blank_str = lilv_node_as_blank(blank);
+ char* blank_tok = lilv_node_get_turtle_token(blank);
+ assert(!strncmp(blank_tok, "_:", 2));
+ assert(!strcmp(blank_tok + 2, blank_str));
+ lilv_free(blank_tok);
+ lilv_node_free(blank_p);
+ lilv_nodes_free(blanks);
+
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
+ lilv_node_free(author_name);
+
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
+ lilv_node_free(author_email);
+
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
+ lilv_node_free(author_homepage);
+
+ LilvNode* thing_uri = lilv_new_uri(world, "http://example.org/thing");
+ LilvNode* name_p = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name");
+ LilvNodes* thing_names =
+ lilv_world_find_nodes(world, thing_uri, name_p, NULL);
+ assert(lilv_nodes_size(thing_names) == 1);
+ LilvNode* thing_name = lilv_nodes_get_first(thing_names);
+ assert(thing_name);
+ assert(lilv_node_is_string(thing_name));
+ assert(!strcmp(lilv_node_as_string(thing_name), "Something else"));
+ LilvNode* thing_name2 = lilv_world_get(world, thing_uri, name_p, NULL);
+ assert(lilv_node_equals(thing_name, thing_name2));
+
+ LilvUIs* uis = lilv_plugin_get_uis(plug);
+ assert(lilv_uis_size(uis) == 0);
+ lilv_uis_free(uis);
+
+ LilvNode* extdata = lilv_new_uri(world, "http://example.org/extdata");
+ LilvNode* noextdata = lilv_new_uri(world, "http://example.org/noextdata");
+ LilvNodes* extdatas = lilv_plugin_get_extension_data(plug);
+ assert(lilv_plugin_has_extension_data(plug, extdata));
+ assert(!lilv_plugin_has_extension_data(plug, noextdata));
+ assert(lilv_nodes_size(extdatas) == 1);
+ assert(lilv_node_equals(lilv_nodes_get_first(extdatas), extdata));
+ lilv_node_free(noextdata);
+ lilv_node_free(extdata);
+ lilv_nodes_free(extdatas);
+
+ lilv_nodes_free(thing_names);
+ lilv_node_free(thing_uri);
+ lilv_node_free(thing_name2);
+ lilv_node_free(name_p);
+ lilv_node_free(control_class);
+ lilv_node_free(audio_class);
+ lilv_node_free(in_class);
+ lilv_node_free(out_class);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test.lv2/manifest.ttl.in b/test/test_plugin.lv2/manifest.ttl.in
index bc3952c..48b009b 100644
--- a/test/test.lv2/manifest.ttl.in
+++ b/test/test_plugin.lv2/manifest.ttl.in
@@ -3,5 +3,5 @@
<http://example.org/lilv-test-plugin>
a lv2:Plugin ;
- lv2:binary <test@SHLIB_EXT@> ;
- rdfs:seeAlso <test.ttl> .
+ lv2:binary <test_plugin@SHLIB_EXT@> ;
+ rdfs:seeAlso <test_plugin.ttl> .
diff --git a/test/test_plugin.lv2/meson.build b/test/test_plugin.lv2/meson.build
new file mode 100644
index 0000000..e6c54cf
--- /dev/null
+++ b/test/test_plugin.lv2/meson.build
@@ -0,0 +1,24 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+module = shared_module(
+ 'test_plugin',
+ files('test_plugin.c'),
+ c_args: c_suppressions,
+ dependencies: [lv2_dep, zix_dep],
+ gnu_symbol_visibility: 'hidden',
+ name_prefix: '',
+)
+
+extension = '.' + module.full_path().split('.')[-1]
+config = configuration_data({'SHLIB_EXT': extension})
+ttl_files = ['manifest.ttl', 'test_plugin.ttl']
+
+foreach f : ttl_files
+ configure_file(
+ input: files(f + '.in'),
+ output: f,
+ configuration: config,
+ )
+endforeach
+
diff --git a/test/test_plugin.lv2/test_plugin.c b/test/test_plugin.lv2/test_plugin.c
new file mode 100644
index 0000000..124f64c
--- /dev/null
+++ b/test/test_plugin.lv2/test_plugin.c
@@ -0,0 +1,427 @@
+// Copyright 2011-2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lv2/atom/atom.h"
+#include "lv2/core/lv2.h"
+#include "lv2/state/state.h"
+#include "lv2/urid/urid.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_URI "http://example.org/lilv-test-plugin"
+
+enum { TEST_INPUT = 0, TEST_OUTPUT = 1, TEST_CONTROL = 2 };
+
+typedef struct {
+ LV2_URID_Map* map;
+ LV2_State_Free_Path* free_path;
+
+ struct {
+ LV2_URID atom_Float;
+ } uris;
+
+ char* tmp_dir_path;
+ char* rec_file_path;
+ FILE* rec_file;
+
+ float* input;
+ float* output;
+ unsigned num_runs;
+} Test;
+
+static void
+cleanup(LV2_Handle instance)
+{
+ Test* test = (Test*)instance;
+ if (test->rec_file) {
+ fclose(test->rec_file);
+ }
+
+ if (test->free_path) {
+ test->free_path->free_path(test->free_path->handle, test->rec_file_path);
+ }
+
+ free(test->tmp_dir_path);
+ free(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;
+ case TEST_CONTROL:
+ 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)
+{
+ (void)descriptor;
+ (void)rate;
+ (void)path;
+
+ Test* test = (Test*)calloc(1, sizeof(Test));
+ if (!test) {
+ return NULL;
+ }
+
+ test->tmp_dir_path = zix_temp_directory_path(NULL);
+
+ LV2_State_Make_Path* make_path = NULL;
+
+ for (int i = 0; features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
+ test->map = (LV2_URID_Map*)features[i]->data;
+ test->uris.atom_Float =
+ test->map->map(test->map->handle, LV2_ATOM__Float);
+ } else if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
+ make_path = (LV2_State_Make_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
+ test->free_path = (LV2_State_Free_Path*)features[i]->data;
+ }
+ }
+
+ if (!test->map) {
+ fprintf(stderr, "Host does not support urid:map\n");
+ free(test);
+ return NULL;
+ }
+
+ if (make_path) {
+ if (!test->free_path) {
+ fprintf(stderr, "Host provided make_path without free_path\n");
+ free(test);
+ return NULL;
+ }
+
+ test->rec_file_path = make_path->path(make_path->handle, "recfile");
+ if (!(test->rec_file = fopen(test->rec_file_path, "w"))) {
+ fprintf(stderr, "ERROR: Failed to open rec file\n");
+ } else {
+ fprintf(test->rec_file, "instantiate\n");
+ }
+ }
+
+ return (LV2_Handle)test;
+}
+
+static void
+run(LV2_Handle instance, uint32_t sample_count)
+{
+ Test* test = (Test*)instance;
+ *test->output = *test->input;
+ if (sample_count == 1) {
+ ++test->num_runs;
+ } else if (sample_count == 2 && test->rec_file) {
+ // Append to rec file (changes size)
+ fprintf(test->rec_file, "run\n");
+ } else if (sample_count == 3 && test->rec_file) {
+ // Change the first byte of rec file (doesn't change size)
+ fseek(test->rec_file, 0, SEEK_SET);
+ fprintf(test->rec_file, "X");
+ fseek(test->rec_file, 0, SEEK_END);
+ }
+}
+
+static uint32_t
+map_uri(Test* plugin, const char* uri)
+{
+ return plugin->map->map(plugin->map->handle, uri);
+}
+
+static LV2_State_Status
+save(LV2_Handle instance,
+ LV2_State_Store_Function store,
+ void* callback_data,
+ uint32_t flags,
+ const LV2_Feature* const* features)
+{
+ (void)flags;
+
+ Test* plugin = (Test*)instance;
+
+ LV2_State_Map_Path* map_path = NULL;
+ LV2_State_Make_Path* make_path = NULL;
+ LV2_State_Free_Path* free_path = NULL;
+ for (int i = 0; features && features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_STATE__mapPath)) {
+ map_path = (LV2_State_Map_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__makePath)) {
+ make_path = (LV2_State_Make_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
+ free_path = (LV2_State_Free_Path*)features[i]->data;
+ }
+ }
+
+ if (!map_path || !free_path) {
+ return LV2_STATE_ERR_NO_FEATURE;
+ }
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/greeting"),
+ "hello",
+ strlen("hello") + 1,
+ map_uri(plugin, LV2_ATOM__String),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint32_t urid = map_uri(plugin, "http://example.org/urivalue");
+ store(callback_data,
+ map_uri(plugin, "http://example.org/uri"),
+ &urid,
+ sizeof(uint32_t),
+ map_uri(plugin, LV2_ATOM__URID),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ // Try to store second value for the same property (should fail)
+ const uint32_t urid2 = map_uri(plugin, "http://example.org/urivalue2");
+ if (!store(callback_data,
+ map_uri(plugin, "http://example.org/uri"),
+ &urid2,
+ sizeof(uint32_t),
+ map_uri(plugin, LV2_ATOM__URID),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
+ return LV2_STATE_ERR_UNKNOWN;
+ }
+
+ // Try to store with a null key (should fail)
+ if (!store(callback_data,
+ 0,
+ &urid2,
+ sizeof(uint32_t),
+ map_uri(plugin, LV2_ATOM__URID),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE)) {
+ return LV2_STATE_ERR_UNKNOWN;
+ }
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/num-runs"),
+ &plugin->num_runs,
+ sizeof(plugin->num_runs),
+ map_uri(plugin, LV2_ATOM__Int),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const float two = 2.0f;
+ store(callback_data,
+ map_uri(plugin, "http://example.org/two"),
+ &two,
+ sizeof(two),
+ map_uri(plugin, LV2_ATOM__Float),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint32_t affirmative = 1;
+ store(callback_data,
+ map_uri(plugin, "http://example.org/true"),
+ &affirmative,
+ sizeof(affirmative),
+ map_uri(plugin, LV2_ATOM__Bool),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint32_t negative = 0;
+ store(callback_data,
+ map_uri(plugin, "http://example.org/false"),
+ &negative,
+ sizeof(negative),
+ map_uri(plugin, LV2_ATOM__Bool),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ const uint8_t blob[] = "I am a blob of arbitrary data.";
+ store(callback_data,
+ map_uri(plugin, "http://example.org/blob"),
+ blob,
+ sizeof(blob),
+ map_uri(plugin, "http://example.org/SomeUnknownType"),
+ LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
+
+ if (map_path) {
+ const char* const file_name = "temp_file.txt";
+
+ char* const tmp_file_path =
+ zix_path_join(NULL, plugin->tmp_dir_path, file_name);
+
+ FILE* file = fopen(tmp_file_path, "w");
+ if (!file) {
+ fprintf(stderr, "error: Failed to open file %s\n", tmp_file_path);
+ free(tmp_file_path);
+ return LV2_STATE_ERR_UNKNOWN;
+ }
+
+ fprintf(file, "Hello\n");
+ fclose(file);
+
+ char* apath = map_path->abstract_path(map_path->handle, tmp_file_path);
+ char* apath2 = map_path->abstract_path(map_path->handle, tmp_file_path);
+ free(tmp_file_path);
+ if (!!strcmp(apath, apath2)) {
+ fprintf(stderr, "error: Path %s != %s\n", apath, apath2);
+ }
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/extfile"),
+ apath,
+ strlen(apath) + 1,
+ map_uri(plugin, LV2_ATOM__Path),
+ LV2_STATE_IS_POD);
+
+ free_path->free_path(free_path->handle, apath);
+ free_path->free_path(free_path->handle, apath2);
+
+ if (plugin->rec_file) {
+ fflush(plugin->rec_file);
+ apath = map_path->abstract_path(map_path->handle, plugin->rec_file_path);
+
+ store(callback_data,
+ map_uri(plugin, "http://example.org/recfile"),
+ apath,
+ strlen(apath) + 1,
+ map_uri(plugin, LV2_ATOM__Path),
+ LV2_STATE_IS_POD);
+
+ free_path->free_path(free_path->handle, apath);
+ }
+
+ if (make_path) {
+ char* spath = make_path->path(make_path->handle, "save");
+ FILE* sfile = fopen(spath, "w");
+ fprintf(sfile, "save");
+ fclose(sfile);
+
+ apath = map_path->abstract_path(map_path->handle, spath);
+ store(callback_data,
+ map_uri(plugin, "http://example.org/save-file"),
+ apath,
+ strlen(apath) + 1,
+ map_uri(plugin, LV2_ATOM__Path),
+ LV2_STATE_IS_POD);
+ free_path->free_path(free_path->handle, apath);
+ free_path->free_path(free_path->handle, spath);
+ }
+ }
+
+ return LV2_STATE_SUCCESS;
+}
+
+static LV2_State_Status
+restore(LV2_Handle instance,
+ LV2_State_Retrieve_Function retrieve,
+ void* callback_data,
+ uint32_t flags,
+ const LV2_Feature* const* features)
+{
+ (void)flags;
+
+ Test* plugin = (Test*)instance;
+
+ LV2_State_Map_Path* map_path = NULL;
+ LV2_State_Free_Path* free_path = NULL;
+ for (int i = 0; features && features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_STATE__mapPath)) {
+ map_path = (LV2_State_Map_Path*)features[i]->data;
+ } else if (!strcmp(features[i]->URI, LV2_STATE__freePath)) {
+ free_path = (LV2_State_Free_Path*)features[i]->data;
+ }
+ }
+
+ size_t size = 0;
+ uint32_t type = 0;
+ uint32_t valflags = 0;
+
+ plugin->num_runs =
+ *(int32_t*)retrieve(callback_data,
+ map_uri(plugin, "http://example.org/num-runs"),
+ &size,
+ &type,
+ &valflags);
+
+ if (!map_path || !free_path) {
+ return LV2_STATE_ERR_NO_FEATURE;
+ }
+
+ char* apath = (char*)retrieve(callback_data,
+ map_uri(plugin, "http://example.org/extfile"),
+ &size,
+ &type,
+ &valflags);
+
+ if (valflags != LV2_STATE_IS_POD) {
+ fprintf(stderr, "error: Restored bad file flags\n");
+ return LV2_STATE_ERR_BAD_FLAGS;
+ }
+
+ if (apath) {
+ char* path = map_path->absolute_path(map_path->handle, apath);
+ FILE* f = fopen(path, "r");
+ char str[8];
+ size_t n_read = fread(str, 1, sizeof(str), f);
+ fclose(f);
+ if (!!strncmp(str, "Hello\n", n_read)) {
+ fprintf(
+ stderr, "error: Restored bad file contents `%s' != `Hello'\n", str);
+ }
+ free_path->free_path(free_path->handle, path);
+ }
+
+ apath = (char*)retrieve(callback_data,
+ map_uri(plugin, "http://example.org/save-file"),
+ &size,
+ &type,
+ &valflags);
+ if (apath) {
+ char* spath = map_path->absolute_path(map_path->handle, apath);
+ FILE* sfile = fopen(spath, "r");
+ if (!sfile) {
+ fprintf(stderr, "error: Failed to open save file %s\n", spath);
+ } else {
+ fclose(sfile);
+ }
+ free_path->free_path(free_path->handle, spath);
+ } else {
+ fprintf(stderr, "error: Failed to restore save file.\n");
+ }
+
+ return LV2_STATE_SUCCESS;
+}
+
+static const void*
+extension_data(const char* uri)
+{
+ static const LV2_State_Interface state = {save, restore};
+ if (!strcmp(uri, LV2_STATE__interface)) {
+ return &state;
+ }
+ return NULL;
+}
+
+static const LV2_Descriptor descriptor = {TEST_URI,
+ instantiate,
+ connect_port,
+ NULL, // activate,
+ run,
+ NULL, // deactivate,
+ cleanup,
+ extension_data};
+
+LV2_SYMBOL_EXPORT
+const LV2_Descriptor*
+lv2_descriptor(uint32_t index)
+{
+ return index ? NULL : &descriptor;
+}
diff --git a/test/test.lv2/test.ttl.in b/test/test_plugin.lv2/test_plugin.ttl.in
index 1c16b4c..1c16b4c 100644
--- a/test/test.lv2/test.ttl.in
+++ b/test/test_plugin.lv2/test_plugin.ttl.in
diff --git a/test/test_port.c b/test/test_port.c
index 63f8bd0..e05dcde 100644
--- a/test/test_port.c
+++ b/test/test_port.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -77,255 +64,255 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
-
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
-
- LilvNode* psym = lilv_new_string(world, "foo");
- const LilvPort* p = lilv_plugin_get_port_by_index(plug, 0);
- const LilvPort* p2 = lilv_plugin_get_port_by_symbol(plug, psym);
- lilv_node_free(psym);
- assert(p != NULL);
- assert(p2 != NULL);
- assert(p == p2);
-
- LilvNode* nopsym = lilv_new_string(world, "thisaintnoportfoo");
- const LilvPort* p3 = lilv_plugin_get_port_by_symbol(plug, nopsym);
- assert(p3 == NULL);
- lilv_node_free(nopsym);
-
- // Try getting an invalid property
- LilvNode* num = lilv_new_int(world, 1);
- LilvNodes* nothing = lilv_port_get_value(plug, p, num);
- assert(!nothing);
- lilv_node_free(num);
-
- LilvNode* audio_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
- LilvNode* control_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
- LilvNode* in_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
- LilvNode* out_class =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
-
- assert(lilv_nodes_size(lilv_port_get_classes(plug, p)) == 2);
- assert(lilv_plugin_get_num_ports(plug) == 4);
- assert(lilv_port_is_a(plug, p, control_class));
- assert(lilv_port_is_a(plug, p, in_class));
- assert(!lilv_port_is_a(plug, p, audio_class));
-
- LilvNodes* port_properties = lilv_port_get_properties(plug, p);
- assert(lilv_nodes_size(port_properties) == 1);
- lilv_nodes_free(port_properties);
-
- // Untranslated name (current locale is set to "C" in main)
- assert(!strcmp(lilv_node_as_string(lilv_port_get_symbol(plug, p)), "foo"));
- LilvNode* name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "store"));
- lilv_node_free(name);
-
- // Exact language match
- set_env("LANG", "de_DE");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "Laden"));
- lilv_node_free(name);
-
- // Exact language match (with charset suffix)
- set_env("LANG", "de_AT.utf8");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "Geschaeft"));
- lilv_node_free(name);
-
- // Partial language match (choose value translated for different country)
- set_env("LANG", "de_CH");
- name = lilv_port_get_name(plug, p);
- assert((!strcmp(lilv_node_as_string(name), "Laden")) ||
- (!strcmp(lilv_node_as_string(name), "Geschaeft")));
- lilv_node_free(name);
-
- // Partial language match (choose country-less language tagged value)
- set_env("LANG", "es_MX");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "tienda"));
- lilv_node_free(name);
-
- // No language match (choose untranslated value)
- set_env("LANG", "cn");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "store"));
- lilv_node_free(name);
-
- // Invalid language
- set_env("LANG", "1!");
- name = lilv_port_get_name(plug, p);
- assert(!strcmp(lilv_node_as_string(name), "store"));
- lilv_node_free(name);
-
- set_env("LANG", "en_CA.utf-8");
-
- // Language tagged value with no untranslated values
- LilvNode* rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
- LilvNodes* comments = lilv_port_get_value(plug, p, rdfs_comment);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
- "comment"));
- LilvNode* comment = lilv_port_get(plug, p, rdfs_comment);
- assert(!strcmp(lilv_node_as_string(comment), "comment"));
- lilv_node_free(comment);
- lilv_nodes_free(comments);
-
- set_env("LANG", "fr");
-
- comments = lilv_port_get_value(plug, p, rdfs_comment);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
- "commentaires"));
- lilv_nodes_free(comments);
-
- set_env("LANG", "cn");
-
- comments = lilv_port_get_value(plug, p, rdfs_comment);
- assert(!comments);
- lilv_nodes_free(comments);
-
- lilv_node_free(rdfs_comment);
-
- set_env("LANG", "C"); // Reset locale
-
- LilvScalePoints* points = lilv_port_get_scale_points(plug, p);
- assert(lilv_scale_points_size(points) == 2);
-
- LilvIter* sp_iter = lilv_scale_points_begin(points);
- const LilvScalePoint* sp0 = lilv_scale_points_get(points, sp_iter);
- assert(sp0);
- sp_iter = lilv_scale_points_next(points, sp_iter);
- const LilvScalePoint* sp1 = lilv_scale_points_get(points, sp_iter);
- assert(sp1);
-
- assert(((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)),
- "Sin") &&
- lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 3) &&
- (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)),
- "Cos") &&
- lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 4)) ||
- ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)),
- "Cos") &&
- lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 4) &&
- (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)),
- "Sin") &&
- lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 3)));
-
- LilvNode* homepage_p =
- lilv_new_uri(world, "http://usefulinc.com/ns/doap#homepage");
- LilvNodes* homepages = lilv_plugin_get_value(plug, homepage_p);
- assert(lilv_nodes_size(homepages) == 1);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(homepages)),
- "http://example.org/someplug"));
-
- LilvNode *min, *max, *def;
- lilv_port_get_range(plug, p, &def, &min, &max);
- assert(def);
- assert(min);
- assert(max);
- assert(lilv_node_as_float(def) == 0.5);
- assert(lilv_node_as_float(min) == -1.0);
- assert(lilv_node_as_float(max) == 1.0);
-
- LilvNode* integer_prop =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#integer");
- LilvNode* toggled_prop =
- lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#toggled");
-
- assert(lilv_port_has_property(plug, p, integer_prop));
- assert(!lilv_port_has_property(plug, p, toggled_prop));
-
- const LilvPort* ep = lilv_plugin_get_port_by_index(plug, 1);
-
- LilvNode* event_type = lilv_new_uri(world, "http://example.org/event");
- LilvNode* event_type_2 =
- lilv_new_uri(world, "http://example.org/otherEvent");
- LilvNode* atom_event = lilv_new_uri(world, "http://example.org/atomEvent");
- assert(lilv_port_supports_event(plug, ep, event_type));
- assert(!lilv_port_supports_event(plug, ep, event_type_2));
- assert(lilv_port_supports_event(plug, ep, atom_event));
-
- LilvNode* name_p = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#name");
- LilvNodes* names = lilv_port_get_value(plug, p, name_p);
- assert(lilv_nodes_size(names) == 1);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)), "store"));
- lilv_nodes_free(names);
-
- LilvNode* true_val = lilv_new_bool(world, true);
- LilvNode* false_val = lilv_new_bool(world, false);
-
- assert(!lilv_node_equals(true_val, false_val));
-
- lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, false_val);
- names = lilv_port_get_value(plug, p, name_p);
- assert(lilv_nodes_size(names) == 4);
- lilv_nodes_free(names);
- lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, true_val);
-
- lilv_node_free(false_val);
- lilv_node_free(true_val);
-
- names = lilv_port_get_value(plug, ep, name_p);
- assert(lilv_nodes_size(names) == 1);
- assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)),
- "Event Input"));
-
- const LilvPort* ap_in = lilv_plugin_get_port_by_index(plug, 2);
-
- assert(lilv_port_is_a(plug, ap_in, in_class));
- assert(!lilv_port_is_a(plug, ap_in, out_class));
- assert(lilv_port_is_a(plug, ap_in, audio_class));
- assert(!lilv_port_is_a(plug, ap_in, control_class));
-
- const LilvPort* ap_out = lilv_plugin_get_port_by_index(plug, 3);
-
- assert(lilv_port_is_a(plug, ap_out, out_class));
- assert(!lilv_port_is_a(plug, ap_out, in_class));
- assert(lilv_port_is_a(plug, ap_out, audio_class));
- assert(!lilv_port_is_a(plug, ap_out, control_class));
-
- assert(lilv_plugin_get_num_ports_of_class(
- plug, control_class, in_class, NULL) == 1);
- assert(
- lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) ==
- 1);
- assert(lilv_plugin_get_num_ports_of_class(
- plug, audio_class, out_class, NULL) == 1);
-
- lilv_nodes_free(names);
- lilv_node_free(name_p);
-
- lilv_node_free(integer_prop);
- lilv_node_free(toggled_prop);
- lilv_node_free(event_type);
- lilv_node_free(event_type_2);
- lilv_node_free(atom_event);
-
- lilv_node_free(min);
- lilv_node_free(max);
- lilv_node_free(def);
-
- lilv_node_free(homepage_p);
- lilv_nodes_free(homepages);
-
- lilv_scale_points_free(points);
- lilv_node_free(control_class);
- lilv_node_free(audio_class);
- lilv_node_free(out_class);
- lilv_node_free(in_class);
-
- delete_bundle(env);
- lilv_test_env_free(env);
-
- return 0;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "port.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
+
+ LilvNode* psym = lilv_new_string(world, "foo");
+ const LilvPort* p = lilv_plugin_get_port_by_index(plug, 0);
+ const LilvPort* p2 = lilv_plugin_get_port_by_symbol(plug, psym);
+ lilv_node_free(psym);
+ assert(p != NULL);
+ assert(p2 != NULL);
+ assert(p == p2);
+
+ LilvNode* nopsym = lilv_new_string(world, "thisaintnoportfoo");
+ const LilvPort* p3 = lilv_plugin_get_port_by_symbol(plug, nopsym);
+ assert(p3 == NULL);
+ lilv_node_free(nopsym);
+
+ // Try getting an invalid property
+ LilvNode* num = lilv_new_int(world, 1);
+ LilvNodes* nothing = lilv_port_get_value(plug, p, num);
+ assert(!nothing);
+ lilv_node_free(num);
+
+ LilvNode* audio_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#AudioPort");
+ LilvNode* control_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#ControlPort");
+ LilvNode* in_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#InputPort");
+ LilvNode* out_class =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#OutputPort");
+
+ assert(lilv_nodes_size(lilv_port_get_classes(plug, p)) == 2);
+ assert(lilv_plugin_get_num_ports(plug) == 4);
+ assert(lilv_port_is_a(plug, p, control_class));
+ assert(lilv_port_is_a(plug, p, in_class));
+ assert(!lilv_port_is_a(plug, p, audio_class));
+
+ LilvNodes* port_properties = lilv_port_get_properties(plug, p);
+ assert(lilv_nodes_size(port_properties) == 1);
+ lilv_nodes_free(port_properties);
+
+ // Untranslated name (current locale is set to "C" in main)
+ assert(!strcmp(lilv_node_as_string(lilv_port_get_symbol(plug, p)), "foo"));
+ LilvNode* name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "store"));
+ lilv_node_free(name);
+
+ // Exact language match
+ set_env("LANG", "de_DE");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "Laden"));
+ lilv_node_free(name);
+
+ // Exact language match (with charset suffix)
+ set_env("LANG", "de_AT.utf8");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "Geschaeft"));
+ lilv_node_free(name);
+
+ // Partial language match (choose value translated for different country)
+ set_env("LANG", "de_CH");
+ name = lilv_port_get_name(plug, p);
+ assert((!strcmp(lilv_node_as_string(name), "Laden")) ||
+ (!strcmp(lilv_node_as_string(name), "Geschaeft")));
+ lilv_node_free(name);
+
+ // Partial language match (choose country-less language tagged value)
+ set_env("LANG", "es_MX");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "tienda"));
+ lilv_node_free(name);
+
+ // No language match (choose untranslated value)
+ set_env("LANG", "cn");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "store"));
+ lilv_node_free(name);
+
+ // Invalid language
+ set_env("LANG", "1!");
+ name = lilv_port_get_name(plug, p);
+ assert(!strcmp(lilv_node_as_string(name), "store"));
+ lilv_node_free(name);
+
+ set_env("LANG", "en_CA.utf-8");
+
+ // Language tagged value with no untranslated values
+ LilvNode* rdfs_comment = lilv_new_uri(world, LILV_NS_RDFS "comment");
+ LilvNodes* comments = lilv_port_get_value(plug, p, rdfs_comment);
+ assert(
+ !strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)), "comment"));
+ LilvNode* comment = lilv_port_get(plug, p, rdfs_comment);
+ assert(!strcmp(lilv_node_as_string(comment), "comment"));
+ lilv_node_free(comment);
+ lilv_nodes_free(comments);
+
+ set_env("LANG", "fr");
+
+ comments = lilv_port_get_value(plug, p, rdfs_comment);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(comments)),
+ "commentaires"));
+ lilv_nodes_free(comments);
+
+ set_env("LANG", "cn");
+
+ comments = lilv_port_get_value(plug, p, rdfs_comment);
+ assert(!comments);
+ lilv_nodes_free(comments);
+
+ lilv_node_free(rdfs_comment);
+
+ set_env("LANG", "C"); // Reset locale
+
+ LilvScalePoints* points = lilv_port_get_scale_points(plug, p);
+ assert(lilv_scale_points_size(points) == 2);
+
+ LilvIter* sp_iter = lilv_scale_points_begin(points);
+ const LilvScalePoint* sp0 = lilv_scale_points_get(points, sp_iter);
+ assert(sp0);
+ sp_iter = lilv_scale_points_next(points, sp_iter);
+ const LilvScalePoint* sp1 = lilv_scale_points_get(points, sp_iter);
+ assert(sp1);
+
+ assert(
+ ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Sin") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 3) &&
+ (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Cos") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 4)) ||
+ ((!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp0)), "Cos") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp0)) == 4) &&
+ (!strcmp(lilv_node_as_string(lilv_scale_point_get_label(sp1)), "Sin") &&
+ lilv_node_as_float(lilv_scale_point_get_value(sp1)) == 3)));
+
+ LilvNode* homepage_p =
+ lilv_new_uri(world, "http://usefulinc.com/ns/doap#homepage");
+ LilvNodes* homepages = lilv_plugin_get_value(plug, homepage_p);
+ assert(lilv_nodes_size(homepages) == 1);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(homepages)),
+ "http://example.org/someplug"));
+
+ LilvNode* min = NULL;
+ LilvNode* max = NULL;
+ LilvNode* def = NULL;
+ lilv_port_get_range(plug, p, &def, &min, &max);
+ assert(def);
+ assert(min);
+ assert(max);
+ assert(lilv_node_as_float(def) == 0.5);
+ assert(lilv_node_as_float(min) == -1.0);
+ assert(lilv_node_as_float(max) == 1.0);
+
+ LilvNode* integer_prop =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#integer");
+ LilvNode* toggled_prop =
+ lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#toggled");
+
+ assert(lilv_port_has_property(plug, p, integer_prop));
+ assert(!lilv_port_has_property(plug, p, toggled_prop));
+
+ const LilvPort* ep = lilv_plugin_get_port_by_index(plug, 1);
+
+ LilvNode* event_type = lilv_new_uri(world, "http://example.org/event");
+ LilvNode* event_type_2 = lilv_new_uri(world, "http://example.org/otherEvent");
+ LilvNode* atom_event = lilv_new_uri(world, "http://example.org/atomEvent");
+ assert(lilv_port_supports_event(plug, ep, event_type));
+ assert(!lilv_port_supports_event(plug, ep, event_type_2));
+ assert(lilv_port_supports_event(plug, ep, atom_event));
+
+ LilvNode* name_p = lilv_new_uri(world, "http://lv2plug.in/ns/lv2core#name");
+ LilvNodes* names = lilv_port_get_value(plug, p, name_p);
+ assert(lilv_nodes_size(names) == 1);
+ assert(!strcmp(lilv_node_as_string(lilv_nodes_get_first(names)), "store"));
+ lilv_nodes_free(names);
+
+ LilvNode* true_val = lilv_new_bool(world, true);
+ LilvNode* false_val = lilv_new_bool(world, false);
+
+ assert(!lilv_node_equals(true_val, false_val));
+
+ lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, false_val);
+ names = lilv_port_get_value(plug, p, name_p);
+ assert(lilv_nodes_size(names) == 4);
+ lilv_nodes_free(names);
+ lilv_world_set_option(world, LILV_OPTION_FILTER_LANG, true_val);
+
+ lilv_node_free(false_val);
+ lilv_node_free(true_val);
+
+ names = lilv_port_get_value(plug, ep, name_p);
+ assert(lilv_nodes_size(names) == 1);
+ assert(
+ !strcmp(lilv_node_as_string(lilv_nodes_get_first(names)), "Event Input"));
+
+ const LilvPort* ap_in = lilv_plugin_get_port_by_index(plug, 2);
+
+ assert(lilv_port_is_a(plug, ap_in, in_class));
+ assert(!lilv_port_is_a(plug, ap_in, out_class));
+ assert(lilv_port_is_a(plug, ap_in, audio_class));
+ assert(!lilv_port_is_a(plug, ap_in, control_class));
+
+ const LilvPort* ap_out = lilv_plugin_get_port_by_index(plug, 3);
+
+ assert(lilv_port_is_a(plug, ap_out, out_class));
+ assert(!lilv_port_is_a(plug, ap_out, in_class));
+ assert(lilv_port_is_a(plug, ap_out, audio_class));
+ assert(!lilv_port_is_a(plug, ap_out, control_class));
+
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, control_class, in_class, NULL) == 1);
+ assert(
+ lilv_plugin_get_num_ports_of_class(plug, audio_class, in_class, NULL) == 1);
+ assert(lilv_plugin_get_num_ports_of_class(
+ plug, audio_class, out_class, NULL) == 1);
+
+ lilv_nodes_free(names);
+ lilv_node_free(name_p);
+
+ lilv_node_free(integer_prop);
+ lilv_node_free(toggled_prop);
+ lilv_node_free(event_type);
+ lilv_node_free(event_type_2);
+ lilv_node_free(atom_event);
+
+ lilv_node_free(min);
+ lilv_node_free(max);
+ lilv_node_free(def);
+
+ lilv_node_free(homepage_p);
+ lilv_nodes_free(homepages);
+
+ lilv_scale_points_free(points);
+ lilv_node_free(control_class);
+ lilv_node_free(audio_class);
+ lilv_node_free(out_class);
+ lilv_node_free(in_class);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_preset.c b/test/test_preset.c
index d26d844..d091318 100644
--- a/test/test_preset.c
+++ b/test/test_preset.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -67,27 +54,30 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "preset.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
- LilvNode* pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
- LilvNodes* related = lilv_plugin_get_related(plug, pset_Preset);
+ LilvNode* pset_Preset = lilv_new_uri(world, LV2_PRESETS__Preset);
+ LilvNodes* related = lilv_plugin_get_related(plug, pset_Preset);
- assert(lilv_nodes_size(related) == 1);
+ assert(lilv_nodes_size(related) == 1);
- lilv_node_free(pset_Preset);
- lilv_nodes_free(related);
+ lilv_node_free(pset_Preset);
+ lilv_nodes_free(related);
- delete_bundle(env);
- lilv_test_env_free(env);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_project.c b/test/test_project.c
index bc2e2c3..cfce35a 100644
--- a/test/test_project.c
+++ b/test/test_project.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -66,32 +53,34 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "project.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
- lilv_node_free(author_name);
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!strcmp(lilv_node_as_string(author_name), "David Robillard"));
+ lilv_node_free(author_name);
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
- lilv_node_free(author_email);
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!strcmp(lilv_node_as_string(author_email), "mailto:d@drobilla.net"));
+ lilv_node_free(author_email);
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(
- !strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
- lilv_node_free(author_homepage);
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(!strcmp(lilv_node_as_string(author_homepage), "http://drobilla.net"));
+ lilv_node_free(author_homepage);
- delete_bundle(env);
- lilv_test_env_free(env);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_project_no_author.c b/test/test_project_no_author.c
index 017d359..5b0e57d 100644
--- a/test/test_project_no_author.c
+++ b/test/test_project_no_author.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -60,28 +47,32 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(
+ env, "project_no_author.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
- LilvNode* author_name = lilv_plugin_get_author_name(plug);
- assert(!author_name);
+ LilvNode* author_name = lilv_plugin_get_author_name(plug);
+ assert(!author_name);
- LilvNode* author_email = lilv_plugin_get_author_email(plug);
- assert(!author_email);
+ LilvNode* author_email = lilv_plugin_get_author_email(plug);
+ assert(!author_email);
- LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
- assert(!author_homepage);
+ LilvNode* author_homepage = lilv_plugin_get_author_homepage(plug);
+ assert(!author_homepage);
- delete_bundle(env);
- lilv_test_env_free(env);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_prototype.c b/test/test_prototype.c
index 4ad516e..4e17a63 100644
--- a/test/test_prototype.c
+++ b/test/test_prototype.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -73,28 +60,31 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "prototype.lv2", manifest_ttl, plugin_ttl)) {
+ return 1;
+ }
- if (start_bundle(env, manifest_ttl, plugin_ttl)) {
- return 1;
- }
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
- // Test non-inherited property
- LilvNode* name = lilv_plugin_get_name(plug);
- assert(!strcmp(lilv_node_as_string(name), "Instance"));
- lilv_node_free(name);
+ // Test non-inherited property
+ LilvNode* name = lilv_plugin_get_name(plug);
+ assert(!strcmp(lilv_node_as_string(name), "Instance"));
+ lilv_node_free(name);
- // Test inherited property
- const LilvNode* binary = lilv_plugin_get_library_uri(plug);
- assert(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
+ // Test inherited property
+ const LilvNode* binary = lilv_plugin_get_library_uri(plug);
+ assert(strstr(lilv_node_as_string(binary), "inst" SHLIB_EXT));
- delete_bundle(env);
- lilv_test_env_free(env);
+ delete_bundle(env);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/test/test_reload_bundle.c b/test/test_reload_bundle.c
index 19644ff..a2630fc 100644
--- a/test/test_reload_bundle.c
+++ b/test/test_reload_bundle.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -26,67 +13,68 @@
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
-
- // Create a simple plugin bundle
- create_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT
- "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"First name\" .");
-
- lilv_world_load_specifications(world);
-
- // Load bundle
- LilvNode* bundle_uri = lilv_new_uri(world, env->test_bundle_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, env->plugin1_uri);
- assert(plug);
-
- // Check that plugin name is correct
- LilvNode* name = lilv_plugin_get_name(plug);
- 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(env);
-
- // Create a new version of the same bundle, but with a different name
- create_bundle(env,
- ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT
- "> ; rdfs:seeAlso <plugin.ttl> .\n",
- ":plug a lv2:Plugin ; "
- "doap:name \"Second name\" .");
-
- // Check that plugin is no longer in the world's plugin list
- 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, env->plugin1_uri);
- assert(plug2);
- assert(plug2 == plug);
-
- // Check that plugin now has new name
- LilvNode* name2 = lilv_plugin_get_name(plug2);
- assert(name2);
- 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);
-
- lilv_node_free(bundle_uri);
- delete_bundle(env);
- lilv_test_env_free(env);
-
- return 0;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ lilv_world_load_all(world);
+
+ // Create a simple plugin bundle
+ create_bundle(env,
+ "reload_bundle.lv2",
+ ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT
+ "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ ":plug a lv2:Plugin ; "
+ "doap:name \"First name\" .");
+
+ lilv_world_load_specifications(world);
+
+ // Load bundle
+ lilv_world_load_bundle(world, env->test_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, env->plugin1_uri);
+ assert(plug);
+
+ // Check that plugin name is correct
+ LilvNode* name = lilv_plugin_get_name(plug);
+ 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, env->test_bundle_uri);
+ delete_bundle(env);
+
+ // Create a new version of the same bundle, but with a different name
+ create_bundle(env,
+ "test_reload_bundle.lv2",
+ ":plug a lv2:Plugin ; lv2:binary <foo" SHLIB_EXT
+ "> ; rdfs:seeAlso <plugin.ttl> .\n",
+ ":plug a lv2:Plugin ; "
+ "doap:name \"Second name\" .");
+
+ // Check that plugin is no longer in the world's plugin list
+ assert(lilv_plugins_size(plugins) == 0);
+
+ // Load new bundle
+ lilv_world_load_bundle(world, env->test_bundle_uri);
+
+ // Check that plugin is present again and is the same LilvPlugin
+ const LilvPlugin* plug2 = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug2);
+ assert(plug2 == plug);
+
+ // Check that plugin now has new name
+ LilvNode* name2 = lilv_plugin_get_name(plug2);
+ assert(name2);
+ assert(!strcmp(lilv_node_as_string(name2), "Second name"));
+ lilv_node_free(name2);
+
+ // Load new bundle again (noop)
+ lilv_world_load_bundle(world, env->test_bundle_uri);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_replace_version.c b/test/test_replace_version.c
index a686572..c6fb3e6 100644
--- a/test/test_replace_version.c
+++ b/test/test_replace_version.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -30,76 +17,76 @@
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
-
- 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 = lilv_strjoin(LILV_TEST_DIR, "old_version.lv2/", 0);
-
- // 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);
- assert(old_plug);
- minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
- micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
- assert(!strcmp(lilv_node_as_string(minor), "1"));
- assert(!strcmp(lilv_node_as_string(micro), "0"));
- lilv_node_free(micro);
- lilv_node_free(minor);
-
- char* new_bundle_path = lilv_strjoin(LILV_TEST_DIR, "new_version.lv2/", 0);
-
- // 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);
- assert(new_plug);
- 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);
- assert(!strcmp(lilv_node_as_string(minor), "2"));
- 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);
- assert(new_plug);
- minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
- micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
- assert(!strcmp(lilv_node_as_string(minor), "2"));
- 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);
-
- lilv_test_env_free(env);
-
- return 0;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ 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 = lilv_strjoin(LILV_TEST_DIR, "old_version.lv2/", 0);
+
+ // 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);
+ assert(old_plug);
+ minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
+ micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
+ assert(!strcmp(lilv_node_as_string(minor), "1"));
+ assert(!strcmp(lilv_node_as_string(micro), "0"));
+ lilv_node_free(micro);
+ lilv_node_free(minor);
+
+ char* new_bundle_path = lilv_strjoin(LILV_TEST_DIR, "new_version.lv2/", 0);
+
+ // 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);
+ assert(new_plug);
+ 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);
+ assert(!strcmp(lilv_node_as_string(minor), "2"));
+ 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);
+ assert(new_plug);
+ minor = lilv_world_get(world, plug_uri, lv2_minorVersion, 0);
+ micro = lilv_world_get(world, plug_uri, lv2_microVersion, 0);
+ assert(!strcmp(lilv_node_as_string(minor), "2"));
+ 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);
+
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_state.c b/test/test_state.c
index a9260b9..67325d2 100644
--- a/test/test_state.c
+++ b/test/test_state.c
@@ -1,38 +1,25 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
#include "lilv_test_uri_map.h"
#include "lilv_test_utils.h"
-#include "../src/filesystem.h"
-#include "../src/lilv_internal.h"
-
#include "lilv/lilv.h"
#include "lv2/core/lv2.h"
#include "lv2/state/state.h"
#include "lv2/urid/urid.h"
#include "serd/serd.h"
+#include "zix/allocator.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
#ifdef _WIN32
-# include <direct.h>
-# define mkdir(path, flags) _mkdir(path)
+# include <direct.h>
+# define mkdir(path, flags) _mkdir(path)
#else
-# include <sys/stat.h>
+# include <sys/stat.h>
#endif
#include <assert.h>
@@ -44,143 +31,149 @@
#define TEST_PLUGIN_URI "http://example.org/lilv-test-plugin"
-typedef struct
-{
- LilvTestEnv* env;
- LilvTestUriMap uri_map;
- LV2_URID_Map map;
- LV2_Feature map_feature;
- LV2_URID_Unmap unmap;
- LV2_Feature unmap_feature;
- LV2_State_Free_Path free_path;
- LV2_Feature free_path_feature;
- const LV2_Feature* features[4];
- LV2_URID atom_Float;
- float in;
- float out;
- float control;
+typedef struct {
+ LilvTestEnv* env;
+ LilvTestUriMap uri_map;
+ LV2_URID_Map map;
+ LV2_Feature map_feature;
+ LV2_URID_Unmap unmap;
+ LV2_Feature unmap_feature;
+ LV2_State_Free_Path free_path;
+ LV2_Feature free_path_feature;
+ const LV2_Feature* features[4];
+ LV2_URID atom_Float;
+ float in;
+ float out;
+ float control;
} TestContext;
-typedef struct
-{
- char* top; ///< Temporary directory that contains everything
- char* shared; ///< Common parent for shared directoryes (top/shared)
- char* scratch; ///< Scratch file directory (top/shared/scratch)
- char* copy; ///< Copy directory (top/shared/scratch)
- char* link; ///< Link directory (top/shared/scratch)
+typedef struct {
+ char* top; ///< Temporary directory that contains everything
+ char* shared; ///< Common parent for shared directoryes (top/shared)
+ char* scratch; ///< Scratch file directory (top/shared/scratch)
+ char* copy; ///< Copy directory (top/shared/scratch)
+ char* link; ///< Link directory (top/shared/scratch)
} TestDirectories;
static void
lilv_free_path(LV2_State_Free_Path_Handle handle, char* path)
{
- (void)handle;
+ (void)handle;
- lilv_free(path);
+ lilv_free(path);
}
static TestContext*
test_context_new(void)
{
- TestContext* ctx = (TestContext*)calloc(1, sizeof(TestContext));
-
- lilv_test_uri_map_init(&ctx->uri_map);
-
- ctx->env = lilv_test_env_new();
- ctx->map.handle = &ctx->uri_map;
- ctx->map.map = map_uri;
- ctx->map_feature.URI = LV2_URID_MAP_URI;
- ctx->map_feature.data = &ctx->map;
- ctx->unmap.handle = &ctx->uri_map;
- ctx->unmap.unmap = unmap_uri;
- ctx->unmap_feature.URI = LV2_URID_UNMAP_URI;
- ctx->unmap_feature.data = &ctx->unmap;
- ctx->free_path.free_path = lilv_free_path;
- ctx->free_path_feature.URI = LV2_STATE__freePath;
- ctx->free_path_feature.data = &ctx->free_path;
- ctx->features[0] = &ctx->map_feature;
- ctx->features[1] = &ctx->unmap_feature;
- ctx->features[2] = &ctx->free_path_feature;
- ctx->features[3] = NULL;
-
- ctx->atom_Float =
- map_uri(&ctx->uri_map, "http://lv2plug.in/ns/ext/atom#Float");
-
- ctx->in = 1.0;
- ctx->out = 42.0;
- ctx->control = 1234.0;
-
- return ctx;
+ TestContext* ctx = (TestContext*)calloc(1, sizeof(TestContext));
+
+ lilv_test_uri_map_init(&ctx->uri_map);
+
+ ctx->env = lilv_test_env_new();
+ ctx->map.handle = &ctx->uri_map;
+ ctx->map.map = map_uri;
+ ctx->map_feature.URI = LV2_URID_MAP_URI;
+ ctx->map_feature.data = &ctx->map;
+ ctx->unmap.handle = &ctx->uri_map;
+ ctx->unmap.unmap = unmap_uri;
+ ctx->unmap_feature.URI = LV2_URID_UNMAP_URI;
+ ctx->unmap_feature.data = &ctx->unmap;
+ ctx->free_path.free_path = lilv_free_path;
+ ctx->free_path_feature.URI = LV2_STATE__freePath;
+ ctx->free_path_feature.data = &ctx->free_path;
+ ctx->features[0] = &ctx->map_feature;
+ ctx->features[1] = &ctx->unmap_feature;
+ ctx->features[2] = &ctx->free_path_feature;
+ ctx->features[3] = NULL;
+
+ ctx->atom_Float =
+ map_uri(&ctx->uri_map, "http://lv2plug.in/ns/ext/atom#Float");
+
+ ctx->in = 1.0;
+ ctx->out = 42.0;
+ ctx->control = 1234.0;
+
+ return ctx;
}
static void
test_context_free(TestContext* ctx)
{
- lilv_test_uri_map_clear(&ctx->uri_map);
- lilv_test_env_free(ctx->env);
- free(ctx);
+ lilv_test_uri_map_clear(&ctx->uri_map);
+ lilv_test_env_free(ctx->env);
+ free(ctx);
}
static TestDirectories
create_test_directories(void)
{
- TestDirectories dirs;
+ TestDirectories dirs;
- char* const top = lilv_create_temporary_directory("lilv_XXXXXX");
- assert(top);
+ char* const top = lilv_create_temporary_directory("lilv_XXXXXX");
+ assert(top);
- /* On MacOS, temporary directories from mkdtemp involve symlinks, so
- resolve it here so that path comparisons in tests work. */
+ /* On MacOS, temporary directories from mkdtemp involve symlinks, so
+ resolve it here so that path comparisons in tests work. */
- dirs.top = lilv_path_canonical(top);
- dirs.shared = lilv_path_join(dirs.top, "shared");
- dirs.scratch = lilv_path_join(dirs.shared, "scratch");
- dirs.copy = lilv_path_join(dirs.shared, "copy");
- dirs.link = lilv_path_join(dirs.shared, "link");
+ dirs.top = zix_canonical_path(NULL, top);
+ dirs.shared = zix_path_join(NULL, dirs.top, "shared");
+ dirs.scratch = zix_path_join(NULL, dirs.shared, "scratch");
+ dirs.copy = zix_path_join(NULL, dirs.shared, "copy");
+ dirs.link = zix_path_join(NULL, dirs.shared, "link");
- assert(!mkdir(dirs.shared, 0700));
- assert(!mkdir(dirs.scratch, 0700));
- assert(!mkdir(dirs.copy, 0700));
- assert(!mkdir(dirs.link, 0700));
+ assert(dirs.top);
+ assert(dirs.shared);
+ assert(dirs.scratch);
+ assert(dirs.copy);
+ assert(dirs.link);
- free(top);
+ assert(!mkdir(dirs.shared, 0700));
+ assert(!mkdir(dirs.scratch, 0700));
+ assert(!mkdir(dirs.copy, 0700));
+ assert(!mkdir(dirs.link, 0700));
- return dirs;
+ free(top);
+
+ return dirs;
}
static TestDirectories
no_test_directories(void)
{
- TestDirectories dirs = {NULL, NULL, NULL, NULL, NULL};
+ TestDirectories dirs = {NULL, NULL, NULL, NULL, NULL};
- return dirs;
+ return dirs;
}
static void
remove_file(const char* path, const char* name, void* data)
{
- char* const full_path = lilv_path_join(path, name);
- assert(!lilv_remove(full_path));
- free(full_path);
+ (void)data;
+
+ char* const full_path = zix_path_join(NULL, path, name);
+ assert(!zix_remove(full_path));
+ free(full_path);
}
static void
cleanup_test_directories(const TestDirectories dirs)
{
- lilv_dir_for_each(dirs.scratch, NULL, remove_file);
- lilv_dir_for_each(dirs.copy, NULL, remove_file);
- lilv_dir_for_each(dirs.link, NULL, remove_file);
-
- assert(!lilv_remove(dirs.link));
- assert(!lilv_remove(dirs.copy));
- assert(!lilv_remove(dirs.scratch));
- assert(!lilv_remove(dirs.shared));
- assert(!lilv_remove(dirs.top));
-
- free(dirs.link);
- free(dirs.copy);
- free(dirs.scratch);
- free(dirs.shared);
- free(dirs.top);
+ zix_dir_for_each(dirs.scratch, NULL, remove_file);
+ zix_dir_for_each(dirs.copy, NULL, remove_file);
+ zix_dir_for_each(dirs.link, NULL, remove_file);
+
+ assert(!zix_remove(dirs.link));
+ assert(!zix_remove(dirs.copy));
+ assert(!zix_remove(dirs.scratch));
+ assert(!zix_remove(dirs.shared));
+ assert(!zix_remove(dirs.top));
+
+ zix_free(NULL, dirs.link);
+ zix_free(NULL, dirs.copy);
+ zix_free(NULL, dirs.scratch);
+ zix_free(NULL, dirs.shared);
+ free(dirs.top);
}
static const void*
@@ -189,27 +182,30 @@ get_port_value(const char* port_symbol,
uint32_t* size,
uint32_t* type)
{
- TestContext* ctx = (TestContext*)user_data;
-
- if (!strcmp(port_symbol, "input")) {
- *size = sizeof(float);
- *type = ctx->atom_Float;
- return &ctx->in;
- } else if (!strcmp(port_symbol, "output")) {
- *size = sizeof(float);
- *type = ctx->atom_Float;
- return &ctx->out;
- } else if (!strcmp(port_symbol, "control")) {
- *size = sizeof(float);
- *type = ctx->atom_Float;
- return &ctx->control;
- } else {
- fprintf(stderr,
- "error: get_port_value for nonexistent port `%s'\n",
- port_symbol);
- *size = *type = 0;
- return NULL;
- }
+ TestContext* ctx = (TestContext*)user_data;
+
+ if (!strcmp(port_symbol, "input")) {
+ *size = sizeof(float);
+ *type = ctx->atom_Float;
+ return &ctx->in;
+ }
+
+ if (!strcmp(port_symbol, "output")) {
+ *size = sizeof(float);
+ *type = ctx->atom_Float;
+ return &ctx->out;
+ }
+
+ if (!strcmp(port_symbol, "control")) {
+ *size = sizeof(float);
+ *type = ctx->atom_Float;
+ return &ctx->control;
+ }
+
+ fprintf(
+ stderr, "error: get_port_value for nonexistent port `%s'\n", port_symbol);
+ *size = *type = 0;
+ return NULL;
}
static void
@@ -219,50 +215,48 @@ set_port_value(const char* port_symbol,
uint32_t size,
uint32_t type)
{
- TestContext* ctx = (TestContext*)user_data;
-
- if (!strcmp(port_symbol, "input")) {
- ctx->in = *(const float*)value;
- } else if (!strcmp(port_symbol, "output")) {
- ctx->out = *(const float*)value;
- } else if (!strcmp(port_symbol, "control")) {
- ctx->control = *(const float*)value;
- } else {
- fprintf(stderr,
- "error: set_port_value for nonexistent port `%s'\n",
- port_symbol);
- }
+ (void)size;
+ (void)type;
+
+ TestContext* ctx = (TestContext*)user_data;
+
+ if (!strcmp(port_symbol, "input")) {
+ ctx->in = *(const float*)value;
+ } else if (!strcmp(port_symbol, "output")) {
+ ctx->out = *(const float*)value;
+ } else if (!strcmp(port_symbol, "control")) {
+ ctx->control = *(const float*)value;
+ } else {
+ fprintf(
+ stderr, "error: set_port_value for nonexistent port `%s'\n", port_symbol);
+ }
}
static char*
make_scratch_path(LV2_State_Make_Path_Handle handle, const char* path)
{
- TestDirectories* dirs = (TestDirectories*)handle;
+ TestDirectories* dirs = (TestDirectories*)handle;
- return lilv_path_join(dirs->scratch, path);
+ return zix_path_join(NULL, dirs->scratch, path);
}
static const LilvPlugin*
load_test_plugin(const TestContext* const ctx)
{
- LilvWorld* world = ctx->env->world;
- uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(LILV_TEST_BUNDLE);
- SerdNode bundle = serd_node_new_file_uri(abs_bundle, 0, 0, true);
- LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf);
- LilvNode* plugin_uri = lilv_new_uri(world, TEST_PLUGIN_URI);
+ LilvWorld* world = ctx->env->world;
+ LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, LILV_TEST_BUNDLE);
+ LilvNode* plugin_uri = lilv_new_uri(world, TEST_PLUGIN_URI);
- lilv_world_load_bundle(world, bundle_uri);
+ lilv_world_load_bundle(world, bundle_uri);
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
- lilv_node_free(plugin_uri);
- lilv_node_free(bundle_uri);
- serd_node_free(&bundle);
- free(abs_bundle);
+ lilv_node_free(plugin_uri);
+ lilv_node_free(bundle_uri);
- assert(plugin);
- return plugin;
+ assert(plugin);
+ return plugin;
}
static LilvState*
@@ -272,735 +266,866 @@ state_from_instance(const LilvPlugin* const plugin,
const TestDirectories* const dirs,
const char* const bundle_path)
{
- return lilv_state_new_from_instance(plugin,
- instance,
- &ctx->map,
- dirs->scratch,
- dirs->copy,
- dirs->link,
- bundle_path,
- get_port_value,
- ctx,
- 0,
- NULL);
+ return lilv_state_new_from_instance(plugin,
+ instance,
+ &ctx->map,
+ dirs->scratch,
+ dirs->copy,
+ dirs->link,
+ bundle_path,
+ get_port_value,
+ ctx,
+ 0,
+ NULL);
}
static void
test_instance_state(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = no_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = no_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
- assert(instance);
+ assert(instance);
- // Get instance state
- LilvState* const state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
+ // Get instance state
+ LilvState* const state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
- // Check that state contains properties saved by the plugin
- assert(lilv_state_get_num_properties(state) == 8);
+ // Check that state contains properties saved by the plugin
+ assert(lilv_state_get_num_properties(state) == 8);
- // Check that state has no URI
- assert(!lilv_state_get_uri(state));
+ // Check that state has no URI
+ assert(!lilv_state_get_uri(state));
- // Check that state can't be saved without a URI
- assert(!lilv_state_to_string(
- ctx->env->world, &ctx->map, &ctx->unmap, state, NULL, NULL));
+ // Check that state can't be saved without a URI
+ assert(!lilv_state_to_string(
+ ctx->env->world, &ctx->map, &ctx->unmap, state, NULL, NULL));
- // Check that we can't delete unsaved state
- assert(lilv_state_delete(ctx->env->world, state));
+ // Check that we can't delete unsaved state
+ assert(lilv_state_delete(ctx->env->world, state));
- lilv_state_free(state);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ lilv_state_free(state);
+ lilv_instance_free(instance);
+ test_context_free(ctx);
}
static void
test_equal(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = no_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = no_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
- assert(instance);
+ assert(instance);
- // Get instance state
- LilvState* const state_1 =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
+ // Get instance state
+ LilvState* const state_1 =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
- // Get another instance state
- LilvState* const state_2 =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
+ // Get another instance state
+ LilvState* const state_2 =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
- // Ensure they are equal
- assert(lilv_state_equals(state_1, state_2));
+ // Ensure they are equal
+ assert(lilv_state_equals(state_1, state_2));
- // Set a label on the second state
- assert(lilv_state_get_label(state_2) == NULL);
- lilv_state_set_label(state_2, "Test State Old Label");
+ // Set a label on the second state
+ assert(lilv_state_get_label(state_2) == NULL);
+ lilv_state_set_label(state_2, "Test State Old Label");
- // Ensure they are no longer equal
- assert(!lilv_state_equals(state_1, state_2));
+ // Ensure they are no longer equal
+ assert(!lilv_state_equals(state_1, state_2));
- lilv_state_free(state_2);
- lilv_state_free(state_1);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ lilv_state_free(state_2);
+ lilv_state_free(state_1);
+ lilv_instance_free(instance);
+ test_context_free(ctx);
}
static void
test_changed_plugin_data(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = no_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
-
- assert(instance);
-
- // Get initial state
- LilvState* const initial_state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Run plugin to change internal state
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &ctx->in);
- lilv_instance_connect_port(instance, 1, &ctx->out);
- lilv_instance_run(instance, 1);
- assert(ctx->in == 1.0);
- assert(ctx->out == 1.0);
-
- // Get a new instance state (which should now differ)
- LilvState* const changed_state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Ensure state has changed
- assert(!lilv_state_equals(initial_state, changed_state));
-
- lilv_state_free(changed_state);
- lilv_state_free(initial_state);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = no_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+
+ assert(instance);
+
+ // Get initial state
+ LilvState* const initial_state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Run plugin to change internal state
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &ctx->in);
+ lilv_instance_connect_port(instance, 1, &ctx->out);
+ lilv_instance_run(instance, 1);
+ assert(ctx->in == 1.0);
+ assert(ctx->out == 1.0);
+
+ // Get a new instance state (which should now differ)
+ LilvState* const changed_state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Ensure state has changed
+ assert(!lilv_state_equals(initial_state, changed_state));
+
+ lilv_state_free(changed_state);
+ lilv_state_free(initial_state);
+ lilv_instance_free(instance);
+ test_context_free(ctx);
}
static void
test_changed_metadata(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = no_test_directories();
- LV2_URID_Map* const map = &ctx->map;
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
-
- assert(instance);
-
- // Get initial state
- LilvState* const initial_state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Save initial state to a string
- char* const initial_string =
- lilv_state_to_string(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- initial_state,
- "http://example.org/initial",
- NULL);
-
- // Get another state
- LilvState* const changed_state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Set a metadata property
- const LV2_URID key = map->map(map->handle, "http://example.org/extra");
- const int32_t value = 1;
- const LV2_URID type =
- map->map(map->handle, "http://lv2plug.in/ns/ext/atom#Int");
- lilv_state_set_metadata(changed_state,
- key,
- &value,
- sizeof(value),
- type,
- LV2_STATE_IS_PORTABLE | LV2_STATE_IS_POD);
-
- // Save changed state to a string
- char* const changed_string =
- lilv_state_to_string(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- changed_state,
- "http://example.org/changed",
- NULL);
-
- // Ensure that strings differ (metadata does not affect state equality)
- assert(strcmp(initial_string, changed_string));
-
- free(changed_string);
- lilv_state_free(changed_state);
- free(initial_string);
- lilv_state_free(initial_state);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = no_test_directories();
+ LV2_URID_Map* const map = &ctx->map;
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+
+ assert(instance);
+
+ // Get initial state
+ LilvState* const initial_state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Save initial state to a string
+ char* const initial_string =
+ lilv_state_to_string(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ initial_state,
+ "http://example.org/initial",
+ NULL);
+
+ // Get another state
+ LilvState* const changed_state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Set a metadata property
+ const LV2_URID key = map->map(map->handle, "http://example.org/extra");
+ const int32_t value = 1;
+ const LV2_URID type =
+ map->map(map->handle, "http://lv2plug.in/ns/ext/atom#Int");
+ lilv_state_set_metadata(changed_state,
+ key,
+ &value,
+ sizeof(value),
+ type,
+ LV2_STATE_IS_PORTABLE | LV2_STATE_IS_POD);
+
+ // Save changed state to a string
+ char* const changed_string =
+ lilv_state_to_string(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ changed_state,
+ "http://example.org/changed",
+ NULL);
+
+ // Ensure that strings differ (metadata does not affect state equality)
+ assert(strcmp(initial_string, changed_string));
+
+ free(changed_string);
+ lilv_state_free(changed_state);
+ free(initial_string);
+ lilv_state_free(initial_state);
+ lilv_instance_free(instance);
+ test_context_free(ctx);
}
static void
test_to_string(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = no_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
-
- assert(instance);
-
- // Get initial state
- LilvState* const initial_state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Run plugin to change internal state
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &ctx->in);
- lilv_instance_connect_port(instance, 1, &ctx->out);
- lilv_instance_run(instance, 1);
- assert(ctx->in == 1.0);
- assert(ctx->out == 1.0);
-
- // Restore instance state to original state
- lilv_state_restore(initial_state, instance, set_port_value, ctx, 0, NULL);
-
- // Take a new snapshot of the state
- LilvState* const restored =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Check that new state matches the initial state
- assert(lilv_state_equals(initial_state, restored));
-
- lilv_state_free(restored);
- lilv_state_free(initial_state);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = no_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+
+ assert(instance);
+
+ // Get initial state
+ LilvState* const initial_state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Run plugin to change internal state
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &ctx->in);
+ lilv_instance_connect_port(instance, 1, &ctx->out);
+ lilv_instance_run(instance, 1);
+ assert(ctx->in == 1.0);
+ assert(ctx->out == 1.0);
+
+ // Restore instance state to original state
+ lilv_state_restore(initial_state, instance, set_port_value, ctx, 0, NULL);
+
+ // Take a new snapshot of the state
+ LilvState* const restored =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Check that new state matches the initial state
+ assert(lilv_state_equals(initial_state, restored));
+
+ lilv_state_free(restored);
+ lilv_state_free(initial_state);
+ lilv_instance_free(instance);
+ test_context_free(ctx);
}
static void
test_string_round_trip(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = no_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
-
- assert(instance);
-
- // Get initial state
- LilvState* const initial_state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Save state to a string
- char* const string = lilv_state_to_string(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- initial_state,
- "http://example.org/string",
- NULL);
-
- // Restore from string
- LilvState* const restored =
- lilv_state_new_from_string(ctx->env->world, &ctx->map, string);
-
- // Ensure they are equal
- assert(lilv_state_equals(initial_state, restored));
-
- // Check that the restored state refers to the correct plugin
- const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(restored);
- assert(!strcmp(lilv_node_as_string(state_plugin_uri), TEST_PLUGIN_URI));
-
- lilv_state_free(restored);
- free(string);
- lilv_state_free(initial_state);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = no_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+
+ assert(instance);
+
+ // Get initial state
+ LilvState* const initial_state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Save state to a string
+ char* const string = lilv_state_to_string(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ initial_state,
+ "http://example.org/string",
+ NULL);
+
+ // Restore from string
+ LilvState* const restored =
+ lilv_state_new_from_string(ctx->env->world, &ctx->map, string);
+
+ // Ensure they are equal
+ assert(lilv_state_equals(initial_state, restored));
+
+ // Check that the restored state refers to the correct plugin
+ const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(restored);
+ assert(!strcmp(lilv_node_as_string(state_plugin_uri), TEST_PLUGIN_URI));
+
+ lilv_state_free(restored);
+ free(string);
+ lilv_state_free(initial_state);
+ lilv_instance_free(instance);
+ test_context_free(ctx);
+}
+
+static SerdStatus
+count_sink(void* const handle,
+ const SerdStatementFlags flags,
+ const SerdNode* const graph,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const object_datatype,
+ const SerdNode* const object_lang)
+{
+ (void)flags;
+ (void)graph;
+ (void)subject;
+ (void)predicate;
+ (void)object;
+ (void)object_datatype;
+ (void)object_lang;
+
+ size_t* const n_statements = (size_t*)handle;
+
+ ++(*n_statements);
+
+ return SERD_SUCCESS;
+}
+
+static size_t
+count_statements(const char* path)
+{
+ size_t n_statements = 0;
+
+ SerdReader* reader = serd_reader_new(
+ SERD_TURTLE, &n_statements, NULL, NULL, NULL, count_sink, NULL);
+
+ SerdNode uri = serd_node_new_file_uri((const uint8_t*)path, NULL, NULL, true);
+
+ assert(uri.buf);
+ assert(!serd_reader_read_file(reader, (const uint8_t*)uri.buf));
+
+ serd_node_free(&uri);
+ serd_reader_free(reader);
+
+ return n_statements;
}
static void
test_to_files(void)
{
- TestContext* const ctx = test_context_new();
- TestDirectories dirs = create_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
-
- LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
- LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
-
- const LV2_Feature* const instance_features[] = {&ctx->map_feature,
- &ctx->free_path_feature,
- &make_path_feature,
- NULL};
-
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, instance_features);
-
- assert(instance);
-
- // Run plugin to generate some recording file data
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &ctx->in);
- lilv_instance_connect_port(instance, 1, &ctx->out);
- lilv_instance_run(instance, 1);
- lilv_instance_run(instance, 2);
- assert(ctx->in == 1.0);
- assert(ctx->out == 1.0);
-
- // Check that the test plugin has made its recording scratch file
- char* const recfile_path = lilv_path_join(dirs.scratch, "recfile");
- assert(lilv_path_exists(recfile_path));
-
- // Get state
- char* const bundle_1_path = lilv_path_join(dirs.top, "state1.lv2");
- LilvState* const state_1 =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_1_path);
-
- // Check that state contains properties saved by the plugin (with files)
- assert(lilv_state_get_num_properties(state_1) == 10);
-
- // Check that a snapshop of the recfile was created
- char* const recfile_copy_1 = lilv_path_join(dirs.copy, "recfile");
- assert(lilv_path_exists(recfile_copy_1));
-
- // Set a label and save state to a bundle
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state_1,
- "http://example.org/state1",
- bundle_1_path,
- "state.ttl"));
-
- // Check that a link to the recfile exists in the saved bundle
- char* const recfile_link_1 = lilv_path_join(bundle_1_path, "recfile");
- assert(lilv_path_exists(recfile_link_1));
-
- // Check that link points to the corresponding copy
- char* const recfile_link_1_real = lilv_path_canonical(recfile_link_1);
- assert(!strcmp(recfile_link_1_real, recfile_copy_1));
-
- // Run plugin again to modify recording file data
- lilv_instance_run(instance, 2);
-
- // Get updated state
- char* const bundle_2_path = lilv_path_join(dirs.top, "state2.lv2");
- LilvState* const state_2 =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_2_path);
-
- // Save updated state to a bundle
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state_2,
- NULL,
- bundle_2_path,
- "state.ttl"));
-
- // Check that a new snapshop of the recfile was created
- char* const recfile_copy_2 = lilv_path_join(dirs.copy, "recfile.2");
- assert(lilv_path_exists(recfile_copy_2));
-
- // Check that a link to the recfile exists in the updated bundle
- char* const recfile_link_2 = lilv_path_join(bundle_2_path, "recfile");
- assert(lilv_path_exists(recfile_link_2));
-
- // Check that link points to the corresponding copy
- char* const recfile_link_2_real = lilv_path_canonical(recfile_link_2);
- assert(!strcmp(recfile_link_2_real, recfile_copy_2));
-
- lilv_dir_for_each(bundle_2_path, NULL, remove_file);
- lilv_dir_for_each(bundle_1_path, NULL, remove_file);
- lilv_remove(bundle_2_path);
- lilv_remove(bundle_1_path);
- cleanup_test_directories(dirs);
-
- free(recfile_link_2_real);
- free(recfile_link_2);
- free(recfile_copy_2);
- lilv_state_free(state_2);
- free(bundle_2_path);
- free(recfile_link_1_real);
- free(recfile_link_1);
- free(recfile_copy_1);
- lilv_state_free(state_1);
- free(bundle_1_path);
- free(recfile_path);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ TestDirectories dirs = create_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+
+ LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
+ LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
+
+ const LV2_Feature* const instance_features[] = {
+ &ctx->map_feature, &ctx->free_path_feature, &make_path_feature, NULL};
+
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, instance_features);
+
+ assert(instance);
+
+ // Run plugin to generate some recording file data
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &ctx->in);
+ lilv_instance_connect_port(instance, 1, &ctx->out);
+ lilv_instance_run(instance, 1);
+ lilv_instance_run(instance, 2);
+ assert(ctx->in == 1.0);
+ assert(ctx->out == 1.0);
+
+ // Check that the test plugin has made its recording scratch file
+ char* const recfile_path = zix_path_join(NULL, dirs.scratch, "recfile");
+ assert(zix_file_type(recfile_path) == ZIX_FILE_TYPE_REGULAR);
+
+ // Get state
+ char* const bundle_1_path = zix_path_join(NULL, dirs.top, "state1.lv2");
+ LilvState* const state_1 =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_1_path);
+
+ // Check that state contains properties saved by the plugin (with files)
+ assert(lilv_state_get_num_properties(state_1) == 10);
+
+ // Check that a snapshop of the recfile was created
+ char* const recfile_copy_1 = zix_path_join(NULL, dirs.copy, "recfile");
+ assert(zix_file_type(recfile_copy_1) == ZIX_FILE_TYPE_REGULAR);
+
+ // Save state to a bundle
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_1,
+ "http://example.org/state1",
+ bundle_1_path,
+ "state.ttl"));
+
+ // Check that a manifest exists
+ char* const manifest_path =
+ zix_path_join(NULL, bundle_1_path, "manifest.ttl");
+ assert(zix_file_type(manifest_path) == ZIX_FILE_TYPE_REGULAR);
+
+ // Check that the expected statements are in the manifest file
+ assert(count_statements(manifest_path) == 3);
+
+ // Check that a link to the recfile exists in the saved bundle
+ char* const recfile_link_1 = zix_path_join(NULL, bundle_1_path, "recfile");
+ assert(zix_file_type(recfile_link_1) == ZIX_FILE_TYPE_REGULAR);
+#ifndef _WIN32
+ assert(zix_symlink_type(recfile_link_1) == ZIX_FILE_TYPE_SYMLINK);
+#endif
+
+ // Check that link points to the corresponding copy
+ assert(zix_file_equals(NULL, recfile_link_1, recfile_copy_1));
+
+ // Run plugin again to modify recording file data
+ lilv_instance_run(instance, 2);
+
+ // Get updated state
+ char* const bundle_2_path = zix_path_join(NULL, dirs.top, "state2.lv2");
+ LilvState* const state_2 =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_2_path);
+
+ // Save updated state to a bundle
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_2,
+ NULL,
+ bundle_2_path,
+ "state.ttl"));
+
+ // Check that a new snapshop of the recfile was created
+ char* const recfile_copy_2 = zix_path_join(NULL, dirs.copy, "recfile.2");
+ assert(zix_file_type(recfile_copy_2) == ZIX_FILE_TYPE_REGULAR);
+
+ // Check that a link to the recfile exists in the updated bundle
+ char* const recfile_link_2 = zix_path_join(NULL, bundle_2_path, "recfile");
+ assert(zix_file_type(recfile_link_2) == ZIX_FILE_TYPE_REGULAR);
+#ifndef _WIN32
+ assert(zix_symlink_type(recfile_link_2) == ZIX_FILE_TYPE_SYMLINK);
+#endif
+
+ // Check that link points to the corresponding copy
+ assert(zix_file_equals(NULL, recfile_link_2, recfile_copy_2));
+
+ lilv_instance_free(instance);
+ zix_dir_for_each(bundle_2_path, NULL, remove_file);
+ zix_dir_for_each(bundle_1_path, NULL, remove_file);
+ assert(!zix_remove(bundle_2_path));
+ assert(!zix_remove(bundle_1_path));
+ cleanup_test_directories(dirs);
+
+ zix_free(NULL, recfile_link_2);
+ zix_free(NULL, recfile_copy_2);
+ lilv_state_free(state_2);
+ zix_free(NULL, bundle_2_path);
+ zix_free(NULL, recfile_link_1);
+ zix_free(NULL, manifest_path);
+ zix_free(NULL, recfile_copy_1);
+ lilv_state_free(state_1);
+ zix_free(NULL, bundle_1_path);
+ zix_free(NULL, recfile_path);
+ test_context_free(ctx);
+}
+
+static void
+test_multi_save(void)
+{
+ TestContext* const ctx = test_context_new();
+ TestDirectories dirs = create_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+
+ LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
+ LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
+
+ const LV2_Feature* const instance_features[] = {
+ &ctx->map_feature, &ctx->free_path_feature, &make_path_feature, NULL};
+
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, instance_features);
+
+ assert(instance);
+
+ // Get state
+ char* const bundle_1_path = zix_path_join(NULL, dirs.top, "state1.lv2");
+ LilvState* const state_1 =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_1_path);
+
+ // Save state to a bundle
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_1,
+ "http://example.org/state1",
+ bundle_1_path,
+ "state.ttl"));
+
+ // Check that a manifest exists
+ char* const manifest_path =
+ zix_path_join(NULL, bundle_1_path, "manifest.ttl");
+ assert(zix_file_type(manifest_path) == ZIX_FILE_TYPE_REGULAR);
+
+ // Check that the state file exists
+ char* const state_path = zix_path_join(NULL, bundle_1_path, "state.ttl");
+ assert(zix_file_type(state_path) == ZIX_FILE_TYPE_REGULAR);
+
+ // Check that the expected statements are in the files
+ assert(count_statements(manifest_path) == 3);
+ assert(count_statements(state_path) == 21);
+
+ // Save state again to the same bundle
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_1,
+ "http://example.org/state1",
+ bundle_1_path,
+ "state.ttl"));
+
+ // Check that everything is the same
+ assert(zix_file_type(manifest_path) == ZIX_FILE_TYPE_REGULAR);
+ assert(zix_file_type(state_path) == ZIX_FILE_TYPE_REGULAR);
+ assert(count_statements(manifest_path) == 3);
+ assert(count_statements(state_path) == 21);
+
+ lilv_instance_free(instance);
+ zix_dir_for_each(bundle_1_path, NULL, remove_file);
+ zix_remove(bundle_1_path);
+ cleanup_test_directories(dirs);
+
+ free(state_path);
+ free(manifest_path);
+ lilv_state_free(state_1);
+ free(bundle_1_path);
+ test_context_free(ctx);
}
static void
test_files_round_trip(void)
{
- TestContext* const ctx = test_context_new();
- TestDirectories dirs = create_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
-
- LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
- LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
-
- const LV2_Feature* const instance_features[] = {&ctx->map_feature,
- &ctx->free_path_feature,
- &make_path_feature,
- NULL};
-
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, instance_features);
-
- assert(instance);
-
- // Run plugin to generate some recording file data
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &ctx->in);
- lilv_instance_connect_port(instance, 1, &ctx->out);
- lilv_instance_run(instance, 1);
- lilv_instance_run(instance, 2);
- assert(ctx->in == 1.0);
- assert(ctx->out == 1.0);
-
- // Save first state to a bundle
- char* const bundle_1_1_path = lilv_path_join(dirs.top, "state1_1.lv2");
- LilvState* const state_1_1 =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_1_1_path);
-
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state_1_1,
- NULL,
- bundle_1_1_path,
- "state.ttl"));
-
- // Save first state to another bundle
- char* const bundle_1_2_path = lilv_path_join(dirs.top, "state1_2.lv2");
- LilvState* const state_1_2 =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_1_2_path);
-
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state_1_2,
- NULL,
- bundle_1_2_path,
- "state.ttl"));
-
- // Load both first state bundles and check that the results are equal
- char* const state_1_1_path = lilv_path_join(bundle_1_1_path, "state.ttl");
- char* const state_1_2_path = lilv_path_join(bundle_1_2_path, "state.ttl");
-
- LilvState* state_1_1_loaded = lilv_state_new_from_file(ctx->env->world,
- &ctx->map,
- NULL,
- state_1_1_path);
-
- LilvState* state_1_2_loaded = lilv_state_new_from_file(ctx->env->world,
- &ctx->map,
- NULL,
- state_1_2_path);
-
- assert(state_1_1_loaded);
- assert(state_1_2_loaded);
- assert(lilv_state_equals(state_1_1_loaded, state_1_2_loaded));
-
- // Run plugin again to modify recording file data
- lilv_instance_run(instance, 2);
-
- // Save updated state to a bundle
- char* const bundle_2_path = lilv_path_join(dirs.top, "state2.lv2");
- LilvState* const state_2 =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_2_path);
-
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state_2,
- NULL,
- bundle_2_path,
- "state.ttl"));
-
- // Load updated state bundle and check that it differs from the others
- char* const state_2_path = lilv_path_join(bundle_2_path, "state.ttl");
-
- LilvState* state_2_loaded = lilv_state_new_from_file(ctx->env->world,
- &ctx->map,
- NULL,
- state_2_path);
-
- assert(state_2_loaded);
- assert(!lilv_state_equals(state_1_1_loaded, state_2_loaded));
-
- lilv_dir_for_each(bundle_1_1_path, NULL, remove_file);
- lilv_dir_for_each(bundle_1_2_path, NULL, remove_file);
- lilv_dir_for_each(bundle_2_path, NULL, remove_file);
- lilv_remove(bundle_1_1_path);
- lilv_remove(bundle_1_2_path);
- lilv_remove(bundle_2_path);
- cleanup_test_directories(dirs);
-
- lilv_state_free(state_2_loaded);
- free(state_2_path);
- lilv_state_free(state_2);
- free(bundle_2_path);
- lilv_state_free(state_1_2_loaded);
- lilv_state_free(state_1_1_loaded);
- free(state_1_2_path);
- free(state_1_1_path);
- lilv_state_free(state_1_2);
- free(bundle_1_2_path);
- lilv_state_free(state_1_1);
- free(bundle_1_1_path);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ TestDirectories dirs = create_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+
+ LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
+ LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
+
+ const LV2_Feature* const instance_features[] = {
+ &ctx->map_feature, &ctx->free_path_feature, &make_path_feature, NULL};
+
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, instance_features);
+
+ assert(instance);
+
+ // Run plugin to generate some recording file data
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &ctx->in);
+ lilv_instance_connect_port(instance, 1, &ctx->out);
+ lilv_instance_run(instance, 1);
+ lilv_instance_run(instance, 2);
+ assert(ctx->in == 1.0);
+ assert(ctx->out == 1.0);
+
+ // Save first state to a bundle
+ char* const bundle_1_1_path = zix_path_join(NULL, dirs.top, "state1_1.lv2");
+ LilvState* const state_1_1 =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_1_1_path);
+
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_1_1,
+ NULL,
+ bundle_1_1_path,
+ "state.ttl"));
+
+ // Save first state to another bundle
+ char* const bundle_1_2_path = zix_path_join(NULL, dirs.top, "state1_2.lv2");
+ LilvState* const state_1_2 =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_1_2_path);
+
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_1_2,
+ NULL,
+ bundle_1_2_path,
+ "state.ttl"));
+
+ // Load both first state bundles and check that the results are equal
+ char* const state_1_1_path =
+ zix_path_join(NULL, bundle_1_1_path, "state.ttl");
+ char* const state_1_2_path =
+ zix_path_join(NULL, bundle_1_2_path, "state.ttl");
+
+ LilvState* state_1_1_loaded =
+ lilv_state_new_from_file(ctx->env->world, &ctx->map, NULL, state_1_1_path);
+
+ LilvState* state_1_2_loaded =
+ lilv_state_new_from_file(ctx->env->world, &ctx->map, NULL, state_1_2_path);
+
+ assert(state_1_1_loaded);
+ assert(state_1_2_loaded);
+ assert(lilv_state_equals(state_1_1_loaded, state_1_2_loaded));
+
+ // Run plugin again to modify recording file data
+ lilv_instance_run(instance, 2);
+
+ // Save updated state to a bundle
+ char* const bundle_2_path = zix_path_join(NULL, dirs.top, "state2.lv2");
+ LilvState* const state_2 =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_2_path);
+
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state_2,
+ NULL,
+ bundle_2_path,
+ "state.ttl"));
+
+ // Load updated state bundle and check that it differs from the others
+ char* const state_2_path = zix_path_join(NULL, bundle_2_path, "state.ttl");
+
+ LilvState* state_2_loaded =
+ lilv_state_new_from_file(ctx->env->world, &ctx->map, NULL, state_2_path);
+
+ assert(state_2_loaded);
+ assert(!lilv_state_equals(state_1_1_loaded, state_2_loaded));
+
+ lilv_instance_free(instance);
+ zix_dir_for_each(bundle_1_1_path, NULL, remove_file);
+ zix_dir_for_each(bundle_1_2_path, NULL, remove_file);
+ zix_dir_for_each(bundle_2_path, NULL, remove_file);
+ zix_remove(bundle_1_1_path);
+ zix_remove(bundle_1_2_path);
+ zix_remove(bundle_2_path);
+ cleanup_test_directories(dirs);
+
+ lilv_state_free(state_2_loaded);
+ free(state_2_path);
+ lilv_state_free(state_2);
+ free(bundle_2_path);
+ lilv_state_free(state_1_2_loaded);
+ lilv_state_free(state_1_1_loaded);
+ free(state_1_2_path);
+ free(state_1_1_path);
+ lilv_state_free(state_1_2);
+ free(bundle_1_2_path);
+ lilv_state_free(state_1_1);
+ free(bundle_1_1_path);
+ test_context_free(ctx);
}
static void
test_world_round_trip(void)
{
- TestContext* const ctx = test_context_new();
- LilvWorld* const world = ctx->env->world;
- TestDirectories dirs = create_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- static const char* const state_uri = "http://example.org/worldState";
-
- LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
- LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
-
- const LV2_Feature* const instance_features[] = {&ctx->map_feature,
- &ctx->free_path_feature,
- &make_path_feature,
- NULL};
-
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, instance_features);
-
- assert(instance);
-
- // Run plugin to generate some recording file data
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &ctx->in);
- lilv_instance_connect_port(instance, 1, &ctx->out);
- lilv_instance_run(instance, 1);
- lilv_instance_run(instance, 2);
- assert(ctx->in == 1.0);
- assert(ctx->out == 1.0);
-
- // Save state to a bundle
- char* const bundle_path = lilv_path_join(dirs.top, "state.lv2/");
- LilvState* const start_state =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_path);
-
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- start_state,
- state_uri,
- bundle_path,
- "state.ttl"));
-
- // Load state bundle into world
- SerdNode bundle_uri =
- serd_node_new_file_uri((const uint8_t*)bundle_path, 0, 0, true);
- LilvNode* const bundle_node =
- lilv_new_uri(world, (const char*)bundle_uri.buf);
- LilvNode* const state_node = lilv_new_uri(world, state_uri);
- lilv_world_load_bundle(world, bundle_node);
- lilv_world_load_resource(world, state_node);
-
- // Ensure the state loaded from the world matches
- LilvState* const restored =
- lilv_state_new_from_world(world, &ctx->map, state_node);
- assert(lilv_state_equals(start_state, restored));
-
- // Unload state from world
- lilv_world_unload_resource(world, state_node);
- lilv_world_unload_bundle(world, bundle_node);
-
- // Ensure that it is no longer present
- assert(!lilv_state_new_from_world(world, &ctx->map, state_node));
-
- lilv_state_delete(world, restored);
- cleanup_test_directories(dirs);
-
- lilv_state_free(restored);
- lilv_node_free(state_node);
- lilv_node_free(bundle_node);
- serd_node_free(&bundle_uri);
- lilv_state_free(start_state);
- free(bundle_path);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ LilvWorld* const world = ctx->env->world;
+ TestDirectories dirs = create_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ static const char* const state_uri = "http://example.org/worldState";
+
+ LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
+ LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
+
+ const LV2_Feature* const instance_features[] = {
+ &ctx->map_feature, &ctx->free_path_feature, &make_path_feature, NULL};
+
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, instance_features);
+
+ assert(instance);
+
+ // Run plugin to generate some recording file data
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &ctx->in);
+ lilv_instance_connect_port(instance, 1, &ctx->out);
+ lilv_instance_run(instance, 1);
+ lilv_instance_run(instance, 2);
+ assert(ctx->in == 1.0);
+ assert(ctx->out == 1.0);
+
+ // Save state to a bundle
+ char* const bundle_path = zix_path_join(NULL, dirs.top, "state.lv2/");
+ LilvState* const start_state =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_path);
+
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ start_state,
+ state_uri,
+ bundle_path,
+ "state.ttl"));
+
+ // Load state bundle into world
+ SerdNode bundle_uri =
+ serd_node_new_file_uri((const uint8_t*)bundle_path, 0, 0, true);
+ LilvNode* const bundle_node =
+ lilv_new_uri(world, (const char*)bundle_uri.buf);
+ LilvNode* const state_node = lilv_new_uri(world, state_uri);
+ lilv_world_load_bundle(world, bundle_node);
+ lilv_world_load_resource(world, state_node);
+
+ // Ensure the state loaded from the world matches
+ LilvState* const restored =
+ lilv_state_new_from_world(world, &ctx->map, state_node);
+ assert(lilv_state_equals(start_state, restored));
+
+ // Unload state from world
+ lilv_world_unload_resource(world, state_node);
+ lilv_world_unload_bundle(world, bundle_node);
+
+ // Ensure that it is no longer present
+ assert(!lilv_state_new_from_world(world, &ctx->map, state_node));
+
+ lilv_instance_free(instance);
+ lilv_state_delete(world, start_state);
+ cleanup_test_directories(dirs);
+
+ lilv_state_free(restored);
+ lilv_node_free(state_node);
+ lilv_node_free(bundle_node);
+ serd_node_free(&bundle_uri);
+ lilv_state_free(start_state);
+ free(bundle_path);
+ test_context_free(ctx);
}
static void
test_label_round_trip(void)
{
- TestContext* const ctx = test_context_new();
- const TestDirectories dirs = create_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
-
- assert(instance);
-
- // Get initial state
- LilvState* const state =
- state_from_instance(plugin, instance, ctx, &dirs, NULL);
-
- // Set a label
- lilv_state_set_label(state, "Monopoly on violence");
-
- // Save to a bundle
- char* const bundle_path = lilv_path_join(dirs.top, "state.lv2/");
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state,
- NULL,
- bundle_path,
- "state.ttl"));
-
- // Load bundle and check the label and that the states are equal
- char* const state_path = lilv_path_join(bundle_path, "state.ttl");
-
- LilvState* const loaded =
- lilv_state_new_from_file(ctx->env->world, &ctx->map, NULL, state_path);
-
- assert(loaded);
- assert(lilv_state_equals(state, loaded));
- assert(!strcmp(lilv_state_get_label(loaded), "Monopoly on violence"));
-
- lilv_state_delete(ctx->env->world, state);
- cleanup_test_directories(dirs);
-
- lilv_state_free(loaded);
- free(state_path);
- free(bundle_path);
- lilv_state_free(state);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ const TestDirectories dirs = create_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, ctx->features);
+
+ assert(instance);
+
+ // Get initial state
+ LilvState* const state =
+ state_from_instance(plugin, instance, ctx, &dirs, NULL);
+
+ // Set a label
+ lilv_state_set_label(state, "Monopoly on violence");
+
+ // Save to a bundle
+ char* const bundle_path = zix_path_join(NULL, dirs.top, "state.lv2/");
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state,
+ NULL,
+ bundle_path,
+ "state.ttl"));
+
+ // Load bundle and check the label and that the states are equal
+ char* const state_path = zix_path_join(NULL, bundle_path, "state.ttl");
+
+ LilvState* const loaded =
+ lilv_state_new_from_file(ctx->env->world, &ctx->map, NULL, state_path);
+
+ assert(loaded);
+ assert(lilv_state_equals(state, loaded));
+ assert(!strcmp(lilv_state_get_label(loaded), "Monopoly on violence"));
+
+ lilv_instance_free(instance);
+ lilv_state_delete(ctx->env->world, state);
+ cleanup_test_directories(dirs);
+
+ lilv_state_free(loaded);
+ free(state_path);
+ free(bundle_path);
+ lilv_state_free(state);
+ test_context_free(ctx);
}
static void
test_bad_subject(void)
{
- TestContext* const ctx = test_context_new();
- LilvNode* const string = lilv_new_string(ctx->env->world, "Not a URI");
+ TestContext* const ctx = test_context_new();
+ LilvNode* const string = lilv_new_string(ctx->env->world, "Not a URI");
+
+ LilvState* const file_state = lilv_state_new_from_file(
+ ctx->env->world, &ctx->map, string, "/I/do/not/matter");
+
+ assert(!file_state);
+
+ LilvState* const world_state =
+ lilv_state_new_from_world(ctx->env->world, &ctx->map, string);
- LilvState* const file_state = lilv_state_new_from_file(ctx->env->world,
- &ctx->map,
- string,
- "/I/do/not/matter");
+ assert(!world_state);
- assert(!file_state);
+ lilv_node_free(string);
+ test_context_free(ctx);
+}
- LilvState* const world_state =
- lilv_state_new_from_world(ctx->env->world, &ctx->map, string);
+static void
+test_missing_path(void)
+{
+ TestContext* const ctx = test_context_new();
+ LilvState* const state = lilv_state_new_from_file(
+ ctx->env->world, &ctx->map, NULL, "/does/not/exist");
- assert(!world_state);
+ assert(!state);
- lilv_node_free(string);
- test_context_free(ctx);
+ test_context_free(ctx);
}
static void
count_file(const char* path, const char* name, void* data)
{
- *(unsigned*)data += 1;
+ (void)path;
+ (void)name;
+
+ *(unsigned*)data += 1;
}
static void
test_delete(void)
{
- TestContext* const ctx = test_context_new();
- TestDirectories dirs = create_test_directories();
- const LilvPlugin* const plugin = load_test_plugin(ctx);
-
- LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
- LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
-
- const LV2_Feature* const instance_features[] = {&ctx->map_feature,
- &ctx->free_path_feature,
- &make_path_feature,
- NULL};
-
- LilvInstance* const instance =
- lilv_plugin_instantiate(plugin, 48000.0, instance_features);
-
- assert(instance);
-
- // Run plugin to generate some recording file data
- lilv_instance_activate(instance);
- lilv_instance_connect_port(instance, 0, &ctx->in);
- lilv_instance_connect_port(instance, 1, &ctx->out);
- lilv_instance_run(instance, 1);
- lilv_instance_run(instance, 2);
- assert(ctx->in == 1.0);
- assert(ctx->out == 1.0);
-
- // Save state to a bundle
- char* const bundle_path = lilv_path_join(dirs.top, "state.lv2/");
- LilvState* const state =
- state_from_instance(plugin, instance, ctx, &dirs, bundle_path);
-
- assert(!lilv_state_save(ctx->env->world,
- &ctx->map,
- &ctx->unmap,
- state,
- NULL,
- bundle_path,
- "state.ttl"));
-
- // Count the number of shared files before doing anything
- unsigned n_shared_files_before = 0;
- lilv_dir_for_each(dirs.shared, &n_shared_files_before, count_file);
-
- // Delete the state
- assert(!lilv_state_delete(ctx->env->world, state));
-
- // Ensure the number of shared files is the same after deletion
- unsigned n_shared_files_after = 0;
- lilv_dir_for_each(dirs.shared, &n_shared_files_after, count_file);
- assert(n_shared_files_before == n_shared_files_after);
-
- // Ensure the state directory has been deleted
- assert(!lilv_path_exists(bundle_path));
-
- cleanup_test_directories(dirs);
-
- lilv_state_free(state);
- free(bundle_path);
- lilv_instance_free(instance);
- test_context_free(ctx);
+ TestContext* const ctx = test_context_new();
+ TestDirectories dirs = create_test_directories();
+ const LilvPlugin* const plugin = load_test_plugin(ctx);
+
+ LV2_State_Make_Path make_path = {&dirs, make_scratch_path};
+ LV2_Feature make_path_feature = {LV2_STATE__makePath, &make_path};
+
+ const LV2_Feature* const instance_features[] = {
+ &ctx->map_feature, &ctx->free_path_feature, &make_path_feature, NULL};
+
+ LilvInstance* const instance =
+ lilv_plugin_instantiate(plugin, 48000.0, instance_features);
+
+ assert(instance);
+
+ // Run plugin to generate some recording file data
+ lilv_instance_activate(instance);
+ lilv_instance_connect_port(instance, 0, &ctx->in);
+ lilv_instance_connect_port(instance, 1, &ctx->out);
+ lilv_instance_run(instance, 1);
+ lilv_instance_run(instance, 2);
+ assert(ctx->in == 1.0);
+ assert(ctx->out == 1.0);
+
+ // Save state to a bundle
+ char* const bundle_path = zix_path_join(NULL, dirs.top, "state.lv2/");
+ LilvState* const state =
+ state_from_instance(plugin, instance, ctx, &dirs, bundle_path);
+
+ assert(!lilv_state_save(ctx->env->world,
+ &ctx->map,
+ &ctx->unmap,
+ state,
+ NULL,
+ bundle_path,
+ "state.ttl"));
+
+ // Count the number of shared files before doing anything
+ unsigned n_shared_files_before = 0;
+ zix_dir_for_each(dirs.shared, &n_shared_files_before, count_file);
+
+ lilv_instance_free(instance);
+
+ // Delete the state
+ assert(!lilv_state_delete(ctx->env->world, state));
+
+ // Ensure the number of shared files is the same after deletion
+ unsigned n_shared_files_after = 0;
+ zix_dir_for_each(dirs.shared, &n_shared_files_after, count_file);
+ assert(n_shared_files_before == n_shared_files_after);
+
+ // Ensure the state directory has been deleted
+ assert(zix_file_type(bundle_path) == ZIX_FILE_TYPE_NONE);
+
+ cleanup_test_directories(dirs);
+
+ lilv_state_free(state);
+ free(bundle_path);
+ test_context_free(ctx);
}
int
main(void)
{
- test_instance_state();
- test_equal();
- test_changed_plugin_data();
- test_changed_metadata();
- test_to_string();
- test_string_round_trip();
- test_to_files();
- test_files_round_trip();
- test_world_round_trip();
- test_label_round_trip();
- test_bad_subject();
- test_delete();
-
- return 0;
+ test_instance_state();
+ test_equal();
+ test_changed_plugin_data();
+ test_changed_metadata();
+ test_to_string();
+ test_string_round_trip();
+ test_to_files();
+ test_multi_save();
+ test_files_round_trip();
+ test_world_round_trip();
+ test_label_round_trip();
+ test_bad_subject();
+ test_missing_path();
+ test_delete();
+
+ return 0;
}
diff --git a/test/test_string.c b/test/test_string.c
index 9eb2456..48021ed 100644
--- a/test/test_string.c
+++ b/test/test_string.c
@@ -1,29 +1,14 @@
-/*
- Copyright 2007-2020 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 setenv */
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
#include "../src/lilv_internal.h"
#ifdef _WIN32
-# include <windows.h>
-# define setenv(n, v, r) SetEnvironmentVariable((n), (v))
-# define unsetenv(n) SetEnvironmentVariable((n), NULL)
+# include <windows.h>
+# define setenv(n, v, r) SetEnvironmentVariable((n), (v))
+# define unsetenv(n) SetEnvironmentVariable((n), NULL)
#endif
#include <assert.h>
@@ -34,23 +19,31 @@ int
main(void)
{
#ifndef _WIN32
- char* s = NULL;
-
- setenv("LILV_TEST_1", "test", 1);
- char* home_foo = lilv_strjoin(getenv("HOME"), "/foo", NULL);
- assert(!strcmp((s = lilv_expand("$LILV_TEST_1")), "test"));
- free(s);
- assert(!strcmp((s = lilv_expand("~")), getenv("HOME")));
- free(s);
- assert(!strcmp((s = lilv_expand("~foo")), "~foo"));
- free(s);
- assert(!strcmp((s = lilv_expand("~/foo")), home_foo));
- free(s);
- assert(!strcmp((s = lilv_expand("$NOT_A_VAR")), "$NOT_A_VAR"));
- free(s);
- free(home_foo);
- unsetenv("LILV_TEST_1");
+ char* s = NULL;
+
+ const char* const home = getenv("HOME");
+
+ setenv("LILV_TEST_1", "test", 1);
+
+ assert(!strcmp((s = lilv_expand("$LILV_TEST_1")), "test"));
+ free(s);
+ if (home) {
+ assert(!strcmp((s = lilv_expand("~")), home));
+ free(s);
+ assert(!strcmp((s = lilv_expand("~foo")), "~foo"));
+ free(s);
+
+ char* const home_foo = lilv_strjoin(home, "/foo", NULL);
+ assert(!strcmp((s = lilv_expand("~/foo")), home_foo));
+ free(s);
+ free(home_foo);
+ }
+
+ assert(!strcmp((s = lilv_expand("$NOT_A_VAR")), "$NOT_A_VAR"));
+ free(s);
+
+ unsetenv("LILV_TEST_1");
#endif
- return 0;
+ return 0;
}
diff --git a/test/test_ui.c b/test/test_ui.c
index 6230318..78ea871 100644
--- a/test/test_ui.c
+++ b/test/test_ui.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -86,95 +73,99 @@ static const char* const plugin_ttl = "\
static unsigned
ui_supported(const char* container_type_uri, const char* ui_type_uri)
{
- return !strcmp(container_type_uri, ui_type_uri);
+ return !strcmp(container_type_uri, ui_type_uri);
}
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- assert(plug);
+ if (create_bundle(env, "ui.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- LilvUIs* uis = lilv_plugin_get_uis(plug);
- assert(lilv_uis_size(uis) == 4);
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- const LilvUI* ui0 = lilv_uis_get(uis, lilv_uis_begin(uis));
- assert(ui0);
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* plug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ assert(plug);
- LilvNode* ui_uri = lilv_new_uri(world, "http://example.org/ui");
- LilvNode* ui2_uri = lilv_new_uri(world, "http://example.org/ui3");
- LilvNode* ui3_uri = lilv_new_uri(world, "http://example.org/ui4");
- LilvNode* noui_uri = lilv_new_uri(world, "http://example.org/notaui");
+ LilvUIs* uis = lilv_plugin_get_uis(plug);
+ assert(lilv_uis_size(uis) == 4);
- const LilvUI* ui0_2 = lilv_uis_get_by_uri(uis, ui_uri);
- assert(ui0 == ui0_2);
- assert(lilv_node_equals(lilv_ui_get_uri(ui0_2), ui_uri));
+ const LilvUI* ui0 = lilv_uis_get(uis, lilv_uis_begin(uis));
+ assert(ui0);
- const LilvUI* ui2 = lilv_uis_get_by_uri(uis, ui2_uri);
- assert(ui2 != ui0);
+ LilvNode* ui_uri = lilv_new_uri(world, "http://example.org/ui");
+ LilvNode* ui2_uri = lilv_new_uri(world, "http://example.org/ui3");
+ LilvNode* ui3_uri = lilv_new_uri(world, "http://example.org/ui4");
+ LilvNode* noui_uri = lilv_new_uri(world, "http://example.org/notaui");
- const LilvUI* ui3 = lilv_uis_get_by_uri(uis, ui3_uri);
- assert(ui3 != ui0);
+ const LilvUI* ui0_2 = lilv_uis_get_by_uri(uis, ui_uri);
+ assert(ui0 == ui0_2);
+ assert(lilv_node_equals(lilv_ui_get_uri(ui0_2), ui_uri));
- const LilvUI* noui = lilv_uis_get_by_uri(uis, noui_uri);
- assert(noui == NULL);
+ const LilvUI* ui2 = lilv_uis_get_by_uri(uis, ui2_uri);
+ assert(ui2 != ui0);
- const LilvNodes* classes = lilv_ui_get_classes(ui0);
- assert(lilv_nodes_size(classes) == 1);
+ const LilvUI* ui3 = lilv_uis_get_by_uri(uis, ui3_uri);
+ assert(ui3 != ui0);
- LilvNode* ui_class_uri =
- lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#GtkUI");
+ const LilvUI* noui = lilv_uis_get_by_uri(uis, noui_uri);
+ assert(noui == NULL);
- LilvNode* unknown_ui_class_uri =
- lilv_new_uri(world, "http://example.org/mysteryUI");
+ const LilvNodes* classes = lilv_ui_get_classes(ui0);
+ assert(lilv_nodes_size(classes) == 1);
- assert(lilv_node_equals(lilv_nodes_get_first(classes), ui_class_uri));
- assert(lilv_ui_is_a(ui0, ui_class_uri));
+ LilvNode* ui_class_uri =
+ lilv_new_uri(world, "http://lv2plug.in/ns/extensions/ui#GtkUI");
- const LilvNode* ui_type = NULL;
- assert(lilv_ui_is_supported(ui0, ui_supported, ui_class_uri, &ui_type));
- assert(!lilv_ui_is_supported(
- ui0, ui_supported, unknown_ui_class_uri, &ui_type));
- assert(lilv_node_equals(ui_type, ui_class_uri));
+ LilvNode* unknown_ui_class_uri =
+ lilv_new_uri(world, "http://example.org/mysteryUI");
- const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
- const LilvNode* ui_bundle_uri = lilv_ui_get_bundle_uri(ui0);
- assert(lilv_node_equals(plug_bundle_uri, ui_bundle_uri));
+ assert(lilv_node_equals(lilv_nodes_get_first(classes), ui_class_uri));
+ assert(lilv_ui_is_a(ui0, ui_class_uri));
- const size_t ui_binary_uri_str_len =
- strlen(lilv_node_as_string(plug_bundle_uri)) + strlen("ui" SHLIB_EXT);
+ const LilvNode* ui_type = NULL;
+ assert(lilv_ui_is_supported(ui0, ui_supported, ui_class_uri, &ui_type));
+ assert(
+ !lilv_ui_is_supported(ui0, ui_supported, unknown_ui_class_uri, &ui_type));
+ assert(lilv_node_equals(ui_type, ui_class_uri));
- char* ui_binary_uri_str = (char*)calloc(1, ui_binary_uri_str_len + 1);
- snprintf(ui_binary_uri_str,
- ui_binary_uri_str_len + 1,
- "%s%s",
- lilv_node_as_string(plug_bundle_uri),
- "ui" SHLIB_EXT);
+ const LilvNode* plug_bundle_uri = lilv_plugin_get_bundle_uri(plug);
+ const LilvNode* ui_bundle_uri = lilv_ui_get_bundle_uri(ui0);
+ assert(lilv_node_equals(plug_bundle_uri, ui_bundle_uri));
- const LilvNode* ui_binary_uri = lilv_ui_get_binary_uri(ui0);
+ const size_t ui_binary_uri_str_len =
+ strlen(lilv_node_as_string(plug_bundle_uri)) + strlen("ui" SHLIB_EXT);
- LilvNode* expected_uri = lilv_new_uri(world, ui_binary_uri_str);
- assert(lilv_node_equals(expected_uri, ui_binary_uri));
+ char* ui_binary_uri_str = (char*)calloc(1, ui_binary_uri_str_len + 1);
+ snprintf(ui_binary_uri_str,
+ ui_binary_uri_str_len + 1,
+ "%s%s",
+ lilv_node_as_string(plug_bundle_uri),
+ "ui" SHLIB_EXT);
- free(ui_binary_uri_str);
- lilv_node_free(unknown_ui_class_uri);
- lilv_node_free(ui_class_uri);
- lilv_node_free(ui_uri);
- lilv_node_free(ui2_uri);
- lilv_node_free(ui3_uri);
- lilv_node_free(noui_uri);
- lilv_node_free(expected_uri);
- lilv_uis_free(uis);
+ const LilvNode* ui_binary_uri = lilv_ui_get_binary_uri(ui0);
- delete_bundle(env);
- lilv_test_env_free(env);
+ LilvNode* expected_uri = lilv_new_uri(world, ui_binary_uri_str);
+ assert(lilv_node_equals(expected_uri, ui_binary_uri));
- return 0;
+ free(ui_binary_uri_str);
+ lilv_node_free(unknown_ui_class_uri);
+ lilv_node_free(ui_class_uri);
+ lilv_node_free(ui_uri);
+ lilv_node_free(ui2_uri);
+ lilv_node_free(ui3_uri);
+ lilv_node_free(noui_uri);
+ lilv_node_free(expected_uri);
+ lilv_uis_free(uis);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_util.c b/test/test_util.c
index 9055e88..2e609da 100644
--- a/test/test_util.c
+++ b/test/test_util.c
@@ -1,67 +1,38 @@
-/*
- Copyright 2007-2020 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 _XOPEN_SOURCE 600 /* for mkstemp */
+// Copyright 2007-2022 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
-#ifdef _WIN32
-# include "lilv_internal.h"
-#endif
-
-#include "../src/filesystem.h"
+#include "lilv_test_utils.h"
-#ifdef _WIN32
-# include <io.h>
-# define mkstemp(pat) _mktemp(pat)
-#endif
+#include "lilv/lilv.h"
+#include "zix/filesystem.h"
+#include "zix/path.h"
#include <assert.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
int
main(void)
{
- assert(!lilv_path_canonical(NULL));
-
- char a_path[16];
- char b_path[16];
- strncpy(a_path, "copy_a_XXXXXX", sizeof(a_path));
- strncpy(b_path, "copy_b_XXXXXX", sizeof(b_path));
- 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);
-
- assert(lilv_copy_file("does/not/exist", "copy"));
- assert(lilv_copy_file(a_path, "not/a/dir/copy"));
- assert(!lilv_copy_file(a_path, "copy_c"));
- assert(!lilv_file_equals(a_path, b_path));
- assert(lilv_file_equals(a_path, a_path));
- assert(lilv_file_equals(a_path, "copy_c"));
- assert(!lilv_file_equals("does/not/exist", b_path));
- assert(!lilv_file_equals(a_path, "does/not/exist"));
- assert(!lilv_file_equals("does/not/exist", "/does/not/either"));
-
- return 0;
+ char* const dir = lilv_create_temporary_directory("lilv_test_util_XXXXXX");
+
+ char* const a_path = zix_path_join(NULL, dir, "copy_a_XXXXXX");
+ char* const b_path = zix_path_join(NULL, dir, "copy_b_XXXXXX");
+
+ FILE* const fa = fopen(a_path, "w");
+ FILE* const fb = fopen(b_path, "w");
+ fprintf(fa, "AA\n");
+ fprintf(fb, "AB\n");
+ fclose(fb);
+ fclose(fa);
+
+ assert(!zix_remove(a_path));
+ assert(!zix_remove(b_path));
+ assert(!zix_remove(dir));
+
+ lilv_free(b_path);
+ lilv_free(a_path);
+ lilv_free(dir);
+ return 0;
}
diff --git a/test/test_value.c b/test/test_value.c
index a6a1fd0..a37c886 100644
--- a/test/test_value.c
+++ b/test/test_value.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -39,135 +26,138 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
-
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
-
- LilvNode* uval = lilv_new_uri(world, "http://example.org");
- LilvNode* sval = lilv_new_string(world, "Foo");
- LilvNode* ival = lilv_new_int(world, 42);
- LilvNode* fval = lilv_new_float(world, 1.6180f);
-
- assert(lilv_node_is_uri(uval));
- assert(lilv_node_is_string(sval));
- assert(lilv_node_is_int(ival));
- assert(lilv_node_is_float(fval));
-
- assert(!lilv_node_is_literal(NULL));
- assert(!lilv_node_is_literal(uval));
- assert(lilv_node_is_literal(sval));
- assert(lilv_node_is_literal(ival));
- assert(lilv_node_is_literal(fval));
- assert(!lilv_node_get_path(fval, NULL));
-
- assert(!strcmp(lilv_node_as_uri(uval), "http://example.org"));
- assert(!strcmp(lilv_node_as_string(sval), "Foo"));
- assert(lilv_node_as_int(ival) == 42);
- assert(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON);
- assert(isnan(lilv_node_as_float(sval)));
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
+
+ if (create_bundle(env, "value.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
+
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
+
+ LilvNode* uval = lilv_new_uri(world, "http://example.org");
+ LilvNode* sval = lilv_new_string(world, "Foo");
+ LilvNode* ival = lilv_new_int(world, 42);
+ LilvNode* fval = lilv_new_float(world, 1.6180f);
+
+ assert(lilv_node_is_uri(uval));
+ assert(lilv_node_is_string(sval));
+ assert(lilv_node_is_int(ival));
+ assert(lilv_node_is_float(fval));
+
+ assert(!lilv_node_is_literal(NULL));
+ assert(!lilv_node_is_literal(uval));
+ assert(lilv_node_is_literal(sval));
+ assert(lilv_node_is_literal(ival));
+ assert(lilv_node_is_literal(fval));
+ assert(!lilv_node_get_path(fval, NULL));
+
+ assert(!strcmp(lilv_node_as_uri(uval), "http://example.org"));
+ assert(!strcmp(lilv_node_as_string(sval), "Foo"));
+ assert(lilv_node_as_int(ival) == 42);
+ assert(fabs(lilv_node_as_float(fval) - 1.6180) < FLT_EPSILON);
+ assert(isnan(lilv_node_as_float(sval)));
#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__GNUC__) && __GNUC__ > 4
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
- assert(!strcmp(lilv_uri_to_path("file:///foo"), "/foo"));
+ assert(!strcmp(lilv_uri_to_path("file:///foo"), "/foo"));
#if defined(__clang__)
-# pragma clang diagnostic pop
+# pragma clang diagnostic pop
#elif defined(__GNUC__) && __GNUC__ > 4
-# pragma GCC diagnostic pop
+# pragma GCC diagnostic pop
#endif
- LilvNode* loc_abs = lilv_new_file_uri(world, NULL, "/foo/bar");
- LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo");
- LilvNode* host_abs = lilv_new_file_uri(world, "host", "/foo/bar");
- LilvNode* host_rel = lilv_new_file_uri(world, "host", "foo");
-
- assert(!strcmp(lilv_node_as_uri(loc_abs), "file:///foo/bar"));
- assert(!strncmp(lilv_node_as_uri(loc_rel), "file:///", 8));
- assert(!strcmp(lilv_node_as_uri(host_abs), "file://host/foo/bar"));
- assert(!strncmp(lilv_node_as_uri(host_rel), "file://host/", 12));
-
- lilv_node_free(host_rel);
- lilv_node_free(host_abs);
- lilv_node_free(loc_rel);
- lilv_node_free(loc_abs);
-
- char* tok = lilv_node_get_turtle_token(uval);
- assert(!strcmp(tok, "<http://example.org>"));
- lilv_free(tok);
- tok = lilv_node_get_turtle_token(sval);
- assert(!strcmp(tok, "Foo"));
- lilv_free(tok);
- tok = lilv_node_get_turtle_token(ival);
- assert(!strcmp(tok, "42"));
- lilv_free(tok);
- tok = lilv_node_get_turtle_token(fval);
- assert(!strncmp(tok, "1.6180", 6));
- lilv_free(tok);
-
- LilvNode* uval_e = lilv_new_uri(world, "http://example.org");
- LilvNode* sval_e = lilv_new_string(world, "Foo");
- LilvNode* ival_e = lilv_new_int(world, 42);
- LilvNode* fval_e = lilv_new_float(world, 1.6180f);
- LilvNode* uval_ne = lilv_new_uri(world, "http://no-example.org");
- LilvNode* sval_ne = lilv_new_string(world, "Bar");
- LilvNode* ival_ne = lilv_new_int(world, 24);
- LilvNode* fval_ne = lilv_new_float(world, 3.14159f);
-
- assert(lilv_node_equals(uval, uval_e));
- assert(lilv_node_equals(sval, sval_e));
- assert(lilv_node_equals(ival, ival_e));
- assert(lilv_node_equals(fval, fval_e));
-
- assert(!lilv_node_equals(uval, uval_ne));
- assert(!lilv_node_equals(sval, sval_ne));
- assert(!lilv_node_equals(ival, ival_ne));
- assert(!lilv_node_equals(fval, fval_ne));
-
- assert(!lilv_node_equals(uval, sval));
- assert(!lilv_node_equals(sval, ival));
- assert(!lilv_node_equals(ival, fval));
-
- LilvNode* uval_dup = lilv_node_duplicate(uval);
- assert(lilv_node_equals(uval, uval_dup));
-
- LilvNode* ifval = lilv_new_float(world, 42.0);
- assert(!lilv_node_equals(ival, ifval));
- lilv_node_free(ifval);
-
- LilvNode* nil = NULL;
- assert(!lilv_node_equals(uval, nil));
- assert(!lilv_node_equals(nil, uval));
- assert(lilv_node_equals(nil, nil));
-
- LilvNode* nil2 = lilv_node_duplicate(nil);
- assert(lilv_node_equals(nil, nil2));
-
- lilv_node_free(uval);
- lilv_node_free(sval);
- lilv_node_free(ival);
- lilv_node_free(fval);
- lilv_node_free(uval_e);
- lilv_node_free(sval_e);
- lilv_node_free(ival_e);
- lilv_node_free(fval_e);
- lilv_node_free(uval_ne);
- lilv_node_free(sval_ne);
- lilv_node_free(ival_ne);
- lilv_node_free(fval_ne);
- lilv_node_free(uval_dup);
- lilv_node_free(nil2);
-
- delete_bundle(env);
- lilv_test_env_free(env);
-
- return 0;
+ LilvNode* loc_abs = lilv_new_file_uri(world, NULL, "/foo/bar");
+ LilvNode* loc_rel = lilv_new_file_uri(world, NULL, "foo");
+ LilvNode* host_abs = lilv_new_file_uri(world, "host", "/foo/bar");
+ LilvNode* host_rel = lilv_new_file_uri(world, "host", "foo");
+
+ assert(!strcmp(lilv_node_as_uri(loc_abs), "file:///foo/bar"));
+ assert(!strncmp(lilv_node_as_uri(loc_rel), "file:///", 8));
+ assert(!strcmp(lilv_node_as_uri(host_abs), "file://host/foo/bar"));
+ assert(!strncmp(lilv_node_as_uri(host_rel), "file://host/", 12));
+
+ lilv_node_free(host_rel);
+ lilv_node_free(host_abs);
+ lilv_node_free(loc_rel);
+ lilv_node_free(loc_abs);
+
+ char* tok = lilv_node_get_turtle_token(uval);
+ assert(!strcmp(tok, "<http://example.org>"));
+ lilv_free(tok);
+ tok = lilv_node_get_turtle_token(sval);
+ assert(!strcmp(tok, "Foo"));
+ lilv_free(tok);
+ tok = lilv_node_get_turtle_token(ival);
+ assert(!strcmp(tok, "42"));
+ lilv_free(tok);
+ tok = lilv_node_get_turtle_token(fval);
+ assert(!strncmp(tok, "1.6180", 6));
+ lilv_free(tok);
+
+ LilvNode* uval_e = lilv_new_uri(world, "http://example.org");
+ LilvNode* sval_e = lilv_new_string(world, "Foo");
+ LilvNode* ival_e = lilv_new_int(world, 42);
+ LilvNode* fval_e = lilv_new_float(world, 1.6180f);
+ LilvNode* uval_ne = lilv_new_uri(world, "http://no-example.org");
+ LilvNode* sval_ne = lilv_new_string(world, "Bar");
+ LilvNode* ival_ne = lilv_new_int(world, 24);
+ LilvNode* fval_ne = lilv_new_float(world, 3.14159f);
+
+ assert(lilv_node_equals(uval, uval_e));
+ assert(lilv_node_equals(sval, sval_e));
+ assert(lilv_node_equals(ival, ival_e));
+ assert(lilv_node_equals(fval, fval_e));
+
+ assert(!lilv_node_equals(uval, uval_ne));
+ assert(!lilv_node_equals(sval, sval_ne));
+ assert(!lilv_node_equals(ival, ival_ne));
+ assert(!lilv_node_equals(fval, fval_ne));
+
+ assert(!lilv_node_equals(uval, sval));
+ assert(!lilv_node_equals(sval, ival));
+ assert(!lilv_node_equals(ival, fval));
+
+ LilvNode* uval_dup = lilv_node_duplicate(uval);
+ assert(lilv_node_equals(uval, uval_dup));
+
+ LilvNode* ifval = lilv_new_float(world, 42.0);
+ assert(!lilv_node_equals(ival, ifval));
+ lilv_node_free(ifval);
+
+ LilvNode* nil = NULL;
+ assert(!lilv_node_equals(uval, nil));
+ assert(!lilv_node_equals(nil, uval));
+ assert(lilv_node_equals(nil, nil));
+
+ LilvNode* nil2 = lilv_node_duplicate(nil);
+ assert(lilv_node_equals(nil, nil2));
+
+ lilv_node_free(uval);
+ lilv_node_free(sval);
+ lilv_node_free(ival);
+ lilv_node_free(fval);
+ lilv_node_free(uval_e);
+ lilv_node_free(sval_e);
+ lilv_node_free(ival_e);
+ lilv_node_free(fval_e);
+ lilv_node_free(uval_ne);
+ lilv_node_free(sval_ne);
+ lilv_node_free(ival_ne);
+ lilv_node_free(fval_ne);
+ lilv_node_free(uval_dup);
+ lilv_node_free(nil2);
+
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_verify.c b/test/test_verify.c
index dd88ba5..e066751 100644
--- a/test/test_verify.c
+++ b/test/test_verify.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -36,22 +23,24 @@ static const char* const plugin_ttl = "\
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- if (start_bundle(env, SIMPLE_MANIFEST_TTL, plugin_ttl)) {
- return 1;
- }
+ if (create_bundle(env, "verify.lv2", SIMPLE_MANIFEST_TTL, plugin_ttl)) {
+ return 1;
+ }
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* explug =
- lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
+ lilv_world_load_specifications(env->world);
+ lilv_world_load_bundle(env->world, env->test_bundle_uri);
- assert(explug);
- assert(lilv_plugin_verify(explug));
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* explug = lilv_plugins_get_by_uri(plugins, env->plugin1_uri);
- delete_bundle(env);
- lilv_test_env_free(env);
+ assert(explug);
+ assert(lilv_plugin_verify(explug));
- return 0;
+ delete_bundle(env);
+ lilv_test_env_free(env);
+
+ return 0;
}
diff --git a/test/test_world.c b/test/test_world.c
index b8572d2..fda8595 100644
--- a/test/test_world.c
+++ b/test/test_world.c
@@ -1,18 +1,5 @@
-/*
- Copyright 2007-2020 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.
-*/
+// Copyright 2007-2020 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
#undef NDEBUG
@@ -26,26 +13,26 @@
int
main(void)
{
- LilvTestEnv* const env = lilv_test_env_new();
- LilvWorld* const world = env->world;
+ LilvTestEnv* const env = lilv_test_env_new();
+ LilvWorld* const world = env->world;
- LilvNode* num = lilv_new_int(env->world, 4);
- LilvNode* uri = lilv_new_uri(env->world, "http://example.org/object");
+ LilvNode* num = lilv_new_int(env->world, 4);
+ LilvNode* uri = lilv_new_uri(env->world, "http://example.org/object");
- LilvNodes* matches = lilv_world_find_nodes(world, num, NULL, NULL);
- assert(!matches);
+ LilvNodes* matches = lilv_world_find_nodes(world, num, NULL, NULL);
+ assert(!matches);
- matches = lilv_world_find_nodes(world, NULL, num, NULL);
- assert(!matches);
+ matches = lilv_world_find_nodes(world, NULL, num, NULL);
+ assert(!matches);
- matches = lilv_world_find_nodes(world, NULL, uri, NULL);
- assert(!matches);
+ matches = lilv_world_find_nodes(world, NULL, uri, NULL);
+ assert(!matches);
- lilv_node_free(uri);
- lilv_node_free(num);
+ lilv_node_free(uri);
+ lilv_node_free(num);
- lilv_world_unload_bundle(world, NULL);
- lilv_test_env_free(env);
+ lilv_world_unload_bundle(world, NULL);
+ lilv_test_env_free(env);
- return 0;
+ return 0;
}
diff --git a/tools/.clang-tidy b/tools/.clang-tidy
new file mode 100644
index 0000000..d8434e2
--- /dev/null
+++ b/tools/.clang-tidy
@@ -0,0 +1,16 @@
+# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+Checks: >
+ -*-magic-numbers,
+ -android-cloexec-fopen,
+ -bugprone-narrowing-conversions,
+ -cert-err33-c,
+ -cert-err34-c,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-narrowing-conversions,
+ -hicpp-signed-bitwise,
+ -llvm-header-guard,
+ -misc-no-recursion,
+ -readability-function-cognitive-complexity,
+InheritParentConfig: true
diff --git a/tools/bench.h b/tools/bench.h
new file mode 100644
index 0000000..d87102e
--- /dev/null
+++ b/tools/bench.h
@@ -0,0 +1,38 @@
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+/**
+ @file bench.h A simple real-time benchmarking API.
+*/
+
+#ifndef BENCH_H
+#define BENCH_H
+
+#include <time.h>
+
+typedef struct timespec BenchmarkTime;
+
+static inline double
+bench_elapsed_s(const BenchmarkTime* start, const BenchmarkTime* end)
+{
+ return ((end->tv_sec - start->tv_sec) +
+ ((end->tv_nsec - start->tv_nsec) * 0.000000001));
+}
+
+static inline BenchmarkTime
+bench_start(void)
+{
+ BenchmarkTime start_t;
+ clock_gettime(CLOCK_REALTIME, &start_t);
+ return start_t;
+}
+
+static inline double
+bench_end(const BenchmarkTime* start_t)
+{
+ BenchmarkTime end_t;
+ clock_gettime(CLOCK_REALTIME, &end_t);
+ return bench_elapsed_s(start_t, &end_t);
+}
+
+#endif /* BENCH_H */
diff --git a/utils/lilv.bash_completion b/tools/lilv.bash_completion
index 4a553a7..d5de5e2 100644
--- a/utils/lilv.bash_completion
+++ b/tools/lilv.bash_completion
@@ -1,10 +1,9 @@
-# Bash auto-completion script written for lv2info and lv2jack.
-# Could be adapted to any other program that takes an
-# LV2 plugin URI as parameter.
+# Copyright 2012-2022 David Robillard <d@drobilla.net>
+# Copyright 2009 Lars Luthman <lars.luthman@gmail.com>
+# SPDX-License-Identifier: 0BSD OR ISC
-# Updated for Lilv by David Robillard <d@drobilla.net> on 2012-01-08.
-# Written by Lars Luthman <lars.luthman@gmail.com> on 2009-10-12.
-# No copyright claimed for this script. Do what you want with it.
+# Bash auto-completion script written for lv2info. Could be adapted to any
+# other program that takes an LV2 plugin URI as parameter.
# For some reason Bash splits the command line not only at whitespace
# but also at ':' signs before putting the parts into COMP_WORDS.
@@ -54,6 +53,3 @@ function _lv2info() {
}
complete -F _lv2info lv2info
-
-# And the same for lv2jack.
-complete -F _lv2info lv2jack
diff --git a/tools/lv2apply.c b/tools/lv2apply.c
new file mode 100644
index 0000000..9c74bf3
--- /dev/null
+++ b/tools/lv2apply.c
@@ -0,0 +1,355 @@
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lilv/lilv.h"
+
+#include "lv2/core/lv2.h"
+
+#include <math.h>
+#include <sndfile.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__GNUC__)
+# define LILV_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
+#else
+# define LILV_LOG_FUNC(fmt, arg1)
+#endif
+
+/** Control port value set from the command line */
+typedef struct Param {
+ const char* sym; ///< Port symbol
+ float value; ///< Control value
+} Param;
+
+/** Port type (only float ports are supported) */
+typedef enum { TYPE_CONTROL, TYPE_AUDIO } PortType;
+
+/** Runtime port information */
+typedef struct {
+ const LilvPort* lilv_port; ///< Port description
+ PortType type; ///< Datatype
+ uint32_t index; ///< Port index
+ float value; ///< Control value (if applicable)
+ bool is_input; ///< True iff an input port
+ bool optional; ///< True iff connection optional
+} Port;
+
+/** Application state */
+typedef struct {
+ LilvWorld* world;
+ const LilvPlugin* plugin;
+ LilvInstance* instance;
+ const char* in_path;
+ const char* out_path;
+ SNDFILE* in_file;
+ SNDFILE* out_file;
+ unsigned n_params;
+ Param* params;
+ unsigned n_ports;
+ unsigned n_audio_in;
+ unsigned n_audio_out;
+ Port* ports;
+} LV2Apply;
+
+static int
+fatal(LV2Apply* self, int status, const char* fmt, ...);
+
+/** Open a sound file with error handling. */
+static SNDFILE*
+sopen(LV2Apply* self, const char* path, int mode, SF_INFO* fmt)
+{
+ SNDFILE* file = sf_open(path, mode, fmt);
+ const int st = sf_error(file);
+ if (st) {
+ fatal(self, 1, "Failed to open %s (%s)\n", path, sf_error_number(st));
+ return NULL;
+ }
+ return file;
+}
+
+/** Close a sound file with error handling. */
+static void
+sclose(const char* path, SNDFILE* file)
+{
+ int st = 0;
+ if (file && (st = sf_close(file))) {
+ fatal(NULL, 1, "Failed to close %s (%s)\n", path, sf_error_number(st));
+ }
+}
+
+/**
+ Read a single frame from a file into an interleaved buffer.
+
+ If more channels are required than are available in the file, the remaining
+ channels are distributed in a round-robin fashion (LRLRL).
+*/
+static bool
+sread(SNDFILE* file, unsigned file_chans, float* buf, unsigned buf_chans)
+{
+ const sf_count_t n_read = sf_readf_float(file, buf, 1);
+ for (unsigned i = file_chans - 1; i < buf_chans; ++i) {
+ buf[i] = buf[i % file_chans];
+ }
+ return n_read == 1;
+}
+
+/** Clean up all resources. */
+static int
+cleanup(int status, LV2Apply* self)
+{
+ sclose(self->in_path, self->in_file);
+ sclose(self->out_path, self->out_file);
+ lilv_instance_free(self->instance);
+ lilv_world_free(self->world);
+ free(self->ports);
+ free(self->params);
+ return status;
+}
+
+/** Print a fatal error and clean up for exit. */
+LILV_LOG_FUNC(3, 4)
+static int
+fatal(LV2Apply* self, int status, const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ return self ? cleanup(status, self) : status;
+}
+
+/**
+ Create port structures from data (via create_port()) for all ports.
+*/
+static int
+create_ports(LV2Apply* self)
+{
+ LilvWorld* world = self->world;
+ const uint32_t n_ports = lilv_plugin_get_num_ports(self->plugin);
+
+ self->n_ports = n_ports;
+ self->ports = (Port*)calloc(self->n_ports, sizeof(Port));
+
+ /* Get default values for all ports */
+ float* values = (float*)calloc(n_ports, sizeof(float));
+ lilv_plugin_get_port_ranges_float(self->plugin, NULL, NULL, values);
+
+ LilvNode* lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
+ LilvNode* lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
+ LilvNode* lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
+ LilvNode* lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
+ LilvNode* lv2_connectionOptional =
+ lilv_new_uri(world, LV2_CORE__connectionOptional);
+
+ for (uint32_t i = 0; i < n_ports; ++i) {
+ Port* port = &self->ports[i];
+ const LilvPort* lport = lilv_plugin_get_port_by_index(self->plugin, i);
+
+ port->lilv_port = lport;
+ port->index = i;
+ port->value = isnan(values[i]) ? 0.0f : values[i];
+ port->optional =
+ lilv_port_has_property(self->plugin, lport, lv2_connectionOptional);
+
+ /* Check if port is an input or output */
+ if (lilv_port_is_a(self->plugin, lport, lv2_InputPort)) {
+ port->is_input = true;
+ } else if (!lilv_port_is_a(self->plugin, lport, lv2_OutputPort) &&
+ !port->optional) {
+ return fatal(self, 1, "Port %u is neither input nor output\n", i);
+ }
+
+ /* Check if port is an audio or control port */
+ if (lilv_port_is_a(self->plugin, lport, lv2_ControlPort)) {
+ port->type = TYPE_CONTROL;
+ } else if (lilv_port_is_a(self->plugin, lport, lv2_AudioPort)) {
+ port->type = TYPE_AUDIO;
+ if (port->is_input) {
+ ++self->n_audio_in;
+ } else {
+ ++self->n_audio_out;
+ }
+ } else if (!port->optional) {
+ return fatal(self, 1, "Port %u has unsupported type\n", i);
+ }
+ }
+
+ lilv_node_free(lv2_connectionOptional);
+ lilv_node_free(lv2_ControlPort);
+ lilv_node_free(lv2_AudioPort);
+ lilv_node_free(lv2_OutputPort);
+ lilv_node_free(lv2_InputPort);
+ free(values);
+
+ return 0;
+}
+
+static void
+print_version(void)
+{
+ printf("lv2apply (lilv) " LILV_VERSION "\n"
+ "Copyright 2007-2021 David Robillard <d@drobilla.net>\n"
+ "License: <http://www.opensource.org/licenses/isc-license>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n");
+}
+
+static int
+print_usage(int status)
+{
+ fprintf(status ? stderr : stdout,
+ "Usage: lv2apply [OPTION]... PLUGIN_URI\n"
+ "Apply an LV2 plugin to an audio file.\n\n"
+ " -V, --version Display version information and exit\n"
+ " -c SYM VAL Control value\n"
+ " -h, --help Display this help and exit\n"
+ " -i IN_FILE Input file\n"
+ " -o OUT_FILE Output file\n");
+ return status;
+}
+
+int
+main(int argc, char** argv)
+{
+ LV2Apply self = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL};
+
+ /* Parse command line arguments */
+ const char* plugin_uri = NULL;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
+ free(self.params);
+ print_version();
+ return 0;
+ }
+
+ if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ free(self.params);
+ return print_usage(0);
+ }
+
+ if (!strcmp(argv[i], "-i")) {
+ self.in_path = argv[++i];
+ } else if (!strcmp(argv[i], "-o")) {
+ self.out_path = argv[++i];
+ } else if (!strcmp(argv[i], "-c")) {
+ if (argc < i + 3) {
+ return fatal(&self, 1, "Missing argument for -c\n");
+ }
+ self.params =
+ (Param*)realloc(self.params, ++self.n_params * sizeof(Param));
+ self.params[self.n_params - 1].sym = argv[++i];
+ self.params[self.n_params - 1].value = atof(argv[++i]);
+ } else if (argv[i][0] == '-') {
+ free(self.params);
+ return print_usage(1);
+ } else if (i == argc - 1) {
+ plugin_uri = argv[i];
+ }
+ }
+
+ /* Check that required arguments are given */
+ if (!self.in_path || !self.out_path || !plugin_uri) {
+ free(self.params);
+ return print_usage(1);
+ }
+
+ /* Create world and plugin URI */
+ self.world = lilv_world_new();
+ LilvNode* uri = lilv_new_uri(self.world, plugin_uri);
+ if (!uri) {
+ return fatal(&self, 2, "Invalid plugin URI <%s>\n", plugin_uri);
+ }
+
+ /* Discover world */
+ lilv_world_load_all(self.world);
+
+ /* Get plugin */
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(self.world);
+ const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, uri);
+ lilv_node_free(uri);
+ if (!(self.plugin = plugin)) {
+ return fatal(&self, 3, "Plugin <%s> not found\n", plugin_uri);
+ }
+
+ /* Open input file */
+ SF_INFO in_fmt = {0, 0, 0, 0, 0, 0};
+ if (!(self.in_file = sopen(&self, self.in_path, SFM_READ, &in_fmt))) {
+ return 4;
+ }
+
+ /* Create port structures */
+ if (create_ports(&self)) {
+ return 5;
+ }
+
+ if (self.n_audio_in == 0 ||
+ (in_fmt.channels != (int)self.n_audio_in && in_fmt.channels != 1)) {
+ return fatal(&self,
+ 6,
+ "Unable to map %d inputs to %u ports\n",
+ in_fmt.channels,
+ self.n_audio_in);
+ }
+
+ /* Set control values */
+ for (unsigned i = 0; i < self.n_params; ++i) {
+ const Param* param = &self.params[i];
+ LilvNode* sym = lilv_new_string(self.world, param->sym);
+ const LilvPort* port = lilv_plugin_get_port_by_symbol(plugin, sym);
+ lilv_node_free(sym);
+ if (!port) {
+ return fatal(&self, 7, "Unknown port `%s'\n", param->sym);
+ }
+
+ self.ports[lilv_port_get_index(plugin, port)].value = param->value;
+ }
+
+ /* Open output file */
+ SF_INFO out_fmt = in_fmt;
+ out_fmt.channels = self.n_audio_out;
+ if (!(self.out_file = sopen(&self, self.out_path, SFM_WRITE, &out_fmt))) {
+ free(self.ports);
+ return 8;
+ }
+
+ /* Instantiate plugin and connect ports */
+ const uint32_t n_ports = lilv_plugin_get_num_ports(plugin);
+ float in_buf[self.n_audio_in > 0 ? self.n_audio_in : 1];
+ float out_buf[self.n_audio_out > 0 ? self.n_audio_out : 1];
+ self.instance = lilv_plugin_instantiate(self.plugin, in_fmt.samplerate, NULL);
+ for (uint32_t p = 0, i = 0, o = 0; p < n_ports; ++p) {
+ if (self.ports[p].type == TYPE_CONTROL) {
+ lilv_instance_connect_port(self.instance, p, &self.ports[p].value);
+ } else if (self.ports[p].type == TYPE_AUDIO) {
+ if (self.ports[p].is_input) {
+ lilv_instance_connect_port(self.instance, p, in_buf + i++);
+ } else {
+ lilv_instance_connect_port(self.instance, p, out_buf + o++);
+ }
+ } else {
+ lilv_instance_connect_port(self.instance, p, NULL);
+ }
+ }
+
+ /* Ports are now connected to buffers in interleaved format, so we can run
+ a single frame at a time and avoid having to interleave buffers to
+ read/write from/to sndfile. */
+
+ lilv_instance_activate(self.instance);
+ while (sread(self.in_file, in_fmt.channels, in_buf, self.n_audio_in)) {
+ lilv_instance_run(self.instance, 1);
+ if (sf_writef_float(self.out_file, out_buf, 1) != 1) {
+ return fatal(&self, 9, "Failed to write to output file\n");
+ }
+ }
+ lilv_instance_deactivate(self.instance);
+
+ return cleanup(0, &self);
+}
diff --git a/tools/lv2bench.c b/tools/lv2bench.c
new file mode 100644
index 0000000..4b7eef7
--- /dev/null
+++ b/tools/lv2bench.c
@@ -0,0 +1,269 @@
+// Copyright 2012-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lilv/lilv.h"
+#include "lv2/atom/atom.h"
+#include "lv2/core/lv2.h"
+#include "lv2/urid/urid.h"
+
+#include "bench.h"
+#include "lilv_config.h"
+#include "uri_table.h"
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static LilvNode* atom_AtomPort = NULL;
+static LilvNode* atom_Sequence = NULL;
+static LilvNode* lv2_AudioPort = NULL;
+static LilvNode* lv2_CVPort = NULL;
+static LilvNode* lv2_ControlPort = NULL;
+static LilvNode* lv2_InputPort = NULL;
+static LilvNode* lv2_OutputPort = NULL;
+static LilvNode* urid_map = NULL;
+
+static bool full_output = false;
+
+static void
+print_version(void)
+{
+ printf("lv2bench (lilv) " LILV_VERSION "\n"
+ "Copyright 2012-2021 David Robillard <d@drobilla.net>\n"
+ "License: <http://www.opensource.org/licenses/isc-license>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n");
+}
+
+static void
+print_usage(void)
+{
+ printf("lv2bench - Benchmark all installed and supported LV2 plugins.\n");
+ printf("Usage: lv2bench [OPTIONS] [PLUGIN_URI]\n");
+ printf("\n");
+ printf(" -V, --version Display version information and exit\n");
+ printf(" -b BLOCK_SIZE Specify block size, in audio frames.\n");
+ printf(" -f, --full Full plottable output.\n");
+ printf(" -h, --help Display this help and exit.\n");
+ printf(" -n FRAMES Total number of audio frames to process\n");
+}
+
+static double
+bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size)
+{
+ URITable uri_table;
+ uri_table_init(&uri_table);
+
+ LV2_URID_Map map = {&uri_table, uri_table_map};
+ LV2_Feature map_feature = {LV2_URID_MAP_URI, &map};
+ LV2_URID_Unmap unmap = {&uri_table, uri_table_unmap};
+ LV2_Feature unmap_feature = {LV2_URID_UNMAP_URI, &unmap};
+ const LV2_Feature* features[] = {&map_feature, &unmap_feature, NULL};
+
+ float* const buf = (float*)calloc(block_size * 2UL, sizeof(float));
+ float* const in = buf;
+ float* const out = buf + block_size;
+ if (!buf) {
+ fprintf(stderr, "Out of memory\n");
+ return 0.0;
+ }
+
+ const size_t atom_capacity = 1024;
+
+ LV2_Atom_Sequence seq_in = {{sizeof(LV2_Atom_Sequence_Body),
+ uri_table_map(&uri_table, LV2_ATOM__Sequence)},
+ {0, 0}};
+
+ LV2_Atom_Sequence* seq_out =
+ (LV2_Atom_Sequence*)malloc(sizeof(LV2_Atom_Sequence) + atom_capacity);
+
+ const char* uri = lilv_node_as_string(lilv_plugin_get_uri(p));
+ LilvNodes* required = lilv_plugin_get_required_features(p);
+ LILV_FOREACH (nodes, i, required) {
+ const LilvNode* feature = lilv_nodes_get(required, i);
+ if (!lilv_node_equals(feature, urid_map)) {
+ fprintf(stderr,
+ "<%s> requires feature <%s>, skipping\n",
+ uri,
+ lilv_node_as_uri(feature));
+ free(seq_out);
+ free(buf);
+ uri_table_destroy(&uri_table);
+ return 0.0;
+ }
+ }
+
+ LilvInstance* instance = lilv_plugin_instantiate(p, 48000.0, features);
+ if (!instance) {
+ fprintf(stderr,
+ "Failed to instantiate <%s>\n",
+ lilv_node_as_uri(lilv_plugin_get_uri(p)));
+ free(seq_out);
+ free(buf);
+ uri_table_destroy(&uri_table);
+ return 0.0;
+ }
+
+ const uint32_t n_ports = lilv_plugin_get_num_ports(p);
+ float* const mins = (float*)calloc(n_ports, sizeof(float));
+ float* const maxes = (float*)calloc(n_ports, sizeof(float));
+ float* const controls = (float*)calloc(n_ports, sizeof(float));
+ lilv_plugin_get_port_ranges_float(p, mins, maxes, controls);
+
+ for (uint32_t index = 0; index < n_ports; ++index) {
+ const LilvPort* port = lilv_plugin_get_port_by_index(p, index);
+ if (lilv_port_is_a(p, port, lv2_ControlPort)) {
+ if (isnan(controls[index])) {
+ if (!isnan(mins[index])) {
+ controls[index] = mins[index];
+ } else if (!isnan(maxes[index])) {
+ controls[index] = maxes[index];
+ } else {
+ controls[index] = 0.0;
+ }
+ }
+ lilv_instance_connect_port(instance, index, &controls[index]);
+ } else if (lilv_port_is_a(p, port, lv2_AudioPort) ||
+ lilv_port_is_a(p, port, lv2_CVPort)) {
+ if (lilv_port_is_a(p, port, lv2_InputPort)) {
+ lilv_instance_connect_port(instance, index, in);
+ } else if (lilv_port_is_a(p, port, lv2_OutputPort)) {
+ lilv_instance_connect_port(instance, index, out);
+ } else {
+ fprintf(stderr,
+ "<%s> port %u neither input nor output, skipping\n",
+ uri,
+ index);
+ lilv_instance_free(instance);
+ free(seq_out);
+ free(buf);
+ free(controls);
+ uri_table_destroy(&uri_table);
+ return 0.0;
+ }
+ } else if (lilv_port_is_a(p, port, atom_AtomPort)) {
+ if (lilv_port_is_a(p, port, lv2_InputPort)) {
+ lilv_instance_connect_port(instance, index, &seq_in);
+ } else {
+ lilv_instance_connect_port(instance, index, seq_out);
+ }
+ } else {
+ fprintf(stderr, "<%s> port %u has unknown type, skipping\n", uri, index);
+ lilv_instance_free(instance);
+ free(seq_out);
+ free(buf);
+ free(controls);
+ uri_table_destroy(&uri_table);
+ return 0.0;
+ }
+ }
+
+ lilv_instance_activate(instance);
+
+ struct timespec ts = bench_start();
+ for (uint32_t i = 0; i < (sample_count / block_size); ++i) {
+ seq_in.atom.size = sizeof(LV2_Atom_Sequence_Body);
+ seq_in.atom.type = uri_table_map(&uri_table, LV2_ATOM__Sequence);
+ seq_out->atom.size = atom_capacity;
+ seq_out->atom.type = uri_table_map(&uri_table, LV2_ATOM__Chunk);
+
+ lilv_instance_run(instance, block_size);
+ }
+ const double elapsed = bench_end(&ts);
+
+ lilv_instance_deactivate(instance);
+ lilv_instance_free(instance);
+ free(controls);
+ free(maxes);
+ free(mins);
+ free(seq_out);
+
+ uri_table_destroy(&uri_table);
+
+ if (full_output) {
+ printf("%u %u ", block_size, sample_count);
+ }
+ printf("%lf %s\n", elapsed, uri);
+
+ free(buf);
+ return elapsed;
+}
+
+int
+main(int argc, char** argv)
+{
+ uint32_t block_size = 512;
+ uint32_t sample_count = (1 << 19);
+
+ int a = 1;
+ for (; a < argc; ++a) {
+ if (!strcmp(argv[a], "-V") || !strcmp(argv[a], "--version")) {
+ print_version();
+ return 0;
+ }
+
+ if (!strcmp(argv[a], "-h") || !strcmp(argv[a], "--help")) {
+ print_usage();
+ return 0;
+ }
+
+ if (!strcmp(argv[a], "-f")) {
+ full_output = true;
+ } else if (!strcmp(argv[a], "-n") && (a + 1 < argc)) {
+ sample_count = atoi(argv[++a]);
+ } else if (!strcmp(argv[a], "-b") && (a + 1 < argc)) {
+ block_size = atoi(argv[++a]);
+ } else if (argv[a][0] != '-') {
+ break;
+ } else {
+ print_usage();
+ return 1;
+ }
+ }
+
+ const char* const plugin_uri_str = (a < argc ? argv[a++] : NULL);
+
+ LilvWorld* world = lilv_world_new();
+ lilv_world_load_all(world);
+
+ atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
+ atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence);
+ lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
+ lv2_CVPort = lilv_new_uri(world, LV2_CORE__CVPort);
+ lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
+ lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
+ lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
+ urid_map = lilv_new_uri(world, LV2_URID__map);
+
+ if (full_output) {
+ printf("# Block Samples Time Plugin\n");
+ }
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ if (plugin_uri_str) {
+ LilvNode* uri = lilv_new_uri(world, plugin_uri_str);
+ bench(lilv_plugins_get_by_uri(plugins, uri), sample_count, block_size);
+ lilv_node_free(uri);
+ } else {
+ LILV_FOREACH (plugins, i, plugins) {
+ bench(lilv_plugins_get(plugins, i), sample_count, block_size);
+ }
+ }
+
+ lilv_node_free(urid_map);
+ lilv_node_free(lv2_OutputPort);
+ lilv_node_free(lv2_InputPort);
+ lilv_node_free(lv2_ControlPort);
+ lilv_node_free(lv2_CVPort);
+ lilv_node_free(lv2_AudioPort);
+ lilv_node_free(atom_Sequence);
+ lilv_node_free(atom_AtomPort);
+
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/tools/lv2info.c b/tools/lv2info.c
new file mode 100644
index 0000000..55acd09
--- /dev/null
+++ b/tools/lv2info.c
@@ -0,0 +1,443 @@
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lilv_config.h"
+
+#include "lilv/lilv.h"
+#include "lv2/core/lv2.h"
+#include "lv2/event/event.h"
+#include "lv2/port-groups/port-groups.h"
+#include "lv2/presets/presets.h"
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static LilvNode* applies_to_pred = NULL;
+static LilvNode* control_class = NULL;
+static LilvNode* event_class = NULL;
+static LilvNode* group_pred = NULL;
+static LilvNode* label_pred = NULL;
+static LilvNode* preset_class = NULL;
+static LilvNode* designation_pred = NULL;
+static LilvNode* supports_event_pred = NULL;
+
+static void
+print_port(const LilvPlugin* p,
+ uint32_t index,
+ float* mins,
+ float* maxes,
+ float* defaults)
+{
+ const LilvPort* port = lilv_plugin_get_port_by_index(p, index);
+
+ printf("\n\tPort %u:\n", index);
+
+ if (!port) {
+ printf("\t\tERROR: Illegal/nonexistent port\n");
+ return;
+ }
+
+ bool first = true;
+
+ const LilvNodes* classes = lilv_port_get_classes(p, port);
+ printf("\t\tType: ");
+ LILV_FOREACH (nodes, i, classes) {
+ const LilvNode* value = lilv_nodes_get(classes, i);
+ if (!first) {
+ printf("\n\t\t ");
+ }
+ printf("%s", lilv_node_as_uri(value));
+ first = false;
+ }
+
+ if (lilv_port_is_a(p, port, event_class)) {
+ LilvNodes* supported = lilv_port_get_value(p, port, supports_event_pred);
+ if (lilv_nodes_size(supported) > 0) {
+ printf("\n\t\tSupported events:\n");
+ LILV_FOREACH (nodes, i, supported) {
+ const LilvNode* value = lilv_nodes_get(supported, i);
+ printf("\t\t\t%s\n", lilv_node_as_uri(value));
+ }
+ }
+ lilv_nodes_free(supported);
+ }
+
+ LilvScalePoints* points = lilv_port_get_scale_points(p, port);
+ if (points) {
+ printf("\n\t\tScale Points:\n");
+ }
+ LILV_FOREACH (scale_points, i, points) {
+ const LilvScalePoint* point = lilv_scale_points_get(points, i);
+ printf("\t\t\t%s = \"%s\"\n",
+ lilv_node_as_string(lilv_scale_point_get_value(point)),
+ lilv_node_as_string(lilv_scale_point_get_label(point)));
+ }
+ lilv_scale_points_free(points);
+
+ const LilvNode* sym = lilv_port_get_symbol(p, port);
+ printf("\n\t\tSymbol: %s\n", lilv_node_as_string(sym));
+
+ LilvNode* name = lilv_port_get_name(p, port);
+ printf("\t\tName: %s\n", lilv_node_as_string(name));
+ lilv_node_free(name);
+
+ LilvNodes* groups = lilv_port_get_value(p, port, group_pred);
+ if (lilv_nodes_size(groups) > 0) {
+ printf("\t\tGroup: %s\n",
+ lilv_node_as_string(lilv_nodes_get_first(groups)));
+ }
+ lilv_nodes_free(groups);
+
+ LilvNodes* designations = lilv_port_get_value(p, port, designation_pred);
+ if (lilv_nodes_size(designations) > 0) {
+ printf("\t\tDesignation: %s\n",
+ lilv_node_as_string(lilv_nodes_get_first(designations)));
+ }
+ lilv_nodes_free(designations);
+
+ if (lilv_port_is_a(p, port, control_class)) {
+ if (!isnan(mins[index])) {
+ printf("\t\tMinimum: %f\n", mins[index]);
+ }
+ if (!isnan(maxes[index])) {
+ printf("\t\tMaximum: %f\n", maxes[index]);
+ }
+ if (!isnan(defaults[index])) {
+ printf("\t\tDefault: %f\n", defaults[index]);
+ }
+ }
+
+ LilvNodes* properties = lilv_port_get_properties(p, port);
+ if (lilv_nodes_size(properties) > 0) {
+ printf("\t\tProperties: ");
+ }
+ first = true;
+ LILV_FOREACH (nodes, i, properties) {
+ if (!first) {
+ printf("\t\t ");
+ }
+ printf("%s\n", lilv_node_as_uri(lilv_nodes_get(properties, i)));
+ first = false;
+ }
+ if (lilv_nodes_size(properties) > 0) {
+ printf("\n");
+ }
+ lilv_nodes_free(properties);
+}
+
+static void
+print_plugin(LilvWorld* world, const LilvPlugin* p)
+{
+ LilvNode* val = NULL;
+
+ printf("%s\n\n", lilv_node_as_uri(lilv_plugin_get_uri(p)));
+
+ val = lilv_plugin_get_name(p);
+ if (val) {
+ printf("\tName: %s\n", lilv_node_as_string(val));
+ lilv_node_free(val);
+ }
+
+ const LilvPluginClass* pclass = lilv_plugin_get_class(p);
+ const LilvNode* class_label = lilv_plugin_class_get_label(pclass);
+ if (class_label) {
+ printf("\tClass: %s\n", lilv_node_as_string(class_label));
+ }
+
+ val = lilv_plugin_get_author_name(p);
+ if (val) {
+ printf("\tAuthor: %s\n", lilv_node_as_string(val));
+ lilv_node_free(val);
+ }
+
+ val = lilv_plugin_get_author_email(p);
+ if (val) {
+ printf("\tAuthor Email: %s\n", lilv_node_as_uri(val));
+ lilv_node_free(val);
+ }
+
+ val = lilv_plugin_get_author_homepage(p);
+ if (val) {
+ printf("\tAuthor Homepage: %s\n", lilv_node_as_uri(val));
+ lilv_node_free(val);
+ }
+
+ if (lilv_plugin_has_latency(p)) {
+ uint32_t latency_port = lilv_plugin_get_latency_port_index(p);
+ printf("\tHas latency: yes, reported by port %u\n", latency_port);
+ } else {
+ printf("\tHas latency: no\n");
+ }
+
+ printf("\tBundle: %s\n",
+ lilv_node_as_uri(lilv_plugin_get_bundle_uri(p)));
+
+ const LilvNode* binary_uri = lilv_plugin_get_library_uri(p);
+ if (binary_uri) {
+ printf("\tBinary: %s\n",
+ lilv_node_as_uri(lilv_plugin_get_library_uri(p)));
+ }
+
+ LilvUIs* uis = lilv_plugin_get_uis(p);
+ if (lilv_nodes_size(uis) > 0) {
+ printf("\tUIs:\n");
+ LILV_FOREACH (uis, i, uis) {
+ const LilvUI* ui = lilv_uis_get(uis, i);
+ printf("\t\t%s\n", lilv_node_as_uri(lilv_ui_get_uri(ui)));
+
+ const char* binary = lilv_node_as_uri(lilv_ui_get_binary_uri(ui));
+
+ const LilvNodes* types = lilv_ui_get_classes(ui);
+ LILV_FOREACH (nodes, t, types) {
+ printf("\t\t\tClass: %s\n",
+ lilv_node_as_uri(lilv_nodes_get(types, t)));
+ }
+
+ if (binary) {
+ printf("\t\t\tBinary: %s\n", binary);
+ }
+
+ printf("\t\t\tBundle: %s\n",
+ lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)));
+ }
+ }
+ lilv_uis_free(uis);
+
+ printf("\tData URIs: ");
+ const LilvNodes* data_uris = lilv_plugin_get_data_uris(p);
+ bool first = true;
+ LILV_FOREACH (nodes, i, data_uris) {
+ if (!first) {
+ printf("\n\t ");
+ }
+ printf("%s", lilv_node_as_uri(lilv_nodes_get(data_uris, i)));
+ first = false;
+ }
+ printf("\n");
+
+ /* Required Features */
+
+ LilvNodes* features = lilv_plugin_get_required_features(p);
+ if (features) {
+ printf("\tRequired Features: ");
+ }
+ first = true;
+ LILV_FOREACH (nodes, i, features) {
+ if (!first) {
+ printf("\n\t ");
+ }
+ printf("%s", lilv_node_as_uri(lilv_nodes_get(features, i)));
+ first = false;
+ }
+ if (features) {
+ printf("\n");
+ }
+ lilv_nodes_free(features);
+
+ /* Optional Features */
+
+ features = lilv_plugin_get_optional_features(p);
+ if (features) {
+ printf("\tOptional Features: ");
+ }
+ first = true;
+ LILV_FOREACH (nodes, i, features) {
+ if (!first) {
+ printf("\n\t ");
+ }
+ printf("%s", lilv_node_as_uri(lilv_nodes_get(features, i)));
+ first = false;
+ }
+ if (features) {
+ printf("\n");
+ }
+ lilv_nodes_free(features);
+
+ /* Extension Data */
+
+ LilvNodes* data = lilv_plugin_get_extension_data(p);
+ if (data) {
+ printf("\tExtension Data: ");
+ }
+ first = true;
+ LILV_FOREACH (nodes, i, data) {
+ if (!first) {
+ printf("\n\t ");
+ }
+ printf("%s", lilv_node_as_uri(lilv_nodes_get(data, i)));
+ first = false;
+ }
+ if (data) {
+ printf("\n");
+ }
+ lilv_nodes_free(data);
+
+ /* Presets */
+
+ LilvNodes* presets = lilv_plugin_get_related(p, preset_class);
+ if (presets) {
+ printf("\tPresets: \n");
+ }
+ LILV_FOREACH (nodes, i, presets) {
+ const LilvNode* preset = lilv_nodes_get(presets, i);
+ lilv_world_load_resource(world, preset);
+ LilvNodes* titles = lilv_world_find_nodes(world, preset, label_pred, NULL);
+ if (titles) {
+ const LilvNode* title = lilv_nodes_get_first(titles);
+ printf("\t %s\n", lilv_node_as_string(title));
+ lilv_nodes_free(titles);
+ } else {
+ fprintf(stderr,
+ "Preset <%s> has no rdfs:label\n",
+ lilv_node_as_string(lilv_nodes_get(presets, i)));
+ }
+ }
+ lilv_nodes_free(presets);
+
+ /* Ports */
+
+ const uint32_t num_ports = lilv_plugin_get_num_ports(p);
+ float* mins = (float*)calloc(num_ports, sizeof(float));
+ float* maxes = (float*)calloc(num_ports, sizeof(float));
+ float* defaults = (float*)calloc(num_ports, sizeof(float));
+ lilv_plugin_get_port_ranges_float(p, mins, maxes, defaults);
+
+ for (uint32_t i = 0; i < num_ports; ++i) {
+ print_port(p, i, mins, maxes, defaults);
+ }
+
+ free(mins);
+ free(maxes);
+ free(defaults);
+}
+
+static void
+print_version(void)
+{
+ printf("lv2info (lilv) " LILV_VERSION "\n"
+ "Copyright 2007-2021 David Robillard <d@drobilla.net>\n"
+ "License: <http://www.opensource.org/licenses/isc-license>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n");
+}
+
+static void
+print_usage(void)
+{
+ printf("Usage: lv2info [OPTION]... PLUGIN_URI\n"
+ "Print information about an installed LV2 plugin.\n\n"
+ " -V, --version Display version information and exit\n"
+ " -h, --help Display this help and exit\n"
+ " -m FILE Add record of plugin to manifest FILE\n"
+ " -p FILE Write Turtle description of plugin to FILE\n\n"
+ "For -p and -m, Turtle files are appended to (not overwritten),\n"
+ "and @prefix directives are only written if the file was empty.\n"
+ "This allows several plugins to be added to a single file.\n");
+}
+
+int
+main(int argc, char** argv)
+{
+ if (argc == 1) {
+ print_usage();
+ return 1;
+ }
+
+ const char* plugin_file = NULL;
+ const char* manifest_file = NULL;
+ const char* plugin_uri = NULL;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
+ print_version();
+ return 0;
+ }
+
+ if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ print_usage();
+ return 0;
+ }
+
+ if (!strcmp(argv[i], "-p")) {
+ plugin_file = argv[++i];
+ } else if (!strcmp(argv[i], "-m")) {
+ manifest_file = argv[++i];
+ } else if (argv[i][0] == '-') {
+ print_usage();
+ return 1;
+ } else if (i == argc - 1) {
+ plugin_uri = argv[i];
+ }
+ }
+
+ int ret = 0;
+
+ LilvWorld* world = lilv_world_new();
+ lilv_world_load_all(world);
+
+ LilvNode* uri = lilv_new_uri(world, plugin_uri);
+ if (!uri) {
+ fprintf(stderr, "Invalid plugin URI\n");
+ lilv_world_free(world);
+ return 1;
+ }
+
+ applies_to_pred = lilv_new_uri(world, LV2_CORE__appliesTo);
+ control_class = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
+ event_class = lilv_new_uri(world, LILV_URI_EVENT_PORT);
+ group_pred = lilv_new_uri(world, LV2_PORT_GROUPS__group);
+ label_pred = lilv_new_uri(world, LILV_NS_RDFS "label");
+ preset_class = lilv_new_uri(world, LV2_PRESETS__Preset);
+ designation_pred = lilv_new_uri(world, LV2_CORE__designation);
+ supports_event_pred = lilv_new_uri(world, LV2_EVENT__supportsEvent);
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+ const LilvPlugin* p = lilv_plugins_get_by_uri(plugins, uri);
+
+ if (p && plugin_file) {
+ LilvNode* base = lilv_new_file_uri(world, NULL, plugin_file);
+
+ FILE* plugin_fd = fopen(plugin_file, "a");
+ if (plugin_fd) {
+ lilv_plugin_write_description(world, p, base, plugin_fd);
+ fclose(plugin_fd);
+ } else {
+ fprintf(stderr, "error: Failed to open %s\n", plugin_file);
+ }
+
+ if (manifest_file) {
+ FILE* manifest_fd = fopen(manifest_file, "a");
+ if (manifest_fd) {
+ lilv_plugin_write_manifest_entry(
+ world, p, base, manifest_fd, plugin_file);
+ fclose(manifest_fd);
+ } else {
+ fprintf(stderr, "error: Failed to open %s\n", manifest_file);
+ }
+ }
+ lilv_node_free(base);
+ } else if (p) {
+ print_plugin(world, p);
+ } else {
+ fprintf(stderr, "Plugin not found.\n");
+ }
+
+ ret = (p != NULL ? 0 : -1);
+
+ lilv_node_free(uri);
+
+ lilv_node_free(supports_event_pred);
+ lilv_node_free(designation_pred);
+ lilv_node_free(preset_class);
+ lilv_node_free(label_pred);
+ lilv_node_free(group_pred);
+ lilv_node_free(event_class);
+ lilv_node_free(control_class);
+ lilv_node_free(applies_to_pred);
+
+ lilv_world_free(world);
+ return ret;
+}
diff --git a/tools/lv2ls.c b/tools/lv2ls.c
new file mode 100644
index 0000000..8203262
--- /dev/null
+++ b/tools/lv2ls.c
@@ -0,0 +1,81 @@
+// Copyright 2007-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "lilv_config.h"
+
+#include "lilv/lilv.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+static void
+list_plugins(const LilvPlugins* list, bool show_names)
+{
+ LILV_FOREACH (plugins, i, list) {
+ const LilvPlugin* p = lilv_plugins_get(list, i);
+ if (show_names) {
+ LilvNode* n = lilv_plugin_get_name(p);
+ printf("%s\n", lilv_node_as_string(n));
+ lilv_node_free(n);
+ } else {
+ printf("%s\n", lilv_node_as_uri(lilv_plugin_get_uri(p)));
+ }
+ }
+}
+
+static void
+print_version(void)
+{
+ printf("lv2ls (lilv) " LILV_VERSION "\n"
+ "Copyright 2007-2021 David Robillard <d@drobilla.net>\n"
+ "License: <http://www.opensource.org/licenses/isc-license>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n");
+}
+
+static void
+print_usage(void)
+{
+ printf("Usage: lv2ls [OPTION]...\n");
+ printf("List all installed LV2 plugins.\n");
+ printf("\n");
+ printf(" -V, --version Display version information and exit\n");
+ printf(" -h, --help Display this help and exit\n");
+ printf(" -n, --names Show names instead of URIs\n");
+ printf("\n");
+ printf("The environment variable LV2_PATH can be used to control where\n");
+ printf(
+ "this (and all other lilv based LV2 hosts) will search for plugins.\n");
+}
+
+int
+main(int argc, char** argv)
+{
+ bool show_names = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "--names") || !strcmp(argv[i], "-n")) {
+ show_names = true;
+ } else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
+ print_version();
+ return 0;
+ } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ print_usage();
+ return 0;
+ } else {
+ print_usage();
+ return 1;
+ }
+ }
+
+ LilvWorld* world = lilv_world_new();
+ lilv_world_load_all(world);
+
+ const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
+
+ list_plugins(plugins, show_names);
+
+ lilv_world_free(world);
+
+ return 0;
+}
diff --git a/tools/meson.build b/tools/meson.build
new file mode 100644
index 0000000..6fa08e3
--- /dev/null
+++ b/tools/meson.build
@@ -0,0 +1,91 @@
+# Copyright 2021-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+include_dirs = include_directories('../src')
+
+#############################
+# "Basic" (Lilv-Only) Tools #
+#############################
+
+basic_tools = [
+ 'lv2info',
+ 'lv2ls',
+]
+
+foreach tool : basic_tools
+ exe = executable(
+ tool,
+ files(tool + '.c'),
+ c_args: c_suppressions,
+ dependencies: lilv_dep,
+ include_directories: include_dirs,
+ install: true,
+ )
+
+ meson.override_find_program(tool, exe)
+
+ install_man(files('..' / 'doc' / tool + '.1'))
+endforeach
+
+install_data(
+ files('lilv.bash_completion'),
+ install_dir: get_option('sysconfdir') / 'bash_completion.d',
+ rename: 'lilv',
+)
+
+###########################
+# lv2apply (uses sndfile) #
+###########################
+
+sndfile_dep = dependency(
+ 'sndfile',
+ version: '>= 1.0.0',
+ required: get_option('tools'),
+)
+
+if sndfile_dep.found()
+ lv2apply = executable(
+ 'lv2apply',
+ files('lv2apply.c'),
+ c_args: c_suppressions,
+ dependencies: [lilv_dep, sndfile_dep],
+ include_directories: include_dirs,
+ install: true,
+ )
+
+ meson.override_find_program('lv2apply', lv2apply)
+
+ install_man(files('..' / 'doc' / 'lv2apply.1'))
+endif
+
+#################################
+# lv2bench (uses clock_gettime) #
+#################################
+
+if host_machine.system() != 'windows'
+ rt_dep = cc.find_library('rt', required: false)
+
+ clock_gettime_code = '''#include <time.h>
+int main(void) { struct timespec t; return clock_gettime(CLOCK_MONOTONIC, &t); }
+'''
+
+ if cc.compiles(
+ clock_gettime_code,
+ args: platform_defines,
+ dependencies: [rt_dep],
+ name: 'clock_gettime',
+ )
+ lv2bench = executable(
+ 'lv2bench',
+ files('lv2bench.c'),
+ c_args: c_suppressions,
+ dependencies: [lilv_dep, rt_dep, sndfile_dep],
+ include_directories: include_dirs,
+ install: true,
+ )
+
+ meson.override_find_program('lv2bench', lv2bench)
+
+ install_man(files('..' / 'doc' / 'lv2bench.1'))
+ endif
+endif
diff --git a/tools/uri_table.h b/tools/uri_table.h
new file mode 100644
index 0000000..e17b02a
--- /dev/null
+++ b/tools/uri_table.h
@@ -0,0 +1,67 @@
+// Copyright 2011-2019 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+/**
+ @file uri_table.h A toy URI map/unmap implementation.
+
+ This file contains function definitions and must only be included once.
+*/
+
+#ifndef URI_TABLE_H
+#define URI_TABLE_H
+
+#include "lv2/urid/urid.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ char** uris;
+ size_t n_uris;
+} URITable;
+
+static void
+uri_table_init(URITable* table)
+{
+ table->uris = NULL;
+ table->n_uris = 0;
+}
+
+static void
+uri_table_destroy(URITable* table)
+{
+ for (size_t i = 0; i < table->n_uris; ++i) {
+ free(table->uris[i]);
+ }
+
+ free(table->uris);
+}
+
+static LV2_URID
+uri_table_map(LV2_URID_Map_Handle handle, const char* uri)
+{
+ URITable* table = (URITable*)handle;
+ for (size_t i = 0; i < table->n_uris; ++i) {
+ if (!strcmp(table->uris[i], uri)) {
+ return i + 1;
+ }
+ }
+
+ const size_t len = strlen(uri);
+ table->uris = (char**)realloc(table->uris, ++table->n_uris * sizeof(char*));
+ table->uris[table->n_uris - 1] = (char*)malloc(len + 1);
+ memcpy(table->uris[table->n_uris - 1], uri, len + 1);
+ return table->n_uris;
+}
+
+static const char*
+uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
+{
+ URITable* table = (URITable*)handle;
+ if (urid > 0 && urid <= table->n_uris) {
+ return table->uris[urid - 1];
+ }
+ return NULL;
+}
+
+#endif /* URI_TABLE_H */
diff --git a/utils/bench.h b/utils/bench.h
deleted file mode 100644
index 7b8da82..0000000
--- a/utils/bench.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- Copyright 2011-2019 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.
-*/
-
-/**
- @file bench.h A simple real-time benchmarking API.
-*/
-
-#ifndef BENCH_H
-#define BENCH_H
-
-#define _POSIX_C_SOURCE 200809L
-
-#include <sys/time.h>
-#include <time.h>
-
-static inline double
-bench_elapsed_s(const struct timespec* start, const struct timespec* end)
-{
- return ((end->tv_sec - start->tv_sec)
- + ((end->tv_nsec - start->tv_nsec) * 0.000000001));
-}
-
-static inline struct timespec
-bench_start(void)
-{
- struct timespec start_t;
- clock_gettime(CLOCK_REALTIME, &start_t);
- return start_t;
-}
-
-static inline double
-bench_end(const struct timespec* start_t)
-{
- struct timespec end_t;
- clock_gettime(CLOCK_REALTIME, &end_t);
- return bench_elapsed_s(start_t, &end_t);
-}
-
-#endif /* BENCH_H */
diff --git a/utils/lilv-bench.c b/utils/lilv-bench.c
deleted file mode 100644
index 59e49fe..0000000
--- a/utils/lilv-bench.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- Copyright 2007-2012 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.
-*/
-
-#include "lilv/lilv.h"
-
-int
-main(int argc, char** argv)
-{
- LilvWorld* world = lilv_world_new();
- lilv_world_load_all(world);
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- LILV_FOREACH(plugins, p, plugins) {
- const LilvPlugin* plugin = lilv_plugins_get(plugins, p);
- lilv_plugin_get_class(plugin);
- }
-
- lilv_world_free(world);
-
- return 0;
-}
diff --git a/utils/lv2apply.c b/utils/lv2apply.c
deleted file mode 100644
index 0ef86df..0000000
--- a/utils/lv2apply.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "lilv/lilv.h"
-
-#include "lv2/core/lv2.h"
-
-#include <math.h>
-#include <sndfile.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined(__GNUC__)
-# define LILV_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
-#else
-# define LILV_LOG_FUNC(fmt, arg1)
-#endif
-
-/** Control port value set from the command line */
-typedef struct Param {
- const char* sym; ///< Port symbol
- float value; ///< Control value
-} Param;
-
-/** Port type (only float ports are supported) */
-typedef enum {
- TYPE_CONTROL,
- TYPE_AUDIO
-} PortType;
-
-/** Runtime port information */
-typedef struct {
- const LilvPort* lilv_port; ///< Port description
- PortType type; ///< Datatype
- uint32_t index; ///< Port index
- float value; ///< Control value (if applicable)
- bool is_input; ///< True iff an input port
- bool optional; ///< True iff connection optional
-} Port;
-
-/** Application state */
-typedef struct {
- LilvWorld* world;
- const LilvPlugin* plugin;
- LilvInstance* instance;
- const char* in_path;
- const char* out_path;
- SNDFILE* in_file;
- SNDFILE* out_file;
- unsigned n_params;
- Param* params;
- unsigned n_ports;
- unsigned n_audio_in;
- unsigned n_audio_out;
- Port* ports;
-} LV2Apply;
-
-static int fatal(LV2Apply* self, int status, const char* fmt, ...);
-
-/** Open a sound file with error handling. */
-static SNDFILE*
-sopen(LV2Apply* self, const char* path, int mode, SF_INFO* fmt)
-{
- SNDFILE* file = sf_open(path, mode, fmt);
- const int st = sf_error(file);
- if (st) {
- fatal(self, 1, "Failed to open %s (%s)\n", path, sf_error_number(st));
- return NULL;
- }
- return file;
-}
-
-/** Close a sound file with error handling. */
-static void
-sclose(const char* path, SNDFILE* file)
-{
- int st;
- if (file && (st = sf_close(file))) {
- fatal(NULL, 1, "Failed to close %s (%s)\n", path, sf_error_number(st));
- }
-}
-
-/**
- Read a single frame from a file into an interleaved buffer.
-
- If more channels are required than are available in the file, the remaining
- channels are distributed in a round-robin fashion (LRLRL).
-*/
-static bool
-sread(SNDFILE* file, unsigned file_chans, float* buf, unsigned buf_chans)
-{
- const sf_count_t n_read = sf_readf_float(file, buf, 1);
- for (unsigned i = file_chans - 1; i < buf_chans; ++i) {
- buf[i] = buf[i % file_chans];
- }
- return n_read == 1;
-}
-
-/** Clean up all resources. */
-static int
-cleanup(int status, LV2Apply* self)
-{
- sclose(self->in_path, self->in_file);
- sclose(self->out_path, self->out_file);
- lilv_instance_free(self->instance);
- lilv_world_free(self->world);
- free(self->ports);
- free(self->params);
- return status;
-}
-
-/** Print a fatal error and clean up for exit. */
-LILV_LOG_FUNC(3, 4)
-static int
-fatal(LV2Apply* self, int status, const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, args);
- va_end(args);
- return self ? cleanup(status, self) : status;
-}
-
-/**
- Create port structures from data (via create_port()) for all ports.
-*/
-static int
-create_ports(LV2Apply* self)
-{
- LilvWorld* world = self->world;
- const uint32_t n_ports = lilv_plugin_get_num_ports(self->plugin);
-
- self->n_ports = n_ports;
- self->ports = (Port*)calloc(self->n_ports, sizeof(Port));
-
- /* Get default values for all ports */
- float* values = (float*)calloc(n_ports, sizeof(float));
- lilv_plugin_get_port_ranges_float(self->plugin, NULL, NULL, values);
-
- LilvNode* lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
- LilvNode* lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
- LilvNode* lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
- LilvNode* lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
- LilvNode* lv2_connectionOptional = lilv_new_uri(world, LV2_CORE__connectionOptional);
-
- for (uint32_t i = 0; i < n_ports; ++i) {
- Port* port = &self->ports[i];
- const LilvPort* lport = lilv_plugin_get_port_by_index(self->plugin, i);
-
- port->lilv_port = lport;
- port->index = i;
- port->value = isnan(values[i]) ? 0.0f : values[i];
- port->optional = lilv_port_has_property(
- self->plugin, lport, lv2_connectionOptional);
-
- /* Check if port is an input or output */
- if (lilv_port_is_a(self->plugin, lport, lv2_InputPort)) {
- port->is_input = true;
- } else if (!lilv_port_is_a(self->plugin, lport, lv2_OutputPort) &&
- !port->optional) {
- return fatal(self, 1, "Port %u is neither input nor output\n", i);
- }
-
- /* Check if port is an audio or control port */
- if (lilv_port_is_a(self->plugin, lport, lv2_ControlPort)) {
- port->type = TYPE_CONTROL;
- } else if (lilv_port_is_a(self->plugin, lport, lv2_AudioPort)) {
- port->type = TYPE_AUDIO;
- if (port->is_input) {
- ++self->n_audio_in;
- } else {
- ++self->n_audio_out;
- }
- } else if (!port->optional) {
- return fatal(self, 1, "Port %u has unsupported type\n", i);
- }
- }
-
- lilv_node_free(lv2_connectionOptional);
- lilv_node_free(lv2_ControlPort);
- lilv_node_free(lv2_AudioPort);
- lilv_node_free(lv2_OutputPort);
- lilv_node_free(lv2_InputPort);
- free(values);
-
- return 0;
-}
-
-static void
-print_version(void)
-{
- printf(
- "lv2apply (lilv) " LILV_VERSION "\n"
- "Copyright 2007-2019 David Robillard <http://drobilla.net>\n"
- "License: <http://www.opensource.org/licenses/isc-license>\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n");
-}
-
-static int
-print_usage(int status)
-{
- fprintf(status ? stderr : stdout,
- "Usage: lv2apply [OPTION]... PLUGIN_URI\n"
- "Apply an LV2 plugin to an audio file.\n\n"
- " -i IN_FILE Input file\n"
- " -o OUT_FILE Output file\n"
- " -c SYM VAL Control value\n"
- " --help Display this help and exit\n"
- " --version Display version information and exit\n");
- return status;
-}
-
-int
-main(int argc, char** argv)
-{
- LV2Apply self = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL
- };
-
- /* Parse command line arguments */
- const char* plugin_uri = NULL;
- for (int i = 1; i < argc; ++i) {
- if (!strcmp(argv[i], "--version")) {
- free(self.params);
- print_version();
- return 0;
- } else if (!strcmp(argv[i], "--help")) {
- free(self.params);
- return print_usage(0);
- } else if (!strcmp(argv[i], "-i")) {
- self.in_path = argv[++i];
- } else if (!strcmp(argv[i], "-o")) {
- self.out_path = argv[++i];
- } else if (!strcmp(argv[i], "-c")) {
- if (argc < i + 3) {
- return fatal(&self, 1, "Missing argument for -c\n");
- }
- self.params = (Param*)realloc(self.params,
- ++self.n_params * sizeof(Param));
- self.params[self.n_params - 1].sym = argv[++i];
- self.params[self.n_params - 1].value = atof(argv[++i]);
- } else if (argv[i][0] == '-') {
- free(self.params);
- return print_usage(1);
- } else if (i == argc - 1) {
- plugin_uri = argv[i];
- }
- }
-
- /* Check that required arguments are given */
- if (!self.in_path || !self.out_path || !plugin_uri) {
- free(self.params);
- return print_usage(1);
- }
-
- /* Create world and plugin URI */
- self.world = lilv_world_new();
- LilvNode* uri = lilv_new_uri(self.world, plugin_uri);
- if (!uri) {
- return fatal(&self, 2, "Invalid plugin URI <%s>\n", plugin_uri);
- }
-
- /* Discover world */
- lilv_world_load_all(self.world);
-
- /* Get plugin */
- const LilvPlugins* plugins = lilv_world_get_all_plugins(self.world);
- const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, uri);
- lilv_node_free(uri);
- if (!(self.plugin = plugin)) {
- return fatal(&self, 3, "Plugin <%s> not found\n", plugin_uri);
- }
-
- /* Open input file */
- SF_INFO in_fmt = { 0, 0, 0, 0, 0, 0 };
- if (!(self.in_file = sopen(&self, self.in_path, SFM_READ, &in_fmt))) {
- return 4;
- }
-
- /* Create port structures */
- if (create_ports(&self)) {
- return 5;
- }
-
- if (self.n_audio_in == 0 ||
- (in_fmt.channels != (int)self.n_audio_in && in_fmt.channels != 1)) {
- return fatal(&self, 6, "Unable to map %d inputs to %u ports\n",
- in_fmt.channels, self.n_audio_in);
- }
-
- /* Set control values */
- for (unsigned i = 0; i < self.n_params; ++i) {
- const Param* param = &self.params[i];
- LilvNode* sym = lilv_new_string(self.world, param->sym);
- const LilvPort* port = lilv_plugin_get_port_by_symbol(plugin, sym);
- lilv_node_free(sym);
- if (!port) {
- return fatal(&self, 7, "Unknown port `%s'\n", param->sym);
- }
-
- self.ports[lilv_port_get_index(plugin, port)].value = param->value;
- }
-
- /* Open output file */
- SF_INFO out_fmt = in_fmt;
- out_fmt.channels = self.n_audio_out;
- if (!(self.out_file = sopen(&self, self.out_path, SFM_WRITE, &out_fmt))) {
- return 8;
- }
-
- /* Instantiate plugin and connect ports */
- const uint32_t n_ports = lilv_plugin_get_num_ports(plugin);
- float in_buf[self.n_audio_in];
- float out_buf[self.n_audio_out];
- self.instance = lilv_plugin_instantiate(
- self.plugin, in_fmt.samplerate, NULL);
- for (uint32_t p = 0, i = 0, o = 0; p < n_ports; ++p) {
- if (self.ports[p].type == TYPE_CONTROL) {
- lilv_instance_connect_port(self.instance, p, &self.ports[p].value);
- } else if (self.ports[p].type == TYPE_AUDIO) {
- if (self.ports[p].is_input) {
- lilv_instance_connect_port(self.instance, p, in_buf + i++);
- } else {
- lilv_instance_connect_port(self.instance, p, out_buf + o++);
- }
- } else {
- lilv_instance_connect_port(self.instance, p, NULL);
- }
- }
-
- /* Ports are now connected to buffers in interleaved format, so we can run
- a single frame at a time and avoid having to interleave buffers to
- read/write from/to sndfile. */
-
- lilv_instance_activate(self.instance);
- while (sread(self.in_file, in_fmt.channels, in_buf, self.n_audio_in)) {
- lilv_instance_run(self.instance, 1);
- if (sf_writef_float(self.out_file, out_buf, 1) != 1) {
- return fatal(&self, 9, "Failed to write to output file\n");
- }
- }
- lilv_instance_deactivate(self.instance);
-
- return cleanup(0, &self);
-}
diff --git a/utils/lv2bench.c b/utils/lv2bench.c
deleted file mode 100644
index dc0fa0b..0000000
--- a/utils/lv2bench.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- Copyright 2012-2019 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
-
-#include "lilv/lilv.h"
-#include "lv2/atom/atom.h"
-#include "lv2/core/lv2.h"
-#include "lv2/urid/urid.h"
-
-#include "bench.h"
-#include "lilv_config.h"
-#include "uri_table.h"
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-static LilvNode* atom_AtomPort = NULL;
-static LilvNode* atom_Sequence = NULL;
-static LilvNode* lv2_AudioPort = NULL;
-static LilvNode* lv2_CVPort = NULL;
-static LilvNode* lv2_ControlPort = NULL;
-static LilvNode* lv2_InputPort = NULL;
-static LilvNode* lv2_OutputPort = NULL;
-static LilvNode* urid_map = NULL;
-
-static bool full_output = false;
-
-static void
-print_version(void)
-{
- printf(
- "lv2bench (lilv) " LILV_VERSION "\n"
- "Copyright 2012-2019 David Robillard <http://drobilla.net>\n"
- "License: <http://www.opensource.org/licenses/isc-license>\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n");
-}
-
-static void
-print_usage(void)
-{
- printf("lv2bench - Benchmark all installed and supported LV2 plugins.\n");
- printf("Usage: lv2bench [OPTIONS] [PLUGIN_URI]\n");
- printf("\n");
- printf(" -b BLOCK_SIZE Specify block size, in audio frames.\n");
- printf(" -f, --full Full plottable output.\n");
- printf(" -h, --help Display this help and exit.\n");
- printf(" -n FRAMES Total number of audio frames to process\n");
- printf(" --version Display version information and exit\n");
-}
-
-static double
-bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size)
-{
- URITable uri_table;
- uri_table_init(&uri_table);
-
- LV2_URID_Map map = { &uri_table, uri_table_map };
- LV2_Feature map_feature = { LV2_URID_MAP_URI, &map };
- LV2_URID_Unmap unmap = { &uri_table, uri_table_unmap };
- LV2_Feature unmap_feature = { LV2_URID_UNMAP_URI, &unmap };
- const LV2_Feature* features[] = { &map_feature, &unmap_feature, NULL };
-
- float* const buf = (float*)calloc(block_size * 2, sizeof(float));
- float* const in = buf;
- float* const out = buf + block_size;
- if (!buf) {
- fprintf(stderr, "Out of memory\n");
- return 0.0;
- }
-
- const size_t atom_capacity = 1024;
-
- LV2_Atom_Sequence seq_in = {
- { sizeof(LV2_Atom_Sequence_Body),
- uri_table_map(&uri_table, LV2_ATOM__Sequence) },
- { 0, 0 } };
-
- LV2_Atom_Sequence* seq_out = (LV2_Atom_Sequence*)malloc(
- sizeof(LV2_Atom_Sequence) + atom_capacity);
-
- const char* uri = lilv_node_as_string(lilv_plugin_get_uri(p));
- LilvNodes* required = lilv_plugin_get_required_features(p);
- LILV_FOREACH(nodes, i, required) {
- const LilvNode* feature = lilv_nodes_get(required, i);
- if (!lilv_node_equals(feature, urid_map)) {
- fprintf(stderr, "<%s> requires feature <%s>, skipping\n",
- uri, lilv_node_as_uri(feature));
- free(buf);
- uri_table_destroy(&uri_table);
- return 0.0;
- }
- }
-
- LilvInstance* instance = lilv_plugin_instantiate(p, 48000.0, features);
- if (!instance) {
- fprintf(stderr, "Failed to instantiate <%s>\n",
- lilv_node_as_uri(lilv_plugin_get_uri(p)));
- free(buf);
- uri_table_destroy(&uri_table);
- return 0.0;
- }
-
- const uint32_t n_ports = lilv_plugin_get_num_ports(p);
- float* const mins = (float*)calloc(n_ports, sizeof(float));
- float* const maxes = (float*)calloc(n_ports, sizeof(float));
- float* const controls = (float*)calloc(n_ports, sizeof(float));
- lilv_plugin_get_port_ranges_float(p, mins, maxes, controls);
-
- for (uint32_t index = 0; index < n_ports; ++index) {
- const LilvPort* port = lilv_plugin_get_port_by_index(p, index);
- if (lilv_port_is_a(p, port, lv2_ControlPort)) {
- if (isnan(controls[index])) {
- if (!isnan(mins[index])) {
- controls[index] = mins[index];
- } else if (!isnan(maxes[index])) {
- controls[index] = maxes[index];
- } else {
- controls[index] = 0.0;
- }
- }
- lilv_instance_connect_port(instance, index, &controls[index]);
- } else if (lilv_port_is_a(p, port, lv2_AudioPort) ||
- lilv_port_is_a(p, port, lv2_CVPort)) {
- if (lilv_port_is_a(p, port, lv2_InputPort)) {
- lilv_instance_connect_port(instance, index, in);
- } else if (lilv_port_is_a(p, port, lv2_OutputPort)) {
- lilv_instance_connect_port(instance, index, out);
- } else {
- fprintf(stderr, "<%s> port %u neither input nor output, skipping\n",
- uri, index);
- lilv_instance_free(instance);
- free(seq_out);
- free(buf);
- free(controls);
- uri_table_destroy(&uri_table);
- return 0.0;
- }
- } else if (lilv_port_is_a(p, port, atom_AtomPort)) {
- if (lilv_port_is_a(p, port, lv2_InputPort)) {
- lilv_instance_connect_port(instance, index, &seq_in);
- } else {
- lilv_instance_connect_port(instance, index, seq_out);
- }
- } else {
- fprintf(stderr, "<%s> port %u has unknown type, skipping\n",
- uri, index);
- lilv_instance_free(instance);
- free(seq_out);
- free(buf);
- free(controls);
- uri_table_destroy(&uri_table);
- return 0.0;
- }
- }
-
- lilv_instance_activate(instance);
-
- struct timespec ts = bench_start();
- for (uint32_t i = 0; i < (sample_count / block_size); ++i) {
- seq_in.atom.size = sizeof(LV2_Atom_Sequence_Body);
- seq_in.atom.type = uri_table_map(&uri_table, LV2_ATOM__Sequence);
- seq_out->atom.size = atom_capacity;
- seq_out->atom.type = uri_table_map(&uri_table, LV2_ATOM__Chunk);
-
- lilv_instance_run(instance, block_size);
- }
- const double elapsed = bench_end(&ts);
-
- lilv_instance_deactivate(instance);
- lilv_instance_free(instance);
- free(controls);
- free(maxes);
- free(mins);
- free(seq_out);
-
- uri_table_destroy(&uri_table);
-
- if (full_output) {
- printf("%u %u ", block_size, sample_count);
- }
- printf("%lf %s\n", elapsed, uri);
-
- free(buf);
- return elapsed;
-}
-
-int
-main(int argc, char** argv)
-{
- uint32_t block_size = 512;
- uint32_t sample_count = (1 << 19);
-
- int a = 1;
- for (; a < argc; ++a) {
- if (!strcmp(argv[a], "--version")) {
- print_version();
- return 0;
- } else if (!strcmp(argv[a], "--help")) {
- print_usage();
- return 0;
- } else if (!strcmp(argv[a], "-f")) {
- full_output = true;
- } else if (!strcmp(argv[a], "-n") && (a + 1 < argc)) {
- sample_count = atoi(argv[++a]);
- } else if (!strcmp(argv[a], "-b") && (a + 1 < argc)) {
- block_size = atoi(argv[++a]);
- } else if (argv[a][0] != '-') {
- break;
- } else {
- print_usage();
- return 1;
- }
- }
-
- const char* const plugin_uri_str = (a < argc ? argv[a++] : NULL);
-
- LilvWorld* world = lilv_world_new();
- lilv_world_load_all(world);
-
- atom_AtomPort = lilv_new_uri(world, LV2_ATOM__AtomPort);
- atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence);
- lv2_AudioPort = lilv_new_uri(world, LV2_CORE__AudioPort);
- lv2_CVPort = lilv_new_uri(world, LV2_CORE__CVPort);
- lv2_ControlPort = lilv_new_uri(world, LV2_CORE__ControlPort);
- lv2_InputPort = lilv_new_uri(world, LV2_CORE__InputPort);
- lv2_OutputPort = lilv_new_uri(world, LV2_CORE__OutputPort);
- urid_map = lilv_new_uri(world, LV2_URID__map);
-
- if (full_output) {
- printf("# Block Samples Time Plugin\n");
- }
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- if (plugin_uri_str) {
- LilvNode* uri = lilv_new_uri(world, plugin_uri_str);
- bench(lilv_plugins_get_by_uri(plugins, uri), sample_count, block_size);
- lilv_node_free(uri);
- } else {
- LILV_FOREACH(plugins, i, plugins) {
- bench(lilv_plugins_get(plugins, i), sample_count, block_size);
- }
- }
-
- lilv_node_free(urid_map);
- lilv_node_free(lv2_OutputPort);
- lilv_node_free(lv2_InputPort);
- lilv_node_free(lv2_ControlPort);
- lilv_node_free(lv2_CVPort);
- lilv_node_free(lv2_AudioPort);
- lilv_node_free(atom_Sequence);
- lilv_node_free(atom_AtomPort);
-
- lilv_world_free(world);
-
- return 0;
-}
diff --git a/utils/lv2info.c b/utils/lv2info.c
deleted file mode 100644
index 0027da1..0000000
--- a/utils/lv2info.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "lilv_config.h"
-
-#include "lilv/lilv.h"
-#include "lv2/core/lv2.h"
-#include "lv2/event/event.h"
-#include "lv2/port-groups/port-groups.h"
-#include "lv2/presets/presets.h"
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static LilvNode* applies_to_pred = NULL;
-static LilvNode* control_class = NULL;
-static LilvNode* event_class = NULL;
-static LilvNode* group_pred = NULL;
-static LilvNode* label_pred = NULL;
-static LilvNode* preset_class = NULL;
-static LilvNode* designation_pred = NULL;
-static LilvNode* supports_event_pred = NULL;
-
-static void
-print_port(const LilvPlugin* p,
- uint32_t index,
- float* mins,
- float* maxes,
- float* defaults)
-{
- const LilvPort* port = lilv_plugin_get_port_by_index(p, index);
-
- printf("\n\tPort %u:\n", index);
-
- if (!port) {
- printf("\t\tERROR: Illegal/nonexistent port\n");
- return;
- }
-
- bool first = true;
-
- const LilvNodes* classes = lilv_port_get_classes(p, port);
- printf("\t\tType: ");
- LILV_FOREACH(nodes, i, classes) {
- const LilvNode* value = lilv_nodes_get(classes, i);
- if (!first) {
- printf("\n\t\t ");
- }
- printf("%s", lilv_node_as_uri(value));
- first = false;
- }
-
- if (lilv_port_is_a(p, port, event_class)) {
- LilvNodes* supported = lilv_port_get_value(
- p, port, supports_event_pred);
- if (lilv_nodes_size(supported) > 0) {
- printf("\n\t\tSupported events:\n");
- LILV_FOREACH(nodes, i, supported) {
- const LilvNode* value = lilv_nodes_get(supported, i);
- printf("\t\t\t%s\n", lilv_node_as_uri(value));
- }
- }
- lilv_nodes_free(supported);
- }
-
- LilvScalePoints* points = lilv_port_get_scale_points(p, port);
- if (points) {
- printf("\n\t\tScale Points:\n");
- }
- LILV_FOREACH(scale_points, i, points) {
- const LilvScalePoint* point = lilv_scale_points_get(points, i);
- printf("\t\t\t%s = \"%s\"\n",
- lilv_node_as_string(lilv_scale_point_get_value(point)),
- lilv_node_as_string(lilv_scale_point_get_label(point)));
- }
- lilv_scale_points_free(points);
-
- const LilvNode* sym = lilv_port_get_symbol(p, port);
- printf("\n\t\tSymbol: %s\n", lilv_node_as_string(sym));
-
- LilvNode* name = lilv_port_get_name(p, port);
- printf("\t\tName: %s\n", lilv_node_as_string(name));
- lilv_node_free(name);
-
- LilvNodes* groups = lilv_port_get_value(p, port, group_pred);
- if (lilv_nodes_size(groups) > 0) {
- printf("\t\tGroup: %s\n",
- lilv_node_as_string(lilv_nodes_get_first(groups)));
- }
- lilv_nodes_free(groups);
-
- LilvNodes* designations = lilv_port_get_value(p, port, designation_pred);
- if (lilv_nodes_size(designations) > 0) {
- printf("\t\tDesignation: %s\n",
- lilv_node_as_string(lilv_nodes_get_first(designations)));
- }
- lilv_nodes_free(designations);
-
- if (lilv_port_is_a(p, port, control_class)) {
- if (!isnan(mins[index])) {
- printf("\t\tMinimum: %f\n", mins[index]);
- }
- if (!isnan(maxes[index])) {
- printf("\t\tMaximum: %f\n", maxes[index]);
- }
- if (!isnan(defaults[index])) {
- printf("\t\tDefault: %f\n", defaults[index]);
- }
- }
-
- LilvNodes* properties = lilv_port_get_properties(p, port);
- if (lilv_nodes_size(properties) > 0) {
- printf("\t\tProperties: ");
- }
- first = true;
- LILV_FOREACH(nodes, i, properties) {
- if (!first) {
- printf("\t\t ");
- }
- printf("%s\n", lilv_node_as_uri(lilv_nodes_get(properties, i)));
- first = false;
- }
- if (lilv_nodes_size(properties) > 0) {
- printf("\n");
- }
- lilv_nodes_free(properties);
-}
-
-static void
-print_plugin(LilvWorld* world,
- const LilvPlugin* p)
-{
- LilvNode* val = NULL;
-
- printf("%s\n\n", lilv_node_as_uri(lilv_plugin_get_uri(p)));
-
- val = lilv_plugin_get_name(p);
- if (val) {
- printf("\tName: %s\n", lilv_node_as_string(val));
- lilv_node_free(val);
- }
-
- const LilvPluginClass* pclass = lilv_plugin_get_class(p);
- const LilvNode* class_label = lilv_plugin_class_get_label(pclass);
- if (class_label) {
- printf("\tClass: %s\n", lilv_node_as_string(class_label));
- }
-
- val = lilv_plugin_get_author_name(p);
- if (val) {
- printf("\tAuthor: %s\n", lilv_node_as_string(val));
- lilv_node_free(val);
- }
-
- val = lilv_plugin_get_author_email(p);
- if (val) {
- printf("\tAuthor Email: %s\n", lilv_node_as_uri(val));
- lilv_node_free(val);
- }
-
- val = lilv_plugin_get_author_homepage(p);
- if (val) {
- printf("\tAuthor Homepage: %s\n", lilv_node_as_uri(val));
- lilv_node_free(val);
- }
-
- if (lilv_plugin_has_latency(p)) {
- uint32_t latency_port = lilv_plugin_get_latency_port_index(p);
- printf("\tHas latency: yes, reported by port %u\n", latency_port);
- } else {
- printf("\tHas latency: no\n");
- }
-
- printf("\tBundle: %s\n",
- lilv_node_as_uri(lilv_plugin_get_bundle_uri(p)));
-
- const LilvNode* binary_uri = lilv_plugin_get_library_uri(p);
- if (binary_uri) {
- printf("\tBinary: %s\n",
- lilv_node_as_uri(lilv_plugin_get_library_uri(p)));
- }
-
- LilvUIs* uis = lilv_plugin_get_uis(p);
- if (lilv_nodes_size(uis) > 0) {
- printf("\tUIs:\n");
- LILV_FOREACH(uis, i, uis) {
- const LilvUI* ui = lilv_uis_get(uis, i);
- printf("\t\t%s\n", lilv_node_as_uri(lilv_ui_get_uri(ui)));
-
- const char* binary = lilv_node_as_uri(lilv_ui_get_binary_uri(ui));
-
- const LilvNodes* types = lilv_ui_get_classes(ui);
- LILV_FOREACH(nodes, t, types) {
- printf("\t\t\tClass: %s\n",
- lilv_node_as_uri(lilv_nodes_get(types, t)));
- }
-
- if (binary) {
- printf("\t\t\tBinary: %s\n", binary);
- }
-
- printf("\t\t\tBundle: %s\n",
- lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)));
- }
- }
- lilv_uis_free(uis);
-
- printf("\tData URIs: ");
- const LilvNodes* data_uris = lilv_plugin_get_data_uris(p);
- bool first = true;
- LILV_FOREACH(nodes, i, data_uris) {
- if (!first) {
- printf("\n\t ");
- }
- printf("%s", lilv_node_as_uri(lilv_nodes_get(data_uris, i)));
- first = false;
- }
- printf("\n");
-
- /* Required Features */
-
- LilvNodes* features = lilv_plugin_get_required_features(p);
- if (features) {
- printf("\tRequired Features: ");
- }
- first = true;
- LILV_FOREACH(nodes, i, features) {
- if (!first) {
- printf("\n\t ");
- }
- printf("%s", lilv_node_as_uri(lilv_nodes_get(features, i)));
- first = false;
- }
- if (features) {
- printf("\n");
- }
- lilv_nodes_free(features);
-
- /* Optional Features */
-
- features = lilv_plugin_get_optional_features(p);
- if (features) {
- printf("\tOptional Features: ");
- }
- first = true;
- LILV_FOREACH(nodes, i, features) {
- if (!first) {
- printf("\n\t ");
- }
- printf("%s", lilv_node_as_uri(lilv_nodes_get(features, i)));
- first = false;
- }
- if (features) {
- printf("\n");
- }
- lilv_nodes_free(features);
-
- /* Extension Data */
-
- LilvNodes* data = lilv_plugin_get_extension_data(p);
- if (data) {
- printf("\tExtension Data: ");
- }
- first = true;
- LILV_FOREACH(nodes, i, data) {
- if (!first) {
- printf("\n\t ");
- }
- printf("%s", lilv_node_as_uri(lilv_nodes_get(data, i)));
- first = false;
- }
- if (data) {
- printf("\n");
- }
- lilv_nodes_free(data);
-
- /* Presets */
-
- LilvNodes* presets = lilv_plugin_get_related(p, preset_class);
- if (presets) {
- printf("\tPresets: \n");
- }
- LILV_FOREACH(nodes, i, presets) {
- const LilvNode* preset = lilv_nodes_get(presets, i);
- lilv_world_load_resource(world, preset);
- LilvNodes* titles = lilv_world_find_nodes(
- world, preset, label_pred, NULL);
- if (titles) {
- const LilvNode* title = lilv_nodes_get_first(titles);
- printf("\t %s\n", lilv_node_as_string(title));
- lilv_nodes_free(titles);
- } else {
- fprintf(stderr, "Preset <%s> has no rdfs:label\n",
- lilv_node_as_string(lilv_nodes_get(presets, i)));
- }
- }
- lilv_nodes_free(presets);
-
- /* Ports */
-
- const uint32_t num_ports = lilv_plugin_get_num_ports(p);
- float* mins = (float*)calloc(num_ports, sizeof(float));
- float* maxes = (float*)calloc(num_ports, sizeof(float));
- float* defaults = (float*)calloc(num_ports, sizeof(float));
- lilv_plugin_get_port_ranges_float(p, mins, maxes, defaults);
-
- for (uint32_t i = 0; i < num_ports; ++i) {
- print_port(p, i, mins, maxes, defaults);
- }
-
- free(mins);
- free(maxes);
- free(defaults);
-}
-
-static void
-print_version(void)
-{
- printf(
- "lv2info (lilv) " LILV_VERSION "\n"
- "Copyright 2007-2019 David Robillard <http://drobilla.net>\n"
- "License: <http://www.opensource.org/licenses/isc-license>\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n");
-}
-
-static void
-print_usage(void)
-{
- printf(
- "Usage: lv2info [OPTION]... PLUGIN_URI\n"
- "Print information about an installed LV2 plugin.\n\n"
- " -p FILE Write Turtle description of plugin to FILE\n"
- " -m FILE Add record of plugin to manifest FILE\n"
- " --help Display this help and exit\n"
- " --version Display version information and exit\n\n"
- "For -p and -m, Turtle files are appended to (not overwritten),\n"
- "and @prefix directives are only written if the file was empty.\n"
- "This allows several plugins to be added to a single file.\n");
-}
-
-int
-main(int argc, char** argv)
-{
- if (argc == 1) {
- print_usage();
- return 1;
- }
-
- const char* plugin_file = NULL;
- const char* manifest_file = NULL;
- const char* plugin_uri = NULL;
- for (int i = 1; i < argc; ++i) {
- if (!strcmp(argv[i], "--version")) {
- print_version();
- return 0;
- } else if (!strcmp(argv[i], "--help")) {
- print_usage();
- return 0;
- } else if (!strcmp(argv[i], "-p")) {
- plugin_file = argv[++i];
- } else if (!strcmp(argv[i], "-m")) {
- manifest_file = argv[++i];
- } else if (argv[i][0] == '-') {
- print_usage();
- return 1;
- } else if (i == argc - 1) {
- plugin_uri = argv[i];
- }
- }
-
- int ret = 0;
-
- LilvWorld* world = lilv_world_new();
- lilv_world_load_all(world);
-
- LilvNode* uri = lilv_new_uri(world, plugin_uri);
- if (!uri) {
- fprintf(stderr, "Invalid plugin URI\n");
- lilv_world_free(world);
- return 1;
- }
-
- applies_to_pred = lilv_new_uri(world, LV2_CORE__appliesTo);
- control_class = lilv_new_uri(world, LILV_URI_CONTROL_PORT);
- event_class = lilv_new_uri(world, LILV_URI_EVENT_PORT);
- group_pred = lilv_new_uri(world, LV2_PORT_GROUPS__group);
- label_pred = lilv_new_uri(world, LILV_NS_RDFS "label");
- preset_class = lilv_new_uri(world, LV2_PRESETS__Preset);
- designation_pred = lilv_new_uri(world, LV2_CORE__designation);
- supports_event_pred = lilv_new_uri(world, LV2_EVENT__supportsEvent);
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
- const LilvPlugin* p = lilv_plugins_get_by_uri(plugins, uri);
-
- if (p && plugin_file) {
- LilvNode* base = lilv_new_file_uri(world, NULL, plugin_file);
-
- FILE* plugin_fd = fopen(plugin_file, "a");
- if (plugin_fd) {
- lilv_plugin_write_description(world, p, base, plugin_fd);
- fclose(plugin_fd);
- } else {
- fprintf(stderr, "error: Failed to open %s\n", plugin_file);
- }
-
- if (manifest_file) {
- FILE* manifest_fd = fopen(manifest_file, "a");
- if (manifest_fd) {
- lilv_plugin_write_manifest_entry(
- world, p, base, manifest_fd, plugin_file);
- fclose(manifest_fd);
- } else {
- fprintf(stderr, "error: Failed to open %s\n", manifest_file);
- }
- }
- lilv_node_free(base);
- } else if (p) {
- print_plugin(world, p);
- } else {
- fprintf(stderr, "Plugin not found.\n");
- }
-
- ret = (p != NULL ? 0 : -1);
-
- lilv_node_free(uri);
-
- lilv_node_free(supports_event_pred);
- lilv_node_free(designation_pred);
- lilv_node_free(preset_class);
- lilv_node_free(label_pred);
- lilv_node_free(group_pred);
- lilv_node_free(event_class);
- lilv_node_free(control_class);
- lilv_node_free(applies_to_pred);
-
- lilv_world_free(world);
- return ret;
-}
-
diff --git a/utils/lv2ls.c b/utils/lv2ls.c
deleted file mode 100644
index 90ae1eb..0000000
--- a/utils/lv2ls.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- Copyright 2007-2019 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.
-*/
-
-#include "lilv_config.h"
-
-#include "lilv/lilv.h"
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-
-static void
-list_plugins(const LilvPlugins* list, bool show_names)
-{
- LILV_FOREACH(plugins, i, list) {
- const LilvPlugin* p = lilv_plugins_get(list, i);
- if (show_names) {
- LilvNode* n = lilv_plugin_get_name(p);
- printf("%s\n", lilv_node_as_string(n));
- lilv_node_free(n);
- } else {
- printf("%s\n", lilv_node_as_uri(lilv_plugin_get_uri(p)));
- }
- }
-}
-
-static void
-print_version(void)
-{
- printf(
- "lv2ls (lilv) " LILV_VERSION "\n"
- "Copyright 2007-2019 David Robillard <http://drobilla.net>\n"
- "License: <http://www.opensource.org/licenses/isc-license>\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n");
-}
-
-static void
-print_usage(void)
-{
- printf("Usage: lv2ls [OPTION]...\n");
- printf("List all installed LV2 plugins.\n");
- printf("\n");
- printf(" -n, --names Show names instead of URIs\n");
- printf(" --help Display this help and exit\n");
- printf(" --version Display version information and exit\n");
- printf("\n");
- printf("The environment variable LV2_PATH can be used to control where\n");
- printf("this (and all other lilv based LV2 hosts) will search for plugins.\n");
-}
-
-int
-main(int argc, char** argv)
-{
- bool show_names = false;
- for (int i = 1; i < argc; ++i) {
- if (!strcmp(argv[i], "--names") || !strcmp(argv[i], "-n")) {
- show_names = true;
- } else if (!strcmp(argv[i], "--version")) {
- print_version();
- return 0;
- } else if (!strcmp(argv[i], "--help")) {
- print_usage();
- return 0;
- } else {
- print_usage();
- return 1;
- }
- }
-
- LilvWorld* world = lilv_world_new();
- lilv_world_load_all(world);
-
- const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
-
- list_plugins(plugins, show_names);
-
- lilv_world_free(world);
-
- return 0;
-}
diff --git a/utils/uri_table.h b/utils/uri_table.h
deleted file mode 100644
index 3b374bb..0000000
--- a/utils/uri_table.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- Copyright 2011-2019 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.
-*/
-
-/**
- @file uri_table.h A toy URI map/unmap implementation.
-
- This file contains function definitions and must only be included once.
-*/
-
-#ifndef URI_TABLE_H
-#define URI_TABLE_H
-
-#include <stdlib.h>
-#include <string.h>
-
-typedef struct {
- char** uris;
- size_t n_uris;
-} URITable;
-
-static void
-uri_table_init(URITable* table)
-{
- table->uris = NULL;
- table->n_uris = 0;
-}
-
-static void
-uri_table_destroy(URITable* table)
-{
- for (size_t i = 0; i < table->n_uris; ++i) {
- free(table->uris[i]);
- }
-
- free(table->uris);
-}
-
-static LV2_URID
-uri_table_map(LV2_URID_Map_Handle handle,
- const char* uri)
-{
- URITable* table = (URITable*)handle;
- for (size_t i = 0; i < table->n_uris; ++i) {
- if (!strcmp(table->uris[i], uri)) {
- return i + 1;
- }
- }
-
- const size_t len = strlen(uri);
- table->uris = (char**)realloc(table->uris, ++table->n_uris * sizeof(char*));
- table->uris[table->n_uris - 1] = (char*)malloc(len + 1);
- memcpy(table->uris[table->n_uris - 1], uri, len + 1);
- return table->n_uris;
-}
-
-static const char*
-uri_table_unmap(LV2_URID_Map_Handle handle,
- LV2_URID urid)
-{
- URITable* table = (URITable*)handle;
- if (urid > 0 && urid <= table->n_uris) {
- return table->uris[urid - 1];
- }
- return NULL;
-}
-
-#endif /* URI_TABLE_H */
diff --git a/waf b/waf
deleted file mode 100755
index 887215c..0000000
--- a/waf
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-
-# Minimal waf script for projects that include waflib directly
-
-import sys
-import inspect
-import os
-
-try:
- from waflib import Context, Scripting
-except Exception as e:
- sys.stderr.write('error: Failed to import waf (%s)\n' % e)
- if os.path.exists('.git'):
- sys.stderr.write("Are submodules up to date? "
- "Try 'git submodule update --init --recursive'\n")
-
- sys.exit(1)
-
-
-def main():
- script_path = os.path.abspath(inspect.getfile(inspect.getmodule(main)))
- project_path = os.path.dirname(script_path)
- Scripting.waf_entry_point(os.getcwd(), Context.WAFVERSION, project_path)
-
-
-if __name__ == '__main__':
- main()
diff --git a/waflib b/waflib
deleted file mode 160000
-Subproject d19992202543ebb810609c074f754b5ec48c0fd
diff --git a/wscript b/wscript
deleted file mode 100644
index 29c19b0..0000000
--- a/wscript
+++ /dev/null
@@ -1,633 +0,0 @@
-#!/usr/bin/env python
-
-import glob
-import os
-import shutil
-import sys
-
-from waflib import Build, Options, Logs
-from waflib.extras import autowaf
-
-# Library and package version (UNIX style major, minor, micro)
-# major increment <=> incompatible changes
-# minor increment <=> compatible changes (additions)
-# micro increment <=> no interface changes
-LILV_VERSION = '0.24.11'
-LILV_MAJOR_VERSION = '0'
-
-# Mandatory waf variables
-APPNAME = 'lilv' # Package name for waf dist
-VERSION = LILV_VERSION # Package version for waf dist
-top = '.' # Source directory
-out = 'build' # Build directory
-
-# Release variables
-uri = 'http://drobilla.net/sw/lilv'
-dist_pattern = 'http://download.drobilla.net/lilv-%d.%d.%d.tar.bz2'
-post_tags = ['Hacking', 'LAD', 'LV2', 'Lilv']
-
-tests = [
- 'test_bad_port_index',
- 'test_bad_port_symbol',
- 'test_classes',
- 'test_discovery',
- 'test_filesystem',
- 'test_get_symbol',
- 'test_no_author',
- 'test_no_verify',
- 'test_plugin',
- 'test_port',
- 'test_preset',
- 'test_project',
- 'test_project_no_author',
- 'test_prototype',
- 'test_reload_bundle',
- 'test_replace_version',
- 'test_state',
- 'test_string',
- 'test_ui',
- 'test_util',
- 'test_value',
- 'test_verify',
- 'test_world',
-]
-
-test_plugins = [
- 'bad_syntax',
- 'failed_instantiation',
- 'failed_lib_descriptor',
- 'lib_descriptor',
- 'missing_descriptor',
- 'missing_name',
- 'missing_plugin',
- 'missing_port',
- 'missing_port_name',
- 'new_version',
- 'old_version'
-]
-
-
-def options(ctx):
- ctx.load('compiler_c')
- ctx.load('compiler_cxx')
- ctx.load('python')
- opt = ctx.configuration_options()
- ctx.add_flags(
- opt,
- {'no-utils': 'do not build command line utilities',
- 'no-bindings': 'do not build python bindings',
- 'dyn-manifest': 'build support for dynamic manifests',
- 'no-bash-completion': 'do not install bash completion script',
- 'static': 'build static library',
- 'no-shared': 'do not build shared library',
- 'static-progs': 'build programs as static binaries'})
-
- opt.add_option('--default-lv2-path', type='string', default='',
- dest='default_lv2_path',
- help='default LV2 path to use if LV2_PATH is unset')
-
-
-def configure(conf):
- conf.load('compiler_c', cache=True)
- try:
- conf.load('compiler_cxx', cache=True)
- conf.define('LILV_CXX', True)
- except Exception:
- pass
-
- if not Options.options.no_bindings:
- try:
- conf.load('python', cache=True)
- conf.check_python_version((2, 6, 0))
- conf.env.LILV_PYTHON = 1
- except Exception as e:
- Logs.warn('Failed to configure Python (%s)\n' % e)
-
- conf.load('autowaf', cache=True)
- autowaf.set_c_lang(conf, 'c99')
-
- conf.env.BASH_COMPLETION = not Options.options.no_bash_completion
- conf.env.BUILD_UTILS = not Options.options.no_utils
- conf.env.BUILD_SHARED = not Options.options.no_shared
- conf.env.STATIC_PROGS = Options.options.static_progs
- conf.env.BUILD_STATIC = (Options.options.static or
- Options.options.static_progs)
-
- if not conf.env.BUILD_SHARED and not conf.env.BUILD_STATIC:
- conf.fatal('Neither a shared nor a static build requested')
-
- if Options.options.strict:
- # Check for programs used by lint target
- conf.find_program("flake8", var="FLAKE8", mandatory=False)
- conf.find_program("clang-tidy", var="CLANG_TIDY", mandatory=False)
- conf.find_program("iwyu_tool", var="IWYU_TOOL", mandatory=False)
-
- if Options.options.ultra_strict:
- autowaf.add_compiler_flags(conf.env, '*', {
- 'clang': [
- '-Wno-documentation-unknown-command',
- '-Wno-nullability-extension',
- ]
- })
-
- autowaf.add_compiler_flags(conf.env, 'c', {
- 'clang': [
- '-Wno-cast-align',
- '-Wno-cast-qual',
- '-Wno-double-promotion',
- '-Wno-float-equal',
- '-Wno-format-nonliteral',
- '-Wno-implicit-float-conversion',
- '-Wno-implicit-int-conversion',
- '-Wno-padded',
- '-Wno-reserved-id-macro',
- '-Wno-shorten-64-to-32',
- '-Wno-sign-conversion',
- '-Wno-switch-enum',
- '-Wno-unused-parameter',
- '-Wno-vla',
- ],
- 'gcc': [
- '-Wno-cast-align',
- '-Wno-cast-qual',
- '-Wno-conversion',
- '-Wno-double-promotion',
- '-Wno-float-equal',
- '-Wno-padded',
- '-Wno-stack-protector',
- '-Wno-suggest-attribute=const',
- '-Wno-suggest-attribute=pure',
- '-Wno-switch-enum',
- '-Wno-unused-parameter',
- '-Wno-vla',
- ],
- 'msvc': [
- '/wd4061', # enumerator in switch is not explicitly handled
- '/wd4365', # signed/unsigned mismatch
- '/wd4514', # unreferenced inline function has been removed
- '/wd4774', # format string is not a string literal
- '/wd4820', # padding added after construct
- '/wd4996', # POSIX name for this item is deprecated
- ],
- })
-
- autowaf.add_compiler_flags(conf.env, 'cxx', {
- 'clang': [
- '-Wno-extra-semi',
- ],
- 'gcc': [
- '-Wno-effc++',
- '-Wno-extra-semi',
- '-Wno-pedantic',
- ],
- })
-
- conf.check_pkg('lv2 >= 1.18.0', uselib_store='LV2')
- conf.check_pkg('serd-0 >= 0.30.0', uselib_store='SERD')
- conf.check_pkg('sord-0 >= 0.14.0', uselib_store='SORD')
- conf.check_pkg('sratom-0 >= 0.4.0', uselib_store='SRATOM')
- conf.check_pkg('sndfile >= 1.0.0', uselib_store='SNDFILE', mandatory=False)
-
- defines = ['_POSIX_C_SOURCE=200809L', '_BSD_SOURCE', '_DEFAULT_SOURCE']
- if conf.env.DEST_OS == 'darwin':
- defines += ['_DARWIN_C_SOURCE']
-
- rt_lib = ['rt']
- if conf.env.DEST_OS == 'darwin' or conf.env.DEST_OS == 'win32':
- rt_lib = []
-
- conf.check_function('c', 'lstat',
- header_name = ['sys/stat.h'],
- defines = defines,
- define_name = 'HAVE_LSTAT',
- return_type = 'int',
- arg_types = 'const char*, struct stat*',
- mandatory = False)
-
- conf.check_function('c', 'flock',
- header_name = 'sys/file.h',
- defines = defines,
- define_name = 'HAVE_FLOCK',
- return_type = 'int',
- arg_types = 'int, int',
- mandatory = False)
-
- conf.check_function('c', 'fileno',
- header_name = 'stdio.h',
- defines = defines,
- define_name = 'HAVE_FILENO',
- return_type = 'int',
- arg_types = 'FILE*',
- mandatory = False)
-
- conf.check_function('c', 'clock_gettime',
- header_name = ['sys/time.h', 'time.h'],
- defines = ['_POSIX_C_SOURCE=200809L'],
- define_name = 'HAVE_CLOCK_GETTIME',
- uselib_store = 'CLOCK_GETTIME',
- lib = rt_lib,
- return_type = 'int',
- arg_types = 'clockid_t, struct timespec*',
- mandatory = False)
-
- conf.check_cc(define_name = 'HAVE_LIBDL',
- lib = 'dl',
- mandatory = False)
-
- if conf.env.DEST_OS == 'win32':
- conf.check_function('c', 'CreateSymbolicLink',
- header_name = ['windows.h'],
- define_name = 'HAVE_CREATESYMBOLICLINK',
- return_type = 'BOOLEAN',
- arg_types = 'LPCSTR, LPCSTR, DWORD',
- mandatory = False)
-
- if Options.options.dyn_manifest:
- conf.define('LILV_DYN_MANIFEST', 1)
-
- lilv_path_sep = ':'
- lilv_dir_sep = '/'
- if conf.env.DEST_OS == 'win32':
- lilv_path_sep = ';'
- lilv_dir_sep = '\\\\'
-
- conf.define('LILV_PATH_SEP', lilv_path_sep)
- conf.define('LILV_DIR_SEP', lilv_dir_sep)
-
- # Set default LV2 path
- lv2_path = Options.options.default_lv2_path
- if lv2_path == '':
- if conf.env.DEST_OS == 'darwin':
- lv2_path = lilv_path_sep.join(['~/Library/Audio/Plug-Ins/LV2',
- '~/.lv2',
- '/usr/local/lib/lv2',
- '/usr/lib/lv2',
- '/Library/Audio/Plug-Ins/LV2'])
- elif conf.env.DEST_OS == 'haiku':
- lv2_path = lilv_path_sep.join(['~/.lv2',
- '/boot/common/add-ons/lv2'])
- elif conf.env.DEST_OS == 'win32':
- lv2_path = lilv_path_sep.join(['%APPDATA%\\\\LV2',
- '%COMMONPROGRAMFILES%\\\\LV2'])
- else:
- libdirname = os.path.basename(conf.env.LIBDIR)
- lv2_path = lilv_path_sep.join(['~/.lv2',
- '/usr/%s/lv2' % libdirname,
- '/usr/local/%s/lv2' % libdirname])
- conf.define('LILV_DEFAULT_LV2_PATH', lv2_path)
-
- autowaf.set_lib_env(conf, 'lilv', LILV_VERSION)
- conf.write_config_header('lilv_config.h', remove=False)
-
- conf.undefine('LILV_DEFAULT_LV2_PATH') # Cmd line errors with VC++
-
- autowaf.display_summary(
- conf,
- {'Default LV2_PATH': lv2_path,
- 'Utilities': bool(conf.env.BUILD_UTILS),
- 'Unit tests': bool(conf.env.BUILD_TESTS),
- 'Dynamic manifest support': conf.is_defined('LILV_DYN_MANIFEST'),
- 'Python bindings': bool(conf.env.LILV_PYTHON)})
-
-
-def build_util(bld, name, defines, libs=''):
- obj = bld(features = 'c cprogram',
- source = name + '.c',
- includes = ['.', './src', './utils'],
- use = 'liblilv',
- uselib = 'SERD SORD SRATOM LV2 ' + libs,
- target = name,
- defines = defines,
- install_path = '${BINDIR}')
- if not bld.env.BUILD_SHARED or bld.env.STATIC_PROGS:
- obj.use = 'liblilv_static'
- if bld.env.STATIC_PROGS:
- if not bld.env.MSVC_COMPILER:
- obj.lib = ['m']
- obj.env.SHLIB_MARKER = obj.env.STLIB_MARKER
- obj.linkflags = ['-static', '-Wl,--start-group']
- return obj
-
-
-def build(bld):
- # C/C++ Headers
- includedir = '${INCLUDEDIR}/lilv-%s/lilv' % LILV_MAJOR_VERSION
- bld.install_files(includedir, bld.path.ant_glob('lilv/*.h'))
- bld.install_files(includedir, bld.path.ant_glob('lilv/*.hpp'))
-
- lib_source = '''
- src/collections.c
- src/filesystem.c
- src/instance.c
- src/lib.c
- src/node.c
- src/plugin.c
- src/pluginclass.c
- src/port.c
- src/query.c
- src/scalepoint.c
- src/state.c
- src/ui.c
- src/util.c
- src/world.c
- src/zix/tree.c
- '''.split()
-
- lib = []
- libflags = ['-fvisibility=hidden']
- defines = []
- if bld.is_defined('HAVE_LIBDL'):
- lib += ['dl']
- if bld.env.DEST_OS == 'win32':
- lib = []
- if bld.env.MSVC_COMPILER:
- libflags = []
-
- # Pkgconfig file
- autowaf.build_pc(bld, 'LILV', LILV_VERSION, LILV_MAJOR_VERSION, [],
- {'LILV_MAJOR_VERSION': LILV_MAJOR_VERSION,
- 'LILV_PKG_DEPS': 'lv2 serd-0 sord-0 sratom-0',
- 'LILV_PKG_LIBS': ' -l'.join([''] + lib)})
-
- # Shared Library
- if bld.env.BUILD_SHARED:
- obj = bld(features = 'c cshlib',
- export_includes = ['.'],
- source = lib_source,
- includes = ['.', './src'],
- name = 'liblilv',
- target = 'lilv-%s' % LILV_MAJOR_VERSION,
- vnum = LILV_VERSION,
- install_path = '${LIBDIR}',
- defines = ['LILV_SHARED', 'LILV_INTERNAL'],
- cflags = libflags,
- lib = lib,
- uselib = 'SERD SORD SRATOM LV2')
-
- # Static library
- if bld.env.BUILD_STATIC:
- obj = bld(features = 'c cstlib',
- export_includes = ['.'],
- source = lib_source,
- includes = ['.', './src'],
- name = 'liblilv_static',
- target = 'lilv-%s' % LILV_MAJOR_VERSION,
- vnum = LILV_VERSION,
- install_path = '${LIBDIR}',
- defines = defines + ['LILV_INTERNAL'],
- uselib = 'SERD SORD SRATOM LV2')
-
- # Python bindings
- if bld.env.LILV_PYTHON:
- bld(features = 'subst',
- is_copy = True,
- source = 'bindings/python/lilv.py',
- target = 'lilv.py',
- install_path = '${PYTHONDIR}')
-
- if bld.env.BUILD_TESTS:
- import re
-
- test_libs = lib
- test_cflags = ['']
- test_linkflags = ['']
- if not bld.env.NO_COVERAGE:
- test_cflags += ['--coverage']
- test_linkflags += ['--coverage']
-
- # Copy skeleton LV2 bundle for tests
- for name in ('manifest.ttl', 'lv2core.ttl'):
- bld(features = 'subst',
- is_copy = True,
- source = 'test/core.lv2/' + name,
- target = 'test/test_lv2_path/core.lv2/' + name,
- install_path = None)
-
- # Make a pattern for shared objects without the 'lib' prefix
- module_pattern = re.sub('^lib', '', bld.env.cshlib_PATTERN)
- shlib_ext = module_pattern[module_pattern.rfind('.'):]
-
- for p in ['test'] + test_plugins:
- obj = bld(features = 'c cshlib',
- source = 'test/%s.lv2/%s.c' % (p, p),
- name = p,
- target = 'test/%s.lv2/%s' % (p, p),
- install_path = None,
- defines = defines,
- cflags = test_cflags,
- linkflags = test_linkflags,
- lib = test_libs,
- uselib = 'LV2')
- obj.env.cshlib_PATTERN = module_pattern
-
- for p in test_plugins:
- if not bld.path.find_node('test/%s.lv2/test_%s.c' % (p, p)):
- continue
-
- obj = bld(features = 'c cprogram',
- source = 'test/%s.lv2/test_%s.c' % (p, p),
- target = 'test/test_%s' % p,
- includes = ['.', './src'],
- use = 'liblilv_profiled',
- install_path = None,
- defines = defines,
- cflags = test_cflags,
- linkflags = test_linkflags,
- lib = test_libs,
- uselib = 'SERD SORD SRATOM LV2')
-
- # Test plugin data files
- for p in ['test'] + test_plugins:
- for i in ['manifest.ttl.in', p + '.ttl.in']:
- bundle = 'test/%s.lv2/' % p
- bld(features = 'subst',
- source = bundle + i,
- target = bundle + i.replace('.in', ''),
- install_path = None,
- SHLIB_EXT = shlib_ext)
-
- # Static profiled library (for unit test code coverage)
- obj = bld(features = 'c cstlib',
- source = lib_source,
- includes = ['.', './src'],
- name = 'liblilv_profiled',
- target = 'lilv_profiled',
- install_path = None,
- defines = defines + ['LILV_INTERNAL'],
- cflags = test_cflags,
- linkflags = test_linkflags,
- lib = test_libs,
- uselib = 'SERD SORD SRATOM LV2')
-
- # Unit test program
- testdir = bld.path.get_bld().make_node('test').abspath()
- bpath = os.path.join(testdir, 'test.lv2')
- bpath = bpath.replace('\\', '/')
- testdir = testdir.replace('\\', '/')
- for test in tests:
- obj = bld(features = 'c cprogram',
- source = ['test/%s.c' % test,
- 'test/lilv_test_utils.c'],
- includes = ['.', './src'],
- use = 'liblilv_profiled',
- lib = test_libs,
- uselib = 'SERD SORD SRATOM LV2',
- target = 'test/' + test,
- install_path = None,
- defines = (defines +
- ['LILV_TEST_BUNDLE=\"%s/\"' % bpath] +
- ['LILV_TEST_DIR=\"%s/\"' % testdir]),
- cflags = test_cflags,
- linkflags = test_linkflags)
-
- # C++ API test
- if 'COMPILER_CXX' in bld.env:
- obj = bld(features = 'cxx cxxprogram',
- source = 'test/lilv_cxx_test.cpp',
- includes = ['.', './src'],
- use = 'liblilv_profiled',
- lib = test_libs,
- uselib = 'SERD SORD SRATOM LV2',
- target = 'test/lilv_cxx_test',
- install_path = None,
- cxxflags = test_cflags,
- linkflags = test_linkflags)
-
- if bld.env.LILV_PYTHON:
- test_bundle = 'bindings/bindings_test_plugin.lv2/'
-
- # Copy Python unittest files
- for i in ['test_api.py']:
- bld(features = 'subst',
- is_copy = True,
- source = 'bindings/test/python/' + i,
- target = 'bindings/' + i,
- install_path = None)
-
- # Build bindings test plugin
- obj = bld(features = 'c cshlib',
- source = 'bindings/test/bindings_test_plugin.c',
- name = 'bindings_test_plugin',
- target = test_bundle + '/bindings_test_plugin',
- install_path = None,
- defines = defines,
- cflags = test_cflags,
- linkflags = test_linkflags,
- lib = test_libs,
- uselib = 'LV2')
- obj.env.cshlib_PATTERN = module_pattern
-
- # Bindings test plugin data files
- for i in ['manifest.ttl.in', 'bindings_test_plugin.ttl.in']:
- bld(features = 'subst',
- source = 'bindings/test/' + i,
- target = test_bundle + i.replace('.in', ''),
- install_path = None,
- SHLIB_EXT = shlib_ext)
-
- # Utilities
- if bld.env.BUILD_UTILS:
- utils = '''
- utils/lilv-bench
- utils/lv2info
- utils/lv2ls
- '''
- for i in utils.split():
- build_util(bld, i, defines)
-
- if bld.env.HAVE_SNDFILE:
- obj = build_util(bld, 'utils/lv2apply', defines, 'SNDFILE')
-
- # lv2bench (less portable than other utilities)
- if (bld.env.DEST_OS != 'win32' and
- bld.is_defined('HAVE_CLOCK_GETTIME') and
- not bld.env.STATIC_PROGS):
- obj = build_util(bld, 'utils/lv2bench', defines)
- if bld.env.DEST_OS != 'darwin':
- obj.lib = ['rt']
-
- # Documentation
- autowaf.build_dox(bld, 'LILV', LILV_VERSION, top, out)
-
- # Man pages
- bld.install_files('${MANDIR}/man1', bld.path.ant_glob('doc/*.1'))
-
- # Bash completion
- if bld.env.BASH_COMPLETION:
- bld.install_as('${SYSCONFDIR}/bash_completion.d/lilv',
- 'utils/lilv.bash_completion')
-
- bld.add_post_fun(autowaf.run_ldconfig)
-
-
-def test(tst):
- with tst.group('unit') as check:
- for test in tests:
- if not (sys.platform == 'win32' and test == 'test_state'):
- check(['./test/' + test])
-
- if tst.is_defined('LILV_CXX'):
- check(['./test/lilv_cxx_test'])
-
- if tst.env.LILV_PYTHON:
- with tst.group('python') as check:
- check(['python', '-m', 'unittest', 'discover', 'bindings/'])
-
- with tst.group('plugin') as check:
- for p in test_plugins:
- prog_name = tst.env.cprogram_PATTERN % ('test_' + p)
- if os.path.exists(os.path.join('test', prog_name)):
- check(['./test/test_' + p, 'test/%s.lv2/' % p])
-
- try:
- shutil.rmtree('state')
- except Exception:
- pass
-
-
-class LintContext(Build.BuildContext):
- fun = cmd = 'lint'
-
-
-def lint(ctx):
- "checks code for style issues"
- import subprocess
-
- st = 0
-
- if "FLAKE8" in ctx.env:
- Logs.info("Running flake8")
- st = subprocess.call([ctx.env.FLAKE8[0],
- "wscript",
- "--ignore",
- "E101,E129,W191,E221,W504,E251,E241,E741"])
- else:
- Logs.warn("Not running flake8")
-
- if "IWYU_TOOL" in ctx.env:
- Logs.info("Running include-what-you-use")
- cmd = [ctx.env.IWYU_TOOL[0], "-o", "clang", "-p", "build"]
- output = subprocess.check_output(cmd).decode('utf-8')
- if 'error: ' in output:
- sys.stdout.write(output)
- st += 1
- else:
- Logs.warn("Not running include-what-you-use")
-
- if "CLANG_TIDY" in ctx.env and "clang" in ctx.env.CC[0]:
- Logs.info("Running clang-tidy")
- sources = glob.glob('src/*.c') + glob.glob('tests/*.c')
- sources = list(map(os.path.abspath, sources))
- procs = []
- for source in sources:
- cmd = [ctx.env.CLANG_TIDY[0], "--quiet", "-p=.", source]
- procs += [subprocess.Popen(cmd, cwd="build")]
-
- for proc in procs:
- stdout, stderr = proc.communicate()
- st += proc.returncode
- else:
- Logs.warn("Not running clang-tidy")
-
- if st != 0:
- sys.exit(st)