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 : }
|