/* SLV2 * Copyright (C) 2007-2011 David 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 "slv2_internal.h" SLV2Matches slv2_plugin_find_statements(SLV2Plugin plugin, SLV2Node subject, SLV2Node predicate, SLV2Node object) { slv2_plugin_load_if_necessary(plugin); SordQuad pat = { subject, predicate, object, NULL }; return sord_find(plugin->world->model, pat); } typedef enum { SLV2_LANG_MATCH_NONE, ///< Language does not match at all SLV2_LANG_MATCH_PARTIAL, ///< Partial (language, but not country) match SLV2_LANG_MATCH_EXACT ///< Exact (language and country) match } SLV2LangMatch; static SLV2LangMatch slv2_lang_matches(const char* a, const char* b) { if (!strcmp(a, b)) { return SLV2_LANG_MATCH_EXACT; } const char* a_dash = strchr(a, '-'); const size_t a_lang_len = a_dash ? (a_dash - a) : 0; const char* b_dash = strchr(b, '-'); const size_t b_lang_len = b_dash ? (b_dash - b) : 0; if (a_lang_len && b_lang_len) { if (a_lang_len == b_lang_len && !strncmp(a, b, a_lang_len)) { return SLV2_LANG_MATCH_PARTIAL; // e.g. a="en-gb", b="en-ca" } } else if (a_lang_len && !strncmp(a, b, a_lang_len)) { return SLV2_LANG_MATCH_PARTIAL; // e.g. a="en", b="en-ca" } else if (b_lang_len && !strncmp(a, b, b_lang_len)) { return SLV2_LANG_MATCH_PARTIAL; // e.g. a="en-ca", b="en" } return SLV2_LANG_MATCH_NONE; } SLV2Values slv2_values_from_stream_objects_i18n(SLV2Plugin p, SLV2Matches stream) { SLV2Values values = slv2_values_new(); SLV2Node nolang = NULL; // Untranslated value SLV2Node partial = NULL; // Partial language match char* syslang = slv2_get_lang(); FOREACH_MATCH(stream) { SLV2Node value = slv2_match_object(stream); if (sord_node_get_type(value) == SORD_LITERAL) { const char* lang = sord_literal_get_lang(value); SLV2LangMatch lm = SLV2_LANG_MATCH_NONE; if (lang) { lm = (syslang) ? slv2_lang_matches(lang, syslang) : SLV2_LANG_MATCH_PARTIAL; } else { nolang = value; if (!syslang) { lm = SLV2_LANG_MATCH_EXACT; } } if (lm == SLV2_LANG_MATCH_EXACT) { // Exact language match, add to results slv2_array_append(values, slv2_value_new_from_node(p->world, value)); } else if (lm == SLV2_LANG_MATCH_PARTIAL) { // Partial language match, save in case we find no exact partial = value; } } else { slv2_array_append(values, slv2_value_new_from_node(p->world, value)); } } slv2_match_end(stream); free(syslang); if (slv2_values_size(values) > 0) { return values; } SLV2Node best = nolang; if (syslang && partial) { // Partial language match for system language best = partial; } else if (!best) { // No languages matches at all, and no untranslated value // Use any value, if possible best = partial; } if (best) { slv2_array_append(values, slv2_value_new_from_node(p->world, best)); } else { // No matches whatsoever slv2_values_free(values); values = NULL; } return values; } SLV2Values slv2_values_from_stream_objects(SLV2Plugin p, SLV2Matches stream) { if (slv2_matches_end(stream)) { slv2_match_end(stream); return NULL; } else if (p->world->filter_language) { return slv2_values_from_stream_objects_i18n(p, stream); } else { SLV2Values values = slv2_values_new(); FOREACH_MATCH(stream) { slv2_array_append( values, slv2_value_new_from_node( p->world, slv2_match_object(stream))); } slv2_match_end(stream); return values; } }