From 7823f743ee0c748ff4ced56838cd737516d857ab Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 4 Jan 2012 19:21:12 +0000 Subject: Implement proper support for LV2_STATE_BUNDLE. Test saving state to default bundle path. Fix memory leaks. git-svn-id: http://svn.drobilla.net/lad/trunk/lilv@3915 a436a847-0d15-0410-975c-d299462d15a1 --- src/lilv_internal.h | 1 + src/plugin.c | 17 ++++---- src/state.c | 115 ++++++++++++++++++++++++++++++++++------------------ src/util.c | 39 ++++++++++++++++++ src/world.c | 40 +----------------- 5 files changed, 128 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/lilv_internal.h b/src/lilv_internal.h index 9f19c1c..7191daa 100644 --- a/src/lilv_internal.h +++ b/src/lilv_internal.h @@ -330,6 +330,7 @@ LilvNodes* lilv_nodes_from_stream_objects(LilvWorld* w, char* lilv_strjoin(const char* first, ...); char* lilv_strdup(const char* str); char* lilv_get_lang(void); +char* lilv_expand(const char* path); typedef void (*VoidFunc)(void); diff --git a/src/plugin.c b/src/plugin.c index 2a7ccee..2bb70c4 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -217,17 +217,20 @@ lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) LilvNode* symbol = lilv_plugin_get_unique( p, port, p->world->lv2_symbol_node); + bool error = false; if (!lilv_node_is_string(symbol) || !is_symbol(symbol->str_val)) { LILV_ERRORF("Plugin <%s> port symbol `%s' is invalid\n", lilv_node_as_uri(p->plugin_uri), lilv_node_as_string(symbol)); - goto error; + error = true; + goto done; } if (!lilv_node_is_int(index)) { LILV_ERRORF("Plugin <%s> port index is not an integer\n", lilv_node_as_uri(p->plugin_uri)); - goto error; + error = true; + goto done; } uint32_t this_index = lilv_node_as_int(index); @@ -265,13 +268,13 @@ lilv_plugin_load_ports_if_necessary(const LilvPlugin* const_p) } lilv_match_end(types); - continue; - - error: + done: lilv_node_free(symbol); lilv_node_free(index); - lilv_plugin_free_ports(p); - break; // Invalid plugin + if (error) { // Invalid plugin + lilv_plugin_free_ports(p); + break; + } } lilv_match_end(ports); diff --git a/src/state.c b/src/state.c index c747937..05570cd 100644 --- a/src/state.c +++ b/src/state.c @@ -307,6 +307,7 @@ new_state_from_model(LilvWorld* world, state->label = lilv_strdup( (const char*)sord_node_get_string(lilv_match_object(i))); sord_iter_free(i); + } else { } // Get port values @@ -609,6 +610,70 @@ pathify(const char* in) return out; } +static int +mkdir_p(const char* dir_path) +{ + char* path = lilv_strdup(dir_path); + const size_t path_len = strlen(path); + for (size_t i = 1; i <= path_len; ++i) { + if (path[i] == LILV_DIR_SEP[0] || path[i] == '\0') { + path[i] = '\0'; + if (mkdir(path, 0755) && errno != EEXIST) { + LILV_ERRORF("Failed to create %s (%s)\n", + path, strerror(errno)); + free(path); + return 1; + } + path[i] = LILV_DIR_SEP[0]; + } + } + + free(path); + return 0; +} + +static int +lilv_default_state_path(LilvWorld* world, + const LilvState* state, + char** path, + char** manifest_path) +{ +#ifdef HAVE_MKDIR + if (!state->label) { + LILV_ERROR("Attempt to save state with no label or path.\n"); + return 1; + } + + char* state_bundle = getenv("LV2_STATE_BUNDLE"); + if (!state_bundle) { + state_bundle = LILV_DEFAULT_STATE_BUNDLE; + } + + // Create ~/.lv2/presets.lv2/ + char* const bundle = lilv_expand(state_bundle); + if (mkdir_p(bundle)) { + free(bundle); + return 3; + } + + char* const filename = pathify(state->label); + + *path = lilv_strjoin( + bundle, LILV_DIR_SEP, filename, ".ttl", NULL); + + *manifest_path = lilv_strjoin( + bundle, LILV_DIR_SEP, "manifest.ttl", NULL); + + free(bundle); + free(filename); + + return 0; +#else + LILV_ERROR("Save to default state path but mkdir is unavailable.\n"); + return 4; +#endif +} + LILV_API int lilv_state_save(LilvWorld* world, @@ -621,49 +686,13 @@ lilv_state_save(LilvWorld* world, char* default_path = NULL; char* default_manifest_path = NULL; if (!path) { -#ifdef HAVE_MKDIR - if (!state->label) { - LILV_ERROR("Attempt to save state with no label or path.\n"); + if (lilv_default_state_path( + world, state, &default_path, &default_manifest_path)) { return 1; } - - const char* const home = getenv("HOME"); - if (!home) { - LILV_ERROR("$HOME is undefined\n"); - return 2; - } - - // Create ~/.lv2/ - char* const lv2dir = lilv_strjoin(home, "/.lv2/", NULL); - if (mkdir(lv2dir, 0755) && errno != EEXIST) { - LILV_ERRORF("Unable to create %s (%s)\n", lv2dir, strerror(errno)); - free(lv2dir); - return 3; - } - - // Create ~/.lv2/presets.lv2/ - char* const bundle = lilv_strjoin(lv2dir, "presets.lv2/", NULL); - if (mkdir(bundle, 0755) && errno != EEXIST) { - LILV_ERRORF("Unable to create %s (%s)\n", lv2dir, strerror(errno)); - free(lv2dir); - free(bundle); - return 4; - } - - char* const filename = pathify(state->label); - default_path = lilv_strjoin(bundle, filename, ".ttl", NULL); - default_manifest_path = lilv_strjoin(bundle, "manifest.ttl", NULL); - + path = default_path; manifest_path = default_manifest_path; - - free(lv2dir); - free(bundle); - free(filename); -#else - LILV_ERROR("Save to default state path but mkdir is unavailable.\n"); - return 1; -#endif } FILE* fd = fopen(path, "w"); @@ -779,6 +808,7 @@ lilv_state_save(LilvWorld* world, serd_writer_write_statement( writer, SERD_ANON_CONT, NULL, &state_node, &p, &o, &t, NULL); + lilv_node_free(node); } else { char name[16]; snprintf(name, sizeof(name), "b%u", i); @@ -835,6 +865,13 @@ void lilv_state_free(LilvState* state) { if (state) { + for (uint32_t i = 0; i < state->num_props; ++i) { + free(state->props[i].value); + } + for (uint32_t i = 0; i < state->num_values; ++i) { + lilv_node_free(state->values[i].value); + free(state->values[i].symbol); + } lilv_node_free(state->plugin_uri); free(state->props); free(state->values); diff --git a/src/util.c b/src/util.c index 0af0e1a..1c9a46e 100644 --- a/src/util.c +++ b/src/util.c @@ -14,6 +14,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _POSIX_SOURCE 1 /* for wordexp */ + #include #include #include @@ -21,6 +23,10 @@ #include "lilv_internal.h" +#ifdef HAVE_WORDEXP +# include +#endif + char* lilv_strjoin(const char* first, ...) { @@ -99,3 +105,36 @@ lilv_get_lang(void) return lang; } + +/** Expand variables (e.g. POSIX ~ or $FOO, Windows %FOO%) in @a path. */ +char* +lilv_expand(const char* path) +{ +#ifdef HAVE_WORDEXP + char* ret = NULL; + wordexp_t p; + if (wordexp(path, &p, 0)) { + LILV_ERRORF("Error expanding path `%s'\n", path); + return lilv_strdup(path); + } + if (p.we_wordc == 0) { + /* Literal directory path (e.g. no variables or ~) */ + ret = lilv_strdup(path); + } else if (p.we_wordc == 1) { + /* Directory path expands (e.g. contains ~ or $FOO) */ + ret = lilv_strdup(p.we_wordv[0]); + } else { + /* Multiple expansions in a single directory path? */ + LILV_ERRORF("Malformed path `%s'\n", path); + ret = lilv_strdup(path); + } + wordfree(&p); +#elif defined(__WIN32__) + static const size_t len = 32767; + char* ret = malloc(len); + ExpandEnvironmentStrings(path, ret, len); +#else + char* ret = lilv_strdup(path); +#endif + return ret; +} diff --git a/src/world.c b/src/world.c index 2029136..8151a73 100644 --- a/src/world.c +++ b/src/world.c @@ -14,7 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define _POSIX_SOURCE 1 /* for wordexp */ +#define _POSIX_SOURCE 1 /* for readdir_r */ #include #include @@ -25,10 +25,6 @@ #include "lilv_internal.h" -#ifdef HAVE_WORDEXP -# include -#endif - LILV_API LilvWorld* lilv_world_new(void) @@ -582,43 +578,11 @@ lilv_world_load_bundle(LilvWorld* world, LilvNode* bundle_uri) serd_node_free(&manifest_uri); } -/** Expand variables (e.g. POSIX ~ or $FOO, Windows %FOO%) in @a path. */ -static char* -expand(const char* path) -{ -#ifdef HAVE_WORDEXP - char* ret = NULL; - wordexp_t p; - if (wordexp(path, &p, 0)) { - LILV_ERRORF("Error expanding path `%s'\n", path); - return lilv_strdup(path); - } - if (p.we_wordc == 0) { - /* Literal directory path (e.g. no variables or ~) */ - ret = lilv_strdup(path); - } else if (p.we_wordc == 1) { - /* Directory path expands (e.g. contains ~ or $FOO) */ - ret = lilv_strdup(p.we_wordv[0]); - } else { - /* Multiple expansions in a single directory path? */ - LILV_ERRORF("Malformed path `%s' ignored\n", path); - } - wordfree(&p); -#elif defined(__WIN32__) - static const size_t len = 32767; - char* ret = malloc(len); - ExpandEnvironmentStrings(path, ret, len); -#else - char* ret = lilv_strdup(path); -#endif - return ret; -} - /** Load all bundles in the directory at @a dir_path. */ static void lilv_world_load_directory(LilvWorld* world, const char* dir_path) { - char* path = expand(dir_path); + char* path = lilv_expand(dir_path); if (!path) { LILV_WARNF("Empty path `%s'\n", path); return; -- cgit v1.2.1