diff options
author | Akira TAGOH <akira@tagoh.org> | 2011-12-28 14:16:32 +0900 |
---|---|---|
committer | Akira TAGOH <akira@tagoh.org> | 2011-12-28 14:16:32 +0900 |
commit | fa2c708c3596ad8fe1b72b39d92126a8083a97b9 (patch) | |
tree | 87de191b3143d8020de48470aea3ae5e9f1cf7c1 | |
parent | 2c43f4ec493416718c82a7a5824e85d0a330ab66 (diff) |
Add script database handler
-rw-r--r-- | liblangtag/Makefile.am | 2 | ||||
-rw-r--r-- | liblangtag/lt-script.c | 374 | ||||
-rw-r--r-- | liblangtag/lt-script.h | 45 | ||||
-rw-r--r-- | tests/Makefile.am | 5 | ||||
-rw-r--r-- | tests/script.c | 56 |
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; +} |