| @@ -1,3 +1,26 @@ | |||
| lilv (0.21.3) unstable; | |||
| * Fix loading files with spaces in their path | |||
| * Add lilv_file_uri_parse() for correct URI to path conversion | |||
| * Add lilv_node_get_path() for convenient file URI path access | |||
| * Add lilv_state_emit_port_values() for special port value handling | |||
| * Add lilv_state_get_uri() | |||
| * Add lilv_state_delete() for deleting user saved presets | |||
| * Fix lilv_world_ask() to work with wildcards | |||
| * Fix creation of duplicate manifest entries when saving state | |||
| * Fix bindings for Python 3 | |||
| * Load discovered owl ontologies as specifications | |||
| * Expose lilv_world_load_specifications() and | |||
| lilv_world_load_plugin_classes() | |||
| * Tolerate passing NULL to lilv_state_restore() | |||
| * Preserve absolute paths in state if no link directory is given | |||
| * Fix a few minor/unlikely memory errors | |||
| * Configure based on compiler target OS for cross-compilation | |||
| * Windows fixes (thanks John Emmas) | |||
| * Minor documentation improvements | |||
| -- David Robillard <d@drobilla.net> Mon, 16 Mar 2015 03:24:05 -0400 | |||
| lilv (0.20.0) stable; | |||
| * Don't load files multiple times if they are listed as rdfs:seeAlso for | |||
| @@ -32,13 +32,13 @@ namespace Lilv { | |||
| def __init__(self, plugins): | |||
| self.plugins = plugins | |||
| self.iter = plugins.begin() | |||
| def next(self): | |||
| self.iter = self.plugins.next(self.iter) | |||
| if not self.plugins.is_end(self.iter): | |||
| return self.plugins.get(self.iter) | |||
| else: | |||
| def __next__(self): | |||
| if self.plugins.is_end(self.iter): | |||
| raise StopIteration | |||
| plugin = self.plugins.get(self.iter) | |||
| self.iter = self.plugins.next(self.iter) | |||
| return plugin | |||
| return Iterator(self) | |||
| @@ -107,9 +107,11 @@ | |||
| if (PyDict_Check( py_obj)) return "dict" ; | |||
| if (PyList_Check( py_obj)) return "list" ; | |||
| if (PyTuple_Check( py_obj)) return "tuple" ; | |||
| if (PyFile_Check( py_obj)) return "file" ; | |||
| if (PyModule_Check( py_obj)) return "module" ; | |||
| %#if PY_MAJOR_VERSION < 3 | |||
| if (PyFile_Check( py_obj)) return "file" ; | |||
| if (PyInstance_Check(py_obj)) return "instance" ; | |||
| %#endif | |||
| return "unkown type"; | |||
| } | |||
| @@ -7,5 +7,5 @@ Name: Lilv | |||
| Version: @LILV_VERSION@ | |||
| Description: Simple C library for hosting LV2 plugins | |||
| Requires: lv2 @PKG_serd_0@ @PKG_sord_0@ @PKG_sratom_0@ | |||
| Libs: -L${libdir} -l@LIB_LILV@ -ldl | |||
| Libs: -L${libdir} -l@LIB_LILV@ @LILV_PKG_LIBS@ -lsratom-0 -lsord-0 -lserd-0 -lm -ldl | |||
| Cflags: -I${includedir}/lilv-@LILV_MAJOR_VERSION@ | |||
| @@ -26,9 +26,8 @@ | |||
| #include <stdint.h> | |||
| #include <stdio.h> | |||
| #include "lv2/lv2.h" | |||
| #include "lv2/state.h" | |||
| #include "lv2/urid.h" | |||
| #include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
| #include "lv2/lv2plug.in/ns/ext/urid/urid.h" | |||
| #ifdef LILV_SHARED | |||
| # ifdef _WIN32 | |||
| @@ -46,6 +45,11 @@ | |||
| #else | |||
| # define LILV_API | |||
| #endif | |||
| #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) | |||
| # define LILV_DEPRECATED __attribute__((__deprecated__)) | |||
| #else | |||
| # define LILV_DEPRECATED | |||
| #endif | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| @@ -105,11 +109,24 @@ typedef void LilvNodes; /**< set<Node>. */ | |||
| 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 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. | |||
| @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_file_uri_parse(const char* uri, char** hostname); | |||
| /** | |||
| Create a new URI value. | |||
| Returned value must be freed by caller with lilv_node_free(). | |||
| @@ -241,6 +258,14 @@ lilv_node_is_string(const LilvNode* value); | |||
| 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. | |||
| */ | |||
| LILV_API char* | |||
| lilv_node_get_path(const LilvNode* value, char** hostname); | |||
| /** | |||
| Return whether this value is a decimal literal. | |||
| */ | |||
| @@ -527,14 +552,14 @@ lilv_world_free(LilvWorld* world); | |||
| with special plugin bundles which are installed to a known location). | |||
| */ | |||
| LILV_API void | |||
| lilv_world_load_all(LilvWorld* world, const char* lv2_path); | |||
| 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). | |||
| 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 | |||
| @@ -545,6 +570,26 @@ LILV_API void | |||
| lilv_world_load_bundle(LilvWorld* world, | |||
| LilvNode* bundle_uri); | |||
| /** | |||
| Load all specifications from currently loaded bundles. | |||
| This is for hosts that explicitly load specific bundles, its use is not | |||
| necessary when using lilv_world_load_all(). This function parses the | |||
| specifications and adds them to the model. | |||
| */ | |||
| LILV_API void | |||
| lilv_world_load_specifications(LilvWorld* world); | |||
| /** | |||
| Load all plugin classes from currently loaded specifications. | |||
| Must be called after lilv_world_load_specifications(). This is for hosts | |||
| that explicitly load specific bundles, its use is not necessary when using | |||
| lilv_world_load_all(). | |||
| */ | |||
| LILV_API void | |||
| lilv_world_load_plugin_classes(LilvWorld* world); | |||
| /** | |||
| Unload a specific bundle. | |||
| @@ -688,13 +733,14 @@ 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 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 | |||
| bundle. | |||
| Typical hosts should not need to use this function. | |||
| Note this always returns a fully qualified URI. If you want a local | |||
| filesystem path, use lilv_uri_to_path. | |||
| filesystem path, use lilv_uri_to_path(). | |||
| @return a shared string which must not be modified or freed. | |||
| */ | |||
| LILV_API const LilvNode* | |||
| @@ -704,7 +750,7 @@ lilv_plugin_get_bundle_uri(const LilvPlugin* plugin); | |||
| Get the (resolvable) URIs of the RDF data files that define a plugin. | |||
| Typical hosts should not need to use this function. | |||
| Note this always returns fully qualified URIs. If you want local | |||
| filesystem paths, use lilv_uri_to_path. | |||
| filesystem paths, use lilv_uri_to_path(). | |||
| @return a list of complete URLs eg. "file:///foo/ABundle.lv2/aplug.ttl", | |||
| which is shared and must not be modified or freed. | |||
| */ | |||
| @@ -714,7 +760,7 @@ lilv_plugin_get_data_uris(const LilvPlugin* plugin); | |||
| /** | |||
| Get the (resolvable) URI of the shared library for `plugin`. | |||
| Note this always returns a fully qualified URI. If you want a local | |||
| filesystem path, use lilv_uri_to_path. | |||
| filesystem path, use lilv_uri_to_path(). | |||
| @return a shared string which must not be modified or freed. | |||
| */ | |||
| LILV_API const LilvNode* | |||
| @@ -766,8 +812,8 @@ lilv_plugin_has_feature(const LilvPlugin* p, | |||
| 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(). | |||
| */ | |||
| @@ -832,7 +878,7 @@ lilv_plugin_get_num_ports(const LilvPlugin* p); | |||
| This is a convenience method for the common case of getting the range of | |||
| all float ports on a plugin, and may be significantly faster than | |||
| repeated calls to lilv_port_get_range. | |||
| repeated calls to lilv_port_get_range(). | |||
| */ | |||
| LILV_API void | |||
| lilv_plugin_get_port_ranges_float(const LilvPlugin* p, | |||
| @@ -873,7 +919,7 @@ lilv_plugin_has_latency(const LilvPlugin* p); | |||
| /** | |||
| 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. | |||
| exists by first calling lilv_plugin_has_latency(). | |||
| Any plugin that introduces unwanted latency that should be compensated for | |||
| (by hosts with the ability/need) MUST provide this port, which is a control | |||
| @@ -891,7 +937,7 @@ lilv_plugin_get_port_by_index(const LilvPlugin* plugin, | |||
| /** | |||
| Get a port on `plugin` by `symbol`. | |||
| Note this function is slower than lilv_plugin_get_port_by_index, | |||
| 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* | |||
| @@ -991,7 +1037,7 @@ lilv_plugin_write_manifest_entry(LilvWorld* world, | |||
| If `type` is NULL, all such resources will be returned, regardless of type. | |||
| To actually load the data for each returned resource, use | |||
| lilv_world_load_resource. | |||
| lilv_world_load_resource(). | |||
| */ | |||
| LILV_API LilvNodes* | |||
| lilv_plugin_get_related(const LilvPlugin* plugin, const LilvNode* type); | |||
| @@ -1014,7 +1060,7 @@ lilv_port_get_node(const LilvPlugin* plugin, | |||
| const LilvPort* port); | |||
| /** | |||
| Port analog of lilv_plugin_get_value. | |||
| Port analog of lilv_plugin_get_value(). | |||
| */ | |||
| LILV_API LilvNodes* | |||
| lilv_port_get_value(const LilvPlugin* plugin, | |||
| @@ -1090,7 +1136,7 @@ lilv_port_get_name(const LilvPlugin* plugin, | |||
| /** | |||
| 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. | |||
| 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. | |||
| */ | |||
| @@ -1116,8 +1162,8 @@ lilv_port_is_a(const LilvPlugin* plugin, | |||
| `def`, `min`, and `max` are outputs, pass pointers to uninitialized | |||
| LilvNode* variables. These will be set to point at new values (which must | |||
| be freed by the caller using lilv_node_free), or NULL if the value does not | |||
| exist. | |||
| be freed by the caller using lilv_node_free()), or NULL if the value does | |||
| not exist. | |||
| */ | |||
| LILV_API void | |||
| lilv_port_get_range(const LilvPlugin* plugin, | |||
| @@ -1153,9 +1199,9 @@ lilv_port_get_scale_points(const LilvPlugin* plugin, | |||
| @return A new LilvState which must be freed with lilv_state_free(), or NULL. | |||
| */ | |||
| LILV_API LilvState* | |||
| lilv_state_new_from_world(LilvWorld* world, | |||
| const LV2_URID_Map* map, | |||
| const LilvNode* subject); | |||
| lilv_state_new_from_world(LilvWorld* world, | |||
| LV2_URID_Map* map, | |||
| const LilvNode* subject); | |||
| /** | |||
| Load a state snapshot from a file. | |||
| @@ -1173,18 +1219,18 @@ lilv_state_new_from_world(LilvWorld* world, | |||
| new memory consumed once this function returns. | |||
| */ | |||
| LILV_API LilvState* | |||
| lilv_state_new_from_file(LilvWorld* world, | |||
| const LV2_URID_Map* map, | |||
| const LilvNode* subject, | |||
| const char* path); | |||
| lilv_state_new_from_file(LilvWorld* world, | |||
| LV2_URID_Map* map, | |||
| const LilvNode* subject, | |||
| const char* path); | |||
| /** | |||
| Load a state snapshot from a string made by lilv_state_to_string(). | |||
| */ | |||
| LILV_API LilvState* | |||
| lilv_state_new_from_string(LilvWorld* world, | |||
| const LV2_URID_Map* map, | |||
| const char* str); | |||
| lilv_state_new_from_string(LilvWorld* world, | |||
| LV2_URID_Map* map, | |||
| const char* str); | |||
| /** | |||
| Function to get a port value. | |||
| @@ -1223,9 +1269,11 @@ typedef const void* (*LilvGetPortValueFunc)(const char* port_symbol, | |||
| @param save_dir Directory of files created by plugin during save (or NULL). | |||
| If the state will be saved, this should be the bundle directory later passed | |||
| to lilv_state_save. | |||
| to lilv_state_save(). | |||
| @param get_value Function to get port values. | |||
| @param get_value Function to get port values (or NULL). If NULL, the | |||
| returned state will not represent port values. This should only be NULL in | |||
| hosts that save and restore port values via some other mechanism. | |||
| @param user_data User data to pass to `get_value`. | |||
| @@ -1301,6 +1349,14 @@ lilv_state_get_num_properties(const LilvState* state); | |||
| LILV_API const LilvNode* | |||
| lilv_state_get_plugin_uri(const LilvState* state); | |||
| /** | |||
| Get the URI of `state`. | |||
| This may return NULL if the state has not been saved and has no URI. | |||
| */ | |||
| LILV_API const LilvNode* | |||
| lilv_state_get_uri(const LilvState* state); | |||
| /** | |||
| Get the label of `state`. | |||
| */ | |||
| @@ -1328,6 +1384,22 @@ typedef void (*LilvSetPortValueFunc)(const char* port_symbol, | |||
| uint32_t size, | |||
| uint32_t type); | |||
| /** | |||
| 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. | |||
| */ | |||
| 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. | |||
| @@ -1338,10 +1410,10 @@ typedef void (*LilvSetPortValueFunc)(const char* port_symbol, | |||
| @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 given `user_data`) to restore each port value, otherwise the host must | |||
| restore the port values itself (using lilv_state_get_port_value) in order to | |||
| completely restore `state`. | |||
| stored in `state`. If `set_value` is provided, it will be called (with the | |||
| given `user_data`) to restore each port value, otherwise the host must | |||
| restore the port values itself (using lilv_state_get_port_value()) in order | |||
| 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 | |||
| @@ -1353,8 +1425,7 @@ typedef void (*LilvSetPortValueFunc)(const char* port_symbol, | |||
| */ | |||
| LILV_API void | |||
| lilv_state_restore(const LilvState* state, | |||
| const LV2_State_Interface* iface, | |||
| LV2_Handle handle, | |||
| LilvInstance* instance, | |||
| LilvSetPortValueFunc set_value, | |||
| void* user_data, | |||
| uint32_t flags, | |||
| @@ -1406,6 +1477,24 @@ lilv_state_to_string(LilvWorld* world, | |||
| const char* uri, | |||
| const char* base_uri); | |||
| /** | |||
| 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 | |||
| permission to delete, including presets shipped with plugins. | |||
| The rdfs:seeAlso file for the state will be removed. The entry in the | |||
| 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. | |||
| */ | |||
| LILV_API int | |||
| lilv_state_delete(LilvWorld* world, | |||
| const LilvState* state); | |||
| /** | |||
| @} | |||
| @name Scale Point | |||
| @@ -1473,7 +1562,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). | |||
| functions like lilv_instance_run() (simple wrappers of functions in lv2.h). | |||
| This is for performance reasons, user code should not use this definition | |||
| in any way (which is why it is not machine documented). | |||
| Truly private implementation details are hidden via `pimpl`. | |||
| @@ -1539,8 +1628,8 @@ lilv_instance_connect_port(LilvInstance* instance, | |||
| /** | |||
| 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. | |||
| locations (as set by lilv_instance_connect_port()). This MUST be called | |||
| before calling lilv_instance_run(). | |||
| */ | |||
| static inline void | |||
| lilv_instance_activate(LilvInstance* instance) | |||
| @@ -1642,8 +1731,8 @@ lilv_ui_get_uri(const LilvUI* 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 finds the | |||
| UI type, avoding the need to use this function (and type specific logic). | |||
| Note that in most cases lilv_ui_is_supported() should be used, which avoids | |||
| the need to use this function (and type specific logic). | |||
| */ | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_classes(const LilvUI* ui); | |||
| @@ -1696,42 +1785,6 @@ lilv_ui_get_bundle_uri(const LilvUI* ui); | |||
| LILV_API const LilvNode* | |||
| lilv_ui_get_binary_uri(const LilvUI* ui); | |||
| /** | |||
| Custom calls | |||
| */ | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_resources_directory(const LilvPlugin* plugin); | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_stylesheet(const LilvPlugin* plugin); | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_icon_template(const LilvPlugin* plugin); | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_settings_template(const LilvPlugin* plugin); | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_template_data(const LilvPlugin* plugin); | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_screenshot(const LilvPlugin* plugin); | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_thumbnail(const LilvPlugin* plugin); | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_supported_features(const LilvUI* ui); | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_required_features(const LilvUI* ui); | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_optional_features(const LilvUI* ui); | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_extension_data(const LilvUI* ui); | |||
| /** | |||
| @} | |||
| @} | |||
| @@ -17,8 +17,6 @@ | |||
| #ifndef LILV_LILVMM_HPP | |||
| #define LILV_LILVMM_HPP | |||
| #include "CarlaDefines.h" | |||
| #include "lilv/lilv.h" | |||
| #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) | |||
| @@ -37,9 +35,6 @@ uri_to_path(const char* uri) { | |||
| #define LILV_WRAP0(RT, prefix, name) \ | |||
| inline RT name() { return lilv_ ## prefix ## _ ## name (me); } | |||
| #define LILV_WRAP0_CONST(RT, prefix, name) \ | |||
| inline RT name() const { return lilv_ ## prefix ## _ ## name (me); } | |||
| #define LILV_WRAP0_VOID(prefix, name) \ | |||
| inline void name() { lilv_ ## prefix ## _ ## name(me); } | |||
| @@ -70,7 +65,6 @@ uri_to_path(const char* uri) { | |||
| #endif | |||
| struct Node { | |||
| inline Node(LilvNode* node) : me(node) {} | |||
| inline Node(const LilvNode* node) : me(lilv_node_duplicate(node)) {} | |||
| inline Node(const Node& copy) : me(lilv_node_duplicate(copy.me)) {} | |||
| @@ -84,26 +78,20 @@ struct Node { | |||
| LILV_WRAP_CONVERSION(LilvNode); | |||
| LILV_WRAP0_CONST(char*, node, get_turtle_token); | |||
| LILV_WRAP0_CONST(bool, node, is_uri); | |||
| LILV_WRAP0_CONST(const char*, node, as_uri); | |||
| LILV_WRAP0_CONST(bool, node, is_blank); | |||
| LILV_WRAP0_CONST(const char*, node, as_blank); | |||
| LILV_WRAP0_CONST(bool, node, is_literal); | |||
| LILV_WRAP0_CONST(bool, node, is_string); | |||
| LILV_WRAP0_CONST(const char*, node, as_string); | |||
| LILV_WRAP0_CONST(bool, node, is_float); | |||
| LILV_WRAP0_CONST(float, node, as_float); | |||
| LILV_WRAP0_CONST(bool, node, is_int); | |||
| LILV_WRAP0_CONST(int, node, as_int); | |||
| LILV_WRAP0_CONST(bool, node, is_bool); | |||
| LILV_WRAP0_CONST(bool, node, as_bool); | |||
| Node& operator=(const Node& copy) { | |||
| lilv_node_free(me); | |||
| me = lilv_node_duplicate(copy.me); | |||
| return *this; | |||
| } | |||
| 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; | |||
| }; | |||
| @@ -138,7 +126,7 @@ struct PluginClass { | |||
| LILV_WRAP0(LilvIter*, prefix, begin); \ | |||
| LILV_WRAP1(LilvIter*, prefix, next, LilvIter*, i); \ | |||
| LILV_WRAP1(bool, prefix, is_end, LilvIter*, i); \ | |||
| const Lilv ## CT* me | |||
| const Lilv ## CT* me; \ | |||
| struct PluginClasses { | |||
| LILV_WRAP_COLL(PluginClasses, PluginClass, plugin_classes); | |||
| @@ -153,24 +141,22 @@ struct ScalePoints { | |||
| struct Nodes { | |||
| LILV_WRAP_COLL(Nodes, Node, nodes); | |||
| LILV_WRAP1(bool, nodes, contains, const Node, node); | |||
| inline Node get_first() const { | |||
| return Node((const LilvNode*)lilv_nodes_get_first(me)); | |||
| } | |||
| LILV_WRAP0(Node, nodes, get_first); | |||
| }; | |||
| struct UI { | |||
| inline UI(const LilvUI* c_obj) : me(c_obj) {} | |||
| LILV_WRAP_CONVERSION(const LilvUI); | |||
| LILV_WRAP0(Node, ui, get_uri); | |||
| LILV_WRAP1(bool, ui, is_a, LilvNode*, ui_class); | |||
| LILV_WRAP0(Node, ui, get_bundle_uri); | |||
| LILV_WRAP0(Node, ui, get_binary_uri); | |||
| LILV_WRAP0(Nodes, ui, get_supported_features); | |||
| LILV_WRAP0(Nodes, ui, get_required_features); | |||
| LILV_WRAP0(Nodes, ui, get_optional_features); | |||
| LILV_WRAP0(Nodes, ui, get_extension_data); | |||
| 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; | |||
| }; | |||
| @@ -234,13 +220,6 @@ struct Plugin { | |||
| LILV_WRAP0(Nodes, plugin, get_extension_data); | |||
| LILV_WRAP0(UIs, plugin, get_uis); | |||
| LILV_WRAP1(Nodes, plugin, get_related, Node, type); | |||
| LILV_WRAP0(Node, plugin, get_modgui_resources_directory); | |||
| LILV_WRAP0(Node, plugin, get_modgui_stylesheet); | |||
| LILV_WRAP0(Node, plugin, get_modgui_icon_template); | |||
| LILV_WRAP0(Node, plugin, get_modgui_settings_template); | |||
| LILV_WRAP0(Node, plugin, get_modgui_template_data); | |||
| LILV_WRAP0(Node, plugin, get_modgui_screenshot); | |||
| LILV_WRAP0(Node, plugin, get_modgui_thumbnail); | |||
| inline Port get_port_by_index(unsigned index) { | |||
| return Port(me, lilv_plugin_get_port_by_index(me, index)); | |||
| @@ -279,14 +258,16 @@ struct Plugins { | |||
| struct Instance { | |||
| inline Instance(LilvInstance* instance) : me(instance) {} | |||
| LILV_DEPRECATED | |||
| inline Instance(Plugin plugin, double sample_rate) | |||
| : me(lilv_plugin_instantiate(plugin, sample_rate, NULL)) {} | |||
| LILV_DEPRECATED | |||
| inline Instance(Plugin plugin, double sample_rate) { | |||
| me = lilv_plugin_instantiate(plugin, sample_rate, NULL); | |||
| } | |||
| LILV_DEPRECATED inline Instance(Plugin plugin, | |||
| double sample_rate, | |||
| LV2_Feature* const* features) | |||
| : me(lilv_plugin_instantiate(plugin, sample_rate, features)) {} | |||
| 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, | |||
| @@ -323,25 +304,22 @@ struct Instance { | |||
| }; | |||
| struct World { | |||
| inline World() : me(lilv_world_new()) {} | |||
| inline virtual ~World() { lilv_world_free(me); } | |||
| inline World() : me(lilv_world_new()) {} | |||
| inline ~World() { lilv_world_free(me); } | |||
| inline LilvNode* new_uri(const char* uri) const { | |||
| inline LilvNode* new_uri(const char* uri) { | |||
| return lilv_new_uri(me, uri); | |||
| } | |||
| inline LilvNode* new_file_uri(const char* host, const char* path) const { | |||
| return lilv_new_file_uri(me, host, path); | |||
| } | |||
| inline LilvNode* new_string(const char* str) const { | |||
| inline LilvNode* new_string(const char* str) { | |||
| return lilv_new_string(me, str); | |||
| } | |||
| inline LilvNode* new_int(int val) const { | |||
| inline LilvNode* new_int(int val) { | |||
| return lilv_new_int(me, val); | |||
| } | |||
| inline LilvNode* new_float(float val) const { | |||
| inline LilvNode* new_float(float val) { | |||
| return lilv_new_float(me, val); | |||
| } | |||
| inline LilvNode* new_bool(bool val) const { | |||
| inline LilvNode* new_bool(bool val) { | |||
| return lilv_new_bool(me, val); | |||
| } | |||
| inline Nodes find_nodes(const LilvNode* subject, | |||
| @@ -351,7 +329,7 @@ struct World { | |||
| } | |||
| LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value); | |||
| LILV_WRAP1_VOID(world, load_all, const char*, lv2_path); | |||
| 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); | |||
| @@ -359,8 +337,6 @@ struct World { | |||
| LILV_WRAP1(int, world, load_resource, const LilvNode*, resource); | |||
| LilvWorld* me; | |||
| CARLA_DECLARE_NON_COPY_STRUCT(World) | |||
| }; | |||
| } /* namespace Lilv */ | |||
| @@ -33,11 +33,12 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
| const LilvNode* const lib_uri = lilv_plugin_get_library_uri(plugin); | |||
| const LilvNode* const bundle_uri = lilv_plugin_get_bundle_uri(plugin); | |||
| const char* bundle_path = lilv_uri_to_path( | |||
| lilv_node_as_uri(lilv_plugin_get_bundle_uri(plugin))); | |||
| char* const bundle_path = lilv_file_uri_parse( | |||
| lilv_node_as_uri(lilv_plugin_get_bundle_uri(plugin)), NULL); | |||
| LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features); | |||
| if (!lib) { | |||
| free(bundle_path); | |||
| return NULL; | |||
| } | |||
| @@ -46,12 +47,13 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
| SerdURI base_uri; | |||
| if (serd_uri_parse((const uint8_t*)bundle_uri_str, &base_uri)) { | |||
| lilv_lib_close(lib); | |||
| 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 = (const LV2_Feature**)malloc(sizeof(LV2_Feature*)); | |||
| local_features[0] = NULL; | |||
| } | |||
| @@ -93,6 +95,7 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, | |||
| } | |||
| free(local_features); | |||
| free(bundle_path); | |||
| if (result) { | |||
| // Failed to instantiate | |||
| @@ -121,4 +124,3 @@ lilv_instance_free(LilvInstance* instance) | |||
| instance->pimpl = NULL; | |||
| free(instance); | |||
| } | |||
| @@ -33,7 +33,7 @@ lilv_lib_open(LilvWorld* world, | |||
| } | |||
| const char* const lib_uri = lilv_node_as_uri(uri); | |||
| const char* const lib_path = lilv_uri_to_path(lib_uri); | |||
| char* const lib_path = lilv_file_uri_parse(lib_uri, NULL); | |||
| if (!lib_path) { | |||
| return NULL; | |||
| } | |||
| @@ -42,13 +42,13 @@ lilv_lib_open(LilvWorld* world, | |||
| void* lib = dlopen(lib_path, RTLD_NOW); | |||
| if (!lib) { | |||
| LILV_ERRORF("Failed to open library %s (%s)\n", lib_path, dlerror()); | |||
| free(lib_path); | |||
| return NULL; | |||
| } | |||
| LV2_Descriptor_Function df = (LV2_Descriptor_Function) | |||
| lilv_dlfunc(lib, "lv2_descriptor"); | |||
| #ifdef LILV_NEW_LV2 | |||
| LV2_Lib_Descriptor_Function ldf = (LV2_Lib_Descriptor_Function) | |||
| lilv_dlfunc(lib, "lv2_lib_descriptor"); | |||
| @@ -57,16 +57,17 @@ lilv_lib_open(LilvWorld* world, | |||
| desc = ldf(bundle_path, features); | |||
| if (!desc) { | |||
| LILV_ERRORF("Call to `lv2_lib_descriptor' in %s failed\n", lib_path); | |||
| free(lib_path); | |||
| return NULL; | |||
| } | |||
| } else | |||
| #endif | |||
| if (!df) { | |||
| } else if (!df) { | |||
| LILV_ERRORF("No `lv2_descriptor' or `lv2_lib_descriptor' in %s\n", | |||
| lib_path); | |||
| dlclose(lib); | |||
| free(lib_path); | |||
| return NULL; | |||
| } | |||
| free(lib_path); | |||
| LilvLib* llib = (LilvLib*)malloc(sizeof(LilvLib)); | |||
| llib->world = world; | |||
| @@ -74,9 +75,7 @@ lilv_lib_open(LilvWorld* world, | |||
| llib->bundle_path = lilv_strdup(bundle_path); | |||
| llib->lib = lib; | |||
| llib->lv2_descriptor = df; | |||
| #ifdef LILV_NEW_LV2 | |||
| llib->desc = desc; | |||
| #endif | |||
| llib->refs = 1; | |||
| zix_tree_insert(world->libs, llib, NULL); | |||
| @@ -89,11 +88,9 @@ lilv_lib_get_plugin(LilvLib* lib, uint32_t index) | |||
| if (lib->lv2_descriptor) { | |||
| return lib->lv2_descriptor(index); | |||
| } | |||
| #ifdef LILV_NEW_LV2 | |||
| if (lib->desc) { | |||
| return lib->desc->get_plugin(lib->desc->handle, index); | |||
| } | |||
| #endif | |||
| return NULL; | |||
| } | |||
| @@ -30,6 +30,8 @@ extern "C" { | |||
| # include <windows.h> | |||
| # define dlopen(path, flags) LoadLibrary(path) | |||
| # define dlclose(lib) FreeLibrary((HMODULE)lib) | |||
| # define unlink(path) _unlink(path) | |||
| # define rmdir(path) _rmdir(path) | |||
| # ifdef _MSC_VER | |||
| # define __func__ __FUNCTION__ | |||
| # define INFINITY DBL_MAX + DBL_MAX | |||
| @@ -39,6 +41,7 @@ extern "C" { | |||
| static inline char* dlerror(void) { return "Unknown error"; } | |||
| #else | |||
| # include <dlfcn.h> | |||
| # include <unistd.h> | |||
| #endif | |||
| #include "serd/serd.h" | |||
| @@ -50,7 +53,7 @@ static inline char* dlerror(void) { return "Unknown error"; } | |||
| #include "lilv/lilv.h" | |||
| #ifdef LILV_DYN_MANIFEST | |||
| # include "lv2/dynmanifest.h" | |||
| # include "lv2/lv2plug.in/ns/ext/dynmanifest/dynmanifest.h" | |||
| #endif | |||
| /* | |||
| @@ -102,9 +105,7 @@ typedef struct { | |||
| char* bundle_path; | |||
| void* lib; | |||
| LV2_Descriptor_Function lv2_descriptor; | |||
| #ifdef LILV_NEW_LV2 | |||
| const LV2_Lib_Descriptor* desc; | |||
| #endif | |||
| uint32_t refs; | |||
| } LilvLib; | |||
| @@ -175,7 +176,7 @@ struct LilvWorldImpl { | |||
| SordNode* lv2_requiredFeature; | |||
| SordNode* lv2_symbol; | |||
| SordNode* lv2_prototype; | |||
| SordNode* null_uri; | |||
| SordNode* owl_Ontology; | |||
| SordNode* pset_value; | |||
| SordNode* rdf_a; | |||
| SordNode* rdf_value; | |||
| @@ -188,6 +189,7 @@ struct LilvWorldImpl { | |||
| SordNode* xsd_decimal; | |||
| SordNode* xsd_double; | |||
| SordNode* xsd_integer; | |||
| SordNode* null_uri; | |||
| } uris; | |||
| LilvOptions opt; | |||
| }; | |||
| @@ -275,6 +277,8 @@ LilvScalePoints* lilv_scale_points_new(void); | |||
| LilvPluginClasses* lilv_plugin_classes_new(void); | |||
| LilvUIs* lilv_uis_new(void); | |||
| LilvNode* lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri); | |||
| const uint8_t* lilv_world_blank_node_prefix(LilvWorld* world); | |||
| SerdStatus lilv_world_load_file(LilvWorld* world, | |||
| @@ -385,3 +385,12 @@ lilv_node_as_bool(const LilvNode* value) | |||
| { | |||
| return lilv_node_is_bool(value) ? value->val.bool_val : false; | |||
| } | |||
| LILV_API 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; | |||
| } | |||
| @@ -27,11 +27,10 @@ | |||
| #include "lilv_config.h" | |||
| #include "lilv_internal.h" | |||
| #include "lv2/ui.h" | |||
| #include "lv2/lv2plug.in/ns/extensions/ui/ui.h" | |||
| #define NS_DOAP (const uint8_t*)"http://usefulinc.com/ns/doap#" | |||
| #define NS_FOAF (const uint8_t*)"http://xmlns.com/foaf/0.1/" | |||
| #define NS_MOD (const uint8_t*)"http://portalmod.com/ns/modgui#" | |||
| /** Ownership of `uri` is taken */ | |||
| LilvPlugin* | |||
| @@ -694,7 +693,7 @@ lilv_plugin_get_latency_port_index(const LilvPlugin* p) | |||
| } else if (des_port) { | |||
| return des_port->index; | |||
| } else { | |||
| return UINT32_MAX; | |||
| return (uint32_t)-1; | |||
| } | |||
| } | |||
| @@ -909,131 +908,6 @@ lilv_plugin_get_author_homepage(const LilvPlugin* plugin) | |||
| return NULL; | |||
| } | |||
| static const SordNode* | |||
| lilv_plugin_get_modgui(const LilvPlugin* p) | |||
| { | |||
| lilv_plugin_load_if_necessary(p); | |||
| SordNode* mod_gui = sord_new_uri( | |||
| p->world->world, NS_MOD "gui"); | |||
| SordIter* gui = lilv_world_query_internal( | |||
| p->world, | |||
| p->plugin_uri->node, | |||
| mod_gui, | |||
| NULL); | |||
| sord_node_free(p->world->world, mod_gui); | |||
| if (sord_iter_end(gui)) { | |||
| sord_iter_free(gui); | |||
| return NULL; | |||
| } | |||
| const SordNode* Gui = sord_iter_get_node(gui, SORD_OBJECT); | |||
| sord_iter_free(gui); | |||
| return Gui; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_resources_directory(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_res = sord_new_uri(sworld, NS_MOD "resourcesDirectory"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_res); | |||
| sord_node_free(sworld, modgui_res); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_stylesheet(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_style = sord_new_uri(sworld, NS_MOD "stylesheet"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_style); | |||
| sord_node_free(sworld, modgui_style); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_icon_template(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_tmpl = sord_new_uri(sworld, NS_MOD "iconTemplate"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_tmpl); | |||
| sord_node_free(sworld, modgui_tmpl); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_settings_template(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_tmpl = sord_new_uri(sworld, NS_MOD "settingsTemplate"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_tmpl); | |||
| sord_node_free(sworld, modgui_tmpl); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_template_data(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_tmpl = sord_new_uri(sworld, NS_MOD "templateData"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_tmpl); | |||
| sord_node_free(sworld, modgui_tmpl); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_screenshot(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_scr = sord_new_uri(sworld, NS_MOD "screenshot"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_scr); | |||
| sord_node_free(sworld, modgui_scr); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API LilvNode* | |||
| lilv_plugin_get_modgui_thumbnail(const LilvPlugin* plugin) | |||
| { | |||
| const SordNode* modgui = lilv_plugin_get_modgui(plugin); | |||
| if (modgui) { | |||
| SordWorld* sworld = plugin->world->world; | |||
| SordNode* modgui_thumb = sord_new_uri(sworld, NS_MOD "thumbnail"); | |||
| LilvNode* ret = lilv_plugin_get_one(plugin, modgui, modgui_thumb); | |||
| sord_node_free(sworld, modgui_thumb); | |||
| return ret; | |||
| } | |||
| return NULL; | |||
| } | |||
| LILV_API bool | |||
| lilv_plugin_is_replaced(const LilvPlugin* plugin) | |||
| { | |||
| @@ -20,8 +20,8 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "lv2/atom.h" | |||
| #include "lv2/event.h" | |||
| #include "lv2/lv2plug.in/ns/ext/atom/atom.h" | |||
| #include "lv2/lv2plug.in/ns/ext/event/event.h" | |||
| #include "lilv_internal.h" | |||
| @@ -18,10 +18,10 @@ | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include "lv2/atom.h" | |||
| #include "lv2/atom-forge.h" | |||
| #include "lv2/presets.h" | |||
| #include "lv2/state.h" | |||
| #include "lv2/lv2plug.in/ns/ext/atom/atom.h" | |||
| #include "lv2/lv2plug.in/ns/ext/atom/forge.h" | |||
| #include "lv2/lv2plug.in/ns/ext/presets/presets.h" | |||
| #include "lv2/lv2plug.in/ns/ext/state/state.h" | |||
| #include "lilv_config.h" | |||
| #include "lilv_internal.h" | |||
| @@ -51,6 +51,7 @@ typedef struct { | |||
| struct LilvStateImpl { | |||
| LilvNode* plugin_uri; ///< Plugin URI | |||
| LilvNode* uri; ///< State/preset URI | |||
| char* dir; ///< Save directory (if saved) | |||
| char* file_dir; ///< Directory for files created by plugin | |||
| char* copy_dir; ///< Directory for snapshots of external files | |||
| @@ -216,7 +217,7 @@ abstract_path(LV2_State_Map_Path_Handle handle, | |||
| 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 | |||
| // 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->file_dir)) { | |||
| // File created by plugin earlier | |||
| @@ -238,13 +239,16 @@ abstract_path(LV2_State_Map_Path_Handle handle, | |||
| // Refer to the latest copy in plugin state | |||
| real_path = copy; | |||
| } | |||
| } else { | |||
| // New path outside state directory | |||
| } 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 | |||
| @@ -334,8 +338,7 @@ lilv_state_new_from_instance(const LilvPlugin* plugin, | |||
| { | |||
| const LV2_Feature** sfeatures = NULL; | |||
| LilvWorld* const world = plugin->world; | |||
| LilvState* const state = (LilvState*)malloc(sizeof(LilvState)); | |||
| memset(state, '\0', sizeof(LilvState)); | |||
| 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); | |||
| @@ -395,26 +398,50 @@ lilv_state_new_from_instance(const LilvPlugin* plugin, | |||
| return state; | |||
| } | |||
| LILV_API void | |||
| lilv_state_emit_port_values(const LilvState* state, | |||
| LilvSetPortValueFunc set_value, | |||
| void* user_data) | |||
| { | |||
| for (uint32_t i = 0; i < state->num_values; ++i) { | |||
| const PortValue* val = &state->values[i]; | |||
| set_value(val->symbol, user_data, val->value, val->size, val->type); | |||
| } | |||
| } | |||
| LILV_API void | |||
| lilv_state_restore(const LilvState* state, | |||
| const LV2_State_Interface* iface, | |||
| LV2_Handle handle, | |||
| 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 }; | |||
| const LV2_Feature** sfeatures = add_features(features, &map_feature, NULL); | |||
| const LV2_Descriptor* desc = instance ? instance->lv2_descriptor : NULL; | |||
| const LV2_State_Interface* iface = (desc && desc->extension_data) | |||
| ? (const LV2_State_Interface*)desc->extension_data(LV2_STATE__interface) | |||
| : NULL; | |||
| if (iface) { | |||
| iface->restore(handle, retrieve_callback, | |||
| (LV2_State_Handle)state, flags, features); | |||
| iface->restore(instance->lv2_handle, retrieve_callback, | |||
| (LV2_State_Handle)state, flags, sfeatures); | |||
| } | |||
| free(sfeatures); | |||
| if (set_value) { | |||
| for (uint32_t i = 0; i < state->num_values; ++i) { | |||
| const PortValue* val = &state->values[i]; | |||
| set_value(val->symbol, user_data, | |||
| val->value, val->size, val->type); | |||
| } | |||
| lilv_state_emit_port_values(state, set_value, user_data); | |||
| } | |||
| } | |||
| @@ -431,10 +458,10 @@ new_state_from_model(LilvWorld* world, | |||
| } | |||
| // Allocate state | |||
| LilvState* const state = (LilvState*)malloc(sizeof(LilvState)); | |||
| memset(state, '\0', sizeof(LilvState)); | |||
| LilvState* const state = (LilvState*)calloc(1, sizeof(LilvState)); | |||
| state->dir = lilv_strdup(dir); | |||
| 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); | |||
| @@ -559,9 +586,9 @@ new_state_from_model(LilvWorld* world, | |||
| } | |||
| LILV_API LilvState* | |||
| lilv_state_new_from_world(LilvWorld* world, | |||
| const LV2_URID_Map* map, | |||
| const LilvNode* node) | |||
| 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", | |||
| @@ -569,17 +596,14 @@ lilv_state_new_from_world(LilvWorld* world, | |||
| return NULL; | |||
| } | |||
| LilvState* state = new_state_from_model( | |||
| world, map, world->model, node->node, NULL); | |||
| return state; | |||
| return new_state_from_model(world, map, world->model, node->node, NULL); | |||
| } | |||
| LILV_API LilvState* | |||
| lilv_state_new_from_file(LilvWorld* world, | |||
| const LV2_URID_Map* map, | |||
| const LilvNode* subject, | |||
| const char* path) | |||
| lilv_state_new_from_file(LilvWorld* world, | |||
| LV2_URID_Map* map, | |||
| const LilvNode* subject, | |||
| const char* path) | |||
| { | |||
| if (subject && !lilv_node_is_uri(subject) | |||
| && !lilv_node_is_blank(subject)) { | |||
| @@ -629,9 +653,9 @@ set_prefixes(SerdEnv* env) | |||
| } | |||
| LILV_API LilvState* | |||
| lilv_state_new_from_string(LilvWorld* world, | |||
| const 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; | |||
| @@ -667,7 +691,7 @@ ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env) | |||
| serd_uri_parse(base->buf, &base_uri); | |||
| } | |||
| SerdEnv* env = serd_env_new(base); | |||
| SerdEnv* env = *new_env ? *new_env : serd_env_new(base); | |||
| set_prefixes(env); | |||
| SerdWriter* writer = serd_writer_new( | |||
| @@ -678,7 +702,10 @@ ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env) | |||
| sink, | |||
| stream); | |||
| *new_env = env; | |||
| if (!*new_env) { | |||
| *new_env = env; | |||
| } | |||
| return writer; | |||
| } | |||
| @@ -697,53 +724,117 @@ ttl_file_writer(FILE* fd, const SerdNode* node, SerdEnv** env) | |||
| return writer; | |||
| } | |||
| static void | |||
| add_to_model(SordWorld* world, | |||
| SerdEnv* env, | |||
| SordModel* model, | |||
| const SerdNode s, | |||
| 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); | |||
| 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); | |||
| } | |||
| 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); | |||
| } | |||
| static int | |||
| add_state_to_manifest(const LilvNode* plugin_uri, | |||
| add_state_to_manifest(LilvWorld* lworld, | |||
| const LilvNode* plugin_uri, | |||
| const char* manifest_path, | |||
| const char* state_uri, | |||
| const char* state_path) | |||
| { | |||
| FILE* fd = fopen(manifest_path, "a"); | |||
| if (!fd) { | |||
| LILV_ERRORF("Failed to open %s (%s)\n", | |||
| manifest_path, strerror(errno)); | |||
| return 4; | |||
| } | |||
| lilv_flock(fd, true); | |||
| SerdNode file = serd_node_new_file_uri(USTR(state_path), 0, 0, 0); | |||
| SordWorld* world = lworld->world; | |||
| SerdNode manifest = serd_node_new_file_uri(USTR(manifest_path), 0, 0, 0); | |||
| SerdEnv* env = NULL; | |||
| SerdWriter* writer = ttl_file_writer(fd, &manifest, &env); | |||
| SerdNode file = serd_node_new_file_uri(USTR(state_path), 0, 0, 0); | |||
| 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); | |||
| 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; | |||
| } | |||
| // <state> a pset:Preset | |||
| // 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)); | |||
| 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, &s, &p, &o, NULL, NULL); | |||
| // <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> | |||
| p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "seeAlso")); | |||
| serd_writer_write_statement(writer, 0, NULL, &s, &p, &file, NULL, NULL); | |||
| add_to_model(world, env, model, | |||
| s, | |||
| serd_node_from_string(SERD_URI, USTR(LILV_NS_RDFS "seeAlso")), | |||
| file); | |||
| // <state> lv2:appliesTo <plugin> | |||
| p = serd_node_from_string(SERD_URI, USTR(LV2_CORE__appliesTo)); | |||
| o = serd_node_from_string( | |||
| SERD_URI, USTR(lilv_node_as_string(plugin_uri))); | |||
| serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); | |||
| 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 | |||
| FILE* wfd = fopen(manifest_path, "w"); | |||
| if (wfd) { | |||
| SerdWriter* writer = ttl_file_writer(wfd, &manifest, &env); | |||
| sord_write(model, writer, NULL); | |||
| serd_writer_free(writer); | |||
| fclose(wfd); | |||
| } else { | |||
| LILV_ERRORF("Failed to open %s for writing (%s)\n", | |||
| manifest_path, strerror(errno)); | |||
| } | |||
| sord_free(model); | |||
| serd_node_free(&file); | |||
| serd_node_free(&manifest); | |||
| serd_writer_free(writer); | |||
| serd_env_free(env); | |||
| lilv_flock(fd, false); | |||
| fclose(fd); | |||
| if (rfd) { | |||
| lilv_flock(rfd, false); | |||
| fclose(rfd); | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -936,31 +1027,32 @@ lilv_state_save(LilvWorld* world, | |||
| return 4; | |||
| } | |||
| // FIXME: make parameter non-const? | |||
| if (state->dir && strcmp(state->dir, abs_dir)) { | |||
| free(state->dir); | |||
| ((LilvState*)state)->dir = lilv_strdup(abs_dir); | |||
| } | |||
| // 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, false); | |||
| SerdEnv* env = NULL; | |||
| SerdWriter* writer = ttl_file_writer(fd, &file, &env); | |||
| SerdNode node = uri ? serd_node_from_string(SERD_URI, USTR(uri)) : file; | |||
| int ret = lilv_state_write( | |||
| world, map, unmap, state, writer, (const char*)node.buf, dir); | |||
| SerdNode file = serd_node_new_file_uri(USTR(path), NULL, NULL, false); | |||
| 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) | |||
| SerdNode dir_uri = serd_node_new_file_uri(USTR(abs_dir), NULL, NULL, false); | |||
| free(state->dir); | |||
| lilv_node_free(state->uri); | |||
| ((LilvState*)state)->dir = (char*)dir_uri.buf; | |||
| ((LilvState*)state)->uri = lilv_new_uri(world, (const char*)node.buf); | |||
| serd_node_free(&file); | |||
| serd_writer_free(writer); | |||
| 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(state->plugin_uri, manifest, uri, path); | |||
| add_state_to_manifest(world, state->plugin_uri, manifest, uri, path); | |||
| free(manifest); | |||
| free(abs_dir); | |||
| @@ -993,6 +1085,75 @@ lilv_state_to_string(LilvWorld* world, | |||
| return (char*)serd_chunk_sink_finish(&chunk); | |||
| } | |||
| LILV_API int | |||
| lilv_state_delete(LilvWorld* world, | |||
| const LilvState* state) | |||
| { | |||
| if (!state->dir || !state->uri) { | |||
| LILV_ERROR("Attempt to delete unsaved state\n"); | |||
| return -1; | |||
| } | |||
| LilvNode* bundle = lilv_new_uri(world, state->dir); | |||
| LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle); | |||
| char* manifest_path = lilv_node_get_path(manifest, NULL); | |||
| SordModel* model = sord_new(world->world, SORD_SPO, false); | |||
| { | |||
| // 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); | |||
| } | |||
| SordNode* file = sord_get( | |||
| model, state->uri->node, world->uris.rdfs_seeAlso, NULL, NULL); | |||
| if (file) { | |||
| // Remove state file | |||
| char* file_path = lilv_file_uri_parse( | |||
| (const char*)sord_node_get_string(file), NULL); | |||
| if (unlink(file_path)) { | |||
| LILV_ERRORF("Failed to remove %s (%s)\n", file_path, strerror(errno)); | |||
| } | |||
| free(file_path); | |||
| } | |||
| // Remove any existing manifest entries for this state | |||
| remove_manifest_entry( | |||
| world->world, model, lilv_node_as_string(state->uri)); | |||
| remove_manifest_entry( | |||
| world->world, world->model, lilv_node_as_string(state->uri)); | |||
| // 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 (unlink(manifest_path)) { | |||
| LILV_ERRORF("Failed to remove %s (%s)\n", | |||
| manifest_path, strerror(errno)); | |||
| } | |||
| char* dir_path = lilv_file_uri_parse(state->dir, NULL); | |||
| if (rmdir(dir_path)) { | |||
| LILV_ERRORF("Failed to remove %s (%s)\n", | |||
| dir_path, strerror(errno)); | |||
| } | |||
| free(dir_path); | |||
| } else { | |||
| // Still something in the manifest, reload bundle | |||
| lilv_world_load_bundle(world, bundle); | |||
| } | |||
| sord_free(model); | |||
| free(manifest_path); | |||
| lilv_node_free(manifest); | |||
| lilv_node_free(bundle); | |||
| return 0; | |||
| } | |||
| LILV_API void | |||
| lilv_state_free(LilvState* state) | |||
| { | |||
| @@ -1005,6 +1166,7 @@ lilv_state_free(LilvState* state) | |||
| 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->props); | |||
| @@ -1073,6 +1235,12 @@ lilv_state_get_plugin_uri(const LilvState* state) | |||
| return state->plugin_uri; | |||
| } | |||
| LILV_API const LilvNode* | |||
| lilv_state_get_uri(const LilvState* state) | |||
| { | |||
| return state->uri; | |||
| } | |||
| LILV_API const char* | |||
| lilv_state_get_label(const LilvState* state) | |||
| { | |||
| @@ -109,54 +109,3 @@ lilv_ui_get_binary_uri(const LilvUI* ui) | |||
| { | |||
| return ui->binary_uri; | |||
| } | |||
| static LilvNodes* | |||
| lilv_ui_get_value_internal(const LilvUI* ui, const SordNode* predicate) | |||
| { | |||
| assert(ui); | |||
| return lilv_world_find_nodes_internal(ui->world, ui->uri->node, predicate, NULL); | |||
| } | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_supported_features(const LilvUI* ui) | |||
| { | |||
| assert(ui); | |||
| LilvNodes* optional = lilv_ui_get_optional_features(ui); | |||
| LilvNodes* required = lilv_ui_get_required_features(ui); | |||
| LilvNodes* result = lilv_nodes_new(); | |||
| LILV_FOREACH(nodes, i, optional) | |||
| zix_tree_insert((ZixTree*)result, lilv_node_duplicate(lilv_nodes_get(optional, i)), NULL); | |||
| LILV_FOREACH(nodes, i, required) | |||
| zix_tree_insert((ZixTree*)result, lilv_node_duplicate(lilv_nodes_get(required, i)), NULL); | |||
| lilv_nodes_free(optional); | |||
| lilv_nodes_free(required); | |||
| return result; | |||
| } | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_required_features(const LilvUI* ui) | |||
| { | |||
| assert(ui); | |||
| assert(ui->world); | |||
| return lilv_ui_get_value_internal(ui, ui->world->uris.lv2_requiredFeature); | |||
| } | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_optional_features(const LilvUI* ui) | |||
| { | |||
| assert(ui); | |||
| assert(ui->world); | |||
| return lilv_ui_get_value_internal(ui, ui->world->uris.lv2_optionalFeature); | |||
| } | |||
| LILV_API const LilvNodes* | |||
| lilv_ui_get_extension_data(const LilvUI* ui) | |||
| { | |||
| assert(ui); | |||
| assert(ui->world); | |||
| return lilv_ui_get_value_internal(ui, ui->world->uris.lv2_extensionData); | |||
| } | |||
| @@ -25,15 +25,28 @@ | |||
| #include <ctype.h> | |||
| #include <errno.h> | |||
| #include <stdarg.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #ifdef _WIN32 | |||
| # define _WIN32_WINNT 0x0600 /* for CreateSymbolicLink */ | |||
| # include <windows.h> | |||
| # include <direct.h> | |||
| # include <io.h> | |||
| # define F_OK 0 | |||
| # define mkdir(path, flags) _mkdir(path) | |||
| # if (defined(_MSC_VER) && (_MSC_VER < 1500)) | |||
| /** Implement 'CreateSymbolicLink()' for MSVC 8 or earlier */ | |||
| BOOLEAN WINAPI | |||
| CreateSymbolicLink(LPCTSTR linkpath, LPCTSTR targetpath, DWORD flags) | |||
| { | |||
| typedef BOOLEAN (WINAPI* PFUNC)(LPCTSTR, LPCTSTR, DWORD); | |||
| PFUNC pfn = (PFUNC)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkA"); | |||
| return pfn ? pfn(linkpath, targetpath, flags) : 0; | |||
| } | |||
| # endif /* _MSC_VER < 1500 */ | |||
| #else | |||
| # include <dirent.h> | |||
| # include <unistd.h> | |||
| @@ -67,13 +80,15 @@ lilv_strjoin(const char* first, ...) | |||
| if (s == NULL) | |||
| break; | |||
| const size_t this_len = strlen(s); | |||
| if (!(result = (char*)realloc(result, len + this_len + 1))) { | |||
| const size_t this_len = strlen(s); | |||
| char* new_result = (char*)realloc(result, len + this_len + 1); | |||
| if (!new_result) { | |||
| free(result); | |||
| LILV_ERROR("realloc() failed\n"); | |||
| return NULL; | |||
| } | |||
| result = new_result; | |||
| memcpy(result + len, s, this_len); | |||
| len += this_len; | |||
| } | |||
| @@ -103,6 +118,12 @@ lilv_uri_to_path(const char* uri) | |||
| return (const char*)serd_uri_to_path((const uint8_t*)uri); | |||
| } | |||
| char* | |||
| lilv_file_uri_parse(const char* uri, char** hostname) | |||
| { | |||
| return (char*)serd_file_uri_parse((const uint8_t*)uri, (uint8_t**)hostname); | |||
| } | |||
| /** Return the current LANG converted to Turtle (i.e. RFC3066) style. | |||
| * For example, if LANG is set to "en_CA.utf-8", this returns "en-ca". | |||
| */ | |||
| @@ -425,7 +446,10 @@ lilv_symlink(const char* oldpath, const char* newpath) | |||
| int ret = 0; | |||
| if (strcmp(oldpath, newpath)) { | |||
| #ifdef _WIN32 | |||
| ret = 0; | |||
| ret = !CreateSymbolicLink(newpath, oldpath, 0); | |||
| if (ret) { | |||
| ret = !CreateHardLink(newpath, oldpath, 0); | |||
| } | |||
| #else | |||
| ret = symlink(oldpath, newpath); | |||
| #endif | |||
| @@ -19,7 +19,7 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "lv2/presets.h" | |||
| #include "lv2/lv2plug.in/ns/ext/presets/presets.h" | |||
| #include "lilv_internal.h" | |||
| @@ -42,12 +42,11 @@ lilv_world_new(void) | |||
| world->loaded_files = zix_tree_new( | |||
| false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free); | |||
| #ifdef LILV_NEW_LV2 | |||
| world->libs = zix_tree_new(false, lilv_lib_compare, NULL, NULL); | |||
| #endif | |||
| #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 NEW_URI(uri) sord_new_uri(world->world, (const uint8_t*)uri) | |||
| @@ -73,6 +72,7 @@ lilv_world_new(void) | |||
| 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"); | |||
| @@ -136,10 +136,8 @@ lilv_world_free(LilvWorld* world) | |||
| zix_tree_free((ZixTree*)world->loaded_files); | |||
| world->loaded_files = NULL; | |||
| #ifdef LILV_NEW_LV2 | |||
| zix_tree_free((ZixTree*)world->libs); | |||
| world->libs = NULL; | |||
| #endif | |||
| zix_tree_free((ZixTree*)world->plugin_classes); | |||
| world->plugin_classes = NULL; | |||
| @@ -190,7 +188,7 @@ lilv_world_find_nodes(LilvWorld* world, | |||
| LILV_ERROR("Both subject and object are NULL\n"); | |||
| return NULL; | |||
| } | |||
| return lilv_world_find_nodes_internal(world, | |||
| subject ? subject->node : NULL, | |||
| predicate->node, | |||
| @@ -237,8 +235,11 @@ lilv_world_ask(LilvWorld* world, | |||
| const LilvNode* predicate, | |||
| const LilvNode* object) | |||
| { | |||
| return sord_ask( | |||
| world->model, subject->node, predicate->node, object->node, NULL); | |||
| return sord_ask(world->model, | |||
| subject ? subject->node : NULL, | |||
| predicate ? predicate->node : NULL, | |||
| object ? object->node : NULL, | |||
| NULL); | |||
| } | |||
| SordModel* | |||
| @@ -452,14 +453,16 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
| typedef void* LV2_Dyn_Manifest_Handle; | |||
| LV2_Dyn_Manifest_Handle handle = NULL; | |||
| // ?dman a dynman:DynManifest | |||
| SordIter* dmanifests = sord_search(world->model, | |||
| NULL, | |||
| world->uris.rdf_a, | |||
| world->uris.dman_DynManifest, | |||
| bundle_node); | |||
| FOREACH_MATCH(dmanifests) { | |||
| const SordNode* dmanifest = sord_iter_get_node(dmanifests, SORD_SUBJECT); | |||
| // ?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, | |||
| @@ -485,9 +488,11 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
| } | |||
| // Open library | |||
| dlerror(); | |||
| void* lib = dlopen(lib_path, RTLD_LAZY); | |||
| if (!lib) { | |||
| LILV_ERRORF("Failed to open dynmanifest library `%s'\n", lib_path); | |||
| LILV_ERRORF("Failed to open dynmanifest library `%s' (%s)\n", | |||
| lib_path, dlerror()); | |||
| sord_iter_free(binaries); | |||
| continue; | |||
| } | |||
| @@ -521,12 +526,14 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
| 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 | |||
| // Parse generated data file into temporary model | |||
| // FIXME | |||
| const SerdNode* base = sord_node_to_serd_node(dmanifest); | |||
| SerdEnv* env = serd_env_new(base); | |||
| @@ -543,25 +550,25 @@ lilv_world_load_dyn_manifest(LilvWorld* world, | |||
| fclose(fd); | |||
| // ?plugin a lv2:Plugin | |||
| SordIter* plug_results = sord_search( | |||
| world->model, | |||
| NULL, | |||
| world->uris.rdf_a, | |||
| world->uris.lv2_Plugin, | |||
| dmanifest); | |||
| FOREACH_MATCH(plug_results) { | |||
| const SordNode* plug = sord_iter_get_node(plug_results, SORD_SUBJECT); | |||
| 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); | |||
| } | |||
| sord_iter_free(plug_results); | |||
| sord_iter_free(binaries); | |||
| sord_iter_free(p); | |||
| sord_free(plugins); | |||
| } | |||
| sord_iter_free(dmanifests); | |||
| sord_iter_free(iter); | |||
| sord_free(model); | |||
| #endif // LILV_DYN_MANIFEST | |||
| } | |||
| static | |||
| LilvNode* | |||
| lilv_world_get_manifest_uri(LilvWorld* world, LilvNode* bundle_uri) | |||
| { | |||
| @@ -592,7 +599,7 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
| lilv_node_free(manifest); | |||
| return; | |||
| } | |||
| // ?plugin a lv2:Plugin | |||
| SordIter* plug_results = sord_search(world->model, | |||
| NULL, | |||
| @@ -607,17 +614,20 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
| lilv_world_load_dyn_manifest(world, bundle_node, manifest); | |||
| // ?specification a lv2:Specification | |||
| SordIter* spec_results = sord_search(world->model, | |||
| NULL, | |||
| world->uris.rdf_a, | |||
| world->uris.lv2_Specification, | |||
| bundle_node); | |||
| FOREACH_MATCH(spec_results) { | |||
| const SordNode* spec = sord_iter_get_node(spec_results, SORD_SUBJECT); | |||
| lilv_world_add_spec(world, spec, bundle_node); | |||
| // ?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); | |||
| } | |||
| sord_iter_free(spec_results); | |||
| lilv_node_free(manifest); | |||
| } | |||
| @@ -645,7 +655,7 @@ lilv_world_unload_file(LilvWorld* world, LilvNode* file) | |||
| { | |||
| ZixTreeIter* iter; | |||
| if (!zix_tree_find((ZixTree*)world->loaded_files, file, &iter)) { | |||
| zix_tree_remove(world->loaded_files, iter); | |||
| zix_tree_remove((ZixTree*)world->loaded_files, iter); | |||
| return 0; | |||
| } | |||
| return 1; | |||
| @@ -654,6 +664,10 @@ lilv_world_unload_file(LilvWorld* world, LilvNode* file) | |||
| LILV_API int | |||
| lilv_world_unload_bundle(LilvWorld* world, LilvNode* bundle_uri) | |||
| { | |||
| if (!bundle_uri) { | |||
| return 0; | |||
| } | |||
| // Remove loaded_files entry for manifest.ttl | |||
| LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle_uri); | |||
| lilv_world_unload_file(world, manifest); | |||
| @@ -670,13 +684,14 @@ load_dir_entry(const char* dir, const char* name, void* data) | |||
| if (!strcmp(name, ".") || !strcmp(name, "..")) | |||
| return; | |||
| const char* scheme = (dir[0] == '/') ? "file://" : "file:///"; | |||
| char* uri = lilv_strjoin(scheme, dir, "/", name, "/", NULL); | |||
| LilvNode* uri_val = lilv_new_uri(world, uri); | |||
| 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, uri_val); | |||
| lilv_node_free(uri_val); | |||
| free(uri); | |||
| 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`. */ | |||
| @@ -727,7 +742,7 @@ lilv_world_load_path(LilvWorld* world, | |||
| } | |||
| } | |||
| static void | |||
| void | |||
| lilv_world_load_specifications(LilvWorld* world) | |||
| { | |||
| for (LilvSpec* spec = world->specs; spec; spec = spec->next) { | |||
| @@ -738,7 +753,7 @@ lilv_world_load_specifications(LilvWorld* world) | |||
| } | |||
| } | |||
| static void | |||
| void | |||
| lilv_world_load_plugin_classes(LilvWorld* world) | |||
| { | |||
| /* FIXME: This loads all classes, not just lv2:Plugin subclasses. | |||
| @@ -782,8 +797,12 @@ lilv_world_load_plugin_classes(LilvWorld* world) | |||
| } | |||
| LILV_API void | |||
| lilv_world_load_all(LilvWorld* world, const char* lv2_path) | |||
| lilv_world_load_all(LilvWorld* world) | |||
| { | |||
| const char* 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); | |||
| @@ -822,7 +841,7 @@ lilv_world_load_file(LilvWorld* world, SerdReader* reader, const LilvNode* uri) | |||
| 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); | |||
| @@ -214,17 +214,6 @@ cleanup_uris(void) | |||
| /*****************************************************************************/ | |||
| static int | |||
| test_utils(void) | |||
| { | |||
| TEST_ASSERT(!strcmp(lilv_uri_to_path("file:///tmp/blah"), "/tmp/blah")); | |||
| TEST_ASSERT(!lilv_uri_to_path("file:/example.org/blah")); | |||
| TEST_ASSERT(!lilv_uri_to_path("http://example.org/blah")); | |||
| return 1; | |||
| } | |||
| /*****************************************************************************/ | |||
| static int | |||
| test_value(void) | |||
| { | |||
| @@ -256,6 +245,7 @@ test_value(void) | |||
| TEST_ASSERT(lilv_node_is_literal(sval)); | |||
| TEST_ASSERT(lilv_node_is_literal(ival)); | |||
| TEST_ASSERT(lilv_node_is_literal(fval)); | |||
| TEST_ASSERT(!lilv_node_get_path(fval, NULL)); | |||
| TEST_ASSERT(!strcmp(lilv_node_as_uri(uval), "http://example.org")); | |||
| TEST_ASSERT(!strcmp(lilv_node_as_string(sval), "Foo")); | |||
| @@ -1534,6 +1524,12 @@ test_state(void) | |||
| // Ensure they are equal | |||
| TEST_ASSERT(lilv_state_equals(state, state2)); | |||
| // Check that we can't delete unsaved state | |||
| TEST_ASSERT(lilv_state_delete(world, state)); | |||
| // Check that state has no URI | |||
| TEST_ASSERT(!lilv_state_get_uri(state)); | |||
| // Check that we can't save a state with no URI | |||
| char* bad_state_str = lilv_state_to_string( | |||
| world, &map, &unmap, state, NULL, NULL); | |||
| @@ -1614,6 +1610,11 @@ test_state(void) | |||
| LilvState* state6 = lilv_state_new_from_world(world, &map, test_state_node); | |||
| TEST_ASSERT(lilv_state_equals(state, state6)); // Round trip accuracy | |||
| // Check that loaded state has correct URI | |||
| TEST_ASSERT(lilv_state_get_uri(state6)); | |||
| TEST_ASSERT(!strcmp(lilv_node_as_string(lilv_state_get_uri(state6)), | |||
| state_uri)); | |||
| lilv_world_unload_resource(world, test_state_node); | |||
| lilv_world_unload_bundle(world, test_state_bundle); | |||
| @@ -1723,6 +1724,9 @@ test_state(void) | |||
| TEST_ASSERT(lilv_state_equals(fstate72, fstate7)); | |||
| TEST_ASSERT(!lilv_state_equals(fstate6, fstate72)); | |||
| // Delete saved state | |||
| lilv_state_delete(world, fstate7); | |||
| lilv_instance_deactivate(instance); | |||
| lilv_instance_free(instance); | |||
| @@ -1867,7 +1871,6 @@ test_string(void) | |||
| /* add tests here */ | |||
| static struct TestCase tests[] = { | |||
| TEST_CASE(utils), | |||
| TEST_CASE(value), | |||
| TEST_CASE(verify), | |||
| TEST_CASE(no_verify), | |||
| @@ -95,6 +95,7 @@ bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size) | |||
| fprintf(stderr, "<%s> requires feature <%s>, skipping\n", | |||
| uri, lilv_node_as_uri(feature)); | |||
| free(buf); | |||
| uri_table_destroy(&uri_table); | |||
| return 0.0; | |||
| } | |||
| } | |||
| @@ -104,6 +105,7 @@ bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size) | |||
| 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; | |||
| } | |||
| @@ -128,6 +130,7 @@ bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size) | |||
| lilv_instance_free(instance); | |||
| free(buf); | |||
| free(controls); | |||
| uri_table_destroy(&uri_table); | |||
| return 0.0; | |||
| } | |||
| } else if (lilv_port_is_a(p, port, atom_AtomPort)) { | |||
| @@ -138,6 +141,7 @@ bench(const LilvPlugin* p, uint32_t sample_count, uint32_t block_size) | |||
| lilv_instance_free(instance); | |||
| free(buf); | |||
| free(controls); | |||
| uri_table_destroy(&uri_table); | |||
| return 0.0; | |||
| } | |||
| } | |||
| @@ -12,7 +12,7 @@ import waflib.Logs as Logs | |||
| # major increment <=> incompatible changes | |||
| # minor increment <=> compatible changes (additions) | |||
| # micro increment <=> no interface changes | |||
| LILV_VERSION = '0.20.0' | |||
| LILV_VERSION = '0.21.3' | |||
| LILV_MAJOR_VERSION = '0' | |||
| # Mandatory waf variables | |||
| @@ -80,14 +80,12 @@ def configure(conf): | |||
| autowaf.check_pkg(conf, 'serd-0', uselib_store='SERD', | |||
| atleast_version='0.14.0', mandatory=True) | |||
| autowaf.check_pkg(conf, 'sord-0', uselib_store='SORD', | |||
| atleast_version='0.12.0', mandatory=True) | |||
| atleast_version='0.13.0', mandatory=True) | |||
| autowaf.check_pkg(conf, 'sratom-0', uselib_store='SRATOM', | |||
| atleast_version='0.4.0', mandatory=True) | |||
| autowaf.define(conf, 'LILV_NEW_LV2', 1) # New LV2 discovery API | |||
| defines = ['_POSIX_C_SOURCE', '_BSD_SOURCE'] | |||
| if Options.platform == 'darwin': | |||
| if conf.env.DEST_OS == 'darwin': | |||
| defines += ['_DARWIN_C_SOURCE'] | |||
| # Check for gcov library (for test coverage) | |||
| @@ -122,7 +120,7 @@ def configure(conf): | |||
| lilv_path_sep = ':' | |||
| lilv_dir_sep = '/' | |||
| if sys.platform == 'win32': | |||
| if conf.env.DEST_OS == 'win32': | |||
| lilv_path_sep = ';' | |||
| lilv_dir_sep = '\\\\' | |||
| @@ -132,16 +130,16 @@ def configure(conf): | |||
| # Set default LV2 path | |||
| lv2_path = Options.options.default_lv2_path | |||
| if lv2_path == '': | |||
| if Options.platform == 'darwin': | |||
| 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 Options.platform == 'haiku': | |||
| elif conf.env.DEST_OS == 'haiku': | |||
| lv2_path = lilv_path_sep.join(['~/.lv2', | |||
| '/boot/common/add-ons/lv2']) | |||
| elif Options.platform == 'win32': | |||
| elif conf.env.DEST_OS == 'win32': | |||
| lv2_path = lilv_path_sep.join(['%APPDATA%\\\\LV2', | |||
| '%COMMONPROGRAMFILES%\\\\LV2']) | |||
| else: | |||
| @@ -184,6 +182,7 @@ def build_util(bld, name, defines): | |||
| obj.lib = ['m'] | |||
| obj.env.SHLIB_MARKER = obj.env.STLIB_MARKER | |||
| obj.linkflags = ['-static', '-Wl,--start-group'] | |||
| obj.lib = ['dl', 'm'] | |||
| return obj | |||
| def build(bld): | |||
| @@ -192,11 +191,6 @@ def build(bld): | |||
| bld.install_files(includedir, bld.path.ant_glob('lilv/*.h')) | |||
| bld.install_files(includedir, bld.path.ant_glob('lilv/*.hpp')) | |||
| # 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'}) | |||
| lib_source = ''' | |||
| src/collections.c | |||
| src/instance.c | |||
| @@ -217,14 +211,20 @@ def build(bld): | |||
| lib = ['dl'] | |||
| libflags = ['-fvisibility=hidden'] | |||
| defines = [] | |||
| if sys.platform == 'win32': | |||
| if bld.env.DEST_OS == 'win32': | |||
| lib = [] | |||
| if bld.env.MSVC_COMPILER: | |||
| libflags = [] | |||
| defines = ['snprintf=_snprintf'] | |||
| elif sys.platform.find('bsd') > 0: | |||
| elif bld.env.DEST_OS.find('bsd') > 0: | |||
| lib = [] | |||
| # 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', | |||
| @@ -358,7 +358,7 @@ def build(bld): | |||
| if bld.is_defined('HAVE_CLOCK_GETTIME') and not bld.env.STATIC_PROGS: | |||
| obj = build_util(bld, 'utils/lv2bench', defines) | |||
| if not bld.env.MSVC_COMPILER: | |||
| obj.lib = ['rt'] | |||
| obj.lib = ['dl', 'rt'] | |||
| # Documentation | |||
| autowaf.build_dox(bld, 'LILV', LILV_VERSION, top, out) | |||
| @@ -377,13 +377,13 @@ def build(bld): | |||
| source = 'bindings/lilv.i', | |||
| target = 'bindings/_lilv', | |||
| includes = ['..'], | |||
| swig_flags = '-c++ -python -Wall -I.. -llilv -features autodoc=1', | |||
| swig_flags = '-c++ -python %s -Wall -I.. -llilv -features autodoc=1' % | |||
| ("-py3" if sys.version_info >= (3,0,0) else ""), | |||
| use = 'liblilv') | |||
| autowaf.use_lib(bld, obj, 'LILV') | |||
| bld.install_files('${PYTHONDIR}', 'bindings/lilv.py') | |||
| bld.add_post_fun(autowaf.run_ldconfig) | |||
| if bld.env.DOCS: | |||
| bld.add_post_fun(fix_docs) | |||