1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * lt-variant.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-mem.h"
20 #include "lt-messages.h"
21 #include "lt-string.h"
22 #include "lt-utils.h"
23 #include "lt-variant.h"
24 #include "lt-variant-private.h"
25 
26 
27 /**
28  * SECTION: lt-variant
29  * @Short_Description: A container class for Variant subtag
30  * @Title: Container - Variant
31  *
32  * This container class provides a data access to Variant subtag entry.
33  */
34 struct _lt_variant_t {
35 	lt_mem_t   parent;
36 	char      *tag;
37 	char      *description;
38 	char      *preferred_tag;
39 	lt_list_t *prefix;
40 };
41 
42 /*< private >*/
43 
44 /*< protected >*/
45 lt_variant_t *
lt_variant_create(void)46 lt_variant_create(void)
47 {
48 	lt_variant_t *retval;
49 
50 	retval = lt_mem_alloc_object(sizeof (lt_variant_t));
51 
52 	return retval;
53 }
54 
55 void
lt_variant_set_tag(lt_variant_t * variant,const char * subtag)56 lt_variant_set_tag(lt_variant_t *variant,
57 		   const char   *subtag)
58 {
59 	lt_return_if_fail (variant != NULL);
60 	lt_return_if_fail (subtag != NULL);
61 
62 	if (variant->tag)
63 		lt_mem_delete_ref(&variant->parent, variant->tag);
64 	variant->tag = strdup(subtag);
65 	lt_mem_add_ref(&variant->parent, variant->tag, free);
66 }
67 
68 void
lt_variant_set_preferred_tag(lt_variant_t * variant,const char * subtag)69 lt_variant_set_preferred_tag(lt_variant_t *variant,
70 			     const char   *subtag)
71 {
72 	lt_return_if_fail (variant != NULL);
73 	lt_return_if_fail (subtag != NULL);
74 
75 	if (variant->preferred_tag)
76 		lt_mem_delete_ref(&variant->parent, variant->preferred_tag);
77 	variant->preferred_tag = strdup(subtag);
78 	lt_mem_add_ref(&variant->parent, variant->preferred_tag, free);
79 }
80 
81 void
lt_variant_set_name(lt_variant_t * variant,const char * description)82 lt_variant_set_name(lt_variant_t *variant,
83 		    const char   *description)
84 {
85 	lt_return_if_fail (variant != NULL);
86 	lt_return_if_fail (description != NULL);
87 
88 	if (variant->description)
89 		lt_mem_delete_ref(&variant->parent, variant->description);
90 	variant->description = strdup(description);
91 	lt_mem_add_ref(&variant->parent, variant->description, free);
92 }
93 
94 void
lt_variant_add_prefix(lt_variant_t * variant,const char * prefix)95 lt_variant_add_prefix(lt_variant_t *variant,
96 		      const char   *prefix)
97 {
98 	lt_bool_t no_prefixes;
99 
100 	lt_return_if_fail (variant != NULL);
101 	lt_return_if_fail (prefix != NULL);
102 
103 	no_prefixes = variant->prefix == NULL;
104 	variant->prefix = lt_list_append(variant->prefix, strdup(prefix), free);
105 	if (no_prefixes)
106 		lt_mem_add_ref(&variant->parent, variant->prefix, lt_list_free);
107 }
108 
109 /*< public >*/
110 /**
111  * lt_variant_ref:
112  * @variant: a #lt_variant_t.
113  *
114  * Increases the reference count of @variant.
115  *
116  * Returns: (transfer none): the same @variant object.
117  */
118 lt_variant_t *
lt_variant_ref(lt_variant_t * variant)119 lt_variant_ref(lt_variant_t *variant)
120 {
121 	lt_return_val_if_fail (variant != NULL, NULL);
122 
123 	return lt_mem_ref(&variant->parent);
124 }
125 
126 /**
127  * lt_variant_unref:
128  * @variant: a #lt_variant_t.
129  *
130  * Decreases the reference count of @variant. when its reference count
131  * drops to 0, the object is finalized (i.e. its memory is freed).
132  */
133 void
lt_variant_unref(lt_variant_t * variant)134 lt_variant_unref(lt_variant_t *variant)
135 {
136 	if (variant)
137 		lt_mem_unref(&variant->parent);
138 }
139 
140 /**
141  * lt_variant_get_better_tag:
142  * @variant: a #lt_variant_t.
143  *
144  * Obtains the better tag for use. this is a convenient function to get
145  * the preferred-value if available.
146  *
147  * Returns: a tag string.
148  */
149 const char *
lt_variant_get_better_tag(const lt_variant_t * variant)150 lt_variant_get_better_tag(const lt_variant_t *variant)
151 {
152 	const char *retval = lt_variant_get_preferred_tag(variant);
153 
154 	if (!retval)
155 		retval = lt_variant_get_tag(variant);
156 
157 	return retval;
158 }
159 
160 /**
161  * lt_variant_get_tag:
162  * @variant: a #lt_variant_t.
163  *
164  * Obtains the tag name.
165  *
166  * Returns: a tag string.
167  */
168 const char *
lt_variant_get_tag(const lt_variant_t * variant)169 lt_variant_get_tag(const lt_variant_t *variant)
170 {
171 	lt_return_val_if_fail (variant != NULL, NULL);
172 
173 	return variant->tag;
174 }
175 
176 /**
177  * lt_variant_get_preferred_tag:
178  * @variant: a #lt_variant_t.
179  *
180  * Obtains the preferred-value. this is available only when the tag is
181  * marked as deprecated.
182  *
183  * Returns: a preferred-value for the tag or %NULL.
184  */
185 const char *
lt_variant_get_preferred_tag(const lt_variant_t * variant)186 lt_variant_get_preferred_tag(const lt_variant_t *variant)
187 {
188 	lt_return_val_if_fail (variant != NULL, NULL);
189 
190 	return variant->preferred_tag;
191 }
192 
193 /**
194  * lt_variant_get_name:
195  * @variant: a #lt_variant_t.
196  *
197  * Obtains the description of the subtag.
198  *
199  * Returns: a description string.
200  */
201 const char *
lt_variant_get_name(const lt_variant_t * variant)202 lt_variant_get_name(const lt_variant_t *variant)
203 {
204 	lt_return_val_if_fail (variant != NULL, NULL);
205 
206 	return variant->description;
207 }
208 
209 /**
210  * lt_variant_get_prefix:
211  * @variant: a #lt_variant_t.
212  *
213  * Obtains the prefix being assigned to the subtag.
214  * This is available only when the subtag has any suitable sequence of
215  * subtags for forming (with other subtags, as appropriate) a language
216  * tag when using the variant.
217  *
218  * Returns: (transfer none): a #lt_list_t contains prefix strings or %NULL.
219  */
220 const lt_list_t *
lt_variant_get_prefix(const lt_variant_t * variant)221 lt_variant_get_prefix(const lt_variant_t *variant)
222 {
223 	lt_return_val_if_fail (variant != NULL, NULL);
224 
225 	return variant->prefix;
226 }
227 
228 /**
229  * lt_variant_dump:
230  * @variant: a #lt_variant_t.
231  *
232  * Dumps the container information to the standard output.
233  */
234 void
lt_variant_dump(const lt_variant_t * variant)235 lt_variant_dump(const lt_variant_t *variant)
236 {
237 	lt_string_t *string = lt_string_new(NULL);
238 	const lt_list_t *list, *l;
239 	const char *preferred = lt_variant_get_preferred_tag(variant);
240 
241 	list = lt_variant_get_prefix(variant);
242 	for (l = list; l != NULL; l = lt_list_next(l)) {
243 		if (lt_string_length(string) == 0)
244 			lt_string_append(string, " (prefix = [");
245 		else
246 			lt_string_append(string, ", ");
247 		lt_string_append(string, (const char *)lt_list_value(l));
248 	}
249 	if (lt_string_length(string) > 0)
250 		lt_string_append(string, "]");
251 	if (preferred) {
252 		if (lt_string_length(string) == 0)
253 			lt_string_append(string, " (");
254 		else
255 			lt_string_append(string, ", ");
256 		lt_string_append_printf(string, "preferred-value: %s",
257 					preferred);
258 	}
259 	if (lt_string_length(string) > 0)
260 		lt_string_append(string, ")");
261 
262 	lt_info("Variant: %s [%s]%s",
263 		lt_variant_get_tag(variant),
264 		lt_variant_get_name(variant),
265 		lt_string_value(string));
266 
267 	lt_string_unref(string);
268 }
269 
270 /**
271  * lt_variant_compare:
272  * @v1: a #lt_variant_t.
273  * @v2: a #lt_variant_t.
274  *
275  * Compare if @v1 and @v2 is the same object or not.
276  *
277  * Returns: %TRUE if it's the same, otherwise %FALSE.
278  */
279 lt_bool_t
lt_variant_compare(const lt_variant_t * v1,const lt_variant_t * v2)280 lt_variant_compare(const lt_variant_t *v1,
281 		   const lt_variant_t *v2)
282 {
283 	const char *s1, *s2;
284 
285 	if (v1 == v2)
286 		return TRUE;
287 
288 	s1 = v1 ? lt_variant_get_tag(v1) : NULL;
289 	s2 = v2 ? lt_variant_get_tag(v2) : NULL;
290 
291 	if (lt_strcmp0(s1, "*") == 0 ||
292 	    lt_strcmp0(s2, "*") == 0)
293 		return TRUE;
294 
295 	return lt_strcmp0(s1, s2) == 0;
296 }
297