summaryrefslogtreecommitdiff
path: root/libxklavier/xklavier_config_iso.c
diff options
context:
space:
mode:
authorSergey Udaltsov <svu@gnome.org>2008-04-21 22:37:33 +0000
committerSergey Udaltsov <svu@gnome.org>2008-04-21 22:37:33 +0000
commit068422e3a7a0aae5983cde5d57ce18e4fb5fa560 (patch)
tree10a9b45adc0bed36315c118235189d1587a78720 /libxklavier/xklavier_config_iso.c
parentae1528e30b7e0a50660a1c69e03b077ad1010dd9 (diff)
downloadlibxklavier-068422e3a7a0aae5983cde5d57ce18e4fb5fa560.tar.gz
adding country/language functions, new dep on iso-codes
Diffstat (limited to 'libxklavier/xklavier_config_iso.c')
-rw-r--r--libxklavier/xklavier_config_iso.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/libxklavier/xklavier_config_iso.c b/libxklavier/xklavier_config_iso.c
new file mode 100644
index 0000000..04434ab
--- /dev/null
+++ b/libxklavier/xklavier_config_iso.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2002-2006 Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <errno.h>
+#include <locale.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#include "xklavier_private.h"
+
+#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
+#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
+
+static GHashTable *country_code_names = NULL;
+static GHashTable *lang_code_names = NULL;
+
+typedef struct {
+ const gchar *domain;
+ const gchar *attr_names[];
+} LookupParams;
+
+typedef struct {
+ GHashTable *code_names;
+ const gchar *tag_name;
+ LookupParams *params;
+} CodeBuildStruct;
+
+static LookupParams countryLookup = { "iso_3166", {"alpha_2_code", NULL} };
+static LookupParams languageLookup =
+ { "iso_639", {"iso_639_2B_code", "iso_639_2T_code", NULL} };
+
+static void
+iso_codes_parse_start_tag(GMarkupParseContext * ctx,
+ const gchar * element_name,
+ const gchar ** attr_names,
+ const gchar ** attr_values,
+ gpointer user_data, GError ** error)
+{
+ const gchar *name;
+ const gchar **san = attr_names, **sav = attr_values;
+ CodeBuildStruct *cbs = (CodeBuildStruct *) user_data;
+
+ /* Is this the tag we are looking for? */
+ if (!g_str_equal(element_name, cbs->tag_name) ||
+ attr_names == NULL || attr_values == NULL) {
+ return;
+ }
+
+ name = NULL;
+
+ /* What would be the value? */
+ while (*attr_names && *attr_values) {
+ if (g_str_equal(*attr_names, "name")) {
+ name = *attr_values;
+ break;
+ }
+
+ attr_names++;
+ attr_values++;
+ }
+
+ if (!name) {
+ return;
+ }
+
+ attr_names = san;
+ attr_values = sav;
+
+ /* Walk again the attributes */
+ while (*attr_names && *attr_values) {
+ const gchar **attr = cbs->params->attr_names;
+ /* Look through all the attributess we are interested in */
+ while (*attr) {
+ if (g_str_equal(*attr_names, *attr)) {
+ if (**attr_values) {
+ g_hash_table_insert(cbs->
+ code_names,
+ g_strdup
+ (*attr_values),
+ g_strdup
+ (name));
+ }
+ }
+ attr++;
+ }
+
+ attr_names++;
+ attr_values++;
+ }
+}
+
+static GHashTable *
+iso_code_names_init(LookupParams * params)
+{
+ GError *err = NULL;
+ gchar *buf, *filename, *tag_name;
+ gsize buf_len;
+ CodeBuildStruct cbs;
+
+ GHashTable *ht = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ tag_name = g_strdup_printf("%s_entry", params->domain);
+
+ cbs.code_names = ht;
+ cbs.tag_name = tag_name;
+ cbs.params = params;
+
+ bindtextdomain(params->domain, ISO_CODES_LOCALESDIR);
+ bind_textdomain_codeset(params->domain, "UTF-8");
+
+ filename =
+ g_strdup_printf("%s/%s.xml", ISO_CODES_DATADIR,
+ params->domain);
+ if (g_file_get_contents(filename, &buf, &buf_len, &err)) {
+ GMarkupParseContext *ctx;
+ GMarkupParser parser = {
+ iso_codes_parse_start_tag,
+ NULL, NULL, NULL, NULL
+ };
+
+ ctx = g_markup_parse_context_new(&parser, 0, &cbs, NULL);
+ if (!g_markup_parse_context_parse(ctx, buf, buf_len, &err)) {
+ g_warning("Failed to parse '%s/%s.xml': %s",
+ ISO_CODES_DATADIR,
+ params->domain, err->message);
+ g_error_free(err);
+ }
+
+ g_markup_parse_context_free(ctx);
+ g_free(buf);
+ } else {
+ g_warning("Failed to load '%s/%s.xml': %s",
+ ISO_CODES_DATADIR, params->domain, err->message);
+ g_error_free(err);
+ }
+ g_free(filename);
+ g_free(tag_name);
+
+ return ht;
+}
+
+typedef const gchar *(*DescriptionGetterFunc) (const gchar * code);
+
+const gchar *
+get_language_iso_code(const gchar * code)
+{
+ const gchar *name;
+
+ if (!lang_code_names) {
+ lang_code_names = iso_code_names_init(&languageLookup);
+ }
+
+ name = g_hash_table_lookup(lang_code_names, code);
+ if (!name) {
+ return NULL;
+ }
+
+ return dgettext("iso_639", name);
+}
+
+const gchar *
+get_country_iso_code(const gchar * code)
+{
+ const gchar *name;
+
+ if (!country_code_names) {
+ country_code_names = iso_code_names_init(&countryLookup);
+ }
+
+ name = g_hash_table_lookup(country_code_names, code);
+ if (!name) {
+ return NULL;
+ }
+
+ return dgettext("iso_3166", name);
+}
+
+static void
+xkl_config_registry_foreach_iso_code(XklConfigRegistry * config,
+ ConfigItemProcessFunc func,
+ const gchar * xpath_exprs[],
+ DescriptionGetterFunc dgf,
+ gpointer data)
+{
+ GHashTable *code_pairs;
+ GHashTableIter iter;
+ xmlXPathObjectPtr xpath_obj;
+ const gchar **xpath_expr;
+ gpointer key, value;
+ XklConfigItem *ci;
+
+ if (!xkl_config_registry_is_initialized(config))
+ return;
+
+ code_pairs = g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (xpath_expr = xpath_exprs; *xpath_expr; xpath_expr++) {
+ xpath_obj =
+ xmlXPathEval((unsigned char *) *xpath_expr,
+ xkl_config_registry_priv(config,
+ xpath_context));
+ if (xpath_obj != NULL) {
+ gint ni;
+ xmlNodeSetPtr nodes = xpath_obj->nodesetval;
+ if (nodes != NULL) {
+ xmlNodePtr *pnode = nodes->nodeTab;
+ for (ni = nodes->nodeNr; --ni >= 0;) {
+ const gchar *iso_code =
+ (const gchar *) (*pnode)->
+ children->content;
+ const gchar *description =
+ dgf(iso_code);
+ if (description)
+ g_hash_table_insert
+ (code_pairs,
+ g_strdup
+ (iso_code),
+ g_strdup
+ (description));
+ pnode++;
+ }
+ }
+ xmlXPathFreeObject(xpath_obj);
+ }
+ }
+
+ g_hash_table_iter_init(&iter, code_pairs);
+ ci = xkl_config_item_new();
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ g_snprintf(ci->name, sizeof(ci->name),
+ (const gchar *) key);
+ g_snprintf(ci->description, sizeof(ci->description),
+ (const gchar *) value);
+ func(config, ci, data);
+ }
+ g_object_unref(G_OBJECT(ci));
+ g_hash_table_unref(code_pairs);
+}
+
+void
+xkl_config_registry_foreach_country(XklConfigRegistry *
+ config,
+ ConfigItemProcessFunc
+ func, gpointer data)
+{
+ const gchar *xpath_exprs[] = {
+ XKBCR_LAYOUT_PATH "/configItem/countryList/iso3166Id",
+ XKBCR_LAYOUT_PATH "/configItem/name",
+ NULL
+ };
+
+ xkl_config_registry_foreach_iso_code(config, func, xpath_exprs,
+ get_country_iso_code, data);
+}
+
+void
+xkl_config_registry_foreach_language(XklConfigRegistry *
+ config,
+ ConfigItemProcessFunc
+ func, gpointer data)
+{
+ const gchar *xpath_exprs[] = {
+ XKBCR_LAYOUT_PATH "/configItem/languageList/iso639Id",
+ NULL
+ };
+
+ xkl_config_registry_foreach_iso_code(config, func, xpath_exprs,
+ get_language_iso_code, data);
+}