summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkira TAGOH <akira@tagoh.org>2011-12-28 14:16:32 +0900
committerAkira TAGOH <akira@tagoh.org>2011-12-28 14:16:32 +0900
commitfa2c708c3596ad8fe1b72b39d92126a8083a97b9 (patch)
tree87de191b3143d8020de48470aea3ae5e9f1cf7c1
parent2c43f4ec493416718c82a7a5824e85d0a330ab66 (diff)
Add script database handler
-rw-r--r--liblangtag/Makefile.am2
-rw-r--r--liblangtag/lt-script.c374
-rw-r--r--liblangtag/lt-script.h45
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/script.c56
5 files changed, 482 insertions, 0 deletions
diff --git a/liblangtag/Makefile.am b/liblangtag/Makefile.am
index 9b307b7..002f7e9 100644
--- a/liblangtag/Makefile.am
+++ b/liblangtag/Makefile.am
@@ -36,6 +36,7 @@ BUILT_FILES = \
liblangtag_public_headers = \
lt-error.h \
lt-lang.h \
+ lt-script.h \
$(NULL)
liblangtag_private_headers = \
lt-mem.h \
@@ -52,6 +53,7 @@ liblangtag_sources = \
lt-error.c \
lt-lang.c \
lt-mem.c \
+ lt-script.c \
$(NULL)
#
stamp_files = \
diff --git a/liblangtag/lt-script.c b/liblangtag/lt-script.c
new file mode 100644
index 0000000..0a38823
--- /dev/null
+++ b/liblangtag/lt-script.c
@@ -0,0 +1,374 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * lt-script.c
+ * Copyright (C) 2011 Akira TAGOH
+ *
+ * Authors:
+ * Akira TAGOH <akira@tagoh.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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include "lt-error.h"
+#include "lt-mem.h"
+#include "lt-script.h"
+
+
+typedef struct _lt_script_entry_t {
+ lt_mem_t parent;
+ gchar *name;
+ gchar *alpha_4_code;
+ gchar *numeric_code;
+} lt_script_entry_t;
+
+struct _lt_script_t {
+ lt_mem_t parent;
+ GHashTable *entries;
+};
+
+/*< private >*/
+static lt_script_entry_t *
+lt_script_entry_new(void)
+{
+ lt_script_entry_t *retval = lt_mem_alloc_object(sizeof (lt_script_entry_t));
+
+ return retval;
+}
+
+static lt_script_entry_t *
+lt_script_entry_ref(lt_script_entry_t *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return lt_mem_ref(&entry->parent);
+}
+
+static void
+lt_script_entry_unref(lt_script_entry_t *entry)
+{
+ if (entry)
+ lt_mem_unref(&entry->parent);
+}
+
+static void
+lt_script_entry_set_name(lt_script_entry_t *entry,
+ const gchar *name)
+{
+ g_return_if_fail (entry != NULL);
+ g_return_if_fail (name != NULL);
+
+ if (entry->name)
+ lt_mem_remove_ref(&entry->parent, entry->name);
+ entry->name = g_strdup(name);
+ lt_mem_add_ref(&entry->parent, entry->name,
+ (lt_destroy_func_t)g_free);
+}
+
+static void
+lt_script_entry_set_code(lt_script_entry_t *entry,
+ const gchar *code)
+{
+ gsize i, len;
+ gboolean is_numeric_code = TRUE;
+
+ g_return_if_fail (entry != NULL);
+ g_return_if_fail (code != NULL);
+
+ len = strlen(code);
+ for (i = 0; i < len; i++) {
+ if (code[i] < '0' || code[i] > '9') {
+ is_numeric_code = FALSE;
+ break;
+ }
+ }
+ if (is_numeric_code) {
+ if (entry->numeric_code)
+ lt_mem_remove_ref(&entry->parent, entry->numeric_code);
+ entry->numeric_code = g_strdup(code);
+ lt_mem_add_ref(&entry->parent, entry->numeric_code,
+ (lt_destroy_func_t)g_free);
+ } else {
+ if (entry->alpha_4_code)
+ lt_mem_remove_ref(&entry->parent, entry->alpha_4_code);
+ entry->alpha_4_code = g_strdup(code);
+ lt_mem_add_ref(&entry->parent, entry->alpha_4_code,
+ (lt_destroy_func_t)g_free);
+ }
+}
+
+static const gchar *
+lt_script_entry_get_name(const lt_script_entry_t *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return entry->name;
+}
+
+static const gchar *
+lt_script_entry_get_alpha_code(const lt_script_entry_t *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return entry->alpha_4_code;
+}
+
+static const gchar *
+lt_script_entry_get_numeric_code(const lt_script_entry_t *entry)
+{
+ g_return_val_if_fail (entry != NULL, NULL);
+
+ return entry->numeric_code;
+}
+
+static gboolean
+lt_script_parse(lt_script_t *script,
+ GError **error)
+{
+ gchar *iso15924;
+ xmlParserCtxtPtr xmlparser = xmlNewParserCtxt();
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr xctxt = NULL;
+ xmlXPathObjectPtr xobj = NULL;
+ gboolean retval = TRUE;
+ GError *err = NULL;
+ int i, n;
+
+ g_return_val_if_fail (script != NULL, FALSE);
+
+ iso15924 = g_build_filename(ISO_PREFIX, "iso_15924.xml", NULL);
+
+ if (!xmlparser) {
+ g_set_error(&err, LT_ERROR, LT_ERR_OOM,
+ "Unable to create an instance of xmlParserCtxt.");
+ goto bail;
+ }
+ doc = xmlCtxtReadFile(xmlparser, iso15924, "UTF-8", 0);
+ if (!doc) {
+ g_set_error(&err, LT_ERROR, LT_ERR_FAIL_ON_XML,
+ "Unable to read the xml file: %s",
+ iso15924);
+ goto bail;
+ }
+ xctxt = xmlXPathNewContext(doc);
+ if (!xctxt) {
+ g_set_error(&err, LT_ERROR, LT_ERR_OOM,
+ "Unable to create an instance of xmlXPathContextPtr.");
+ goto bail;
+ }
+ xobj = xmlXPathEvalExpression((const xmlChar *)"/iso_15924_entries/iso_15924_entry", xctxt);
+ if (!xobj) {
+ g_set_error(&err, LT_ERROR, LT_ERR_FAIL_ON_XML,
+ "No valid elements for %s",
+ doc->name);
+ goto bail;
+ }
+ n = xmlXPathNodeSetGetLength(xobj->nodesetval);
+
+ for (i = 0; i < n; i++) {
+ xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
+ xmlChar *p;
+ lt_script_entry_t *le;
+
+ if (!ent) {
+ g_set_error(&err, LT_ERROR, LT_ERR_FAIL_ON_XML,
+ "Unable to obtain the xml node via XPath.");
+ goto bail;
+ }
+ le = lt_script_entry_new();
+ if (!le) {
+ g_set_error(&err, LT_ERROR, LT_ERR_OOM,
+ "Unable to create an instance of lt_script_entry_t.");
+ goto bail;
+ }
+ p = xmlGetProp(ent, (const xmlChar *)"name");
+ lt_script_entry_set_name(le, (const gchar *)p);
+ if (g_strcmp0((const gchar *)p, lt_script_entry_get_name(le)) != 0) {
+ g_warning("buggy 'name' entry in %s: %s",
+ iso15924, p);
+ xmlFree(p);
+ goto bail1;
+ }
+ xmlFree(p);
+ g_hash_table_replace(script->entries,
+ (gchar *)lt_script_entry_get_name(le),
+ lt_script_entry_ref(le));
+ p = xmlGetProp(ent, (const xmlChar *)"alpha_4_code");
+ lt_script_entry_set_code(le, (const gchar *)p);
+ if (g_strcmp0((const gchar *)p, lt_script_entry_get_alpha_code(le)) != 0) {
+ g_warning("buggy 'alpha_4_code' entry for %s in %s: %s",
+ lt_script_entry_get_name(le),
+ iso15924, p);
+ xmlFree(p);
+ goto bail1;
+ }
+ xmlFree(p);
+ g_hash_table_replace(script->entries,
+ (gchar *)lt_script_entry_get_alpha_code(le),
+ lt_script_entry_ref(le));
+ p = xmlGetProp(ent, (const xmlChar *)"numeric_code");
+ lt_script_entry_set_code(le, (const gchar *)p);
+ if (g_strcmp0((const gchar *)p, lt_script_entry_get_numeric_code(le)) != 0) {
+ g_warning("buggy 'numeric_code' entry for %s in %s: %s",
+ lt_script_entry_get_name(le),
+ iso15924, p);
+ xmlFree(p);
+ goto bail1;
+ }
+ xmlFree(p);
+ g_hash_table_replace(script->entries,
+ (gchar *)lt_script_entry_get_numeric_code(le),
+ lt_script_entry_ref(le));
+ bail1:
+ lt_script_entry_unref(le);
+ }
+
+ bail:
+ if (err) {
+ if (error)
+ *error = g_error_copy(err);
+ else
+ g_warning(err->message);
+ g_error_free(err);
+ retval = FALSE;
+ }
+ if (xobj)
+ xmlXPathFreeObject(xobj);
+ if (xctxt)
+ xmlXPathFreeContext(xctxt);
+ if (doc)
+ xmlFreeDoc(doc);
+ if (xmlparser)
+ xmlFreeParserCtxt(xmlparser);
+ g_free(iso15924);
+
+ xmlCleanupParser();
+
+ return retval;
+}
+
+/*< public >*/
+lt_script_t *
+lt_script_new(void)
+{
+ lt_script_t *retval = lt_mem_alloc_object(sizeof (lt_script_t));
+
+ if (retval) {
+ GError *err = NULL;
+
+ retval->entries = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify)lt_script_entry_unref);
+ lt_mem_add_ref(&retval->parent, retval->entries,
+ (lt_destroy_func_t)g_hash_table_destroy);
+
+ lt_script_parse(retval, &err);
+ if (err) {
+ g_printerr(err->message);
+ lt_script_unref(retval);
+ retval = NULL;
+ g_error_free(err);
+ }
+ }
+
+ return retval;
+}
+
+lt_script_t *
+lt_script_ref(lt_script_t *script)
+{
+ g_return_val_if_fail (script != NULL, NULL);
+
+ return lt_mem_ref(&script->parent);
+}
+
+void
+lt_script_unref(lt_script_t *script)
+{
+ if (script)
+ lt_mem_unref(&script->parent);
+}
+
+GList *
+lt_script_get_scripts(lt_script_t *script)
+{
+ GHashTableIter iter;
+ gpointer key, val;
+ GList *retval = NULL;
+
+ g_return_val_if_fail (script != NULL, NULL);
+
+ g_hash_table_iter_init(&iter, script->entries);
+ while (g_hash_table_iter_next(&iter, &key, &val)) {
+ lt_script_entry_t *le = val;
+
+ retval = g_list_append(retval, (gpointer)lt_script_entry_get_name(le));
+ }
+
+ return retval;
+}
+
+const gchar *
+lt_script_lookup_script(lt_script_t *script,
+ const gchar *code)
+{
+ lt_script_entry_t *le;
+
+ g_return_val_if_fail (script != NULL, NULL);
+ g_return_val_if_fail (code != NULL, NULL);
+
+ le = g_hash_table_lookup(script->entries, code);
+ if (le)
+ return lt_script_entry_get_name(le);
+
+ return NULL;
+}
+
+const gchar *
+lt_script_lookup_alpha_code(lt_script_t *script,
+ const gchar *script_name)
+{
+ lt_script_entry_t *le;
+
+ g_return_val_if_fail (script != NULL, NULL);
+ g_return_val_if_fail (script_name != NULL, NULL);
+
+ le = g_hash_table_lookup(script->entries, script_name);
+ if (le)
+ return lt_script_entry_get_alpha_code(le);
+
+ return NULL;
+}
+
+const gchar *
+lt_script_lookup_numeric_code(lt_script_t *script,
+ const gchar *script_name)
+{
+ lt_script_entry_t *le;
+
+ g_return_val_if_fail (script != NULL, NULL);
+ g_return_val_if_fail (script_name != NULL, NULL);
+
+ le = g_hash_table_lookup(script->entries, script_name);
+ if (le)
+ return lt_script_entry_get_numeric_code(le);
+
+ return NULL;
+}
diff --git a/liblangtag/lt-script.h b/liblangtag/lt-script.h
new file mode 100644
index 0000000..81ae970
--- /dev/null
+++ b/liblangtag/lt-script.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * lt-script.h
+ * Copyright (C) 2011 Akira TAGOH
+ *
+ * Authors:
+ * Akira TAGOH <akira@tagoh.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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __LT_SCRIPT_H__
+#define __LT_SCRIPT_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _lt_script_t lt_script_t;
+
+
+lt_script_t *lt_script_new (void);
+lt_script_t *lt_script_ref (lt_script_t *script);
+void lt_script_unref (lt_script_t *script);
+GList *lt_script_get_scripts (lt_script_t *script);
+const gchar *lt_script_lookup_script (lt_script_t *script,
+ const gchar *code);
+const gchar *lt_script_lookup_alpha_code (lt_script_t *script,
+ const gchar *script_name);
+const gchar *lt_script_lookup_numeric_code(lt_script_t *script,
+ const gchar *script_name);
+
+G_END_DECLS
+
+#endif /* __LT_SCRIPT_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 23d394c..a9be25c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -38,8 +38,13 @@ noinst_HEADERS = \
$(NULL)
noinst_PROGRAMS = \
test-lang \
+ test-script \
$(NULL)
#
test_lang_SOURCES = \
lang.c \
$(NULL)
+#
+test_script_SOURCES = \
+ script.c \
+ $(NULL)
diff --git a/tests/script.c b/tests/script.c
new file mode 100644
index 0000000..920059a
--- /dev/null
+++ b/tests/script.c
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * script.c
+ * Copyright (C) 2011 Akira TAGOH
+ *
+ * Authors:
+ * Akira TAGOH <akira@tagoh.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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <locale.h>
+#include "lt-script.h"
+
+int
+main(int argc,
+ char **argv)
+{
+ lt_script_t *script;
+
+ setlocale(LC_ALL, "");
+
+ script = lt_script_new();
+
+ if (g_strcmp0(argv[1], "list") == 0) {
+ GList *l = lt_script_get_scripts(script), *ll;
+
+ for (ll = l; ll != NULL; ll = g_list_next(ll)) {
+ g_print("%s\n", (gchar *)ll->data);
+ }
+ g_list_free(l);
+ } else if (g_strcmp0(argv[1], "code") == 0) {
+ g_print("%s\n", lt_script_lookup_alpha_code(script, argv[2]));
+ g_print("%s\n", lt_script_lookup_numeric_code(script, argv[2]));
+ } else if (g_strcmp0(argv[1], "script") == 0) {
+ g_print("%s\n", lt_script_lookup_script(script, argv[2]));
+ }
+
+ lt_script_unref(script);
+
+ return 0;
+}