File: | liblangtag/unxlngi6.pro/misc/build/liblangtag-0.2/liblangtag/lt-tag.c |
Location: | line 1103, column 5 |
Description: | Value stored to 'l' is never read |
1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2 | /* |
3 | * lt-tag.c |
4 | * Copyright (C) 2011-2012 Akira TAGOH |
5 | * |
6 | * Authors: |
7 | * Akira TAGOH <akira@tagoh.org> |
8 | * |
9 | * This library is free software: you can redistribute it and/or |
10 | * modify it under the terms of the GNU Lesser General Public |
11 | * License as published by the Free Software Foundation, either |
12 | * version 3 of the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | */ |
22 | #ifdef HAVE_CONFIG_H1 |
23 | #include "config.h" |
24 | #endif |
25 | |
26 | #include <string.h> |
27 | #include "lt-database.h" |
28 | #include "lt-error.h" |
29 | #include "lt-ext-module-private.h" |
30 | #include "lt-extension-private.h" |
31 | #include "lt-mem.h" |
32 | #include "lt-utils.h" |
33 | #include "lt-tag.h" |
34 | #include "lt-tag-private.h" |
35 | |
36 | |
37 | /** |
38 | * SECTION: lt-tag |
39 | * @Short_Description: A container class for Language tag |
40 | * @Title: Container - Tag |
41 | * |
42 | * This container class provides an interface to deal with the language tag. |
43 | */ |
44 | typedef struct _lt_tag_scanner_t { |
45 | lt_mem_t parent; |
46 | gchar *string; |
47 | gsize length; |
48 | gsize position; |
49 | } lt_tag_scanner_t; |
50 | |
51 | struct _lt_tag_t { |
52 | lt_mem_t parent; |
53 | gint32 wildcard_map; |
54 | gchar *tag_string; |
55 | lt_lang_t *language; |
56 | lt_extlang_t *extlang; |
57 | lt_script_t *script; |
58 | lt_region_t *region; |
59 | GList *variants; |
60 | lt_extension_t *extension; |
61 | GString *privateuse; |
62 | lt_grandfathered_t *grandfathered; |
63 | }; |
64 | |
65 | /*< private >*/ |
66 | static void |
67 | _lt_tag_gstring_free(GString *string) |
68 | { |
69 | g_string_free(string, TRUE(!(0))); |
70 | } |
71 | |
72 | static gboolean |
73 | _lt_tag_gstring_compare(const GString *v1, |
74 | const GString *v2) |
75 | { |
76 | gboolean retval = FALSE(0); |
77 | gchar *s1, *s2; |
78 | |
79 | if (v1 == v2) |
80 | return TRUE(!(0)); |
81 | |
82 | s1 = v1 ? lt_strlower(g_strdup(v1->str)) : NULL((void*)0); |
83 | s2 = v2 ? lt_strlower(g_strdup(v2->str)) : NULL((void*)0); |
84 | |
85 | if (g_strcmp0(s1, "*") == 0 || |
86 | g_strcmp0(s2, "*") == 0) { |
87 | retval = TRUE(!(0)); |
88 | goto bail; |
89 | } |
90 | |
91 | retval = g_strcmp0(s1, s2) == 0; |
92 | bail: |
93 | g_free(s1); |
94 | g_free(s2); |
95 | |
96 | return retval; |
97 | } |
98 | |
99 | static void |
100 | _lt_tag_variants_list_free(GList *list) |
101 | { |
102 | GList *l; |
103 | |
104 | for (l = list; l != NULL((void*)0); l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0))) { |
105 | lt_variant_unref(l->data); |
106 | } |
107 | g_list_free(list); |
108 | } |
109 | |
110 | static lt_tag_scanner_t * |
111 | lt_tag_scanner_new(const gchar *tag) |
112 | { |
113 | lt_tag_scanner_t *retval = lt_mem_alloc_object(sizeof (lt_tag_scanner_t)); |
114 | |
115 | if (retval) { |
116 | retval->string = g_strdup(tag); |
117 | lt_mem_add_ref(&retval->parent, retval->string, |
118 | (lt_destroy_func_t)g_free); |
119 | retval->length = strlen(tag); |
120 | } |
121 | |
122 | return retval; |
123 | } |
124 | |
125 | static void |
126 | lt_tag_scanner_unref(lt_tag_scanner_t *scanner) |
127 | { |
128 | if (scanner) |
129 | lt_mem_unref(&scanner->parent); |
130 | } |
131 | |
132 | static gboolean |
133 | lt_tag_scanner_get_token(lt_tag_scanner_t *scanner, |
134 | gchar **retval, |
135 | gsize *length, |
136 | GError **error) |
137 | { |
138 | GString *string = NULL((void*)0); |
139 | gchar c; |
140 | GError *err = NULL((void*)0); |
141 | |
142 | g_return_val_if_fail (scanner != NULL, FALSE)do{ if (scanner != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "scanner != NULL"); return ( (0)); }; }while (0); |
143 | |
144 | if (scanner->position >= scanner->length) { |
145 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_EOT, |
146 | "No more tokens in buffer"); |
147 | goto bail; |
148 | } |
149 | |
150 | string = g_string_new(NULL((void*)0)); |
151 | while (scanner->position < scanner->length) { |
152 | c = scanner->string[scanner->position++]; |
153 | if (c == 0) { |
154 | if (string->len == 0) { |
155 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_EOT, |
156 | "No more tokens in buffer"); |
157 | } |
158 | scanner->position--; |
159 | break; |
160 | } |
161 | if (c == '*') { |
162 | if (string->len > 0) { |
163 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
164 | "Invalid wildcard: positon = %" G_GSIZE_FORMAT"u", |
165 | scanner->position - 1); |
166 | break; |
167 | } |
168 | } else if (!g_ascii_isalnum(c)((g_ascii_table[(guchar) (c)] & G_ASCII_ALNUM) != 0) && c != '-' && c != 0) { |
169 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
170 | "Invalid character for tag: '%c'", c); |
171 | break; |
172 | } |
173 | g_string_append_c(string, c)g_string_append_c_inline (string, c); |
174 | |
175 | if (c == '-' || |
176 | c == '*') |
177 | break; |
178 | if (scanner->string[scanner->position] == '-' || |
179 | scanner->string[scanner->position] == 0) |
180 | break; |
181 | } |
182 | bail: |
183 | if (err) { |
184 | if (error) |
185 | *error = g_error_copy(err); |
186 | else |
187 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
188 | g_error_free(err); |
189 | if (string) |
190 | g_string_free(string, TRUE(!(0))); |
191 | *retval = NULL((void*)0); |
192 | *length = 0; |
193 | |
194 | return FALSE(0); |
195 | } |
196 | |
197 | *length = string->len; |
198 | *retval = g_string_free(string, FALSE(0)); |
199 | |
200 | return TRUE(!(0)); |
201 | } |
202 | |
203 | static gboolean |
204 | lt_tag_scanner_is_eof(lt_tag_scanner_t *scanner) |
205 | { |
206 | g_return_val_if_fail (scanner != NULL, TRUE)do{ if (scanner != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "scanner != NULL"); return ( (!(0))); }; }while (0); |
207 | g_return_val_if_fail (scanner->position <= scanner->length, TRUE)do{ if (scanner->position <= scanner->length) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "scanner->position <= scanner->length" ); return ((!(0))); }; }while (0); |
208 | |
209 | return scanner->string[scanner->position] == 0 || |
210 | scanner->position >= scanner->length; |
211 | } |
212 | |
213 | static gint |
214 | _lt_tag_variant_compare(gconstpointer a, |
215 | gconstpointer b) |
216 | { |
217 | return (gulong)a - (gulong)b; |
218 | } |
219 | |
220 | #define DEFUNC_TAG_FREE(__func__) \ |
221 | G_INLINE_FUNCstatic __inline __attribute__ ((unused)) void \ |
222 | lt_tag_free_ ##__func__ (lt_tag_t *tag) \ |
223 | { \ |
224 | if (tag->__func__) { \ |
225 | lt_mem_remove_ref(&tag->parent, tag->__func__); \ |
226 | tag->__func__ = NULL((void*)0); \ |
227 | } \ |
228 | } |
229 | |
230 | DEFUNC_TAG_FREE (language) |
231 | DEFUNC_TAG_FREE (extlang) |
232 | DEFUNC_TAG_FREE (script) |
233 | DEFUNC_TAG_FREE (region) |
234 | DEFUNC_TAG_FREE (variants) |
235 | DEFUNC_TAG_FREE (extension) |
236 | DEFUNC_TAG_FREE (grandfathered) |
237 | DEFUNC_TAG_FREE (tag_string) |
238 | |
239 | #undef DEFUNC_TAG_FREE |
240 | |
241 | #define DEFUNC_TAG_SET(__func__, __unref_func__) \ |
242 | G_INLINE_FUNCstatic __inline __attribute__ ((unused)) void \ |
243 | lt_tag_set_ ##__func__ (lt_tag_t *tag, gpointer p) \ |
244 | { \ |
245 | lt_tag_free_ ##__func__ (tag); \ |
246 | if (p) { \ |
247 | tag->__func__ = p; \ |
248 | lt_mem_add_ref(&tag->parent, tag->__func__, \ |
249 | (lt_destroy_func_t)__unref_func__); \ |
250 | } \ |
251 | } |
252 | |
253 | DEFUNC_TAG_SET (language, lt_lang_unref) |
254 | DEFUNC_TAG_SET (extlang, lt_extlang_unref) |
255 | DEFUNC_TAG_SET (script, lt_script_unref) |
256 | DEFUNC_TAG_SET (region, lt_region_unref) |
257 | DEFUNC_TAG_SET (extension, lt_extension_unref) |
258 | DEFUNC_TAG_SET (grandfathered, lt_grandfathered_unref) |
259 | DEFUNC_TAG_SET (tag_string, g_free) |
260 | |
261 | G_INLINE_FUNCstatic __inline __attribute__ ((unused)) void |
262 | lt_tag_set_variant(lt_tag_t *tag, |
263 | gpointer p) |
264 | { |
265 | gboolean no_variants = (tag->variants == NULL((void*)0)); |
266 | |
267 | if (p) { |
268 | tag->variants = g_list_append(tag->variants, p); |
269 | if (no_variants) |
270 | lt_mem_add_ref(&tag->parent, tag->variants, |
271 | (lt_destroy_func_t)_lt_tag_variants_list_free); |
272 | } else { |
273 | g_warn_if_reached()do { g_warn_message ("LangTag", "lt-tag.c", 273, ((const char *) (__PRETTY_FUNCTION__)), ((void*)0)); } while (0); |
274 | } |
275 | } |
276 | |
277 | #undef DEFUNC_TAG_SET |
278 | |
279 | static void |
280 | lt_tag_fill_wildcard(lt_tag_t *tag, |
281 | lt_tag_state_t begin, |
282 | lt_tag_state_t end) |
283 | { |
284 | lt_tag_state_t i; |
285 | lt_lang_db_t *langdb; |
286 | lt_extlang_db_t *extlangdb; |
287 | lt_script_db_t *scriptdb; |
288 | lt_region_db_t *regiondb; |
289 | lt_variant_db_t *variantdb; |
290 | lt_extension_t *e; |
291 | |
292 | for (i = begin; i < end; i++) { |
293 | tag->wildcard_map |= (1 << (i - 1)); |
294 | switch (i) { |
295 | case STATE_LANG: |
296 | langdb = lt_db_get_lang(); |
297 | lt_tag_set_language(tag, lt_lang_db_lookup(langdb, "*")); |
298 | lt_lang_db_unref(langdb); |
299 | break; |
300 | case STATE_EXTLANG: |
301 | extlangdb = lt_db_get_extlang(); |
302 | lt_tag_set_extlang(tag, lt_extlang_db_lookup(extlangdb, "*")); |
303 | lt_extlang_db_unref(extlangdb); |
304 | break; |
305 | case STATE_SCRIPT: |
306 | scriptdb = lt_db_get_script(); |
307 | lt_tag_set_script(tag, lt_script_db_lookup(scriptdb, "*")); |
308 | lt_script_db_unref(scriptdb); |
309 | break; |
310 | case STATE_REGION: |
311 | regiondb = lt_db_get_region(); |
312 | lt_tag_set_region(tag, lt_region_db_lookup(regiondb, "*")); |
313 | lt_region_db_unref(regiondb); |
314 | break; |
315 | case STATE_VARIANT: |
316 | variantdb = lt_db_get_variant(); |
317 | lt_tag_set_variant(tag, lt_variant_db_lookup(variantdb, "*")); |
318 | lt_variant_db_unref(variantdb); |
319 | break; |
320 | case STATE_EXTENSION: |
321 | e = lt_extension_create(); |
322 | lt_extension_add_singleton(e, '*', NULL((void*)0), NULL((void*)0)); |
323 | lt_tag_set_extension(tag, e); |
324 | break; |
325 | case STATE_PRIVATEUSE: |
326 | g_string_truncate(tag->privateuse, 0); |
327 | g_string_append(tag->privateuse, "*"); |
328 | break; |
329 | default: |
330 | break; |
331 | } |
332 | } |
333 | } |
334 | |
335 | static gboolean |
336 | lt_tag_parse_prestate(lt_tag_t *tag, |
337 | const gchar *token, |
338 | gsize length, |
339 | lt_tag_state_t *state, |
340 | GError **error) |
341 | { |
342 | gboolean retval = TRUE(!(0)); |
343 | |
344 | if (g_strcmp0(token, "-") == 0) { |
345 | switch (*state) { |
346 | case STATE_PRE_EXTLANG: |
347 | *state = STATE_EXTLANG; |
348 | break; |
349 | case STATE_PRE_SCRIPT: |
350 | *state = STATE_SCRIPT; |
351 | break; |
352 | case STATE_PRE_REGION: |
353 | *state = STATE_REGION; |
354 | break; |
355 | case STATE_PRE_VARIANT: |
356 | *state = STATE_VARIANT; |
357 | break; |
358 | case STATE_PRE_EXTENSION: |
359 | *state = STATE_EXTENSION; |
360 | break; |
361 | case STATE_IN_EXTENSION: |
362 | *state = STATE_EXTENSIONTOKEN; |
363 | break; |
364 | case STATE_IN_EXTENSIONTOKEN: |
365 | *state = STATE_EXTENSIONTOKEN2; |
366 | break; |
367 | case STATE_PRE_PRIVATEUSE: |
368 | *state = STATE_PRIVATEUSE; |
369 | break; |
370 | case STATE_IN_PRIVATEUSE: |
371 | *state = STATE_PRIVATEUSETOKEN; |
372 | break; |
373 | case STATE_IN_PRIVATEUSETOKEN: |
374 | *state = STATE_PRIVATEUSETOKEN2; |
375 | break; |
376 | default: |
377 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
378 | "Invalid syntax found during parsing a token: %s", |
379 | token); |
380 | retval = FALSE(0); |
381 | break; |
382 | } |
383 | } else { |
384 | retval = FALSE(0); |
385 | } |
386 | |
387 | return retval; |
388 | } |
389 | |
390 | static gboolean |
391 | lt_tag_parse_state(lt_tag_t *tag, |
392 | const gchar *token, |
393 | gsize length, |
394 | lt_tag_state_t *state, |
395 | GError **error) |
396 | { |
397 | gboolean retval = TRUE(!(0)); |
398 | const gchar *p; |
399 | |
400 | switch (*state) { |
401 | case STATE_LANG: |
402 | if (length == 1) { |
403 | if (g_ascii_strcasecmp(token, "x") == 0) { |
404 | g_string_append(tag->privateuse, token); |
405 | *state = STATE_IN_PRIVATEUSE; |
406 | break; |
407 | } else { |
408 | invalid_tag: |
409 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
410 | "Invalid language subtag: %s", token); |
411 | break; |
412 | } |
413 | } else if (length >= 2 && length <= 3) { |
414 | lt_lang_db_t *langdb = lt_db_get_lang(); |
415 | |
416 | /* shortest ISO 639 code */ |
417 | tag->language = lt_lang_db_lookup(langdb, token); |
418 | lt_lang_db_unref(langdb); |
419 | if (!tag->language) { |
420 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
421 | "Unknown ISO 639 code: %s", |
422 | token); |
423 | break; |
424 | } |
425 | /* validate if it's really shortest one */ |
426 | p = lt_lang_get_tag(tag->language); |
427 | if (!p || g_ascii_strcasecmp(token, p) != 0) { |
428 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
429 | "No such language subtag: %s", |
430 | token); |
431 | lt_lang_unref(tag->language); |
432 | tag->language = NULL((void*)0); |
433 | break; |
434 | } |
435 | lt_mem_add_ref(&tag->parent, tag->language, |
436 | (lt_destroy_func_t)lt_lang_unref); |
437 | *state = STATE_PRE_EXTLANG; |
438 | } else if (length == 4) { |
439 | /* reserved for future use */ |
440 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
441 | "Reserved for future use: %s", |
442 | token); |
443 | } else if (length >= 5 && length <= 8) { |
444 | /* registered language subtag */ |
445 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
446 | "XXX: registered language tag: %s", |
447 | token); |
448 | } else { |
449 | goto invalid_tag; |
450 | } |
451 | break; |
452 | case STATE_EXTLANG: |
453 | if (length == 3) { |
454 | lt_extlang_db_t *extlangdb = lt_db_get_extlang(); |
455 | |
456 | tag->extlang = lt_extlang_db_lookup(extlangdb, token); |
457 | lt_extlang_db_unref(extlangdb); |
458 | if (tag->extlang) { |
459 | const gchar *prefix = lt_extlang_get_prefix(tag->extlang); |
460 | const gchar *subtag = lt_extlang_get_tag(tag->extlang); |
461 | const gchar *lang = lt_lang_get_better_tag(tag->language); |
462 | |
463 | if (prefix && |
464 | g_ascii_strcasecmp(prefix, lang) != 0) { |
465 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
466 | "extlang '%s' is supposed to be used with %s, but %s", |
467 | subtag, prefix, lang); |
468 | lt_extlang_unref(tag->extlang); |
469 | tag->extlang = NULL((void*)0); |
470 | } else { |
471 | lt_mem_add_ref(&tag->parent, tag->extlang, |
472 | (lt_destroy_func_t)lt_extlang_unref); |
473 | *state = STATE_PRE_SCRIPT; |
474 | } |
475 | break; |
476 | } |
477 | /* try to check something else */ |
478 | } else { |
479 | /* it may be a script */ |
480 | } |
481 | case STATE_SCRIPT: |
482 | if (length == 4) { |
483 | lt_script_db_t *scriptdb = lt_db_get_script(); |
484 | |
485 | lt_tag_set_script(tag, lt_script_db_lookup(scriptdb, token)); |
486 | lt_script_db_unref(scriptdb); |
487 | if (tag->script) { |
488 | *state = STATE_PRE_REGION; |
489 | break; |
490 | } |
491 | /* try to check something else */ |
492 | } else { |
493 | /* it may be a region */ |
494 | } |
495 | case STATE_REGION: |
496 | if (length == 2 || |
497 | (length == 3 && |
498 | g_ascii_isdigit(token[0])((g_ascii_table[(guchar) (token[0])] & G_ASCII_DIGIT) != 0 ) && |
499 | g_ascii_isdigit(token[1])((g_ascii_table[(guchar) (token[1])] & G_ASCII_DIGIT) != 0 ) && |
500 | g_ascii_isdigit(token[2])((g_ascii_table[(guchar) (token[2])] & G_ASCII_DIGIT) != 0 ))) { |
501 | lt_region_db_t *regiondb = lt_db_get_region(); |
502 | |
503 | lt_tag_set_region(tag, lt_region_db_lookup(regiondb, token)); |
504 | lt_region_db_unref(regiondb); |
505 | if (tag->region) { |
506 | *state = STATE_PRE_VARIANT; |
507 | break; |
508 | } |
509 | /* try to check something else */ |
510 | } else { |
511 | /* it may be a variant */ |
512 | } |
513 | case STATE_VARIANT: |
514 | if ((length >=5 && length <= 8) || |
515 | (length == 4 && g_ascii_isdigit(token[0])((g_ascii_table[(guchar) (token[0])] & G_ASCII_DIGIT) != 0 ))) { |
516 | lt_variant_db_t *variantdb = lt_db_get_variant(); |
517 | lt_variant_t *variant; |
518 | |
519 | variant = lt_variant_db_lookup(variantdb, token); |
520 | lt_variant_db_unref(variantdb); |
521 | if (variant) { |
522 | const GList *prefixes = lt_variant_get_prefix(variant), *l; |
523 | gchar *langtag = lt_tag_canonicalize(tag, error); |
524 | GString *str_prefixes = g_string_new(NULL((void*)0)); |
525 | gboolean matched = FALSE(0); |
526 | |
527 | if (error && *error) { |
528 | /* ignore it and fallback to the original tag string */ |
529 | g_error_free(*error); |
530 | *error = NULL((void*)0); |
531 | langtag = g_strdup(tag->tag_string); |
532 | } |
533 | for (l = prefixes; l != NULL((void*)0); l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0))) { |
534 | const gchar *s = l->data; |
535 | |
536 | if (str_prefixes->len > 0) |
537 | g_string_append(str_prefixes, ","); |
538 | g_string_append(str_prefixes, s); |
539 | |
540 | if (g_ascii_strncasecmp(s, langtag, strlen(s)) == 0) { |
541 | matched = TRUE(!(0)); |
542 | break; |
543 | } |
544 | } |
545 | if (prefixes && !matched) { |
546 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
547 | "variant '%s' is supposed to be used with %s, but %s", |
548 | token, str_prefixes->str, tag->tag_string); |
549 | lt_variant_unref(variant); |
550 | } else { |
551 | if (!tag->variants) { |
552 | lt_tag_set_variant(tag, variant); |
553 | } else { |
554 | GList *prefixes = (GList *)lt_variant_get_prefix(variant); |
555 | const gchar *tstr; |
556 | |
557 | lt_tag_free_tag_string(tag); |
558 | tstr = lt_tag_get_string(tag); |
559 | if (prefixes && !g_list_find_custom(prefixes, tstr, (GCompareFunc)g_strcmp0)) { |
560 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
561 | "Variant isn't allowed for %s: %s", |
562 | tstr, |
563 | lt_variant_get_tag(variant)); |
564 | lt_variant_unref(variant); |
565 | } else if (!prefixes && g_list_find_custom(tag->variants, variant, _lt_tag_variant_compare)) { |
566 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
567 | "Duplicate variants: %s", |
568 | lt_variant_get_tag(variant)); |
569 | lt_variant_unref(variant); |
570 | } else { |
571 | tag->variants = g_list_append(tag->variants, |
572 | variant); |
573 | } |
574 | } |
575 | /* multiple variants are allowed. */ |
576 | *state = STATE_PRE_VARIANT; |
577 | } |
578 | g_free(langtag); |
579 | g_string_free(str_prefixes, TRUE(!(0))); |
580 | break; |
581 | } |
582 | /* try to check something else */ |
583 | } else { |
584 | /* it may be an extension */ |
585 | } |
586 | case STATE_EXTENSION: |
587 | extension: |
588 | if (length == 1 && |
589 | token[0] != 'x' && |
590 | token[0] != 'X' && |
591 | token[0] != '*' && |
592 | token[0] != '-') { |
593 | if (!tag->extension) |
594 | lt_tag_set_extension(tag, lt_extension_create()); |
595 | if (lt_extension_has_singleton(tag->extension, token[0])) { |
596 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
597 | "Duplicate singleton for extension: %s", token); |
598 | } else { |
599 | if (lt_extension_add_singleton(tag->extension, |
600 | token[0], |
601 | tag, error)) { |
602 | *state = STATE_IN_EXTENSION; |
603 | } |
604 | } |
605 | break; |
606 | } else { |
607 | /* it may be a private use */ |
608 | } |
609 | case STATE_PRIVATEUSE: |
610 | if (length == 1 && (token[0] == 'x' || token[0] == 'X')) { |
611 | g_string_append(tag->privateuse, token); |
612 | *state = STATE_IN_PRIVATEUSE; |
613 | } else { |
614 | /* No state to try */ |
615 | retval = FALSE(0); |
616 | } |
617 | break; |
618 | case STATE_EXTENSIONTOKEN: |
619 | case STATE_EXTENSIONTOKEN2: |
620 | if (length >= 2 && length <= 8) { |
621 | if (lt_extension_add_tag(tag->extension, |
622 | token, error)) |
623 | *state = STATE_IN_EXTENSIONTOKEN; |
624 | } else { |
625 | if (*state == STATE_EXTENSIONTOKEN2 && |
626 | lt_extension_validate_state(tag->extension)) { |
627 | /* No need to destroy the previous tokens. |
628 | * fallback to check the extension again. |
629 | */ |
630 | goto extension; |
631 | } |
632 | lt_extension_cancel_tag(tag->extension); |
633 | /* No state to try */ |
634 | retval = FALSE(0); |
635 | } |
636 | break; |
637 | case STATE_PRIVATEUSETOKEN: |
638 | case STATE_PRIVATEUSETOKEN2: |
639 | if (length <= 8) { |
640 | g_string_append_printf(tag->privateuse, "-%s", token); |
641 | *state = STATE_IN_PRIVATEUSETOKEN; |
642 | } else { |
643 | /* 'x'/'X' is reserved singleton for the private use subtag. |
644 | * so nothing to fallback to anything else. |
645 | */ |
646 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
647 | "Invalid tag for the private use: token = '%s'", |
648 | token); |
649 | } |
650 | break; |
651 | default: |
652 | g_set_error(error, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
653 | "Unable to parse tag: %s, token = '%s' state = %d", |
654 | tag->tag_string, token, *state); |
655 | break; |
656 | } |
657 | if (*error) |
658 | retval = FALSE(0); |
659 | |
660 | return retval; |
661 | } |
662 | |
663 | static gboolean |
664 | _lt_tag_parse(lt_tag_t *tag, |
665 | const gchar *langtag, |
666 | gboolean allow_wildcard, |
667 | lt_tag_state_t *state, |
668 | GError **error) |
669 | { |
670 | lt_tag_scanner_t *scanner = NULL((void*)0); |
671 | lt_grandfathered_db_t *grandfathereddb; |
672 | gchar *token = NULL((void*)0); |
673 | gsize len = 0; |
674 | GError *err = NULL((void*)0); |
675 | gboolean retval = TRUE(!(0)); |
676 | lt_tag_state_t wildcard = STATE_NONE; |
677 | gint count = 0; |
678 | |
679 | g_return_val_if_fail (tag != NULL, FALSE)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return ((0) ); }; }while (0); |
680 | g_return_val_if_fail (langtag != NULL, FALSE)do{ if (langtag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "langtag != NULL"); return ( (0)); }; }while (0); |
681 | |
682 | lt_tag_clear(tag); |
683 | |
684 | grandfathereddb = lt_db_get_grandfathered(); |
685 | lt_tag_set_grandfathered(tag, lt_grandfathered_db_lookup(grandfathereddb, langtag)); |
686 | lt_grandfathered_db_unref(grandfathereddb); |
687 | if (tag->grandfathered) { |
688 | /* no need to lookup anymore. */ |
689 | goto bail; |
690 | } |
691 | |
692 | scanner = lt_tag_scanner_new(langtag); |
693 | *state = STATE_LANG; |
694 | while (!lt_tag_scanner_is_eof(scanner)) { |
695 | if (token) { |
696 | g_free(token); |
697 | token = NULL((void*)0); |
698 | } |
699 | if (!lt_tag_scanner_get_token(scanner, &token, &len, &err)) { |
700 | if (err) |
701 | break; |
702 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
703 | "Unrecoverable error"); |
704 | break; |
705 | } |
706 | count++; |
707 | if (!token || len == 0) { |
708 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
709 | "No valid tokens found"); |
710 | break; |
711 | } |
712 | if (!lt_tag_parse_prestate(tag, token, len, state, &err)) { |
713 | if (err) |
714 | break; |
715 | if (allow_wildcard && g_strcmp0(token, "*") == 0) { |
716 | wildcard = *state; |
717 | if (*state == STATE_LANG) |
718 | *state += 1; |
719 | else |
720 | *state -= 1; |
721 | } else { |
722 | if (!lt_tag_parse_state(tag, token, len, state, &err)) |
723 | break; |
724 | if (wildcard != STATE_NONE) { |
725 | lt_tag_fill_wildcard(tag, wildcard, *state - 1); |
726 | wildcard = STATE_NONE; |
727 | } |
728 | } |
729 | } |
730 | } |
731 | if (wildcard != STATE_NONE) { |
732 | lt_tag_fill_wildcard(tag, wildcard, STATE_END); |
733 | } |
734 | if (!err && |
735 | *state != STATE_PRE_EXTLANG && |
736 | *state != STATE_PRE_SCRIPT && |
737 | *state != STATE_PRE_REGION && |
738 | *state != STATE_PRE_VARIANT && |
739 | *state != STATE_PRE_EXTENSION && |
740 | *state != STATE_PRE_PRIVATEUSE && |
741 | *state != STATE_IN_EXTENSIONTOKEN && |
742 | *state != STATE_IN_PRIVATEUSETOKEN && |
743 | *state != STATE_NONE) { |
744 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
745 | "Invalid tag: %s, last token = '%s', state = %d, parsed count = %d", |
746 | langtag, token, *state, count); |
747 | } |
748 | bail: |
749 | lt_tag_set_tag_string(tag, g_strdup(langtag)); |
750 | lt_tag_scanner_unref(scanner); |
751 | if (err) { |
752 | if (error) |
753 | *error = g_error_copy(err); |
754 | else |
755 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
756 | g_error_free(err); |
757 | retval = FALSE(0); |
758 | } |
759 | g_free(token); |
760 | |
761 | return retval; |
762 | } |
763 | |
764 | static gboolean |
765 | _lt_tag_match(const lt_tag_t *v1, |
766 | lt_tag_t *v2, |
767 | lt_tag_state_t state) |
768 | { |
769 | g_return_val_if_fail (v1 != NULL, FALSE)do{ if (v1 != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v1 != NULL"); return ((0)) ; }; }while (0); |
770 | g_return_val_if_fail (v2 != NULL, FALSE)do{ if (v2 != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v2 != NULL"); return ((0)) ; }; }while (0); |
771 | |
772 | if (state > STATE_EXTLANG && !v2->extlang && v1->extlang) { |
773 | lt_extlang_db_t *db = lt_db_get_extlang(); |
774 | |
775 | lt_tag_set_extlang(v2, lt_extlang_db_lookup(db, "")); |
776 | lt_extlang_db_unref(db); |
777 | } |
778 | if (state > STATE_SCRIPT && !v2->script && v1->script) { |
779 | lt_script_db_t *db = lt_db_get_script(); |
780 | |
781 | lt_tag_set_script(v2, lt_script_db_lookup(db, "")); |
782 | lt_script_db_unref(db); |
783 | } |
784 | if (state > STATE_REGION && !v2->region && v1->region) { |
785 | lt_region_db_t *db = lt_db_get_region(); |
786 | |
787 | lt_tag_set_region(v2, lt_region_db_lookup(db, "")); |
788 | lt_region_db_unref(db); |
789 | } |
790 | if (state > STATE_VARIANT && !v2->variants && v1->variants) { |
791 | lt_variant_db_t *db = lt_db_get_variant(); |
792 | |
793 | lt_tag_set_variant(v2, lt_variant_db_lookup(db, "")); |
794 | lt_variant_db_unref(db); |
795 | } |
796 | if (state > STATE_EXTENSION && !v2->extension && v1->extension) { |
797 | lt_extension_t *e = lt_extension_create(); |
798 | |
799 | lt_extension_add_singleton(e, ' ', NULL((void*)0), NULL((void*)0)); |
800 | lt_tag_set_extension(v2, e); |
801 | } |
802 | |
803 | return lt_tag_compare(v1, v2); |
804 | } |
805 | |
806 | static void |
807 | _lt_tag_subtract(lt_tag_t *tag, |
808 | const lt_tag_t *rtag) |
809 | { |
810 | if (rtag->language) { |
811 | lt_tag_free_language(tag); |
812 | } |
813 | if (rtag->extlang) { |
814 | lt_tag_free_extlang(tag); |
815 | } |
816 | if (rtag->script) { |
817 | lt_tag_free_script(tag); |
818 | } |
819 | if (rtag->region) { |
820 | lt_tag_free_region(tag); |
821 | } |
822 | if (rtag->variants) { |
823 | lt_tag_free_variants(tag); |
824 | } |
825 | if (rtag->extension) { |
826 | /* XXX: how to deal with the multiple extensions? */ |
827 | lt_tag_free_extension(tag); |
828 | } |
829 | if (rtag->privateuse) { |
830 | if (tag->privateuse) |
831 | g_string_truncate(tag->privateuse, 0); |
832 | } |
833 | } |
834 | |
835 | static void |
836 | _lt_tag_replace(lt_tag_t *tag, |
837 | const lt_tag_t *rtag) |
838 | { |
839 | if (rtag->language) { |
840 | g_return_if_fail (!tag->language)do{ if (!tag->language) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "!tag->language"); return ; }; }while (0); |
841 | lt_tag_set_language(tag, lt_lang_ref(rtag->language)); |
842 | } |
843 | if (rtag->extlang) { |
844 | g_return_if_fail (!tag->extlang)do{ if (!tag->extlang) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "!tag->extlang"); return ; }; }while (0); |
845 | lt_tag_set_extlang(tag, lt_extlang_ref(rtag->extlang)); |
846 | } |
847 | if (rtag->script) { |
848 | g_return_if_fail (!tag->script)do{ if (!tag->script) { } else { g_return_if_fail_warning ( "LangTag", __PRETTY_FUNCTION__, "!tag->script"); return; } ; }while (0); |
849 | lt_tag_set_script(tag, lt_script_ref(rtag->script)); |
850 | } |
851 | if (rtag->region) { |
852 | g_return_if_fail (!tag->region)do{ if (!tag->region) { } else { g_return_if_fail_warning ( "LangTag", __PRETTY_FUNCTION__, "!tag->region"); return; } ; }while (0); |
853 | lt_tag_set_region(tag, lt_region_ref(rtag->region)); |
854 | } |
855 | if (rtag->variants) { |
856 | GList *l = rtag->variants; |
857 | |
858 | g_return_if_fail (!tag->variants)do{ if (!tag->variants) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "!tag->variants"); return ; }; }while (0); |
859 | |
860 | while (l != NULL((void*)0)) { |
861 | lt_tag_set_variant(tag, lt_variant_ref(l->data)); |
862 | l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0)); |
863 | } |
864 | } |
865 | if (rtag->extension) { |
866 | g_return_if_fail (!tag->extension)do{ if (!tag->extension) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "!tag->extension"); return ; }; }while (0); |
867 | lt_tag_set_extension(tag, lt_extension_ref(rtag->extension)); |
868 | } |
869 | if (rtag->privateuse) { |
870 | g_string_truncate(tag->privateuse, 0); |
871 | g_string_append(tag->privateuse, rtag->privateuse->str); |
872 | } |
873 | } |
874 | |
875 | /*< protected >*/ |
876 | lt_tag_state_t |
877 | lt_tag_parse_wildcard(lt_tag_t *tag, |
878 | const gchar *tag_string, |
879 | GError **error) |
880 | { |
881 | GError *err = NULL((void*)0); |
882 | lt_tag_state_t retval = STATE_NONE; |
883 | gboolean ret = _lt_tag_parse(tag, tag_string, TRUE(!(0)), &retval, &err); |
884 | |
885 | if (!ret && !err) { |
886 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_FAIL_ON_SCANNER, |
887 | "Unknown error during parsing a tag."); |
888 | } |
889 | if (err) { |
890 | if (error) |
891 | *error = g_error_copy(err); |
892 | else |
893 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
894 | g_error_free(err); |
895 | } |
896 | |
897 | return retval; |
898 | } |
899 | |
900 | /*< public >*/ |
901 | /** |
902 | * lt_tag_new: |
903 | * |
904 | * Create a new instance of #lt_tag_t. |
905 | * |
906 | * Returns: (transfer full): a new instance of #lt_tag_t. |
907 | */ |
908 | lt_tag_t * |
909 | lt_tag_new(void) |
910 | { |
911 | lt_tag_t *retval = lt_mem_alloc_object(sizeof (lt_tag_t)); |
912 | |
913 | if (retval) { |
914 | retval->privateuse = g_string_new(NULL((void*)0)); |
915 | lt_mem_add_ref(&retval->parent, retval->privateuse, |
916 | (lt_destroy_func_t)_lt_tag_gstring_free); |
917 | } |
918 | |
919 | return retval; |
920 | } |
921 | |
922 | /** |
923 | * lt_tag_ref: |
924 | * @tag: a #lt_tag_t. |
925 | * |
926 | * Increases the reference count of @tag. |
927 | * |
928 | * Returns: (transfer none): the same @tag object. |
929 | */ |
930 | lt_tag_t * |
931 | lt_tag_ref(lt_tag_t *tag) |
932 | { |
933 | g_return_val_if_fail (tag != NULL, NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return (((void *)0)); }; }while (0); |
934 | |
935 | return lt_mem_ref(&tag->parent); |
936 | } |
937 | |
938 | /** |
939 | * lt_tag_unref: |
940 | * @tag: a #lt_tag_t. |
941 | * |
942 | * Decreases the reference count of @tag. when its reference count |
943 | * drops to 0, the object is finalized (i.e. its memory is freed). |
944 | */ |
945 | void |
946 | lt_tag_unref(lt_tag_t *tag) |
947 | { |
948 | if (tag) |
949 | lt_mem_unref(&tag->parent); |
950 | } |
951 | |
952 | /** |
953 | * lt_tag_clear: |
954 | * @tag: a #lt_tag_t. |
955 | * |
956 | * (Re-)Initialize all of the subtag information stored in @tag. |
957 | */ |
958 | void |
959 | lt_tag_clear(lt_tag_t *tag) |
960 | { |
961 | g_return_if_fail (tag != NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return; }; } while (0); |
962 | |
963 | lt_tag_free_tag_string(tag); |
964 | lt_tag_free_language(tag); |
965 | lt_tag_free_extlang(tag); |
966 | lt_tag_free_script(tag); |
967 | lt_tag_free_region(tag); |
968 | lt_tag_free_variants(tag); |
969 | lt_tag_free_extension(tag); |
970 | if (tag->privateuse) { |
971 | g_string_truncate(tag->privateuse, 0); |
972 | } |
973 | lt_tag_free_grandfathered(tag); |
974 | } |
975 | |
976 | /** |
977 | * lt_tag_parse: |
978 | * @tag: a #lt_tag_t. |
979 | * @tag_string: language tag to be parsed. |
980 | * @error: (allow-none): a #GError or %NULL. |
981 | * |
982 | * Parse @tag_string and create appropriate instances for subtags. |
983 | * |
984 | * Returns: %TRUE if it's successfully completed, otherwise %FALSE. |
985 | */ |
986 | gboolean |
987 | lt_tag_parse(lt_tag_t *tag, |
988 | const gchar *tag_string, |
989 | GError **error) |
990 | { |
991 | lt_tag_state_t state = STATE_NONE; |
992 | |
993 | return _lt_tag_parse(tag, tag_string, FALSE(0), &state, error); |
994 | } |
995 | |
996 | /** |
997 | * lt_tag_copy: |
998 | * @tag: a #lt_tag_t. |
999 | * |
1000 | * Create a copy instance of @tag. |
1001 | * |
1002 | * Returns: (transfer full): a new instance of #lt_tag_t or %NULL if fails. |
1003 | */ |
1004 | lt_tag_t * |
1005 | lt_tag_copy(const lt_tag_t *tag) |
1006 | { |
1007 | lt_tag_t *retval; |
1008 | GList *l; |
1009 | |
1010 | g_return_val_if_fail (tag != NULL, NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return (((void *)0)); }; }while (0); |
1011 | |
1012 | retval = lt_tag_new(); |
1013 | retval->wildcard_map = tag->wildcard_map; |
1014 | if (tag->language) { |
1015 | lt_tag_set_language(retval, lt_lang_ref(tag->language)); |
1016 | } |
1017 | if (tag->extlang) { |
1018 | lt_tag_set_extlang(retval, lt_extlang_ref(tag->extlang)); |
1019 | } |
1020 | if (tag->script) { |
1021 | lt_tag_set_script(retval, lt_script_ref(tag->script)); |
1022 | } |
1023 | if (tag->region) { |
1024 | lt_tag_set_region(retval, lt_region_ref(tag->region)); |
1025 | } |
1026 | l = tag->variants; |
1027 | while (l != NULL((void*)0)) { |
1028 | lt_tag_set_variant(retval, lt_variant_ref(l->data)); |
1029 | l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0)); |
1030 | } |
1031 | if (tag->extension) { |
1032 | lt_tag_set_extension(retval, lt_extension_copy(tag->extension)); |
1033 | } |
1034 | if (tag->privateuse) { |
1035 | g_string_append(retval->privateuse, tag->privateuse->str); |
1036 | } |
1037 | if (tag->grandfathered) { |
1038 | lt_tag_set_grandfathered(retval, lt_grandfathered_ref(tag->grandfathered)); |
1039 | } |
1040 | |
1041 | return retval; |
1042 | } |
1043 | |
1044 | /** |
1045 | * lt_tag_truncate: |
1046 | * @tag: a #lt_tag_t. |
1047 | * @error: (allow-none): a #GError. |
1048 | * |
1049 | * Truncate the last subtag. |
1050 | * |
1051 | * Returns: %TRUE if a subtag was truncated, otherwise %FALSE. |
1052 | */ |
1053 | gboolean |
1054 | lt_tag_truncate(lt_tag_t *tag, |
1055 | GError **error) |
1056 | { |
1057 | GError *err = NULL((void*)0); |
1058 | gboolean retval = TRUE(!(0)); |
1059 | |
1060 | g_return_val_if_fail (tag != NULL, FALSE)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return ((0) ); }; }while (0); |
1061 | |
1062 | if (tag->grandfathered) { |
1063 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_NO_TAG, |
1064 | "Grandfathered subtag can't be truncated."); |
1065 | goto bail; |
1066 | } |
1067 | while (1) { |
1068 | if (tag->privateuse && tag->privateuse->len > 0) { |
1069 | g_string_truncate(tag->privateuse, 0); |
1070 | break; |
1071 | } |
1072 | if (tag->extension) { |
1073 | gint i; |
1074 | gchar c; |
1075 | gboolean has_tag = FALSE(0); |
1076 | |
1077 | lt_extension_truncate(tag->extension); |
1078 | for (i = 0; i < LT_MAX_EXT_MODULES(('9' - '0' + 1) + ('z' - 'a' + 1) + 2); i++) { |
1079 | c = lt_ext_module_singleton_int_to_char(i); |
1080 | |
1081 | if (c == 'x') |
1082 | continue; |
1083 | has_tag = lt_extension_has_singleton(tag->extension, c); |
1084 | if (has_tag) |
1085 | break; |
1086 | } |
1087 | if (!has_tag) { |
1088 | lt_tag_free_extension(tag); |
1089 | } |
1090 | break; |
1091 | } |
1092 | if (tag->variants) { |
1093 | GList *l = g_list_last(tag->variants); |
1094 | lt_variant_t *v = l->data; |
1095 | |
1096 | if (tag->variants == l) { |
1097 | lt_mem_delete_ref(&tag->parent, tag->variants); |
1098 | tag->variants = g_list_delete_link(tag->variants, l); |
1099 | if (tag->variants) |
1100 | lt_mem_add_ref(&tag->parent, tag->variants, |
1101 | (lt_destroy_func_t)_lt_tag_variants_list_free); |
1102 | } else { |
1103 | l = g_list_delete_link(l, l); |
Value stored to 'l' is never read | |
1104 | } |
1105 | lt_variant_unref(v); |
1106 | break; |
1107 | } |
1108 | if (tag->region) { |
1109 | lt_tag_free_region(tag); |
1110 | break; |
1111 | } |
1112 | if (tag->script) { |
1113 | lt_tag_free_script(tag); |
1114 | break; |
1115 | } |
1116 | if (tag->extlang) { |
1117 | lt_tag_free_extlang(tag); |
1118 | break; |
1119 | } |
1120 | if (tag->language) { |
1121 | lt_tag_free_language(tag); |
1122 | break; |
1123 | } |
1124 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_NO_TAG, |
1125 | "No tags to be truncated."); |
1126 | goto bail; |
1127 | } |
1128 | lt_tag_free_tag_string(tag); |
1129 | bail: |
1130 | if (err) { |
1131 | if (error) |
1132 | *error = g_error_copy(err); |
1133 | else |
1134 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
1135 | g_error_free(err); |
1136 | retval = FALSE(0); |
1137 | } |
1138 | |
1139 | return retval; |
1140 | } |
1141 | |
1142 | /** |
1143 | * lt_tag_get_string: |
1144 | * @tag: a #lt_tag_t. |
1145 | * |
1146 | * Obtains a language tag in string. |
1147 | * |
1148 | * Returns: a language tag string. |
1149 | */ |
1150 | const gchar * |
1151 | lt_tag_get_string(lt_tag_t *tag) |
1152 | { |
1153 | GString *string; |
1154 | GList *l; |
1155 | |
1156 | if (tag->tag_string) |
1157 | return tag->tag_string; |
1158 | |
1159 | string = g_string_new(NULL((void*)0)); |
1160 | if (tag->grandfathered) |
1161 | g_string_append(string, lt_grandfathered_get_tag(tag->grandfathered)); |
1162 | else if (tag->language) { |
1163 | g_string_append(string, lt_lang_get_tag(tag->language)); |
1164 | if (tag->extlang) |
1165 | g_string_append_printf(string, "-%s", |
1166 | lt_extlang_get_tag(tag->extlang)); |
1167 | if (tag->script) |
1168 | g_string_append_printf(string, "-%s", |
1169 | lt_script_get_tag(tag->script)); |
1170 | if (tag->region) |
1171 | g_string_append_printf(string, "-%s", |
1172 | lt_region_get_tag(tag->region)); |
1173 | l = tag->variants; |
1174 | while (l != NULL((void*)0)) { |
1175 | g_string_append_printf(string, "-%s", |
1176 | lt_variant_get_tag(l->data)); |
1177 | l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0)); |
1178 | } |
1179 | if (tag->extension) |
1180 | g_string_append_printf(string, "-%s", |
1181 | lt_extension_get_tag(tag->extension)); |
1182 | if (tag->privateuse && tag->privateuse->len > 0) |
1183 | g_string_append_printf(string, "-%s", tag->privateuse->str); |
1184 | } else if (tag->privateuse && tag->privateuse->len > 0) { |
1185 | g_string_append(string, tag->privateuse->str); |
1186 | } |
1187 | |
1188 | lt_tag_set_tag_string(tag, g_string_free(string, FALSE(0))); |
1189 | |
1190 | return tag->tag_string; |
1191 | } |
1192 | |
1193 | /** |
1194 | * lt_tag_canonicalize: |
1195 | * @tag: a #lt_tag_t. |
1196 | * @error: (allow-none): a #GError or %NULL. |
1197 | * |
1198 | * Canonicalize the language tag according to various information of subtags. |
1199 | * |
1200 | * Returns: a language tag string. |
1201 | */ |
1202 | gchar * |
1203 | lt_tag_canonicalize(lt_tag_t *tag, |
1204 | GError **error) |
1205 | { |
1206 | gchar *retval = NULL((void*)0); |
1207 | GString *string = NULL((void*)0); |
1208 | GError *err = NULL((void*)0); |
1209 | GList *l; |
1210 | lt_redundant_db_t *rdb = NULL((void*)0); |
1211 | lt_redundant_t *r = NULL((void*)0); |
1212 | lt_tag_t *ctag = NULL((void*)0); |
1213 | |
1214 | g_return_val_if_fail (tag != NULL, NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return (((void *)0)); }; }while (0); |
1215 | |
1216 | string = g_string_new(NULL((void*)0)); |
1217 | if (tag->grandfathered) { |
1218 | g_string_append(string, lt_grandfathered_get_better_tag(tag->grandfathered)); |
1219 | goto bail1; |
1220 | } |
1221 | |
1222 | ctag = lt_tag_copy(tag); |
1223 | rdb = lt_db_get_redundant(); |
1224 | while (1) { |
1225 | const gchar *tag_string = lt_tag_get_string(ctag); |
1226 | |
1227 | if (tag_string[0] == 0) |
1228 | break; |
1229 | if (r) |
1230 | lt_redundant_unref(r); |
1231 | r = lt_redundant_db_lookup(rdb, tag_string); |
1232 | if (r) { |
1233 | const gchar *preferred = lt_redundant_get_preferred_tag(r); |
1234 | |
1235 | if (preferred) { |
1236 | lt_tag_t *rtag = lt_tag_new(); |
1237 | lt_tag_t *ntag = lt_tag_new(); |
1238 | |
1239 | if (!lt_tag_parse(rtag, lt_redundant_get_tag(r), &err)) { |
1240 | lt_tag_unref(rtag); |
1241 | lt_tag_unref(ntag); |
1242 | goto bail1; |
1243 | } |
1244 | if (!lt_tag_parse(ntag, preferred, &err)) { |
1245 | lt_tag_unref(rtag); |
1246 | lt_tag_unref(ntag); |
1247 | goto bail1; |
1248 | } |
1249 | _lt_tag_subtract(tag, rtag); |
1250 | _lt_tag_replace(tag, ntag); |
1251 | lt_tag_unref(rtag); |
1252 | lt_tag_unref(ntag); |
1253 | } |
1254 | break; |
1255 | } else { |
1256 | if (!lt_tag_truncate(ctag, &err)) |
1257 | goto bail1; |
1258 | } |
1259 | } |
1260 | |
1261 | if (tag->language) { |
1262 | gsize len; |
1263 | lt_extlang_db_t *edb = lt_db_get_extlang(); |
1264 | lt_extlang_t *e; |
1265 | |
1266 | /* If the language tag starts with a primary language subtag |
1267 | * that is also an extlang subtag, then the language tag is |
1268 | * prepended with the extlang's 'Prefix'. |
1269 | */ |
1270 | e = lt_extlang_db_lookup(edb, lt_lang_get_better_tag(tag->language)); |
1271 | if (e) { |
1272 | const gchar *prefix = lt_extlang_get_prefix(e); |
1273 | |
1274 | if (prefix) |
1275 | g_string_append_printf(string, "%s-", prefix); |
1276 | lt_extlang_unref(e); |
1277 | } |
1278 | lt_extlang_db_unref(edb); |
1279 | |
1280 | g_string_append(string, lt_lang_get_better_tag(tag->language)); |
1281 | if (tag->extlang) { |
1282 | const gchar *preferred = lt_extlang_get_preferred_tag(tag->extlang); |
1283 | |
1284 | if (preferred) { |
1285 | g_string_truncate(string, 0); |
1286 | g_string_append(string, preferred); |
1287 | } else { |
1288 | g_string_append_printf(string, "-%s", |
1289 | lt_extlang_get_tag(tag->extlang)); |
1290 | } |
1291 | } |
1292 | if (tag->script) { |
1293 | const gchar *script = lt_script_get_tag(tag->script); |
1294 | const gchar *suppress = lt_lang_get_suppress_script(tag->language); |
1295 | |
1296 | if (!suppress || |
1297 | g_ascii_strcasecmp(suppress, script)) |
1298 | g_string_append_printf(string, "-%s", script); |
1299 | } |
1300 | if (tag->region) { |
1301 | g_string_append_printf(string, "-%s", lt_region_get_better_tag(tag->region)); |
1302 | } |
1303 | l = tag->variants; |
1304 | len = string->len; |
1305 | while (l != NULL((void*)0)) { |
1306 | lt_variant_t *variant = l->data; |
1307 | const gchar *better = lt_variant_get_better_tag(variant); |
1308 | const gchar *s = lt_variant_get_tag(variant); |
1309 | |
1310 | if (better && g_ascii_strcasecmp(s, better) != 0) { |
1311 | /* ignore all of variants prior to this one */ |
1312 | g_string_truncate(string, len); |
1313 | } |
1314 | g_string_append_printf(string, "-%s", better ? better : s); |
1315 | l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0)); |
1316 | } |
1317 | if (tag->extension) { |
1318 | gchar *s = lt_extension_get_canonicalized_tag(tag->extension); |
1319 | |
1320 | g_string_append_printf(string, "-%s", s); |
1321 | g_free(s); |
1322 | } |
1323 | } |
1324 | if (tag->privateuse && tag->privateuse->len > 0) { |
1325 | g_string_append_printf(string, "%s%s", |
1326 | string->len > 0 ? "-" : "", |
1327 | tag->privateuse->str); |
1328 | } |
1329 | if (string->len == 0) { |
1330 | g_set_error(&err, LT_ERROR(lt_error_get_quark()), LT_ERR_NO_TAG, |
1331 | "No tag to convert."); |
1332 | } |
1333 | bail1: |
1334 | if (ctag) |
1335 | lt_tag_unref(ctag); |
1336 | if (rdb) |
1337 | lt_redundant_db_unref(rdb); |
1338 | if (r) |
1339 | lt_redundant_unref(r); |
1340 | retval = g_string_free(string, FALSE(0)); |
1341 | if (err) { |
1342 | if (error) |
1343 | *error = g_error_copy(err); |
1344 | else |
1345 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
1346 | g_error_free(err); |
1347 | if (retval) |
1348 | g_free(retval); |
1349 | retval = NULL((void*)0); |
1350 | } |
1351 | |
1352 | return retval; |
1353 | } |
1354 | |
1355 | /** |
1356 | * lt_tag_convert_to_locale: |
1357 | * @tag: a #lt_tag_t. |
1358 | * @error: (allow-none): a #GError or %NULL. |
1359 | * |
1360 | * Convert the language tag to the locale. |
1361 | * |
1362 | * Returns: a locale string or %NULL if fails |
1363 | */ |
1364 | gchar * |
1365 | lt_tag_convert_to_locale(lt_tag_t *tag, |
1366 | GError **error) |
1367 | { |
1368 | gchar *retval = NULL((void*)0); |
1369 | GString *string = NULL((void*)0); |
1370 | GError *err = NULL((void*)0); |
1371 | const gchar *mod = NULL((void*)0); |
1372 | gchar *canonical_tag = NULL((void*)0); |
1373 | lt_tag_t *ctag; |
1374 | |
1375 | g_return_val_if_fail (tag != NULL, NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return (((void *)0)); }; }while (0); |
1376 | |
1377 | canonical_tag = lt_tag_canonicalize(tag, &err); |
1378 | if (!canonical_tag) |
1379 | goto bail; |
1380 | ctag = lt_tag_new(); |
1381 | if (!lt_tag_parse(ctag, canonical_tag, &err)) { |
1382 | lt_tag_unref(ctag); |
1383 | goto bail; |
1384 | } |
1385 | string = g_string_new(NULL((void*)0)); |
1386 | g_string_append(string, lt_lang_get_better_tag(ctag->language)); |
1387 | if (ctag->region) |
1388 | g_string_append_printf(string, "_%s", |
1389 | lt_region_get_tag(ctag->region)); |
1390 | if (ctag->script) { |
1391 | mod = lt_script_convert_to_modifier(ctag->script); |
1392 | if (mod) |
1393 | g_string_append_printf(string, "@%s", mod); |
1394 | } |
1395 | lt_tag_unref(ctag); |
1396 | |
1397 | bail: |
1398 | g_free(canonical_tag); |
1399 | if (string) |
1400 | retval = g_string_free(string, FALSE(0)); |
1401 | if (err) { |
1402 | if (error) |
1403 | *error = g_error_copy(err); |
1404 | else |
1405 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
1406 | g_error_free(err); |
1407 | if (retval) |
1408 | g_free(retval); |
1409 | retval = NULL((void*)0); |
1410 | } |
1411 | |
1412 | return retval; |
1413 | } |
1414 | |
1415 | /** |
1416 | * lt_tag_dump: |
1417 | * @tag: a #lt_tag_t. |
1418 | * |
1419 | * Dumps the container information to the standard output. |
1420 | */ |
1421 | void |
1422 | lt_tag_dump(const lt_tag_t *tag) |
1423 | { |
1424 | GList *l; |
1425 | |
1426 | g_return_if_fail (tag != NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return; }; } while (0); |
1427 | |
1428 | if (tag->grandfathered) { |
1429 | lt_grandfathered_dump(tag->grandfathered); |
1430 | return; |
1431 | } |
1432 | lt_lang_dump(tag->language); |
1433 | if (tag->extlang) |
1434 | lt_extlang_dump(tag->extlang); |
1435 | if (tag->script) |
1436 | lt_script_dump(tag->script); |
1437 | if (tag->region) |
1438 | lt_region_dump(tag->region); |
1439 | l = tag->variants; |
1440 | while (l != NULL((void*)0)) { |
1441 | lt_variant_t *variant = l->data; |
1442 | |
1443 | lt_variant_dump(variant); |
1444 | l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0)); |
1445 | } |
1446 | if (tag->extension) |
1447 | lt_extension_dump(tag->extension); |
1448 | if (tag->privateuse->len > 0) |
1449 | g_print("Private Use: %s\n", tag->privateuse->str); |
1450 | } |
1451 | |
1452 | /** |
1453 | * lt_tag_compare: |
1454 | * @v1: a #lt_tag_t. |
1455 | * @v2: a #lt_tag_t. |
1456 | * |
1457 | * Compare if @v1 and @v2 is the same object or not. |
1458 | * |
1459 | * Returns: %TRUE if it's the same, otherwise %FALSE. |
1460 | */ |
1461 | gboolean |
1462 | lt_tag_compare(const lt_tag_t *v1, |
1463 | const lt_tag_t *v2) |
1464 | { |
1465 | gboolean retval = TRUE(!(0)); |
1466 | const GList *l1, *l2; |
1467 | |
1468 | g_return_val_if_fail (v1 != NULL, FALSE)do{ if (v1 != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v1 != NULL"); return ((0)) ; }; }while (0); |
1469 | g_return_val_if_fail (v2 != NULL, FALSE)do{ if (v2 != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v2 != NULL"); return ((0)) ; }; }while (0); |
1470 | g_return_val_if_fail (v1->grandfathered == NULL, FALSE)do{ if (v1->grandfathered == ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v1->grandfathered == NULL" ); return ((0)); }; }while (0); |
1471 | g_return_val_if_fail (v2->grandfathered == NULL, FALSE)do{ if (v2->grandfathered == ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v2->grandfathered == NULL" ); return ((0)); }; }while (0); |
1472 | |
1473 | retval &= lt_lang_compare(v1->language, v2->language); |
1474 | if (v2->extlang) |
1475 | retval &= lt_extlang_compare(v1->extlang, v2->extlang); |
1476 | if (v2->script) |
1477 | retval &= lt_script_compare(v1->script, v2->script); |
1478 | if (v2->region) |
1479 | retval &= lt_region_compare(v1->region, v2->region); |
1480 | l1 = v1->variants; |
1481 | l2 = v2->variants; |
1482 | while (l2 != NULL((void*)0)) { |
1483 | lt_variant_t *vv1, *vv2; |
1484 | |
1485 | vv1 = l1 ? l1->data : NULL((void*)0); |
1486 | vv2 = l2->data; |
1487 | retval &= lt_variant_compare(vv1, vv2); |
1488 | l1 = l1 ? g_list_next(l1)((l1) ? (((GList *)(l1))->next) : ((void*)0)) : NULL((void*)0); |
1489 | l2 = g_list_next(l2)((l2) ? (((GList *)(l2))->next) : ((void*)0)); |
1490 | } |
1491 | if (v2->extension) |
1492 | retval &= lt_extension_compare(v1->extension, v2->extension); |
1493 | if (v2->privateuse && v2->privateuse->len > 0) |
1494 | retval &= _lt_tag_gstring_compare(v1->privateuse, v2->privateuse); |
1495 | |
1496 | return retval; |
1497 | } |
1498 | |
1499 | /** |
1500 | * lt_tag_match: |
1501 | * @v1: a #lt_tag_t. |
1502 | * @v2: a language range string. |
1503 | * @error: (allow-none): a #GError or %NULL. |
1504 | * |
1505 | * Try matching of @v1 and @v2. any of subtags in @v2 is allowed to use |
1506 | * the wildcard according to the syntax in RFC 4647. |
1507 | * |
1508 | * Returns: %TRUE if it matches, otherwise %FALSE. |
1509 | */ |
1510 | gboolean |
1511 | lt_tag_match(const lt_tag_t *v1, |
1512 | const gchar *v2, |
1513 | GError **error) |
1514 | { |
1515 | gboolean retval = FALSE(0); |
1516 | lt_tag_t *t2 = NULL((void*)0); |
1517 | lt_tag_state_t state = STATE_NONE; |
1518 | GError *err = NULL((void*)0); |
1519 | |
1520 | g_return_val_if_fail (v1 != NULL, FALSE)do{ if (v1 != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v1 != NULL"); return ((0)) ; }; }while (0); |
1521 | g_return_val_if_fail (v2 != NULL, FALSE)do{ if (v2 != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "v2 != NULL"); return ((0)) ; }; }while (0); |
1522 | |
1523 | t2 = lt_tag_new(); |
1524 | state = lt_tag_parse_wildcard(t2, v2, &err); |
1525 | if (err) |
1526 | goto bail; |
1527 | retval = _lt_tag_match(v1, t2, state); |
1528 | bail: |
1529 | if (err) { |
1530 | if (error) |
1531 | *error = g_error_copy(err); |
1532 | else |
1533 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
1534 | g_error_free(err); |
1535 | retval = FALSE(0); |
1536 | } |
1537 | if (t2) |
1538 | lt_tag_unref(t2); |
1539 | |
1540 | return retval; |
1541 | } |
1542 | |
1543 | /** |
1544 | * lt_tag_lookup: |
1545 | * @tag: a #lt_tag_t. |
1546 | * @pattern: a language range string. |
1547 | * @error: (allow-none): a #GError or %NULL. |
1548 | * |
1549 | * Lookup the language tag that @tag meets with @pattern. |
1550 | * Any of subtags in @pattern is allowed to use the wildcard according to |
1551 | * the syntax in RFC 4647. |
1552 | * |
1553 | * Returns: a language tag string if any matches, otherwise %NULL. |
1554 | */ |
1555 | gchar * |
1556 | lt_tag_lookup(const lt_tag_t *tag, |
1557 | const gchar *pattern, |
1558 | GError **error) |
1559 | { |
1560 | lt_tag_t *t2 = NULL((void*)0); |
1561 | lt_tag_state_t state = STATE_NONE; |
1562 | GError *err = NULL((void*)0); |
1563 | GList *l; |
1564 | gchar *retval = NULL((void*)0); |
1565 | |
1566 | g_return_val_if_fail (tag != NULL, NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return (((void *)0)); }; }while (0); |
1567 | g_return_val_if_fail (pattern != NULL, NULL)do{ if (pattern != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "pattern != NULL"); return ( ((void*)0)); }; }while (0); |
1568 | |
1569 | t2 = lt_tag_new(); |
1570 | state = lt_tag_parse_wildcard(t2, pattern, &err); |
1571 | if (err) |
1572 | goto bail; |
1573 | if (_lt_tag_match(tag, t2, state)) { |
1574 | gint32 i; |
1575 | |
1576 | for (i = 0; i < (STATE_END - 1); i++) { |
1577 | if (t2->wildcard_map & (1 << i)) { |
1578 | switch (i + 1) { |
1579 | case STATE_LANG: |
1580 | lt_tag_set_language(t2, lt_lang_ref(tag->language)); |
1581 | break; |
1582 | case STATE_EXTLANG: |
1583 | lt_tag_free_extlang(t2); |
1584 | if (tag->extlang) { |
1585 | lt_tag_set_extlang(t2, lt_extlang_ref(tag->extlang)); |
1586 | } |
1587 | break; |
1588 | case STATE_SCRIPT: |
1589 | lt_tag_free_script(t2); |
1590 | if (tag->script) { |
1591 | lt_tag_set_script(t2, lt_script_ref(tag->script)); |
1592 | } |
1593 | break; |
1594 | case STATE_REGION: |
1595 | lt_tag_free_region(t2); |
1596 | if (tag->region) { |
1597 | lt_tag_set_region(t2, lt_region_ref(tag->region)); |
1598 | } |
1599 | break; |
1600 | case STATE_VARIANT: |
1601 | lt_tag_free_variants(t2); |
1602 | l = tag->variants; |
1603 | while (l != NULL((void*)0)) { |
1604 | lt_tag_set_variant(t2, lt_variant_ref(l->data)); |
1605 | l = g_list_next(l)((l) ? (((GList *)(l))->next) : ((void*)0)); |
1606 | } |
1607 | break; |
1608 | case STATE_EXTENSION: |
1609 | case STATE_EXTENSIONTOKEN: |
1610 | case STATE_EXTENSIONTOKEN2: |
1611 | lt_tag_free_extension(t2); |
1612 | if (tag->extension) { |
1613 | lt_tag_set_extension(t2, lt_extension_ref(tag->extension)); |
1614 | } |
1615 | break; |
1616 | case STATE_PRIVATEUSE: |
1617 | case STATE_PRIVATEUSETOKEN: |
1618 | case STATE_PRIVATEUSETOKEN2: |
1619 | if (t2->privateuse) { |
1620 | g_string_truncate(t2->privateuse, 0); |
1621 | } |
1622 | if (tag->privateuse) { |
1623 | g_string_append(t2->privateuse, tag->privateuse->str); |
1624 | } |
1625 | break; |
1626 | default: |
1627 | break; |
1628 | } |
1629 | } |
1630 | } |
1631 | lt_tag_free_tag_string(t2); |
1632 | retval = g_strdup(lt_tag_get_string(t2)); |
1633 | } |
1634 | bail: |
1635 | if (err) { |
1636 | if (error) |
1637 | *error = g_error_copy(err); |
1638 | else |
1639 | g_warning(err->message)g_log ("LangTag", G_LOG_LEVEL_WARNING, err->message); |
1640 | g_error_free(err); |
1641 | } |
1642 | if (t2) |
1643 | lt_tag_unref(t2); |
1644 | |
1645 | return retval; |
1646 | } |
1647 | |
1648 | #define DEFUNC_GET_SUBTAG(__func__,__type__) \ |
1649 | const __type__ * \ |
1650 | lt_tag_get_ ##__func__ (const lt_tag_t *tag) \ |
1651 | { \ |
1652 | g_return_val_if_fail (tag != NULL, NULL)do{ if (tag != ((void*)0)) { } else { g_return_if_fail_warning ("LangTag", __PRETTY_FUNCTION__, "tag != NULL"); return (((void *)0)); }; }while (0); \ |
1653 | \ |
1654 | return tag->__func__; \ |
1655 | } |
1656 | |
1657 | /** |
1658 | * lt_tag_get_language: |
1659 | * @tag: a #lt_tag_t. |
1660 | * |
1661 | * Obtain a #lt_lang_t instance in @tag. |
1662 | * |
1663 | * Returns: (transfer none): a #lt_lang_t. |
1664 | */ |
1665 | DEFUNC_GET_SUBTAG (language, lt_lang_t) |
1666 | /** |
1667 | * lt_tag_get_extlang: |
1668 | * @tag: a #lt_tag_t. |
1669 | * |
1670 | * Obtain a #lt_extlang_t instance in @tag. |
1671 | * |
1672 | * Returns: (transfer none): a #lt_extlang_t. |
1673 | */ |
1674 | DEFUNC_GET_SUBTAG (extlang, lt_extlang_t) |
1675 | /** |
1676 | * lt_tag_get_script: |
1677 | * @tag: a #lt_tag_t. |
1678 | * |
1679 | * Obtain a #lt_script_t instance in @tag. |
1680 | * |
1681 | * Returns: (transfer none): a #lt_script_t. |
1682 | */ |
1683 | DEFUNC_GET_SUBTAG (script, lt_script_t) |
1684 | /** |
1685 | * lt_tag_get_region: |
1686 | * @tag: a #lt_tag_t. |
1687 | * |
1688 | * Obtain a #lt_region_t instance in @tag. |
1689 | * |
1690 | * Returns: (transfer none): a #lt_region_t. |
1691 | */ |
1692 | DEFUNC_GET_SUBTAG (region, lt_region_t) |
1693 | /** |
1694 | * lt_tag_get_variants: |
1695 | * @tag: a #lt_tag_t. |
1696 | * |
1697 | * Obtain a list of #lt_variant_t instance in @tag. |
1698 | * |
1699 | * Returns: (element-type lt_variant_t) (transfer none): a #GList containing #lt_variant_t. |
1700 | */ |
1701 | DEFUNC_GET_SUBTAG (variants, GList) |
1702 | /** |
1703 | * lt_tag_get_extension: |
1704 | * @tag: a #lt_tag_t. |
1705 | * |
1706 | * Obtain a #lt_extension_t instance in @tag. |
1707 | * |
1708 | * Returns: (transfer none): a #lt_extension_t. |
1709 | */ |
1710 | DEFUNC_GET_SUBTAG (extension, lt_extension_t) |
1711 | /** |
1712 | * lt_tag_get_privateuse: |
1713 | * @tag: a #lt_tag_t. |
1714 | * |
1715 | * Obtain a #GString instance in @tag. |
1716 | * |
1717 | * Returns: (transfer none): a #GString. |
1718 | */ |
1719 | DEFUNC_GET_SUBTAG (privateuse, GString) |
1720 | /** |
1721 | * lt_tag_get_grandfathered: |
1722 | * @tag: a #lt_tag_t. |
1723 | * |
1724 | * Obtain a #lt_grandfathered_t instance in @tag. |
1725 | * |
1726 | * Returns: (transfer none): a #lt_grandfathered_t. |
1727 | */ |
1728 | DEFUNC_GET_SUBTAG (grandfathered, lt_grandfathered_t) |
1729 | |
1730 | #undef DEFUNC_GET_SUBTAG |