LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/langtag/liblangtag - lt-region-db.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 96 123 78.0 %
Date: 2012-12-17 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       2             : /* 
       3             :  * lt-region-db.c
       4             :  * Copyright (C) 2011-2012 Akira TAGOH
       5             :  * 
       6             :  * Authors:
       7             :  *   Akira TAGOH  <akira@tagoh.org>
       8             :  * 
       9             :  * You may distribute under the terms of either the GNU
      10             :  * Lesser General Public License or the Mozilla Public
      11             :  * License, as specified in the README file.
      12             :  */
      13             : #ifdef HAVE_CONFIG_H
      14             : #include "config.h"
      15             : #endif
      16             : 
      17             : #include <stdlib.h>
      18             : #include <string.h>
      19             : #include <libxml/xpath.h>
      20             : #include "lt-error.h"
      21             : #include "lt-mem.h"
      22             : #include "lt-messages.h"
      23             : #include "lt-trie.h"
      24             : #include "lt-utils.h"
      25             : #include "lt-xml.h"
      26             : #include "lt-region.h"
      27             : #include "lt-region-private.h"
      28             : #include "lt-region-db.h"
      29             : 
      30             : 
      31             : /**
      32             :  * SECTION:lt-region-db
      33             :  * @Short_Description: An interface to access Region Database
      34             :  * @Title: Database - Region
      35             :  *
      36             :  * This class provides an interface to access Region database. which has been
      37             :  * registered as ISO 3166-1 and UN M.49 code.
      38             :  */
      39             : struct _lt_region_db_t {
      40             :         lt_mem_t   parent;
      41             :         lt_xml_t  *xml;
      42             :         lt_trie_t *region_entries;
      43             : };
      44             : 
      45             : 
      46             : /*< private >*/
      47             : static lt_bool_t
      48           4 : lt_region_db_parse(lt_region_db_t  *regiondb,
      49             :                    lt_error_t     **error)
      50             : {
      51           4 :         lt_bool_t retval = TRUE;
      52           4 :         xmlDocPtr doc = NULL;
      53           4 :         xmlXPathContextPtr xctxt = NULL;
      54           4 :         xmlXPathObjectPtr xobj = NULL;
      55           4 :         lt_error_t *err = NULL;
      56             :         int i, n;
      57             : 
      58           4 :         lt_return_val_if_fail (regiondb != NULL, FALSE);
      59             : 
      60           4 :         doc = lt_xml_get_subtag_registry(regiondb->xml);
      61           4 :         xctxt = xmlXPathNewContext(doc);
      62           4 :         if (!xctxt) {
      63           0 :                 lt_error_set(&err, LT_ERR_OOM,
      64             :                              "Unable to create an instance of xmlXPathContextPtr.");
      65           0 :                 goto bail;
      66             :         }
      67           4 :         xobj = xmlXPathEvalExpression((const xmlChar *)"/registry/region", xctxt);
      68           4 :         if (!xobj) {
      69           0 :                 lt_error_set(&err, LT_ERR_FAIL_ON_XML,
      70             :                              "No valid elements for %s",
      71             :                              doc->name);
      72           0 :                 goto bail;
      73             :         }
      74           4 :         n = xmlXPathNodeSetGetLength(xobj->nodesetval);
      75             : 
      76        1208 :         for (i = 0; i < n; i++) {
      77        1204 :                 xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
      78             :                 xmlNodePtr cnode;
      79        1204 :                 xmlChar *subtag = NULL, *desc = NULL, *preferred = NULL;
      80        1204 :                 lt_region_t *le = NULL;
      81             :                 char *s;
      82             : 
      83        1204 :                 if (!ent) {
      84           0 :                         lt_error_set(&err, LT_ERR_FAIL_ON_XML,
      85             :                                      "Unable to obtain the xml node via XPath.");
      86           0 :                         goto bail;
      87             :                 }
      88        1204 :                 cnode = ent->children;
      89       11020 :                 while (cnode != NULL) {
      90        8612 :                         if (xmlStrcmp(cnode->name, (const xmlChar *)"subtag") == 0) {
      91        1204 :                                 if (subtag) {
      92           0 :                                         lt_warning("Duplicate subtag element in region: previous value was '%s'",
      93             :                                                    subtag);
      94             :                                 } else {
      95        1204 :                                         subtag = xmlNodeGetContent(cnode);
      96             :                                 }
      97       13612 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"added") == 0 ||
      98        7500 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"text") == 0 ||
      99        2548 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"deprecated") == 0 ||
     100        1252 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"comments") == 0) {
     101             :                                 /* ignore it */
     102        1228 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"description") == 0) {
     103             :                                 /* wonder if many descriptions helps something. or is it a bug? */
     104        1204 :                                 if (!desc)
     105        1204 :                                         desc = xmlNodeGetContent(cnode);
     106          24 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"preferred-value") == 0) {
     107          24 :                                 if (preferred) {
     108           0 :                                         lt_warning("Duplicate preferred-value element in region: previous value was '%s'",
     109             :                                                    preferred);
     110             :                                 } else {
     111          24 :                                         preferred = xmlNodeGetContent(cnode);
     112             :                                 }
     113             :                         } else {
     114           0 :                                 lt_warning("Unknown node under /registry/region: %s", cnode->name);
     115             :                         }
     116        8612 :                         cnode = cnode->next;
     117             :                 }
     118        1204 :                 if (!subtag) {
     119           0 :                         lt_warning("No subtag node: description = '%s', preferred-value = '%s'",
     120             :                                    desc, preferred);
     121           0 :                         goto bail1;
     122             :                 }
     123        1204 :                 if (!desc) {
     124           0 :                         lt_warning("No description node: subtag = '%s', preferred-value = '%s'",
     125             :                                    subtag, preferred);
     126           0 :                         goto bail1;
     127             :                 }
     128        1204 :                 le = lt_region_create();
     129        1204 :                 if (!le) {
     130           0 :                         lt_error_set(&err, LT_ERR_OOM,
     131             :                                      "Unable to create an instance of lt_region_t.");
     132           0 :                         goto bail1;
     133             :                 }
     134        1204 :                 lt_region_set_tag(le, (const char *)subtag);
     135        1204 :                 lt_region_set_name(le, (const char *)desc);
     136        1204 :                 if (preferred)
     137          24 :                         lt_region_set_preferred_tag(le, (const char *)preferred);
     138             : 
     139        1204 :                 s = strdup(lt_region_get_tag(le));
     140        1204 :                 lt_trie_replace(regiondb->region_entries,
     141        1204 :                                 lt_strlower(s),
     142        1204 :                                 lt_region_ref(le),
     143             :                                 (lt_destroy_func_t)lt_region_unref);
     144        1204 :                 free(s);
     145             :           bail1:
     146        1204 :                 if (subtag)
     147        1204 :                         xmlFree(subtag);
     148        1204 :                 if (desc)
     149        1204 :                         xmlFree(desc);
     150        1204 :                 if (preferred)
     151          24 :                         xmlFree(preferred);
     152        1204 :                 lt_region_unref(le);
     153             :         }
     154             :   bail:
     155           4 :         if (lt_error_is_set(err, LT_ERR_ANY)) {
     156           0 :                 if (error)
     157           0 :                         *error = lt_error_ref(err);
     158             :                 else
     159           0 :                         lt_error_print(err, LT_ERR_ANY);
     160           0 :                 lt_error_unref(err);
     161           0 :                 retval = FALSE;
     162             :         }
     163             : 
     164           4 :         if (xobj)
     165           4 :                 xmlXPathFreeObject(xobj);
     166           4 :         if (xctxt)
     167           4 :                 xmlXPathFreeContext(xctxt);
     168             : 
     169           4 :         return retval;
     170             : }
     171             : 
     172             : /*< public >*/
     173             : /**
     174             :  * lt_region_db_new:
     175             :  *
     176             :  * Create a new instance of a #lt_region_db_t.
     177             :  *
     178             :  * Returns: (transfer full): a new instance of #lt_region_db_t.
     179             :  */
     180             : lt_region_db_t *
     181           4 : lt_region_db_new(void)
     182             : {
     183           4 :         lt_region_db_t *retval = lt_mem_alloc_object(sizeof (lt_region_db_t));
     184             : 
     185           4 :         if (retval) {
     186           4 :                 lt_error_t *err = NULL;
     187             :                 lt_region_t *le;
     188             : 
     189           4 :                 retval->region_entries = lt_trie_new();
     190           4 :                 lt_mem_add_ref(&retval->parent, retval->region_entries,
     191             :                                (lt_destroy_func_t)lt_trie_unref);
     192             : 
     193           4 :                 le = lt_region_create();
     194           4 :                 lt_region_set_tag(le, "*");
     195           4 :                 lt_region_set_name(le, "Wildcard entry");
     196           4 :                 lt_trie_replace(retval->region_entries,
     197             :                                 lt_region_get_tag(le),
     198             :                                 le,
     199             :                                 (lt_destroy_func_t)lt_region_unref);
     200           4 :                 le = lt_region_create();
     201           4 :                 lt_region_set_tag(le, "");
     202           4 :                 lt_region_set_name(le, "Empty entry");
     203           4 :                 lt_trie_replace(retval->region_entries,
     204             :                                 lt_region_get_tag(le),
     205             :                                 le,
     206             :                                 (lt_destroy_func_t)lt_region_unref);
     207             : 
     208           4 :                 retval->xml = lt_xml_new();
     209           4 :                 if (!retval->xml) {
     210           0 :                         lt_region_db_unref(retval);
     211           0 :                         retval = NULL;
     212             :                         goto bail;
     213             :                 }
     214           4 :                 lt_mem_add_ref(&retval->parent, retval->xml,
     215             :                                (lt_destroy_func_t)lt_xml_unref);
     216             : 
     217           4 :                 lt_region_db_parse(retval, &err);
     218           4 :                 if (lt_error_is_set(err, LT_ERR_ANY)) {
     219           0 :                         lt_error_print(err, LT_ERR_ANY);
     220           0 :                         lt_region_db_unref(retval);
     221           0 :                         retval = NULL;
     222           0 :                         lt_error_unref(err);
     223             :                 }
     224             :         }
     225             :   bail:
     226             : 
     227           4 :         return retval;
     228             : }
     229             : 
     230             : /**
     231             :  * lt_region_db_ref:
     232             :  * @regiondb: a #lt_region_db_t.
     233             :  *
     234             :  * Increases the reference count of @regiondb.
     235             :  *
     236             :  * Returns: (transfer none): the same @regiondb object.
     237             :  */
     238             : lt_region_db_t *
     239           6 : lt_region_db_ref(lt_region_db_t *regiondb)
     240             : {
     241           6 :         lt_return_val_if_fail (regiondb != NULL, NULL);
     242             : 
     243           6 :         return lt_mem_ref(&regiondb->parent);
     244             : }
     245             : 
     246             : /**
     247             :  * lt_region_db_unref:
     248             :  * @regiondb: a #lt_region_db_t.
     249             :  *
     250             :  * Decreases the reference count of @regiondb. when its reference count
     251             :  * drops to 0, the object is finalized (i.e. its memory is freed).
     252             :  */
     253             : void
     254          10 : lt_region_db_unref(lt_region_db_t *regiondb)
     255             : {
     256          10 :         if (regiondb)
     257          10 :                 lt_mem_unref(&regiondb->parent);
     258          10 : }
     259             : 
     260             : /**
     261             :  * lt_region_db_lookup:
     262             :  * @regiondb: a #lt_region_db_t.
     263             :  * @language_or_code: a region code to lookup.
     264             :  *
     265             :  * Lookup @lt_region_t if @language_or_code is valid and registered into
     266             :  * the database.
     267             :  *
     268             :  * Returns: (transfer full): a #lt_region_t that meets with @language_or_code.
     269             :  *                           otherwise %NULL.
     270             :  */
     271             : lt_region_t *
     272           6 : lt_region_db_lookup(lt_region_db_t *regiondb,
     273             :                     const char     *language_or_code)
     274             : {
     275             :         lt_region_t *retval;
     276             :         char *s;
     277             : 
     278           6 :         lt_return_val_if_fail (regiondb != NULL, NULL);
     279           6 :         lt_return_val_if_fail (language_or_code != NULL, NULL);
     280             : 
     281           6 :         s = strdup(language_or_code);
     282           6 :         retval = lt_trie_lookup(regiondb->region_entries,
     283           6 :                                 lt_strlower(s));
     284           6 :         free(s);
     285           6 :         if (retval)
     286           6 :                 return lt_region_ref(retval);
     287             : 
     288           0 :         return NULL;
     289             : }

Generated by: LCOV version 1.10