LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/langtag/liblangtag - lt-variant-db.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 91 130 70.0 %
Date: 2012-12-17 Functions: 3 5 60.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-variant-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-variant.h"
      22             : #include "lt-variant-private.h"
      23             : #include "lt-list.h"
      24             : #include "lt-mem.h"
      25             : #include "lt-messages.h"
      26             : #include "lt-trie.h"
      27             : #include "lt-utils.h"
      28             : #include "lt-xml.h"
      29             : #include "lt-variant-db.h"
      30             : 
      31             : 
      32             : /**
      33             :  * SECTION: lt-variant-db
      34             :  * @Short_Description: An interface to access Variant Database
      35             :  * @Title: Database - Variant
      36             :  *
      37             :  * This class provides an interface to access Variant database. which has been
      38             :  * registered with IANA.
      39             :  */
      40             : struct _lt_variant_db_t {
      41             :         lt_mem_t   parent;
      42             :         lt_xml_t  *xml;
      43             :         lt_trie_t *variant_entries;
      44             : };
      45             : 
      46             : /*< private >*/
      47             : static lt_bool_t
      48           4 : lt_variant_db_parse(lt_variant_db_t  *variantdb,
      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 (variantdb != NULL, FALSE);
      59             : 
      60           4 :         doc = lt_xml_get_subtag_registry(variantdb->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/variant", 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         248 :         for (i = 0; i < n; i++) {
      77         244 :                 xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
      78             :                 xmlNodePtr cnode;
      79         244 :                 xmlChar *subtag = NULL, *desc = NULL, *preferred = NULL;
      80         244 :                 lt_variant_t *le = NULL;
      81             :                 char *s;
      82         244 :                 lt_list_t *prefix_list = NULL, *l;
      83             : 
      84         244 :                 if (!ent) {
      85           0 :                         lt_error_set(&err, LT_ERR_FAIL_ON_XML,
      86             :                                      "Unable to obtain the xml node via XPath.");
      87           0 :                         goto bail;
      88             :                 }
      89         244 :                 cnode = ent->children;
      90        3212 :                 while (cnode != NULL) {
      91        2724 :                         if (xmlStrcmp(cnode->name, (const xmlChar *)"subtag") == 0) {
      92         244 :                                 if (subtag) {
      93           0 :                                         lt_warning("Duplicate subtag element in variant: previous value was '%s'",
      94             :                                                    subtag);
      95             :                                 } else {
      96         244 :                                         subtag = xmlNodeGetContent(cnode);
      97             :                                 }
      98        4716 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"added") == 0 ||
      99        2988 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"text") == 0 ||
     100        1368 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"comments") == 0 ||
     101         616 :                                    xmlStrcmp(cnode->name, (const xmlChar *)"deprecated") == 0) {
     102             :                                 /* ignore it */
     103         612 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"description") == 0) {
     104             :                                 /* wonder if many descriptions helps something or is it a bug? */
     105         324 :                                 if (!desc)
     106         244 :                                         desc = xmlNodeGetContent(cnode);
     107         288 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"prefix") == 0) {
     108         568 :                                 prefix_list = lt_list_append(prefix_list,
     109         284 :                                                              xmlNodeGetContent(cnode),
     110             :                                                              (lt_destroy_func_t)xmlFree);
     111           4 :                         } else if (xmlStrcmp(cnode->name, (const xmlChar *)"preferred-value") == 0) {
     112           4 :                                 if (preferred) {
     113           0 :                                         lt_warning("Duplicate preferred-value element in variant: previous value was '%s'",
     114             :                                                    preferred);
     115             :                                 } else {
     116           4 :                                         preferred = xmlNodeGetContent(cnode);
     117             :                                 }
     118             :                         } else {
     119           0 :                                 lt_warning("Unknown node under /registry/variant: %s", cnode->name);
     120             :                         }
     121        2724 :                         cnode = cnode->next;
     122             :                 }
     123         244 :                 if (!subtag) {
     124           0 :                         lt_warning("No subtag node: description = '%s', prefix = '%s', preferred-value = '%s'",
     125             :                                    desc, prefix_list ? (char *)lt_list_value(prefix_list) : "N/A", preferred);
     126           0 :                         goto bail1;
     127             :                 }
     128         244 :                 if (!desc) {
     129           0 :                         lt_warning("No description node: subtag = '%s', prefix = '%s', preferred-value = '%s'",
     130             :                                    subtag, prefix_list ? (char *)lt_list_value(prefix_list) : "N/A", preferred);
     131           0 :                         goto bail1;
     132             :                 }
     133         244 :                 le = lt_variant_create();
     134         244 :                 if (!le) {
     135           0 :                         lt_error_set(&err, LT_ERR_OOM,
     136             :                                      "Unable to create an instance of lt_variant_t.");
     137           0 :                         goto bail1;
     138             :                 }
     139         244 :                 lt_variant_set_tag(le, (const char *)subtag);
     140         244 :                 lt_variant_set_name(le, (const char *)desc);
     141         528 :                 for (l = prefix_list; l != NULL; l = lt_list_next(l)) {
     142         284 :                         lt_variant_add_prefix(le, lt_list_value(l));
     143             :                 }
     144         244 :                 lt_list_free(prefix_list);
     145         244 :                 if (preferred)
     146           4 :                         lt_variant_set_preferred_tag(le, (const char *)preferred);
     147             : 
     148         244 :                 s = strdup(lt_variant_get_tag(le));
     149         244 :                 lt_trie_replace(variantdb->variant_entries,
     150         244 :                                 lt_strlower(s),
     151         244 :                                 lt_variant_ref(le),
     152             :                                 (lt_destroy_func_t)lt_variant_unref);
     153         244 :                 free(s);
     154             :           bail1:
     155         244 :                 if (subtag)
     156         244 :                         xmlFree(subtag);
     157         244 :                 if (desc)
     158         244 :                         xmlFree(desc);
     159         244 :                 if (preferred)
     160           4 :                         xmlFree(preferred);
     161         244 :                 lt_variant_unref(le);
     162             :         }
     163             :   bail:
     164           4 :         if (lt_error_is_set(err, LT_ERR_ANY)) {
     165           0 :                 if (error)
     166           0 :                         *error = lt_error_ref(err);
     167             :                 else
     168           0 :                         lt_error_print(err, LT_ERR_ANY);
     169           0 :                 lt_error_unref(err);
     170           0 :                 retval = FALSE;
     171             :         }
     172             : 
     173           4 :         if (xobj)
     174           4 :                 xmlXPathFreeObject(xobj);
     175           4 :         if (xctxt)
     176           4 :                 xmlXPathFreeContext(xctxt);
     177             : 
     178           4 :         return retval;
     179             : }
     180             : 
     181             : /*< public >*/
     182             : /**
     183             :  * lt_variant_db_new:
     184             :  *
     185             :  * Create a new instance of a #lt_variant_db_t.
     186             :  *
     187             :  * Returns: (transfer full): a new instance of #lt_variant_db_t.
     188             :  */
     189             : lt_variant_db_t *
     190           4 : lt_variant_db_new(void)
     191             : {
     192           4 :         lt_variant_db_t *retval = lt_mem_alloc_object(sizeof (lt_variant_db_t));
     193             : 
     194           4 :         if (retval) {
     195           4 :                 lt_error_t *err = NULL;
     196             :                 lt_variant_t *le;
     197             : 
     198           4 :                 retval->variant_entries = lt_trie_new();
     199           4 :                 lt_mem_add_ref(&retval->parent, retval->variant_entries,
     200             :                                (lt_destroy_func_t)lt_trie_unref);
     201             : 
     202           4 :                 le = lt_variant_create();
     203           4 :                 lt_variant_set_tag(le, "*");
     204           4 :                 lt_variant_set_name(le, "Wildcard entry");
     205           4 :                 lt_trie_replace(retval->variant_entries,
     206             :                                 lt_variant_get_tag(le),
     207             :                                 le,
     208             :                                 (lt_destroy_func_t)lt_variant_unref);
     209           4 :                 le = lt_variant_create();
     210           4 :                 lt_variant_set_tag(le, "");
     211           4 :                 lt_variant_set_name(le, "Empty entry");
     212           4 :                 lt_trie_replace(retval->variant_entries,
     213             :                                 lt_variant_get_tag(le),
     214             :                                 le,
     215             :                                 (lt_destroy_func_t)lt_variant_unref);
     216             : 
     217           4 :                 retval->xml = lt_xml_new();
     218           4 :                 if (!retval->xml) {
     219           0 :                         lt_variant_db_unref(retval);
     220           0 :                         retval = NULL;
     221             :                         goto bail;
     222             :                 }
     223           4 :                 lt_mem_add_ref(&retval->parent, retval->xml,
     224             :                                (lt_destroy_func_t)lt_xml_unref);
     225             : 
     226           4 :                 lt_variant_db_parse(retval, &err);
     227           4 :                 if (lt_error_is_set(err, LT_ERR_ANY)) {
     228           0 :                         lt_error_print(err, LT_ERR_ANY);
     229           0 :                         lt_error_unref(err);
     230           0 :                         lt_variant_db_unref(retval);
     231           0 :                         retval = NULL;
     232             :                 }
     233             :         }
     234             :   bail:
     235             : 
     236           4 :         return retval;
     237             : }
     238             : 
     239             : /**
     240             :  * lt_variant_db_ref:
     241             :  * @variantdb: a #lt_variant_db_t.
     242             :  *
     243             :  * Increases the reference count of @variantdb.
     244             :  *
     245             :  * Returns: (transfer none): the same @variantdb object.
     246             :  */
     247             : lt_variant_db_t *
     248           0 : lt_variant_db_ref(lt_variant_db_t *variantdb)
     249             : {
     250           0 :         lt_return_val_if_fail (variantdb != NULL, NULL);
     251             : 
     252           0 :         return lt_mem_ref(&variantdb->parent);
     253             : }
     254             : 
     255             : /**
     256             :  * lt_variant_db_unref:
     257             :  * @variantdb: a #lt_variant_db_t.
     258             :  *
     259             :  * Decreases the reference count of @variantdb. when its reference count
     260             :  * drops to 0, the object is finalized (i.e. its memory is freed).
     261             :  */
     262             : void
     263           4 : lt_variant_db_unref(lt_variant_db_t *variantdb)
     264             : {
     265           4 :         if (variantdb)
     266           4 :                 lt_mem_unref(&variantdb->parent);
     267           4 : }
     268             : 
     269             : /**
     270             :  * lt_variant_db_lookup:
     271             :  * @variantdb: a #lt_variant_db_t.
     272             :  * @subtag: a subtag name to lookup.
     273             :  *
     274             :  * Lookup @lt_variant_t if @subtag is valid and registered into the database.
     275             :  *
     276             :  * Returns: (transfer full): a #lt_variant_t that meets with @subtag.
     277             :  *                           otherwise %NULL.
     278             :  */
     279             : lt_variant_t *
     280           0 : lt_variant_db_lookup(lt_variant_db_t *variantdb,
     281             :                      const char      *subtag)
     282             : {
     283             :         lt_variant_t *retval;
     284             :         char *s;
     285             : 
     286           0 :         lt_return_val_if_fail (variantdb != NULL, NULL);
     287           0 :         lt_return_val_if_fail (subtag != NULL, NULL);
     288             : 
     289           0 :         s = strdup(subtag);
     290           0 :         retval = lt_trie_lookup(variantdb->variant_entries,
     291           0 :                                 lt_strlower(s));
     292           0 :         free(s);
     293           0 :         if (retval)
     294           0 :                 return lt_variant_ref(retval);
     295             : 
     296           0 :         return NULL;
     297             : }

Generated by: LCOV version 1.10