Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 : /*
3 : * lt-redundant-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-redundant.h"
22 : #include "lt-redundant-private.h"
23 : #include "lt-mem.h"
24 : #include "lt-messages.h"
25 : #include "lt-trie.h"
26 : #include "lt-utils.h"
27 : #include "lt-xml.h"
28 : #include "lt-redundant-db.h"
29 :
30 :
31 : /**
32 : * SECTION: lt-redundant-db
33 : * @Short_Description: An interface to access Redundant Database
34 : * @Title: Database - Redundant
35 : *
36 : * This class provides an interface to access Redundant database.
37 : * which were mostly made redundant by the advent of either RFC 4646
38 : * or RFC 5646.
39 : */
40 : struct _lt_redundant_db_t {
41 : lt_mem_t parent;
42 : lt_xml_t *xml;
43 : lt_trie_t *redundant_entries;
44 : };
45 :
46 : /*< private >*/
47 : static lt_bool_t
48 4 : lt_redundant_db_parse(lt_redundant_db_t *redundantdb,
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 (redundantdb != NULL, FALSE);
59 :
60 4 : doc = lt_xml_get_subtag_registry(redundantdb->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/redundant", 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 268 : for (i = 0; i < n; i++) {
77 264 : xmlNodePtr ent = xmlXPathNodeSetItem(xobj->nodesetval, i);
78 : xmlNodePtr cnode;
79 264 : xmlChar *tag = NULL, *desc = NULL, *preferred = NULL;
80 264 : lt_redundant_t *le = NULL;
81 : char *s;
82 :
83 264 : 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 264 : cnode = ent->children;
89 2760 : while (cnode != NULL) {
90 2232 : if (xmlStrcmp(cnode->name, (const xmlChar *)"tag") == 0) {
91 264 : if (tag) {
92 0 : lt_warning("Duplicate tag element in redundant: previous value was '%s'",
93 : tag);
94 : } else {
95 264 : tag = xmlNodeGetContent(cnode);
96 : }
97 3672 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"added") == 0 ||
98 2160 : xmlStrcmp(cnode->name, (const xmlChar *)"text") == 0 ||
99 456 : xmlStrcmp(cnode->name, (const xmlChar *)"deprecated") == 0) {
100 : /* ignore it */
101 360 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"description") == 0) {
102 : /* wonder if many descriptions helps something. or is it a bug? */
103 264 : if (!desc)
104 264 : desc = xmlNodeGetContent(cnode);
105 96 : } else if (xmlStrcmp(cnode->name, (const xmlChar *)"preferred-value") == 0) {
106 96 : if (preferred) {
107 0 : lt_warning("Duplicate preferred-value element in redundant: previous value was '%s'",
108 : preferred);
109 : } else {
110 96 : preferred = xmlNodeGetContent(cnode);
111 : }
112 : } else {
113 0 : lt_warning("Unknown node under /registry/redundant: %s", cnode->name);
114 : }
115 2232 : cnode = cnode->next;
116 : }
117 264 : if (!tag) {
118 0 : lt_warning("No tag node: description = '%s', preferred-value = '%s'",
119 : desc, preferred);
120 0 : goto bail1;
121 : }
122 264 : if (!desc) {
123 0 : lt_warning("No description node: tag = '%s', preferred-value = '%s'",
124 : tag, preferred);
125 0 : goto bail1;
126 : }
127 264 : le = lt_redundant_create();
128 264 : if (!le) {
129 0 : lt_error_set(&err, LT_ERR_OOM,
130 : "Unable to create an instance of lt_redundant_t.");
131 0 : goto bail1;
132 : }
133 264 : lt_redundant_set_tag(le, (const char *)tag);
134 264 : lt_redundant_set_name(le, (const char *)desc);
135 264 : if (preferred)
136 96 : lt_redundant_set_preferred_tag(le, (const char *)preferred);
137 :
138 264 : s = strdup(lt_redundant_get_tag(le));
139 264 : lt_trie_replace(redundantdb->redundant_entries,
140 264 : lt_strlower(s),
141 264 : lt_redundant_ref(le),
142 : (lt_destroy_func_t)lt_redundant_unref);
143 264 : free(s);
144 : bail1:
145 264 : if (tag)
146 264 : xmlFree(tag);
147 264 : if (desc)
148 264 : xmlFree(desc);
149 264 : if (preferred)
150 96 : xmlFree(preferred);
151 264 : lt_redundant_unref(le);
152 : }
153 : bail:
154 4 : if (lt_error_is_set(err, LT_ERR_ANY)) {
155 0 : if (error)
156 0 : *error = lt_error_ref(err);
157 : else
158 0 : lt_error_print(err, LT_ERR_ANY);
159 0 : lt_error_unref(err);
160 0 : retval = FALSE;
161 : }
162 :
163 4 : if (xobj)
164 4 : xmlXPathFreeObject(xobj);
165 4 : if (xctxt)
166 4 : xmlXPathFreeContext(xctxt);
167 :
168 4 : return retval;
169 : }
170 :
171 : /*< public >*/
172 : /**
173 : * lt_redundant_db_new:
174 : *
175 : * Create a new instance of a #lt_redundant_db_t.
176 : *
177 : * Returns: (transfer full): a new instance of #lt_redundant_db_t.
178 : */
179 : lt_redundant_db_t *
180 4 : lt_redundant_db_new(void)
181 : {
182 4 : lt_redundant_db_t *retval = lt_mem_alloc_object(sizeof (lt_redundant_db_t));
183 :
184 4 : if (retval) {
185 4 : lt_error_t *err = NULL;
186 :
187 4 : retval->redundant_entries = lt_trie_new();
188 4 : lt_mem_add_ref(&retval->parent, retval->redundant_entries,
189 : (lt_destroy_func_t)lt_trie_unref);
190 :
191 4 : retval->xml = lt_xml_new();
192 4 : if (!retval->xml) {
193 0 : lt_redundant_db_unref(retval);
194 0 : retval = NULL;
195 : goto bail;
196 : }
197 4 : lt_mem_add_ref(&retval->parent, retval->xml,
198 : (lt_destroy_func_t)lt_xml_unref);
199 :
200 4 : lt_redundant_db_parse(retval, &err);
201 4 : if (lt_error_is_set(err, LT_ERR_ANY)) {
202 0 : lt_error_print(err, LT_ERR_ANY);
203 0 : lt_redundant_db_unref(retval);
204 0 : retval = NULL;
205 0 : lt_error_unref(err);
206 : }
207 : }
208 : bail:
209 :
210 4 : return retval;
211 : }
212 :
213 : /**
214 : * lt_redundant_db_ref:
215 : * @redundantdb: a #lt_redundant_db_t.
216 : *
217 : * Increases the reference count of @redundantdb.
218 : *
219 : * Returns: (transfer none): the same @redundantdb object.
220 : */
221 : lt_redundant_db_t *
222 4 : lt_redundant_db_ref(lt_redundant_db_t *redundantdb)
223 : {
224 4 : lt_return_val_if_fail (redundantdb != NULL, NULL);
225 :
226 4 : return lt_mem_ref(&redundantdb->parent);
227 : }
228 :
229 : /**
230 : * lt_redundant_db_unref:
231 : * @redundantdb: a #lt_redundant_db_t.
232 : *
233 : * Decreases the reference count of @redundantdb. when its reference count
234 : * drops to 0, the object is finalized (i.e. its memory is freed).
235 : */
236 : void
237 8 : lt_redundant_db_unref(lt_redundant_db_t *redundantdb)
238 : {
239 8 : if (redundantdb)
240 8 : lt_mem_unref(&redundantdb->parent);
241 8 : }
242 :
243 : /**
244 : * lt_redundant_db_lookup:
245 : * @redundantdb: a #lt_redundant_db_t.
246 : * @tag: a tag name to lookup.
247 : *
248 : * Lookup @lt_redundant_t if @tag is valid and registered into the database.
249 : *
250 : * Returns: (transfer full): a #lt_redundant_t that meets with @tag.
251 : * otherwise %NULL.
252 : */
253 : lt_redundant_t *
254 10 : lt_redundant_db_lookup(lt_redundant_db_t *redundantdb,
255 : const char *tag)
256 : {
257 : lt_redundant_t *retval;
258 : char *s;
259 :
260 10 : lt_return_val_if_fail (redundantdb != NULL, NULL);
261 10 : lt_return_val_if_fail (tag != NULL, NULL);
262 :
263 10 : s = strdup(tag);
264 10 : retval = lt_trie_lookup(redundantdb->redundant_entries,
265 10 : lt_strlower(s));
266 10 : free(s);
267 10 : if (retval)
268 2 : return lt_redundant_ref(retval);
269 :
270 8 : return NULL;
271 : }
|