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