Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 : /*
3 : * lt-extension.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 "lt-error.h"
20 : #include "lt-mem.h"
21 : #include "lt-messages.h"
22 : #include "lt-utils.h"
23 : #include "lt-ext-module-private.h"
24 : #include "lt-extension.h"
25 : #include "lt-extension-private.h"
26 :
27 :
28 : /**
29 : * SECTION: lt-extension
30 : * @Short_Description: A container class for Extension subtag
31 : * @Title: Container - Extension
32 : *
33 : * This container class provides a data access to Extension subtag entry.
34 : */
35 : struct _lt_extension_t {
36 : lt_mem_t parent;
37 : lt_string_t *cached_tag;
38 : lt_ext_module_t *module;
39 : int singleton;
40 : lt_ext_module_data_t *extensions[LT_MAX_EXT_MODULES + 1];
41 : };
42 :
43 : /*< private >*/
44 :
45 : /*< protected >*/
46 : lt_extension_t *
47 0 : lt_extension_create(void)
48 : {
49 0 : lt_extension_t *retval = lt_mem_alloc_object(sizeof (lt_extension_t));
50 :
51 0 : if (retval) {
52 0 : retval->cached_tag = lt_string_new(NULL);
53 0 : lt_mem_add_ref(&retval->parent, retval->cached_tag,
54 : (lt_destroy_func_t)lt_string_unref);
55 : }
56 :
57 0 : return retval;
58 : }
59 :
60 : lt_bool_t
61 0 : lt_extension_has_singleton(lt_extension_t *extension,
62 : char singleton_c)
63 : {
64 : int singleton;
65 :
66 0 : lt_return_val_if_fail (extension != NULL, FALSE);
67 :
68 0 : singleton = lt_ext_module_singleton_char_to_int(singleton_c);
69 0 : if (singleton < 0)
70 0 : return FALSE;
71 :
72 0 : return extension->extensions[singleton] != NULL;
73 : }
74 :
75 : lt_bool_t
76 0 : lt_extension_add_singleton(lt_extension_t *extension,
77 : char singleton_c,
78 : const lt_tag_t *tag,
79 : lt_error_t **error)
80 : {
81 0 : int singleton = lt_ext_module_singleton_char_to_int(singleton_c);
82 : lt_ext_module_t *m;
83 : lt_ext_module_data_t *d;
84 0 : lt_error_t *err = NULL;
85 :
86 0 : lt_return_val_if_fail (extension != NULL, FALSE);
87 0 : lt_return_val_if_fail (singleton_c != 'X' && singleton_c != 'x', FALSE);
88 0 : lt_return_val_if_fail (!lt_extension_has_singleton(extension, singleton_c), FALSE);
89 0 : lt_return_val_if_fail (singleton >= 0, FALSE);
90 :
91 0 : m = lt_ext_module_lookup(singleton_c);
92 0 : d = lt_ext_module_create_data(m);
93 0 : if (!d) {
94 0 : lt_ext_module_unref(m);
95 0 : lt_error_set(&err, LT_ERR_OOM,
96 : "Unable to create an instance of lt_ext_module_data_t.");
97 :
98 0 : goto bail;
99 : }
100 0 : if (tag && !lt_ext_module_precheck_tag(m, d, tag, &err)) {
101 0 : lt_ext_module_data_unref(d);
102 0 : lt_ext_module_unref(m);
103 :
104 0 : goto bail;
105 : }
106 0 : if (extension->module)
107 0 : lt_mem_delete_ref(&extension->parent, extension->module);
108 0 : extension->module = m;
109 0 : lt_mem_add_ref(&extension->parent, extension->module,
110 : (lt_destroy_func_t)lt_ext_module_unref);
111 0 : extension->extensions[singleton] = d;
112 0 : lt_mem_add_ref(&extension->parent, extension->extensions[singleton],
113 : (lt_destroy_func_t)lt_ext_module_data_unref);
114 0 : extension->singleton = singleton;
115 :
116 0 : if (lt_string_length(extension->cached_tag) > 0)
117 0 : lt_string_append_printf(extension->cached_tag, "-%c", singleton_c);
118 : else
119 0 : lt_string_append_c(extension->cached_tag, singleton_c);
120 :
121 : bail:
122 0 : if (lt_error_is_set(err, LT_ERR_ANY)) {
123 0 : if (error)
124 0 : *error = lt_error_ref(err);
125 : else
126 0 : lt_error_print(err, LT_ERR_ANY);
127 0 : lt_error_unref(err);
128 :
129 0 : return FALSE;
130 : }
131 :
132 0 : return TRUE;
133 : }
134 :
135 : lt_bool_t
136 0 : lt_extension_add_tag(lt_extension_t *extension,
137 : const char *subtag,
138 : lt_error_t **error)
139 : {
140 : lt_bool_t retval;
141 0 : lt_error_t *err = NULL;
142 :
143 0 : lt_return_val_if_fail (extension != NULL, FALSE);
144 0 : lt_return_val_if_fail (subtag != NULL, FALSE);
145 0 : lt_return_val_if_fail (extension->module != NULL, FALSE);
146 0 : lt_return_val_if_fail (extension->extensions[extension->singleton] != NULL, FALSE);
147 :
148 0 : retval = lt_ext_module_parse_tag(extension->module,
149 0 : extension->extensions[extension->singleton],
150 : subtag,
151 : &err);
152 0 : if (retval)
153 0 : lt_string_append_printf(extension->cached_tag, "-%s", subtag);
154 :
155 0 : 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 0 : return retval;
165 : }
166 :
167 : void
168 0 : lt_extension_cancel_tag(lt_extension_t *extension)
169 : {
170 0 : lt_return_if_fail (extension != NULL);
171 :
172 0 : if (extension->module && extension->extensions[extension->singleton]) {
173 : char *tags, singleton[4], *p, *lastp;
174 0 : lt_list_t *l = NULL, *ll;
175 :
176 0 : lt_mem_delete_ref(&extension->parent, extension->module);
177 0 : extension->module = NULL;
178 0 : lt_mem_delete_ref(&extension->parent, extension->extensions[extension->singleton]);
179 0 : extension->extensions[extension->singleton] = NULL;
180 :
181 0 : lastp = p = tags = strdup(lt_string_value(extension->cached_tag));
182 0 : while (p) {
183 0 : p = strchr(p, '-');
184 0 : if (p) {
185 0 : *p = 0;
186 0 : p++;
187 : }
188 0 : l = lt_list_append(l, lastp, NULL);
189 0 : lastp = p;
190 : }
191 0 : singleton[0] = lt_ext_module_singleton_int_to_char(extension->singleton);
192 0 : singleton[1] = 0;
193 0 : lt_string_clear(extension->cached_tag);
194 0 : for (ll = l; ll != NULL; ll = lt_list_next(ll)) {
195 0 : if (lt_strcmp0(lt_list_value(ll), singleton) == 0) {
196 0 : if (ll == l)
197 0 : l = NULL;
198 0 : lt_list_free(ll);
199 0 : break;
200 : }
201 0 : if (lt_string_length(extension->cached_tag) > 0)
202 0 : lt_string_append_printf(extension->cached_tag,
203 0 : "-%s", (char *)lt_list_value(ll));
204 : else
205 0 : lt_string_append(extension->cached_tag, lt_list_value(ll));
206 : }
207 0 : lt_list_free(l);
208 0 : if (tags)
209 0 : free(tags);
210 : }
211 : }
212 :
213 : lt_extension_t *
214 0 : lt_extension_copy(lt_extension_t *extension)
215 : {
216 : lt_extension_t *retval;
217 : int i;
218 :
219 0 : lt_return_val_if_fail (extension != NULL, NULL);
220 :
221 0 : retval = lt_extension_create();
222 0 : if (retval) {
223 0 : lt_string_append(retval->cached_tag, lt_string_value(extension->cached_tag));
224 0 : if (extension->module) {
225 0 : retval->module = lt_ext_module_ref(extension->module);
226 0 : lt_mem_add_ref(&retval->parent, retval->module,
227 : (lt_destroy_func_t)lt_ext_module_unref);
228 0 : retval->singleton = extension->singleton;
229 0 : for (i = 0; i < LT_MAX_EXT_MODULES; i++) {
230 0 : if (extension->extensions[i]) {
231 0 : retval->extensions[i] = lt_ext_module_data_ref(extension->extensions[i]);
232 0 : lt_mem_add_ref(&retval->parent, retval->extensions[i],
233 : (lt_destroy_func_t)lt_ext_module_data_unref);
234 : }
235 : }
236 : }
237 : }
238 :
239 0 : return retval;
240 : }
241 :
242 : lt_bool_t
243 0 : lt_extension_validate_state(lt_extension_t *extension)
244 : {
245 0 : lt_bool_t retval = TRUE;
246 :
247 0 : lt_return_val_if_fail (extension != NULL, FALSE);
248 :
249 0 : if (extension->module) {
250 0 : retval = lt_ext_module_validate_tag(extension->module,
251 0 : extension->extensions[extension->singleton]);
252 : }
253 :
254 0 : return retval;
255 : }
256 :
257 : /*< public >*/
258 : /**
259 : * lt_extension_ref:
260 : * @extension: a #lt_extension_t.
261 : *
262 : * Increases the reference count of @extension.
263 : *
264 : * Returns: (transfer none): the same @extension object.
265 : */
266 : lt_extension_t *
267 0 : lt_extension_ref(lt_extension_t *extension)
268 : {
269 0 : lt_return_val_if_fail (extension != NULL, NULL);
270 :
271 0 : return lt_mem_ref(&extension->parent);
272 : }
273 :
274 : /**
275 : * lt_extension_unref:
276 : * @extension: a #lt_extension_t.
277 : *
278 : * Decreases the reference count of @extension. when its reference count
279 : * drops to 0, the object is finalized (i.e. its memory is freed).
280 : */
281 : void
282 0 : lt_extension_unref(lt_extension_t *extension)
283 : {
284 0 : if (extension)
285 0 : lt_mem_unref(&extension->parent);
286 0 : }
287 :
288 : /**
289 : * lt_extension_get_tag:
290 : * @extension: a #lt_extension_t.
291 : *
292 : * Obtain the tag string.
293 : *
294 : * Returns: the tag string.
295 : */
296 : const char *
297 0 : lt_extension_get_tag(lt_extension_t *extension)
298 : {
299 0 : lt_return_val_if_fail (extension != NULL, NULL);
300 :
301 0 : return lt_string_value(extension->cached_tag);
302 : }
303 :
304 : /**
305 : * lt_extension_get_canonicalized_tag:
306 : * @extension: a #lt_extension_t.
307 : *
308 : * Generate a canonicalized tag.
309 : *
310 : * Returns: a string. this must be freed.
311 : */
312 : char *
313 0 : lt_extension_get_canonicalized_tag(lt_extension_t *extension)
314 : {
315 : lt_string_t *string;
316 : int i;
317 : char c, *s;
318 : lt_ext_module_t *m;
319 :
320 0 : lt_return_val_if_fail (extension != NULL, NULL);
321 :
322 0 : string = lt_string_new(NULL);
323 :
324 0 : for (i = 0; i < LT_MAX_EXT_MODULES; i++) {
325 0 : if (extension->extensions[i]) {
326 0 : if (lt_string_length(string) > 0)
327 0 : lt_string_append_c(string, '-');
328 0 : c = lt_ext_module_singleton_int_to_char(i);
329 0 : lt_string_append_c(string, c);
330 0 : if (c != ' ' && c != '*') {
331 0 : m = lt_ext_module_lookup(c);
332 0 : if (m) {
333 0 : s = lt_ext_module_get_tag(m, extension->extensions[i]);
334 0 : lt_string_append_printf(string, "-%s", s);
335 0 : free(s);
336 0 : lt_ext_module_unref(m);
337 : } else {
338 0 : lt_warning("Unable to obtain the certain module instance: singleton = '%c", c);
339 0 : break;
340 : }
341 : }
342 : }
343 : }
344 :
345 0 : return lt_string_free(string, FALSE);
346 : }
347 :
348 : /**
349 : * lt_extension_dump:
350 : * @extension: a #lt_extension_t.
351 : *
352 : * Dumps the container information to the standard output.
353 : */
354 : void
355 0 : lt_extension_dump(lt_extension_t *extension)
356 : {
357 : int i;
358 : char c;
359 : char *s;
360 : lt_ext_module_t *m;
361 :
362 0 : lt_return_if_fail (extension != NULL);
363 :
364 0 : lt_info("Extensions:");
365 0 : for (i = 0; i < LT_MAX_EXT_MODULES; i++) {
366 0 : if (extension->extensions[i]) {
367 0 : c = lt_ext_module_singleton_int_to_char(i);
368 0 : if (c == ' ') {
369 0 : lt_info(" '' [empty]");
370 0 : } else if (c == '*') {
371 0 : lt_info(" '*' [wildcard]");
372 : } else {
373 0 : m = lt_ext_module_lookup(c);
374 0 : if (m) {
375 0 : s = lt_ext_module_get_tag(m, extension->extensions[i]);
376 0 : lt_info(" %c-%s", c, s);
377 0 : free(s);
378 0 : lt_ext_module_unref(m);
379 : } else {
380 0 : lt_warning(" [failed to obtain the module instance: singleton = '%c', data = %p]",
381 : c, extension->extensions[i]);
382 : }
383 : }
384 : }
385 : }
386 : }
387 :
388 : /**
389 : * lt_extension_compare:
390 : * @v1: a #lt_extension_t.
391 : * @v2: a #lt_extension_t.
392 : *
393 : * Compare if @v1 and @v2 is the same object or not.
394 : *
395 : * Returns: %TRUE if it's the same, otherwise %FALSE.
396 : */
397 : lt_bool_t
398 0 : lt_extension_compare(const lt_extension_t *v1,
399 : const lt_extension_t *v2)
400 : {
401 : int i;
402 0 : char *s1 = NULL, *s2 = NULL;
403 0 : lt_ext_module_t *m = NULL;
404 0 : lt_bool_t retval = TRUE;
405 :
406 0 : if (v1 == v2)
407 0 : return TRUE;
408 :
409 0 : if ((v1 && v1->extensions[LT_MAX_EXT_MODULES - 1]) ||
410 0 : (v2 && v2->extensions[LT_MAX_EXT_MODULES - 1]))
411 0 : return TRUE;
412 :
413 0 : if ((!v1 && v2) ||
414 0 : (v1 && !v2))
415 0 : return FALSE;
416 :
417 0 : for (i = 0; i < LT_MAX_EXT_MODULES - 2; i++) {
418 0 : if ((!v1->extensions[i] && v2->extensions[i]) ||
419 0 : (v1->extensions[i] && !v2->extensions[i])) {
420 0 : retval = FALSE;
421 0 : break;
422 : }
423 :
424 0 : if (m)
425 0 : lt_ext_module_unref(m);
426 0 : m = lt_ext_module_lookup(lt_ext_module_singleton_int_to_char(i));
427 0 : if (s1)
428 0 : free(s1);
429 0 : if (s2)
430 0 : free(s2);
431 0 : s1 = lt_ext_module_get_tag(m, v1->extensions[i]);
432 0 : s2 = lt_ext_module_get_tag(m, v2->extensions[i]);
433 0 : if (lt_strcmp0(s1, s2)) {
434 0 : retval = FALSE;
435 0 : break;
436 : }
437 : }
438 :
439 0 : if (m)
440 0 : lt_ext_module_unref(m);
441 0 : if (s1)
442 0 : free(s1);
443 0 : if (s2)
444 0 : free(s2);
445 :
446 0 : return retval;
447 : }
448 :
449 : /**
450 : * lt_extension_truncate:
451 : * @extension: a #lt_extension_t.
452 : *
453 : * Truncate the last extension.
454 : *
455 : * Returns: %TRUE if a subtag of the extension is truncated. otherwise %FALSE.
456 : */
457 : lt_bool_t
458 0 : lt_extension_truncate(lt_extension_t *extension)
459 : {
460 : int i;
461 0 : lt_bool_t retval = FALSE;
462 :
463 0 : lt_return_val_if_fail (extension != NULL, FALSE);
464 :
465 0 : for (i = LT_MAX_EXT_MODULES - 1; i >= 0; i--) {
466 0 : if (extension->extensions[i]) {
467 0 : lt_mem_delete_ref(&extension->parent, extension->extensions[i]);
468 0 : extension->extensions[i] = NULL;
469 0 : retval = TRUE;
470 0 : break;
471 : }
472 : }
473 :
474 0 : return retval;
475 : }
|