From 7fd4168fe8581e46f4ee35cc182db6220b6eed04 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 6 Jun 2006 20:20:33 +0000 Subject: Moved libslv2 into it's own subdirectory git-svn-id: http://svn.drobilla.net/lad/libslv2@4 a436a847-0d15-0410-975c-d299462d15a1 --- src/Makefile.am | 14 +++ src/plugin.c | 190 ++++++++++++++++++++++++++++++++++++++++ src/plugininstance.c | 100 +++++++++++++++++++++ src/pluginlist.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/port.c | 163 ++++++++++++++++++++++++++++++++++ src/query.c | 123 ++++++++++++++++++++++++++ src/util.c | 121 +++++++++++++++++++++++++ src/util.h | 53 +++++++++++ 8 files changed, 1007 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/plugin.c create mode 100644 src/plugininstance.c create mode 100644 src/pluginlist.c create mode 100644 src/port.c create mode 100644 src/query.c create mode 100644 src/util.c create mode 100644 src/util.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..5f6cea2 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = -std=c99 -I$(top_srcdir)/include -I$(top_srcdir) @RASQAL_CFLAGS@ -DLIBSLV2_SOURCE +AM_LDFLAGS = `pkg-config --libs rasqal` + +lib_LTLIBRARIES = libslv2.la +libslv2_la_LIBADD = @RASQAL_LIBS@ + +libslv2_la_SOURCES = \ + util.h \ + plugin.c \ + query.c \ + port.c \ + pluginlist.c \ + util.c \ + plugininstance.c diff --git a/src/plugin.c b/src/plugin.c new file mode 100644 index 0000000..27fb481 --- /dev/null +++ b/src/plugin.c @@ -0,0 +1,190 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + + +SLV2Plugin* +slv2_plugin_duplicate(const SLV2Plugin* p) +{ + assert(p); + struct _Plugin* result = malloc(sizeof(struct _Plugin)); + result->plugin_uri = p->plugin_uri; + result->bundle_url = p->bundle_url; + result->data_url = p->data_url; + result->lib_url = p->lib_url; + return result; +} + + +const unsigned char* +slv2_plugin_get_uri(const SLV2Plugin* p) +{ + assert(p); + return p->plugin_uri; +} + + +const unsigned char* +slv2_plugin_get_data_url(const SLV2Plugin* p) +{ + assert(p); + return p->data_url; +} + + +const unsigned char* +slv2_plugin_get_data_path(const SLV2Plugin* p) +{ + assert(p); + if (!strncmp((char*)p->data_url, "file://", 7)) + return (p->data_url) + 7; + else + return NULL; +} + + +const unsigned char* +slv2_plugin_get_library_url(const SLV2Plugin* p) +{ + assert(p); + return p->lib_url; +} + + +const unsigned char* +slv2_plugin_get_library_path(const SLV2Plugin* p) +{ + assert(p); + if (!strncmp((char*)p->lib_url, "file://", 7)) + return (p->lib_url) + 7; + else + return NULL; +} + + +bool +slv2_plugin_verify(const SLV2Plugin* plugin) +{ + // FIXME: finish this (properly) + /* + size_t num_values = 0; + + struct SLV2Property* prop = slv2_plugin_get_property(plugin, "doap:name"); + if (prop) { + num_values = prop->num_values; + free(prop); + } + if (num_values < 1) + return false; + + prop = slv2_plugin_get_property(plugin, "doap:license"); + num_values = prop->num_values; + free(prop); + if (num_values < 1) + return false; +*/ + return true; +} + + +unsigned char* +slv2_plugin_get_name(const SLV2Plugin* plugin) +{ +// FIXME: leak + unsigned char* result = NULL; + struct _Property* prop = slv2_plugin_get_property(plugin, "doap:name"); + + // FIXME: guaranteed to be the untagged one? + if (prop && prop->num_values >= 1) + result = prop->values[0]; + + return result; +} + + +SLV2Property +slv2_plugin_get_property(const SLV2Plugin* p, + const char* property) +{ + assert(p); + assert(property); + + /* + uchar* header = slv2_query_header(p); + uchar* lang_filter = slv2_query_lang_filter(U("?value")); + + uchar* query_string = ustrjoin( + header, + U("SELECT DISTINCT ?value FROM data: WHERE { \n"), + U("plugin: "), property, U(" ?value . \n"), + ((lang_filter != NULL) ? lang_filter : U("")), + "}", 0); + + free(header); + free(lang_filter);*/ + + rasqal_init(); + + rasqal_query_results* results = slv2_plugin_run_query(p, + U("SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: "), property, U(" ?value . \n" + "} \n"), 0); + + struct _Property* result = slv2_query_get_results(results); + + //free(query_string); + rasqal_free_query_results(results); + rasqal_finish(); + + return result; +} + + +unsigned long +slv2_plugin_get_num_ports(const SLV2Plugin* p) +{ + unsigned long result = 0; + + rasqal_init(); + + + rasqal_query_results* results = slv2_plugin_run_query(p, + U("SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: lv2:port ?value . \n" + "} \n"), 0); + + while (!rasqal_query_results_finished(results)) { + ++result; + rasqal_query_results_next(results); + } + + rasqal_free_query_results(results); + rasqal_finish(); + + return result; +} + diff --git a/src/plugininstance.c b/src/plugininstance.c new file mode 100644 index 0000000..40de08c --- /dev/null +++ b/src/plugininstance.c @@ -0,0 +1,100 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + + +SLV2Instance* +slv2_plugin_instantiate(const SLV2Plugin* plugin, + unsigned long sample_rate, + const LV2_Host_Feature** host_features) +{ + struct _Instance* result = NULL; + + const unsigned char* const lib_path = slv2_plugin_get_library_path(plugin); + if (!lib_path) + return NULL; + + void* lib = dlopen((char*)lib_path, RTLD_NOW); + if (!lib) { + printf("Unable to open library %s\n", lib_path); + return NULL; + } + + LV2_Descriptor_Function df = dlsym(lib, "lv2_descriptor"); + + if (!df) { + printf("Could not find symbol 'lv2_descriptor', " + "%s is not a LV2 plugin.\n", lib_path); + dlclose(lib); + return NULL; + } else { + // Search for plugin by URI + + const char* const bundle_path = url2path(plugin->bundle_url); + + for (unsigned long i=0; 1; ++i) { + const LV2_Descriptor* ld = df(i); + + if (!ld) { + printf("Did not find plugin %s in %s\n", + plugin->plugin_uri, plugin->lib_url); + dlclose(lib); + break; // return NULL + } else if (!strcmp(ld->URI, (char*)plugin->plugin_uri)) { + //printf("Found %s at index %ld in:\n\t%s\n\n", plugin->plugin_uri, i, lib_path); + + assert(ld->instantiate); + + // Create SLV2Instance to return + result = malloc(sizeof(struct _Instance)); + /*result->plugin = malloc(sizeof(struct _Plugin)); + memcpy(result->plugin, plugin, sizeof(struct _Plugin));*/ + result->descriptor = ld; + result->lib_handle = lib; + result->lv2_handle = ld->instantiate(ld, sample_rate, (char*)bundle_path, host_features); + break; + } + } + } + + return result; +} + + +void +slv2_instance_free(SLV2Instance* instance) +{ + struct _Instance* i = (struct _Instance*)instance; + i->descriptor->cleanup(i->lv2_handle); + i->descriptor = NULL; + dlclose(i->lib_handle); + i->lib_handle = NULL; + free(i); +} + + diff --git a/src/pluginlist.c b/src/pluginlist.c new file mode 100644 index 0000000..61e4c4b --- /dev/null +++ b/src/pluginlist.c @@ -0,0 +1,243 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + + +struct _PluginList* +slv2_list_new() +{ + struct _PluginList* result = malloc(sizeof(struct _PluginList)); + result->num_plugins = 0; + result->plugins = NULL; + return result; +} + + +void +slv2_list_free(SLV2List list) +{ + list->num_plugins = 0; + free(list->plugins); + free(list); +} + + +void +slv2_list_load_all(SLV2List list) +{ + assert(list != NULL); + + char* slv2_path = getenv("LV2_PATH"); + + if (!slv2_path) { + slv2_path = "~/.lv2:/usr/local/lib/lv2:usr/lib/lv2"; + + printf("$LV2_PATH is unset. Using default path %s\n", + slv2_path); + } + + slv2_list_load_path(list, slv2_path); +} + + +/* This is the parser for manifest.ttl */ +void +slv2_list_load_bundle(SLV2List list, + const unsigned char* bundle_base_uri) +{ + // FIXME: ew + unsigned char* manifest_uri = malloc( + (strlen((char*)bundle_base_uri) + strlen("manifest.ttl") + 2) * sizeof(unsigned char)); + memcpy(manifest_uri, bundle_base_uri, strlen((char*)bundle_base_uri)+1 * sizeof(unsigned char)); + if (bundle_base_uri[strlen((char*)bundle_base_uri)-1] == '/') + strcat((char*)manifest_uri, (char*)"manifest.ttl"); + else + strcat((char*)manifest_uri, (char*)"/manifest.ttl"); + + rasqal_init(); + rasqal_query_results *results; + raptor_uri *base_uri = raptor_new_uri(manifest_uri); + rasqal_query *rq = rasqal_new_query((const char*)"sparql", (const uchar*)base_uri); + + unsigned char* query_string = + U("PREFIX rdfs: \n" + "PREFIX : \n\n" + + "SELECT DISTINCT $plugin_uri $data_url $lib_url FROM <> WHERE { \n" + "$plugin_uri :binary $lib_url ; \n" + " rdfs:seeAlso $data_url . \n" + "} \n"); + + //printf("%s\n\n", query_string); + + rasqal_query_prepare(rq, (const uchar*)query_string, base_uri); + results = rasqal_query_execute(rq); + + while (!rasqal_query_results_finished(results)) { + + // Create a new plugin + struct _Plugin* new_plugin = malloc(sizeof(struct _Plugin)); + new_plugin->bundle_url = ustrdup(bundle_base_uri); + + rasqal_literal* literal = NULL; + + literal = rasqal_query_results_get_binding_value_by_name(results, + U("plugin_uri")); + if (literal) + new_plugin->plugin_uri = ustrdup(rasqal_literal_as_string(literal)); + + literal = rasqal_query_results_get_binding_value_by_name(results, + U("data_url")); + if (literal) + new_plugin->data_url = ustrdup(rasqal_literal_as_string(literal)); + + literal = rasqal_query_results_get_binding_value_by_name(results, + U("lib_url")); + if (literal) + new_plugin->lib_url = ustrdup(rasqal_literal_as_string(literal)); + + /* Add the plugin if it's valid */ + if (new_plugin->lib_url && new_plugin->data_url && new_plugin->plugin_uri + && slv2_plugin_verify(new_plugin)) { + /* Yes, this is disgusting, but it doesn't seem there's a way to know + * how many matches there are before iterating over them */ + list->num_plugins++; + list->plugins = realloc(list->plugins, + list->num_plugins * sizeof(struct _Plugin*)); + list->plugins[list->num_plugins-1] = new_plugin; + } + + rasqal_query_results_next(results); + } + + rasqal_free_query_results(results); + rasqal_free_query(rq); + raptor_free_uri(base_uri); + rasqal_finish(); + + free(manifest_uri); +} + + +/* Add all the plugins found in dir to list. + * (Private helper function, not exposed in public API) + */ +void +add_plugins_from_dir(SLV2List list, const char* dir) +{ + DIR* pdir = opendir(dir); + if (!pdir) + return; + + struct dirent* pfile; + while ((pfile = readdir(pdir))) { + if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) + continue; + + char* bundle_path = (char*)ustrjoin(U(dir), U("/"), U(pfile->d_name), 0); + char* bundle_url = (char*)ustrjoin(U("file://"), U(dir), U("/"), U(pfile->d_name), 0); + DIR* bundle_dir = opendir(bundle_path); + + if (bundle_dir != NULL) { + closedir(bundle_dir); + + slv2_list_load_bundle(list, U(bundle_url)); + //printf("Loaded bundle %s\n", bundle_url); + } + + free(bundle_path); + } + + closedir(pdir); +} + + +void +slv2_list_load_path(SLV2List list, + const char* slv2_path) +{ + + char* path = (char*)ustrjoin(U(slv2_path), U(":"), 0); + + char* dir = path; // Pointer into path + + // Go through string replacing ':' with '\0', using the substring, + // then replacing it with 'X' and moving on. eg strtok on crack. + while (strchr(path, ':') != NULL) { + char* delim = strchr(path, ':'); + *delim = '\0'; + + add_plugins_from_dir(list, dir); + + *delim = 'X'; + dir = delim + 1; + } + + //char* slv2_path = strdup(slv2 + + free(path); +} + + +unsigned long +slv2_list_get_length(const SLV2List list) +{ + assert(list != NULL); + return list->num_plugins; +} + + +SLV2Plugin* +slv2_list_get_plugin_by_uri(const SLV2List list, const unsigned char* uri) +{ + if (list->num_plugins > 0) { + assert(list->plugins != NULL); + + for (unsigned long i=0; i < list->num_plugins; ++i) + if (!strcmp((char*)list->plugins[i]->plugin_uri, (char*)uri)) + return list->plugins[i]; + } + + return NULL; +} + + +SLV2Plugin* +slv2_list_get_plugin_by_index(const SLV2List list, unsigned long index) +{ + if (list->num_plugins == 0) + return NULL; + + assert(list->plugins != NULL); + + return (index < list->num_plugins) ? list->plugins[index] : NULL; +} + diff --git a/src/port.c b/src/port.c new file mode 100644 index 0000000..e25eb2f --- /dev/null +++ b/src/port.c @@ -0,0 +1,163 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include "util.h" + +enum SLV2PortClass +slv2_port_get_class(SLV2Plugin* p, + unsigned long index) +{ + struct _Property* class = slv2_port_get_property(p, index, U("rdf:type")); + assert(class); + assert(class->num_values == 1); + assert(class->values); + + if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#InputControlRatePort")) + return SLV2_CONTROL_RATE_INPUT; + else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#OutputControlRatePort")) + return SLV2_CONTROL_RATE_OUTPUT; + else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#InputAudioRatePort")) + return SLV2_AUDIO_RATE_INPUT; + else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#OutputAudioRatePort")) + return SLV2_AUDIO_RATE_OUTPUT; + else + return SLV2_UNKNOWN_PORT_CLASS; +} + + +enum SLV2DataType +slv2_port_get_data_type(SLV2Plugin* p, + unsigned long index) +{ + SLV2Property type = slv2_port_get_property(p, index, U("lv2:datatype")); + assert(type); + assert(type->num_values == 1); + assert(type->values); + + if (!strcmp((char*)type->values[0], "http://lv2plug.in/ontology#float")) + return SLV2_DATA_TYPE_FLOAT; + else + return SLV2_UNKNOWN_DATA_TYPE; +} + + +SLV2Property +slv2_port_get_property(SLV2Plugin* p, + unsigned long index, + const uchar* property) +{ + assert(p); + assert(property); + + char index_str[4]; + snprintf(index_str, 4, "%ld", index); + + rasqal_init(); + + rasqal_query_results* results = slv2_plugin_run_query(p, + U("SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: lv2:port ?port \n" + "?port lv2:index "), index_str, U(" \n" + "?port "), property, U(" ?value . \n}\n"), 0); + + SLV2Property result = slv2_query_get_results(results); + + rasqal_free_query_results(results); + rasqal_finish(); + + return result; +} + + +uchar* +slv2_port_get_symbol(SLV2Plugin* p, unsigned long index) +{ + // FIXME: leaks + uchar* result = NULL; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:symbol")); + + if (prop && prop->num_values == 1) + result = (uchar*)strdup((char*)prop->values[0]); + free(prop); + + return result; +} + + +float +slv2_port_get_default_value(SLV2Plugin* p, + unsigned long index) +{ + // FIXME: do casting properly in the SPARQL query + + float result = 0.0f; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:default")); + + if (prop && prop->num_values == 1) + result = atof((char*)prop->values[0]); + + return result; +} + + +float +slv2_port_get_minimum_value(SLV2Plugin* p, + unsigned long index) +{ + // FIXME: do casting properly in the SPARQL query + + float result = 0.0f; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:minimum")); + + if (prop && prop->num_values == 1) + result = atof((char*)prop->values[0]); + + return result; +} + + +float +slv2_port_get_maximum_value(SLV2Plugin* p, + unsigned long index) +{ + // FIXME: do casting properly in the SPARQL query + + float result = 0.0f; + + SLV2Property prop + = slv2_port_get_property(p, index, U("lv2:maximum")); + + if (prop && prop->num_values == 1) + result = atof((char*)prop->values[0]); + + return result; +} + diff --git a/src/query.c b/src/query.c new file mode 100644 index 0000000..2030735 --- /dev/null +++ b/src/query.c @@ -0,0 +1,123 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include + + +unsigned char* +slv2_query_header(const SLV2Plugin* p) +{ + const unsigned char* plugin_uri = slv2_plugin_get_uri(p); + const unsigned char* data_file_url = slv2_plugin_get_data_url(p); + + unsigned char* query_string = ustrjoin(U( + "PREFIX rdf: \n" + "PREFIX rdfs: \n" + "PREFIX doap: \n" + "PREFIX lv2: \n" + "PREFIX plugin: <"), plugin_uri, U("> \n"), + U("PREFIX data: <"), data_file_url, U("> \n\n"), 0); + + return query_string; +} + + +unsigned char* +slv2_query_lang_filter(const uchar* variable) +{ + uchar* result = NULL; + uchar* const lang = (uchar*)getenv("LANG"); + if (lang) { + // FILTER( LANG(?value) = "en" || LANG(?value) = "" ) + result = ustrjoin( + //U("FILTER (lang(?value) = \""), lang, U("\")\n"), 0); + U("FILTER( lang(?value) = \""), lang, + U("\" || lang(?value) = \"\" )\n"), 0); + } + + return result; +} + + +rasqal_query_results* +slv2_plugin_run_query(const SLV2Plugin* p, + const uchar* first, ...) +{ + va_list args_list; + va_start(args_list, first); + va_list args_copy; + va_copy(args_copy, args_list); + + /* FIXME: Too much unecessary allocation */ + uchar* header = slv2_query_header(p); + uchar* args_str = vstrjoin(first, args_copy); + uchar* query_str = ustrjoin(header, args_str, 0); + + assert(p); + assert(query_str); + + rasqal_query *rq = rasqal_new_query("sparql", NULL); + + //printf("Query: \n%s\n\n", query_str); + + rasqal_query_prepare(rq, query_str, NULL); + rasqal_query_results* results = rasqal_query_execute(rq); + + rasqal_free_query(rq); + + free(query_str); + free(args_str); + free(header); + + return results; +} + + +SLV2Property +slv2_query_get_results(rasqal_query_results* results) +{ + struct _Property* result = NULL; + + if (rasqal_query_results_get_count(results) > 0) { + result = malloc(sizeof(struct _Property)); + result->num_values = 0; + result->values = NULL; + } + + while (!rasqal_query_results_finished(results)) { + + rasqal_literal* literal = + rasqal_query_results_get_binding_value_by_name(results, U("value")); + assert(literal != NULL); + + // Add value on to the array. Yes, this is disgusting. + result->num_values++; + // FIXME LEAK: + result->values = realloc(result->values, result->num_values * sizeof(char*)); + result->values[result->num_values-1] = ustrdup(rasqal_literal_as_string(literal)); + + rasqal_query_results_next(results); + } + + return result; +} + diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..55953b8 --- /dev/null +++ b/src/util.c @@ -0,0 +1,121 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _XOPEN_SOURCE 500 + +#include +#include +#include +#include +#include + + +void +ustrappend(uchar** dst, const uchar* suffix) +{ + assert(dst); + assert(*dst); + assert(suffix); + + const size_t new_length = strlen((char*)*dst) + strlen((char*)suffix) + 1; + *dst = realloc(*dst, (new_length * sizeof(char))); + assert(dst); + strcat((char*)*dst, (char*)suffix); +} + + +uchar* +ustrdup(const uchar* src) +{ + assert(src); + return (uchar*)strdup((char*)src); +} + + +uchar* +ustrjoin(const uchar* first, ...) +{ + // FIXME: this is horribly, awfully, disgracefully slow + + va_list args_list; + va_start(args_list, first); + + va_list args_copy; + va_copy(args_copy, args_list); + + uchar* result = vstrjoin(first, args_copy); + + //va_end(args_copy); + va_end(args_list); + + return result; + + /* + va_list args_list; + uchar* arg = NULL; + uchar* result = ustrdup(first); + + va_start(args_list, first); + + while ((arg = va_arg(args_list, uchar*)) != (uchar*)0) + ustrappend(&result, arg); + + va_end(args_list); + + return result;*/ +} + + +uchar* +vstrjoin(const uchar* first, va_list args_list) +{ + // FIXME: this is horribly, awfully, disgracefully slow + + uchar* arg = NULL; + uchar* result = ustrdup(first); + + while ((arg = va_arg(args_list, uchar*)) != NULL) + ustrappend(&result, arg); + + va_end(args_list); + + return result; +} + + + +/** Convert a URL to a local filesystem path (ie by chopping off the + * leading "file://". + * + * Returns NULL if URL is not a valid URL on the local filesystem. + * Result is simply a pointer in to \a url and must not be free()'d. + */ +const char* +url2path(const uchar* const url) +{ + /*assert(strlen((char*)url) > 8); + char* result = calloc(strlen((char*)url)-7+1, sizeof(char)); + strcpy(result, (char*)url+7); + return result;*/ + if (!strncmp((char*)url, "file://", 7)) + return (char*)url + 7; + else + return NULL; +} + + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..dbb7801 --- /dev/null +++ b/src/util.h @@ -0,0 +1,53 @@ +/* LibSLV2 + * Copyright (C) 2006 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __UTIL_H +#define __UTIL_H + +#include +#include + +/* Cast a char* to an unsigned char* (Used for string literals) */ +#define U(x) (unsigned char*)(x) + +/** Append \a suffix to \a *dst, reallocating \a dst as necessary. + * + * \a dst will (possibly) be freed, it must be dynamically allocated with malloc + * or NULL. + */ +void +ustrappend(uchar** dst, const uchar* suffix); + +uchar* +ustrdup(const uchar* src); + +/** Join all arguments into one string. + * + * Arguments are not modified, return value must be free()'d. + */ +uchar* +ustrjoin(const uchar* first, ...); + +uchar* +vstrjoin(const uchar* first, va_list args_list); + +const char* +url2path(const uchar* const url); + + +#endif -- cgit v1.2.1