From 0b6bdcce6cea21909553a334629a5b3d004bd553 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 11 Feb 2011 23:37:12 +0000 Subject: Add support for boolean values. Replace slv2_world_filter_language with extensible option system (slv2_world_set_option). git-svn-id: http://svn.drobilla.net/lad/trunk/slv2@2923 a436a847-0d15-0410-975c-d299462d15a1 --- ChangeLog | 3 ++- slv2/value.h | 26 ++++++++++++++++++++++++++ slv2/world.h | 11 +++++++++-- src/slv2_internal.h | 5 ++++- src/value.c | 47 +++++++++++++++++++++++++++++++++++++++++------ src/world.c | 39 ++++++++++++++++++++++++++++----------- test/slv2_test.c | 30 ++++++++++++++++++++++++++---- 7 files changed, 136 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4861b46..3ef6154 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,7 +7,8 @@ slv2 (UNRELEASED) unstable; urgency=low * Remove use of redland (librdf) in favour of Serd and Sord * Remove slv2_world_new_using_rdf_world and slv2_plugin_query_sparql * Remove separate i18n versions of functions and implement i18n everywhere - * Add slv2_world_filter_language ( to optionally disable i18n). + * Add slv2_world_set_option for runtime configuration of SLV2 features. + * Add SLV2_OPTION_FILTER_LANG option (to optionally disable i18n). * *** API BREAK *** -- David Robillard (UNRELEASED) diff --git a/slv2/value.h b/slv2/value.h index 541c3de..84c5b94 100644 --- a/slv2/value.h +++ b/slv2/value.h @@ -62,6 +62,14 @@ SLV2_API SLV2Value slv2_value_new_float(SLV2World world, float val); +/** Create a new boolean value. + * + * Returned value must be freed by caller with slv2_value_free. + */ +SLV2_API +SLV2Value +slv2_value_new_bool(SLV2World world, bool val); + /** Free an SLV2Value. */ SLV2_API @@ -197,6 +205,24 @@ SLV2_API int slv2_value_as_int(SLV2Value value); +/** Return whether this value is a boolean. + * + * Time = O(1) + */ +SLV2_API +bool +slv2_value_is_bool(SLV2Value value); + +/** Return \a value as a bool. + * + * Valid to call only if slv2_value_is_bool(\a value) returns true. + * + * Time = O(1) + */ +SLV2_API +bool +slv2_value_as_bool(SLV2Value value); + /** @} */ #ifdef __cplusplus diff --git a/slv2/world.h b/slv2/world.h index 15dddf8..8bd4b35 100644 --- a/slv2/world.h +++ b/slv2/world.h @@ -52,14 +52,21 @@ SLV2_API SLV2World slv2_world_new(void); -/** Enable/disable language filtering for @a world. +/** Enable/disable language filtering. + * Language filtering applies to any functions that return (a) value(s). * With filtering enabled, SLV2 will automatically return the best value(s) * for the current LANG. With filtering disabled, all matching values will * be returned regardless of language tag. Filtering is enabled by default. */ +#define SLV2_OPTION_FILTER_LANG "http://drobilla.net/ns/slv2#filter-lang" + +/** Set an SLV2 option for @a world. + */ SLV2_API void -slv2_world_filter_language(SLV2World world, bool filter); +slv2_world_set_option(SLV2World world, + const char* uri, + const SLV2Value value); /** Destroy the world, mwahaha. * diff --git a/src/slv2_internal.h b/src/slv2_internal.h index f8ba415..e5aac33 100644 --- a/src/slv2_internal.h +++ b/src/slv2_internal.h @@ -214,8 +214,9 @@ struct _SLV2World { SLV2Node rdfs_subclassof_node; SLV2Node slv2_bundleuri_node; SLV2Node slv2_dmanifest_node; - SLV2Node xsd_integer_node; + SLV2Node xsd_boolean_node; SLV2Node xsd_decimal_node; + SLV2Node xsd_integer_node; SLV2Value doap_name_val; SLV2Value lv2_name_val; bool filter_language; @@ -256,6 +257,7 @@ typedef enum _SLV2ValueType { SLV2_VALUE_STRING, SLV2_VALUE_INT, SLV2_VALUE_FLOAT, + SLV2_VALUE_BOOL, SLV2_VALUE_BLANK } SLV2ValueType; @@ -265,6 +267,7 @@ struct _SLV2Value { union { int int_val; float float_val; + bool bool_val; SLV2Node uri_val; } val; }; diff --git a/src/value.c b/src/value.c index e08b7fd..dc75e07 100644 --- a/src/value.c +++ b/src/value.c @@ -57,13 +57,16 @@ slv2_value_set_numerics_from_string(SLV2Value val) setlocale(LC_NUMERIC, locale); free(locale); break; + case SLV2_VALUE_BOOL: + val->val.bool_val = (!strcmp(val->str_val, "true")); + break; } } -/** Note that if @a type is numeric, slv2_value_set_numerics_from_string MUST be - * called or the returned value will be corrupt! It is not automatically - * called from here to avoid the parsing overhead and imprecision when the - * true numeric value is already known. +/** Note that if @a type is numeric or boolean, the returned value is corrupt + * until slv2_value_set_numerics_from_string is called. It is not + * automatically called from here to avoid overhead and imprecision when the + * exact string value is known. */ SLV2Value slv2_value_new(SLV2World world, SLV2ValueType type, const char* str) @@ -82,6 +85,7 @@ slv2_value_new(SLV2World world, SLV2ValueType type, const char* str) case SLV2_VALUE_STRING: case SLV2_VALUE_INT: case SLV2_VALUE_FLOAT: + case SLV2_VALUE_BOOL: val->str_val = strdup(str); break; } @@ -108,10 +112,12 @@ slv2_value_new_from_node(SLV2World world, SordNode node) case SORD_LITERAL: datatype_uri = sord_literal_get_datatype(node); if (datatype_uri) { - if (sord_node_equals(datatype_uri, world->xsd_integer_node)) - type = SLV2_VALUE_INT; + if (sord_node_equals(datatype_uri, world->xsd_boolean_node)) + type = SLV2_VALUE_BOOL; else if (sord_node_equals(datatype_uri, world->xsd_decimal_node)) type = SLV2_VALUE_FLOAT; + else if (sord_node_equals(datatype_uri, world->xsd_integer_node)) + type = SLV2_VALUE_INT; else SLV2_ERRORF("Unknown datatype %s\n", sord_node_get_string(datatype_uri)); } @@ -119,6 +125,7 @@ slv2_value_new_from_node(SLV2World world, SordNode node) switch (result->type) { case SLV2_VALUE_INT: case SLV2_VALUE_FLOAT: + case SLV2_VALUE_BOOL: slv2_value_set_numerics_from_string(result); default: break; @@ -171,6 +178,15 @@ slv2_value_new_float(SLV2World world, float val) return ret; } +SLV2_API +SLV2Value +slv2_value_new_bool(SLV2World world, bool val) +{ + SLV2Value ret = slv2_value_new(world, SLV2_VALUE_BOOL, val ? "true" : "false"); + ret->val.bool_val = val; + return ret; +} + SLV2_API SLV2Value slv2_value_duplicate(SLV2Value val) @@ -228,6 +244,8 @@ slv2_value_equals(SLV2Value value, SLV2Value other) return (value->val.int_val == other->val.int_val); case SLV2_VALUE_FLOAT: return (value->val.float_val == other->val.float_val); + case SLV2_VALUE_BOOL: + return (value->val.bool_val == other->val.bool_val); } return false; /* shouldn't get here */ @@ -254,6 +272,7 @@ slv2_value_get_turtle_token(SLV2Value value) break; case SLV2_VALUE_STRING: case SLV2_VALUE_QNAME_UNUSED: + case SLV2_VALUE_BOOL: result = strdup(value->str_val); break; case SLV2_VALUE_INT: @@ -383,3 +402,19 @@ slv2_value_as_float(SLV2Value value) else // slv2_value_is_int(value) return (float)value->val.int_val; } + +SLV2_API +bool +slv2_value_is_bool(SLV2Value value) +{ + return (value && value->type == SLV2_VALUE_BOOL); +} + +SLV2_API +bool +slv2_value_as_bool(SLV2Value value) +{ + assert(value); + assert(slv2_value_is_bool(value)); + return value->val.bool_val; +} diff --git a/src/world.c b/src/world.c index f690909..a1ed8c9 100644 --- a/src/world.c +++ b/src/world.c @@ -83,8 +83,9 @@ slv2_world_new() world->rdfs_subclassof_node = NEW_URI(SLV2_NS_RDFS "subClassOf"); world->slv2_bundleuri_node = NEW_URI(SLV2_NS_SLV2 "bundleURI"); world->slv2_dmanifest_node = NEW_URI(SLV2_NS_SLV2 "dynamic-manifest"); - world->xsd_integer_node = NEW_URI(SLV2_NS_XSD "integer"); + world->xsd_boolean_node = NEW_URI(SLV2_NS_XSD "boolean"); world->xsd_decimal_node = NEW_URI(SLV2_NS_XSD "decimal"); + world->xsd_integer_node = NEW_URI(SLV2_NS_XSD "integer"); world->doap_name_val = NEW_URI_VAL(SLV2_NS_DOAP "name"); world->lv2_name_val = NEW_URI_VAL(SLV2_NS_LV2 "name"); @@ -138,20 +139,26 @@ slv2_world_free(SLV2World world) slv2_node_free(world->rdfs_class_node); slv2_node_free(world->slv2_bundleuri_node); slv2_node_free(world->slv2_dmanifest_node); - slv2_node_free(world->xsd_integer_node); + slv2_node_free(world->xsd_boolean_node); slv2_node_free(world->xsd_decimal_node); + slv2_node_free(world->xsd_integer_node); slv2_value_free(world->doap_name_val); slv2_value_free(world->lv2_name_val); - /* - for (unsigned i = 0; i < ((GPtrArray*)world->plugins)->len; ++i) - slv2_plugin_free(g_ptr_array_index((GPtrArray*)world->plugins, i)); - g_ptr_array_unref(world->plugins); - */ +#define SLV2_FOREACH(iter, seq) \ + for (GSequenceIter* (iter) = g_sequence_get_begin_iter(seq); \ + (iter) != g_sequence_get_end_iter(seq); \ + (iter) = g_sequence_iter_next(iter)) + + SLV2_FOREACH(i, world->plugins) { + SLV2Plugin p = g_sequence_get(i); + slv2_plugin_free(p); + } + g_sequence_free(world->plugins); world->plugins = NULL; - //g_ptr_array_unref(world->plugin_classes); + g_sequence_free(world->plugin_classes); world->plugin_classes = NULL; sord_free(world->model); @@ -164,12 +171,20 @@ slv2_world_free(SLV2World world) SLV2_API void -slv2_world_filter_language(SLV2World world, bool filter) +slv2_world_set_option(SLV2World world, + const char* option, + const SLV2Value value) { - world->filter_language = filter; + if (!strcmp(option, SLV2_OPTION_FILTER_LANG)) { + if (slv2_value_is_bool(value)) { + world->filter_language = slv2_value_as_bool(value); + return; + } + } else { + SLV2_WARNF("Unrecognized or invalid option `%s'\n", option); + } } - static SLV2Matches slv2_world_find_statements(SLV2World world, Sord model, @@ -434,6 +449,8 @@ slv2_world_load_bundle(SLV2World world, SLV2Value bundle_uri) sord_add(world->model, bundle_uri_tup); } slv2_match_end(spec_results); + + serd_node_free(&manifest_uri); } // Expand POSIX things in path (particularly ~) diff --git a/test/slv2_test.c b/test/slv2_test.c index a7f7faf..8c1f790 100644 --- a/test/slv2_test.c +++ b/test/slv2_test.c @@ -557,6 +557,8 @@ test_plugin() "lv2:optionalFeature lv2:hardRTCapable ; " "lv2:requiredFeature ; " ":foo 1.6180 ; " + ":bar true ; " + ":baz false ; " "doap:maintainer [ foaf:name \"David Robillard\" ; " " foaf:homepage ; foaf:mbox ] ; " "lv2:port [ " @@ -662,13 +664,27 @@ test_plugin() slv2_values_free(required); slv2_values_free(optional); - SLV2Value foo_p = slv2_value_new_uri(world, "http://example.org/foo"); - SLV2Values foos = slv2_plugin_get_value(plug, foo_p); + SLV2Value foo_p = slv2_value_new_uri(world, "http://example.org/foo"); + SLV2Values foos = slv2_plugin_get_value(plug, foo_p); TEST_ASSERT(slv2_values_size(foos) == 1); TEST_ASSERT(fabs(slv2_value_as_float(slv2_values_get_at(foos, 0)) - 1.6180) < FLT_EPSILON); slv2_value_free(foo_p); slv2_values_free(foos); + SLV2Value bar_p = slv2_value_new_uri(world, "http://example.org/bar"); + SLV2Values bars = slv2_plugin_get_value(plug, bar_p); + TEST_ASSERT(slv2_values_size(bars) == 1); + TEST_ASSERT(slv2_value_as_bool(slv2_values_get_at(bars, 0)) == true); + slv2_value_free(bar_p); + slv2_values_free(bars); + + SLV2Value baz_p = slv2_value_new_uri(world, "http://example.org/baz"); + SLV2Values bazs = slv2_plugin_get_value(plug, baz_p); + TEST_ASSERT(slv2_values_size(bazs) == 1); + TEST_ASSERT(slv2_value_as_bool(slv2_values_get_at(bazs, 0)) == false); + slv2_value_free(baz_p); + slv2_values_free(bazs); + SLV2Value author_name = slv2_plugin_get_author_name(plug); TEST_ASSERT(!strcmp(slv2_value_as_string(author_name), "David Robillard")); slv2_value_free(author_name); @@ -854,11 +870,17 @@ test_port() "store")); slv2_values_free(names); - slv2_world_filter_language(world, false); + SLV2Value true_val = slv2_value_new_bool(world, true); + SLV2Value false_val = slv2_value_new_bool(world, false); + + slv2_world_set_option(world, SLV2_OPTION_FILTER_LANG, false_val); names = slv2_port_get_value(plug, p, name_p); TEST_ASSERT(slv2_values_size(names) == 4); slv2_values_free(names); - slv2_world_filter_language(world, true); + slv2_world_set_option(world, SLV2_OPTION_FILTER_LANG, true_val); + + slv2_value_free(false_val); + slv2_value_free(true_val); names = slv2_port_get_value(plug, ep, name_p); TEST_ASSERT(slv2_values_size(names) == 1); -- cgit v1.2.1