LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/langtag/liblangtag - lt-lang-db.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 113 143 79.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-lang-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 <string.h>
      18             : #include <libxml/xpath.h>
      19             : #include "lt-error.h"
      20             : #include "lt-mem.h"
      21             : #include "lt-messages.h"
      22             : #include "lt-trie.h"
      23             : #include "lt-utils.h"
      24             : #include "lt-xml.h"
      25             : #include "lt-lang-private.h"
      26             : #include "lt-lang-db.h"
      27             : 
      28             : 
      29             : /**
      30             :  * SECTION: lt-lang-db
      31             :  * @Short_Description: An interface to access Language Database
      32             :  * @Title: Database - Language
      33             :  *
      34             :  * This class provides an interface to access Language database. which has been
      35             :  * registered as ISO 639 code.
      36             :  */
      37             : struct _lt_lang_db_t {
      38             :         lt_mem_t   parent;
      39             :         lt_xml_t  *xml;
      40             :         lt_trie_t *lang_entries;
      41             : };
      42             : 
      43             : /*< private >*/
      44             : static lt_bool_t
      45           4 : lt_lang_db_parse(lt_lang_db_t  *langdb,
      46             :                  lt_error_t   **error)
      47             : {
      48           4 :         lt_bool_t retval = TRUE;
      49           4 :         xmlDocPtr doc = NULL;
      50           4 :         xmlXPathContextPtr xctxt = NULL;
      51           4 :         xmlXPathObjectPtr xobj = NULL;
      52           4 :         lt_error_t *err = NULL;
      53             :         int i, n;
      54             : 
      55           4 :         lt_return_val_if_fail (langdb != NULL, FALSE);
      56             : 
      57           4 :         doc = lt_xml_get_subtag_registry(langdb->xml);
      58           4 :         xctxt = xmlXPathNewContext(doc);
      59           4 :         if (!xctxt) {
      60           0 :                 lt_error_set(&err, LT_ERR_OOM,
      61             :                              "Unable to create an instance of xmlXPathContextPtr.");
      62           0 :                 goto bail;
      63             :         }
      64           4 :         xobj = xmlXPathEvalExpression((const xmlChar *)"/registry/language", xctxt);
      65           4 :         if (!xobj) {
      66           0 :                 lt_error_set(&err, LT_ERR_FAIL_ON_XML,
      67             :                              "No valid elements for %s",
      68             :                              doc->name);
      69           0 :                 goto bail;
      70             :         }
      71           4 :         n = xmlXPathNodeSetGetLength(xobj->nodesetval);
      72             : 
      73       31808 :         for (i = 0; i < n; i++) {
      74       31804 :                 xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
      75             :                 xmlNodePtr cnode;
      76       31804 :                 xmlChar *subtag = NULL, *desc = NULL, *scope = NULL, *macrolang = NULL;
      77       31804 :                 xmlChar *preferred = NULL, *suppress = NULL;
      78       31804 :                 lt_lang_t *le = NULL;
      79             :                 char *s;
      80             : 
      81       31804 :                 if (!ent) {
      82           0 :                         lt_error_set(&err, LT_ERR_FAIL_ON_XML,
      83             :                                      "Unable to obtain the xml node via XPath.");
      84           0 :                         goto bail;
      85             :                 }
      86       31804 :                 cnode = ent->children;
      87      295204 :                 while (cnode != NULL) {
      88      231596 :                         if (xmlStrcmp(cnode->name, (const xmlChar *)"subtag") == 0) {
      89       31804 :                                 if (subtag) {
      90           0 :                                         lt_warning("Duplicate subtag element in language: previous value was '%s'",
      91             :                                                    subtag);
      92             :                                 } else {
      93       31804 :                                         subtag = xmlNodeGetContent(cnode);
      94             :                                 }
      95      367780 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"added") == 0 ||
      96      335736 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"deprecated") == 0 ||
      97      203796 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"text") == 0 ||
      98       36048 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"comments") == 0) {
      99             :                                 /* ignore it */
     100       35908 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"description") == 0) {
     101             :                                 /* wonder if many descriptions helps something. or is it a bug? */
     102       32760 :                                 if (!desc)
     103       31804 :                                         desc = xmlNodeGetContent(cnode);
     104        3148 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"scope") == 0) {
     105         732 :                                 if (scope) {
     106           0 :                                         lt_warning("Duplicate scope element in language: previous value was '%s'",
     107             :                                                    scope);
     108             :                                 } else {
     109         732 :                                         scope = xmlNodeGetContent(cnode);
     110             :                                 }
     111        2416 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"macrolanguage") == 0) {
     112        1772 :                                 if (macrolang) {
     113           0 :                                         lt_warning("Duplicate macrolanguage element in language: previous value was '%s'",
     114             :                                                    macrolang);
     115             :                                 } else {
     116        1772 :                                         macrolang = xmlNodeGetContent(cnode);
     117             :                                 }
     118         644 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"preferred-value") == 0) {
     119         108 :                                 if (preferred) {
     120           0 :                                         lt_warning("Duplicate preferred-value element in language: previous value was '%s'",
     121             :                                                    preferred);
     122             :                                 } else {
     123         108 :                                         preferred = xmlNodeGetContent(cnode);
     124             :                                 }
     125         536 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"suppress-script") == 0) {
     126         536 :                                 if (suppress) {
     127           0 :                                         lt_warning("Duplicate suppress-script element in language: previous value was '%s'",
     128             :                                                    suppress);
     129             :                                 } else {
     130         536 :                                         suppress = xmlNodeGetContent(cnode);
     131             :                                 }
     132             :                         } else {
     133           0 :                                 lt_warning("Unknown node under /registry/language: %s", cnode->name);
     134             :                         }
     135      231596 :                         cnode = cnode->next;
     136             :                 }
     137       31804 :                 if (!subtag) {
     138           0 :                         lt_warning("No subtag node: description = '%s', scope = '%s', macrolanguage = '%s'",
     139             :                                    desc, scope, macrolang);
     140           0 :                         goto bail1;
     141             :                 }
     142       31804 :                 if (!desc) {
     143           0 :                         lt_warning("No description node: subtag = '%s', scope = '%s', macrolanguage = '%s'",
     144             :                                    subtag, scope, macrolang);
     145           0 :                         goto bail1;
     146             :                 }
     147       31804 :                 le = lt_lang_create();
     148       31804 :                 if (!le) {
     149           0 :                         lt_error_set(&err, LT_ERR_OOM,
     150             :                                      "Unable to create an instance of lt_lang_t.");
     151           0 :                         goto bail1;
     152             :                 }
     153       31804 :                 lt_lang_set_tag(le, (const char *)subtag);
     154       31804 :                 lt_lang_set_name(le, (const char *)desc);
     155       31804 :                 if (scope)
     156         732 :                         lt_lang_set_scope(le, (const char *)scope);
     157       31804 :                 if (macrolang)
     158        1772 :                         lt_lang_set_macro_language(le, (const char *)macrolang);
     159       31804 :                 if (preferred)
     160         108 :                         lt_lang_set_preferred_tag(le, (const char *)preferred);
     161       31804 :                 if (suppress)
     162         536 :                         lt_lang_set_suppress_script(le, (const char *)suppress);
     163             : 
     164       31804 :                 s = strdup(lt_lang_get_tag(le));
     165       31804 :                 lt_trie_replace(langdb->lang_entries,
     166       31804 :                                 lt_strlower(s),
     167       31804 :                                 lt_lang_ref(le),
     168             :                                 (lt_destroy_func_t)lt_lang_unref);
     169       31804 :                 free(s);
     170             :           bail1:
     171       31804 :                 if (subtag)
     172       31804 :                         xmlFree(subtag);
     173       31804 :                 if (desc)
     174       31804 :                         xmlFree(desc);
     175       31804 :                 if (scope)
     176         732 :                         xmlFree(scope);
     177       31804 :                 if (macrolang)
     178        1772 :                         xmlFree(macrolang);
     179       31804 :                 if (preferred)
     180         108 :                         xmlFree(preferred);
     181       31804 :                 if (suppress)
     182         536 :                         xmlFree(suppress);
     183       31804 :                 lt_lang_unref(le);
     184             :         }
     185             :   bail:
     186           4 :         if (lt_error_is_set(err, LT_ERR_ANY)) {
     187           0 :                 if (error)
     188           0 :                         *error = lt_error_ref(err);
     189             :                 else
     190           0 :                         lt_error_print(err, LT_ERR_ANY);
     191           0 :                 lt_error_unref(err);
     192           0 :                 retval = FALSE;
     193             :         }
     194             : 
     195           4 :         if (xobj)
     196           4 :                 xmlXPathFreeObject(xobj);
     197           4 :         if (xctxt)
     198           4 :                 xmlXPathFreeContext(xctxt);
     199             : 
     200           4 :         return retval;
     201             : }
     202             : 
     203             : /*< public >*/
     204             : /**
     205             :  * lt_lang_db_new:
     206             :  *
     207             :  * Create a new instance of a #lt_lang_db_t.
     208             :  *
     209             :  * Returns: (transfer full): a new instance of #lt_lang_db_t.
     210             :  */
     211             : lt_lang_db_t *
     212           4 : lt_lang_db_new(void)
     213             : {
     214           4 :         lt_lang_db_t *retval = lt_mem_alloc_object(sizeof (lt_lang_db_t));
     215             : 
     216           4 :         if (retval) {
     217           4 :                 lt_error_t *err = NULL;
     218             :                 lt_lang_t *le;
     219             : 
     220           4 :                 retval->lang_entries = lt_trie_new();
     221           4 :                 lt_mem_add_ref(&retval->parent, retval->lang_entries,
     222             :                                (lt_destroy_func_t)lt_trie_unref);
     223             : 
     224           4 :                 le = lt_lang_create();
     225           4 :                 lt_lang_set_tag(le, "*");
     226           4 :                 lt_lang_set_name(le, "Wildcard entry");
     227           4 :                 lt_trie_replace(retval->lang_entries,
     228             :                                 lt_lang_get_tag(le),
     229             :                                 le,
     230             :                                 (lt_destroy_func_t)lt_lang_unref);
     231             : 
     232           4 :                 retval->xml = lt_xml_new();
     233           4 :                 if (!retval->xml) {
     234           0 :                         lt_lang_db_unref(retval);
     235           0 :                         retval = NULL;
     236             :                         goto bail;
     237             :                 }
     238           4 :                 lt_mem_add_ref(&retval->parent, retval->xml,
     239             :                                (lt_destroy_func_t)lt_xml_unref);
     240             : 
     241           4 :                 lt_lang_db_parse(retval, &err);
     242           4 :                 if (lt_error_is_set(err, LT_ERR_ANY)) {
     243           0 :                         lt_error_print(err, LT_ERR_ANY);
     244           0 :                         lt_lang_db_unref(retval);
     245           0 :                         retval = NULL;
     246           0 :                         lt_error_unref(err);
     247             :                 }
     248             :         }
     249             :   bail:
     250             : 
     251           4 :         return retval;
     252             : }
     253             : 
     254             : /**
     255             :  * lt_lang_db_ref:
     256             :  * @langdb: a #lt_lang_db_t.
     257             :  *
     258             :  * Increases the reference count of @langdb.
     259             :  *
     260             :  * Returns: (transfer none): the same @langdb object.
     261             :  */
     262             : lt_lang_db_t *
     263          20 : lt_lang_db_ref(lt_lang_db_t *langdb)
     264             : {
     265          20 :         lt_return_val_if_fail (langdb != NULL, NULL);
     266             : 
     267          20 :         return lt_mem_ref(&langdb->parent);
     268             : }
     269             : 
     270             : /**
     271             :  * lt_lang_db_unref:
     272             :  * @langdb: a #lt_lang_db_t.
     273             :  *
     274             :  * Decreases the reference count of @langdb. when its reference count
     275             :  * drops to 0, the object is finalized (i.e. its memory is freed).
     276             :  */
     277             : void
     278          24 : lt_lang_db_unref(lt_lang_db_t *langdb)
     279             : {
     280          24 :         if (langdb)
     281          24 :                 lt_mem_unref(&langdb->parent);
     282          24 : }
     283             : 
     284             : /**
     285             :  * lt_lang_db_lookup:
     286             :  * @langdb: a #lt_lang_db_t.
     287             :  * @subtag: a subtag name to lookup.
     288             :  *
     289             :  * Lookup @lt_lang_t if @subtag is valid and registered into the database.
     290             :  *
     291             :  * Returns: (transfer full): a #lt_lang_t that meets with @subtag.
     292             :  *                           otherwise %NULL.
     293             :  */
     294             : lt_lang_t *
     295          20 : lt_lang_db_lookup(lt_lang_db_t *langdb,
     296             :                   const char   *subtag)
     297             : {
     298             :         lt_lang_t *retval;
     299             :         char *s;
     300             : 
     301          20 :         lt_return_val_if_fail (langdb != NULL, NULL);
     302          20 :         lt_return_val_if_fail (subtag != NULL, NULL);
     303             : 
     304          20 :         s = strdup(subtag);
     305          20 :         retval = lt_trie_lookup(langdb->lang_entries, lt_strlower(s));
     306          20 :         free(s);
     307          20 :         if (retval)
     308          20 :                 return lt_lang_ref(retval);
     309             : 
     310           0 :         return NULL;
     311             : }

Generated by: LCOV version 1.10