Bug Summary

File:libcafe-desktop/cafe-languages.c
Warning:line 1120, column 3
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cafe-languages.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/libcafe-desktop -fcoverage-compilation-dir=/rootdir/libcafe-desktop -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -D G_LOG_DOMAIN="CafeDesktop" -D CAFELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libcafe-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-02-12-210954-15794-1 -x c cafe-languages.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2008 Red Hat, Inc,
4 * 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Written by : William Jon McCann <mccann@jhu.edu>
20 * Ray Strode <rstrode@redhat.com>
21 */
22
23#include "config.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno(*__errno_location ()).h>
30#include <dirent.h>
31#include <locale.h>
32#include <langinfo.h>
33#include <sys/stat.h>
34
35#include <glib.h>
36#include <glib/gi18n.h>
37#include <glib/gstdio.h>
38
39#define CAFE_DESKTOP_USE_UNSTABLE_API
40#include "cafe-languages.h"
41
42#include <langinfo.h>
43#ifndef __LC_LAST13
44#define __LC_LAST13 13
45#endif
46
47#define ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" ISO_CODES_PREFIX"/usr" "/share/xml/iso-codes"
48#define ISO_CODES_LOCALESDIR"/usr" "/share/locale" ISO_CODES_PREFIX"/usr" "/share/locale"
49
50typedef struct _CafeLocale {
51 char *id;
52 char *name;
53 char *language_code;
54 char *territory_code;
55 char *codeset;
56 char *modifier;
57} CafeLocale;
58
59static GHashTable *cafe_languages_map;
60static GHashTable *cafe_territories_map;
61static GHashTable *cafe_available_locales_map;
62static GHashTable *cafe_language_count_map;
63static GHashTable *cafe_territory_count_map;
64
65static char * construct_language_name (const char *language,
66 const char *territory,
67 const char *codeset,
68 const char *modifier);
69
70static gboolean language_name_is_valid (const char *language_name);
71
72static void
73cafe_locale_free (CafeLocale *locale)
74{
75 if (locale == NULL((void*)0)) {
76 return;
77 }
78
79 g_free (locale->id);
80 g_free (locale->name);
81 g_free (locale->codeset);
82 g_free (locale->modifier);
83 g_free (locale->language_code);
84 g_free (locale->territory_code);
85 g_free (locale);
86}
87
88static char *
89normalize_codeset (const char *codeset)
90{
91 if (codeset == NULL((void*)0))
92 return NULL((void*)0);
93
94 if (g_str_equal (codeset, "UTF-8")(strcmp ((const char *) (codeset), (const char *) ("UTF-8")) ==
0)
||
95 g_str_equal (codeset, "utf8")(strcmp ((const char *) (codeset), (const char *) ("utf8")) ==
0)
)
96 return g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
97
98 return g_strdup (codeset)g_strdup_inline (codeset);
99}
100
101/**
102 * cafe_parse_locale:
103 * @locale: a locale string
104 * @language_codep: (out) (allow-none) (transfer full): location to
105 * store the language code, or %NULL
106 * @country_codep: (out) (allow-none) (transfer full): location to
107 * store the country code, or %NULL
108 * @codesetp: (out) (allow-none) (transfer full): location to
109 * store the codeset, or %NULL
110 * @modifierp: (out) (allow-none) (transfer full): location to
111 * store the modifier, or %NULL
112 *
113 * Extracts the various components of a locale string of the form
114 * [language[_country][.codeset][@modifier]]. See
115 * http://en.wikipedia.org/wiki/Locale.
116 *
117 * Return value: %TRUE if parsing was successful.
118 *
119 * Since: 1.22
120 */
121gboolean
122cafe_parse_locale (const char *locale,
123 char **language_codep,
124 char **country_codep,
125 char **codesetp,
126 char **modifierp)
127{
128 static GRegex *re = NULL((void*)0);
129 GMatchInfo *match_info;
130 gboolean res;
131 gchar *normalized_codeset = NULL((void*)0);
132 gchar *normalized_name = NULL((void*)0);
133 gboolean retval;
134
135 match_info = NULL((void*)0);
136 retval = FALSE(0);
137
138 if (re == NULL((void*)0)) {
139 GError *error = NULL((void*)0);
140 re = g_regex_new ("^(?P<language>[^_.@[:space:]]+)"
141 "(_(?P<territory>[[:upper:]]+))?"
142 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
143 "(@(?P<modifier>[[:ascii:]]+))?$",
144 0, 0, &error);
145 if (re == NULL((void*)0)) {
146 g_warning ("%s", error->message);
147 g_error_free (error);
148 goto out;
149 }
150 }
151
152 if (!g_regex_match (re, locale, 0, &match_info) ||
153 g_match_info_is_partial_match (match_info)) {
154 g_warning ("locale '%s' isn't valid\n", locale);
155 goto out;
156 }
157
158 res = g_match_info_matches (match_info);
159 if (! res) {
160 g_warning ("Unable to parse locale: %s", locale);
161 goto out;
162 }
163
164 retval = TRUE(!(0));
165
166 if (language_codep != NULL((void*)0)) {
167 *language_codep = g_match_info_fetch_named (match_info, "language");
168 }
169
170 if (country_codep != NULL((void*)0)) {
171 *country_codep = g_match_info_fetch_named (match_info, "territory");
172
173 if (*country_codep != NULL((void*)0) &&
174 *country_codep[0] == '\0') {
175 g_free (*country_codep);
176 *country_codep = NULL((void*)0);
177 }
178 }
179
180 if (codesetp != NULL((void*)0)) {
181 *codesetp = g_match_info_fetch_named (match_info, "codeset");
182
183 if (*codesetp != NULL((void*)0) &&
184 *codesetp[0] == '\0') {
185 g_free (*codesetp);
186 *codesetp = NULL((void*)0);
187 }
188 }
189
190 if (modifierp != NULL((void*)0)) {
191 *modifierp = g_match_info_fetch_named (match_info, "modifier");
192
193 if (*modifierp != NULL((void*)0) &&
194 *modifierp[0] == '\0') {
195 g_free (*modifierp);
196 *modifierp = NULL((void*)0);
197 }
198 }
199
200 if (codesetp != NULL((void*)0) && *codesetp != NULL((void*)0)) {
201 normalized_codeset = normalize_codeset (*codesetp);
202 normalized_name = construct_language_name (language_codep ? *language_codep : NULL((void*)0),
203 country_codep ? *country_codep : NULL((void*)0),
204 normalized_codeset,
205 modifierp ? *modifierp : NULL((void*)0));
206
207 if (language_name_is_valid (normalized_name)) {
208 g_free (*codesetp);
209 *codesetp = normalized_codeset;
210 } else {
211 g_free (normalized_codeset);
212 }
213 g_free (normalized_name);
214 }
215
216 out:
217 g_match_info_free (match_info);
218
219 return retval;
220}
221
222static char *
223construct_language_name (const char *language,
224 const char *territory,
225 const char *codeset,
226 const char *modifier)
227{
228 char *name;
229
230 g_assert (language != NULL && language[0] != 0)do { if (language != ((void*)0) && language[0] != 0) ;
else g_assertion_message_expr ("CafeDesktop", "cafe-languages.c"
, 230, ((const char*) (__func__)), "language != NULL && language[0] != 0"
); } while (0)
;
231 g_assert (territory == NULL || territory[0] != 0)do { if (territory == ((void*)0) || territory[0] != 0) ; else
g_assertion_message_expr ("CafeDesktop", "cafe-languages.c",
231, ((const char*) (__func__)), "territory == NULL || territory[0] != 0"
); } while (0)
;
232 g_assert (codeset == NULL || codeset[0] != 0)do { if (codeset == ((void*)0) || codeset[0] != 0) ; else g_assertion_message_expr
("CafeDesktop", "cafe-languages.c", 232, ((const char*) (__func__
)), "codeset == NULL || codeset[0] != 0"); } while (0)
;
233 g_assert (modifier == NULL || modifier[0] != 0)do { if (modifier == ((void*)0) || modifier[0] != 0) ; else g_assertion_message_expr
("CafeDesktop", "cafe-languages.c", 233, ((const char*) (__func__
)), "modifier == NULL || modifier[0] != 0"); } while (0)
;
234
235 name = g_strdup_printf ("%s%s%s%s%s%s%s",
236 language,
237 territory != NULL((void*)0)? "_" : "",
238 territory != NULL((void*)0)? territory : "",
239 codeset != NULL((void*)0)? "." : "",
240 codeset != NULL((void*)0)? codeset : "",
241 modifier != NULL((void*)0)? "@" : "",
242 modifier != NULL((void*)0)? modifier : "");
243
244 return name;
245}
246
247/**
248 * cafe_normalize_locale:
249 * @locale: a locale string
250 *
251 * Gets the normalized locale string in the form
252 * [language[_country][.codeset][@modifier]] for @name.
253 *
254 * Return value: (transfer full): normalized locale string. Caller
255 * takes ownership.
256 *
257 * Since: 1.22
258 */
259char *
260cafe_normalize_locale (const char *locale)
261{
262 char *normalized_name;
263 gboolean valid;
264 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
265 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
266 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
267 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *modifier = NULL((void*)0);
268
269 if (locale[0] == '\0') {
270 return NULL((void*)0);
271 }
272
273 valid = cafe_parse_locale (locale,
274 &language_code,
275 &territory_code,
276 &codeset, &modifier);
277 if (!valid)
278 return NULL((void*)0);
279
280 normalized_name = construct_language_name (language_code,
281 territory_code,
282 codeset, modifier);
283 return normalized_name;
284}
285
286static gboolean
287language_name_is_valid (const char *language_name)
288{
289 gboolean is_valid;
290 int lc_type_id = LC_MESSAGES5;
291 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
292
293 old_locale = g_strdup (setlocale (lc_type_id, NULL))g_strdup_inline (setlocale (lc_type_id, ((void*)0)));
294 is_valid = setlocale (lc_type_id, language_name) != NULL((void*)0);
295 setlocale (lc_type_id, old_locale);
296
297 return is_valid;
298}
299
300static void
301language_name_get_codeset_details (const char *language_name,
302 char **pcodeset,
303 gboolean *is_utf8)
304{
305 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
306 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
307
308 old_locale = g_strdup (setlocale (LC_CTYPE, NULL))g_strdup_inline (setlocale (0, ((void*)0)));
309
310 if (setlocale (LC_CTYPE0, language_name) == NULL((void*)0))
311 return;
312
313 codeset = nl_langinfo (CODESETCODESET);
314
315 if (pcodeset != NULL((void*)0)) {
316 *pcodeset = g_strdup (codeset)g_strdup_inline (codeset);
317 }
318
319 if (is_utf8 != NULL((void*)0)) {
320 codeset = normalize_codeset (codeset);
321
322 *is_utf8 = strcmp (codeset, "UTF-8") == 0;
323 }
324
325 setlocale (LC_CTYPE0, old_locale);
326}
327
328static gboolean
329locale_dir_has_mo_files (const gchar* path)
330{
331 GDir *dir;
332 const char *name;
333 gboolean has_translations;
334
335 has_translations = FALSE(0);
336 dir = g_dir_open (path, 0, NULL((void*)0));
337
338 if (dir == NULL((void*)0)) {
339 goto out;
340 }
341
342 do {
343 name = g_dir_read_name (dir);
344
345 if (name == NULL((void*)0)) {
346 break;
347 }
348
349 if (g_str_has_suffix (name, ".mo")(__builtin_constant_p (".mo")? __extension__ ({ const char * const
__str = (name); const char * const __suffix = (".mo"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (name, ".mo") )
) {
350 has_translations = TRUE(!(0));
351 break;
352 }
353 } while (name != NULL((void*)0));
354 g_dir_close (dir);
355
356 out:
357 return has_translations;
358}
359
360/**
361 * cafe_language_has_translations:
362 * @code: an ISO 639 code string
363 *
364 * Returns %TRUE if there are translations for language @code.
365 *
366 * Return value: %TRUE if there are translations for language @code.
367 *
368 * Since: 1.22
369 */
370gboolean
371cafe_language_has_translations (const char *code)
372{
373 gboolean has_translations;
374 gchar *path = NULL((void*)0);
375
376 path = g_build_filename (CAFELOCALEDIR"/usr/share/locale", code, "LC_MESSAGES", NULL((void*)0));
377 has_translations = locale_dir_has_mo_files (path);
378
379 if (!has_translations) {
380 g_free(path);
381 path = g_build_filename ("/usr/share/locale", code, "LC_MESSAGES", NULL((void*)0));
382 has_translations = locale_dir_has_mo_files (path);
383 }
384
385 g_free(path);
386 return has_translations;
387}
388
389static gboolean
390add_locale (const char *language_name,
391 gboolean utf8_only)
392{
393 CafeLocale *locale;
394 CafeLocale *old_locale;
395 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *name = NULL((void*)0);
396 gboolean is_utf8 = FALSE(0);
397 gboolean valid = FALSE(0);
398
399 g_return_val_if_fail (language_name != NULL, FALSE)do { if ((language_name != ((void*)0))) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "language_name != NULL"
); return ((0)); } } while (0)
;
400 g_return_val_if_fail (*language_name != '\0', FALSE)do { if ((*language_name != '\0')) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "*language_name != '\\0'"
); return ((0)); } } while (0)
;
401
402 language_name_get_codeset_details (language_name, NULL((void*)0), &is_utf8);
403
404 if (is_utf8) {
405 name = g_strdup (language_name)g_strdup_inline (language_name);
406 } else if (utf8_only) {
407
408 if (strchr (language_name, '.'))
409 return FALSE(0);
410
411 /* If the locale name has no dot, assume that its
412 * encoding part is missing and try again after adding
413 * ".UTF-8". This catches locale names like "de_DE".
414 */
415 name = g_strdup_printf ("%s.UTF-8", language_name);
416
417 language_name_get_codeset_details (name, NULL((void*)0), &is_utf8);
418 if (!is_utf8)
419 return FALSE(0);
420 } else {
421 name = g_strdup (language_name)g_strdup_inline (language_name);
422 }
423
424 if (!language_name_is_valid (name)) {
425 g_debug ("Ignoring '%s' as a locale, since it's invalid", name);
426 return FALSE(0);
427 }
428
429 locale = g_new0 (CafeLocale, 1)((CafeLocale *) g_malloc0_n ((1), sizeof (CafeLocale)));
430 valid = cafe_parse_locale (name,
431 &locale->language_code,
432 &locale->territory_code,
433 &locale->codeset,
434 &locale->modifier);
435 if (!valid) {
436 cafe_locale_free (locale);
437 return FALSE(0);
438 }
439
440 locale->id = construct_language_name (locale->language_code, locale->territory_code,
441 NULL((void*)0), locale->modifier);
442 locale->name = construct_language_name (locale->language_code, locale->territory_code,
443 locale->codeset, locale->modifier);
444
445 if (!cafe_language_has_translations (locale->name) &&
446 !cafe_language_has_translations (locale->id) &&
447 !cafe_language_has_translations (locale->language_code) &&
448 utf8_only) {
449 g_debug ("Ignoring '%s' as a locale, since it lacks translations", locale->name);
450 cafe_locale_free (locale);
451 return FALSE(0);
452 }
453
454 if (!utf8_only) {
455 g_free (locale->id);
456 locale->id = g_strdup (locale->name)g_strdup_inline (locale->name);
457 }
458
459 old_locale = g_hash_table_lookup (cafe_available_locales_map, locale->id);
460 if (old_locale != NULL((void*)0)) {
461 if (strlen (old_locale->name) > strlen (locale->name)) {
462 cafe_locale_free (locale);
463 return FALSE(0);
464 }
465 }
466
467 g_hash_table_insert (cafe_available_locales_map, g_strdup (locale->id)g_strdup_inline (locale->id), locale);
468
469 return TRUE(!(0));
470}
471
472static int
473select_dirs (const struct dirent *dirent)
474{
475 int result = 0;
476
477 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
478 mode_t mode = 0;
479
480#ifdef _DIRENT_HAVE_D_TYPE
481 if (dirent->d_type != DT_UNKNOWNDT_UNKNOWN && dirent->d_type != DT_LNKDT_LNK) {
482 mode = DTTOIF (dirent->d_type)((dirent->d_type) << 12);
483 } else
484#endif
485 {
486 struct stat st;
487 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *path = NULL((void*)0);
488
489 path = g_build_filename (CAFELOCALEDIR"/usr/share/locale", dirent->d_name, NULL((void*)0));
490 if (g_statstat (path, &st) == 0) {
491 mode = st.st_mode;
492 }
493 }
494
495 result = S_ISDIR (mode)((((mode)) & 0170000) == (0040000));
496 }
497
498 return result;
499}
500
501static gboolean
502collect_locales_from_directory (void)
503{
504 gboolean found_locales = FALSE(0);
505 struct dirent **dirents;
506 int ndirents;
507 int cnt;
508
509 ndirents = scandir (CAFELOCALEDIR"/usr/share/locale", &dirents, select_dirs, alphasort);
510
511 for (cnt = 0; cnt < ndirents; ++cnt) {
512 if (add_locale (dirents[cnt]->d_name, TRUE(!(0))))
513 found_locales = TRUE(!(0));
514 }
515
516 if (ndirents > 0) {
517 free (dirents);
518 }
519 return found_locales;
520}
521
522static gboolean
523collect_locales_from_localebin (void)
524{
525 gboolean found_locales = FALSE(0);
526 const gchar *argv[] = { "locale", "-a", NULL((void*)0) };
527 g_auto (GStrv)__attribute__((cleanup(glib_auto_cleanup_GStrv))) GStrv lines = NULL((void*)0);
528 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *output = NULL((void*)0);
529
530 if (g_spawn_sync (NULL((void*)0), (gchar **) argv, NULL((void*)0),
531 G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL,
532 NULL((void*)0), NULL((void*)0), &output, NULL((void*)0), NULL((void*)0), NULL((void*)0)) == FALSE(0))
533 return FALSE(0);
534
535 g_return_val_if_fail (output != NULL, FALSE)do { if ((output != ((void*)0))) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "output != NULL"
); return ((0)); } } while (0)
;
536
537 lines = g_strsplit (output, "\n", 0);
538 if (lines) {
539 gchar **linep;
540
541 linep = lines;
542 while (*linep) {
543 if (*linep[0] && add_locale (*linep, TRUE(!(0))))
544 found_locales = TRUE(!(0));
545 linep++;
546 }
547 }
548
549 return found_locales;
550}
551
552static void
553count_languages_and_territories (void)
554{
555 gpointer value;
556 GHashTableIter iter;
557
558 cafe_language_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
559 cafe_territory_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
560
561 g_hash_table_iter_init (&iter, cafe_available_locales_map);
562 while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) {
563 CafeLocale *locale;
564
565 locale = (CafeLocale *) value;
566
567 if (locale->language_code != NULL((void*)0)) {
568 int count;
569
570 count = GPOINTER_TO_INT (g_hash_table_lookup (cafe_language_count_map, locale->language_code))((gint) (glong) (g_hash_table_lookup (cafe_language_count_map
, locale->language_code)))
;
571 count++;
572 g_hash_table_insert (cafe_language_count_map, g_strdup (locale->language_code)g_strdup_inline (locale->language_code), GINT_TO_POINTER (count)((gpointer) (glong) (count)));
573 }
574
575 if (locale->territory_code != NULL((void*)0)) {
576 int count;
577
578 count = GPOINTER_TO_INT (g_hash_table_lookup (cafe_territory_count_map, locale->territory_code))((gint) (glong) (g_hash_table_lookup (cafe_territory_count_map
, locale->territory_code)))
;
579 count++;
580 g_hash_table_insert (cafe_territory_count_map, g_strdup (locale->territory_code)g_strdup_inline (locale->territory_code), GINT_TO_POINTER (count)((gpointer) (glong) (count)));
581 }
582 }
583}
584
585static void
586collect_locales (void)
587{
588 gboolean found_localebin_locales = FALSE(0);
589 gboolean found_dir_locales = FALSE(0);
590
591 if (cafe_available_locales_map == NULL((void*)0)) {
592 cafe_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cafe_locale_free);
593 }
594
595 found_localebin_locales = collect_locales_from_localebin ();
596
597 found_dir_locales = collect_locales_from_directory ();
598
599 if (!(found_localebin_locales || found_dir_locales)) {
600 g_warning ("Could not read list of available locales from libc, "
601 "guessing possible locales from available translations, "
602 "but list may be incomplete!");
603 }
604
605 count_languages_and_territories ();
606}
607
608static gint
609get_language_count (const char *language)
610{
611 if (cafe_language_count_map == NULL((void*)0)) {
612 collect_locales ();
613 }
614
615 return GPOINTER_TO_INT (g_hash_table_lookup (cafe_language_count_map, language))((gint) (glong) (g_hash_table_lookup (cafe_language_count_map
, language)))
;
616}
617
618static gboolean
619is_unique_language (const char *language)
620{
621 return get_language_count (language) == 1;
622}
623
624static gint
625get_territory_count (const char *territory)
626{
627 if (cafe_territory_count_map == NULL((void*)0)) {
628 collect_locales ();
629 }
630
631 return GPOINTER_TO_INT (g_hash_table_lookup (cafe_territory_count_map, territory))((gint) (glong) (g_hash_table_lookup (cafe_territory_count_map
, territory)))
;
632}
633
634static gboolean
635is_unique_territory (const char *territory)
636{
637 return get_territory_count (territory) == 1;
638}
639
640static gboolean
641is_fallback_language (const char *code)
642{
643 const char *fallback_language_names[] = { "C", "POSIX", NULL((void*)0) };
644 int i;
645
646 for (i = 0; fallback_language_names[i] != NULL((void*)0); i++) {
647 if (strcmp (code, fallback_language_names[i]) == 0) {
648 return TRUE(!(0));
649 }
650 }
651
652 return FALSE(0);
653}
654
655static const char *
656get_language (const char *code)
657{
658 const char *name;
659 int len;
660
661 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"CafeDesktop", "cafe-languages.c", 661, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
662
663 if (is_fallback_language (code)) {
664 return "Unspecified";
665 }
666
667 len = strlen (code);
668 if (len != 2 && len != 3) {
669 return NULL((void*)0);
670 }
671
672 name = (const char *) g_hash_table_lookup (cafe_languages_map, code);
673
674 return name;
675}
676
677static char *
678get_first_item_in_semicolon_list (const char *list)
679{
680 char **items;
681 char *item;
682
683 /* Some entries in iso codes have multiple values, separated
684 * by semicolons. Not really sure which one to pick, so
685 * we just arbitrarily pick the first one.
686 */
687 items = g_strsplit (list, "; ", 2);
688
689 item = g_strdup (items[0])g_strdup_inline (items[0]);
690 g_strfreev (items);
691
692 return item;
693}
694
695static char *
696capitalize_utf8_string (const char *str)
697{
698 char first[8] = { 0 };
699
700 if (!str)
701 return NULL((void*)0);
702
703 g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
704
705 return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL((void*)0));
706}
707
708static char *
709get_translated_language (const char *code,
710 const char *locale)
711{
712 const char *language;
713 char *name;
714
715 language = get_language (code);
716
717 name = NULL((void*)0);
718 if (language != NULL((void*)0)) {
719 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
720
721 if (locale != NULL((void*)0)) {
722 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
723 setlocale (LC_MESSAGES5, locale);
724 }
725
726 if (is_fallback_language (code)) {
727 name = g_strdup (_("Unspecified"))g_strdup_inline (gettext ("Unspecified"));
728 } else {
729 const char *translated_name;
730
731 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
732 translated_name = dgettext ("iso_639", language);
733 tmp = get_first_item_in_semicolon_list (translated_name);
734 name = capitalize_utf8_string (tmp);
735 }
736
737 if (locale != NULL((void*)0)) {
738 setlocale (LC_MESSAGES5, old_locale);
739 }
740 }
741
742 return name;
743}
744
745static const char *
746get_territory (const char *code)
747{
748 const char *name;
749 int len;
750
751 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"CafeDesktop", "cafe-languages.c", 751, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
752
753 len = strlen (code);
754 if (len != 2 && len != 3) {
755 return NULL((void*)0);
756 }
757
758 name = (const char *) g_hash_table_lookup (cafe_territories_map, code);
759
760 return name;
761}
762
763static char *
764get_translated_territory (const char *code,
765 const char *locale)
766{
767 const char *territory;
768 char *name;
769
770 territory = get_territory (code);
771
772 name = NULL((void*)0);
773 if (territory != NULL((void*)0)) {
774 const char *translated_territory;
775 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
776 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
777
778 if (locale != NULL((void*)0)) {
779 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
780 setlocale (LC_MESSAGES5, locale);
781 }
782
783 translated_territory = dgettext ("iso_3166", territory);
784 tmp = get_first_item_in_semicolon_list (translated_territory);
785 name = capitalize_utf8_string (tmp);
786
787 if (locale != NULL((void*)0)) {
788 setlocale (LC_MESSAGES5, old_locale);
789 }
790 }
791
792 return name;
793}
794
795static void
796languages_parse_start_tag (GMarkupParseContext *ctx G_GNUC_UNUSED__attribute__ ((__unused__)),
797 const char *element_name,
798 const char **attr_names,
799 const char **attr_values,
800 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)),
801 GError **error G_GNUC_UNUSED__attribute__ ((__unused__)))
802{
803 const char *ccode_longB;
804 const char *ccode_longT;
805 const char *ccode;
806 const char *ccode_id;
807 const char *lang_name;
808
809 if (! (g_str_equal (element_name, "iso_639_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_entry"
)) == 0)
|| g_str_equal (element_name, "iso_639_3_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_3_entry"
)) == 0)
)
810 || attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
811 return;
812 }
813
814 ccode = NULL((void*)0);
815 ccode_longB = NULL((void*)0);
816 ccode_longT = NULL((void*)0);
817 ccode_id = NULL((void*)0);
818 lang_name = NULL((void*)0);
819
820 while (*attr_names && *attr_values) {
821 if (g_str_equal (*attr_names, "iso_639_1_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_1_code"
)) == 0)
) {
822 /* skip if empty */
823 if (**attr_values) {
824 if (strlen (*attr_values) != 2) {
825 return;
826 }
827 ccode = *attr_values;
828 }
829 } else if (g_str_equal (*attr_names, "iso_639_2B_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2B_code"
)) == 0)
) {
830 /* skip if empty */
831 if (**attr_values) {
832 if (strlen (*attr_values) != 3) {
833 return;
834 }
835 ccode_longB = *attr_values;
836 }
837 } else if (g_str_equal (*attr_names, "iso_639_2T_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2T_code"
)) == 0)
) {
838 /* skip if empty */
839 if (**attr_values) {
840 if (strlen (*attr_values) != 3) {
841 return;
842 }
843 ccode_longT = *attr_values;
844 }
845 } else if (g_str_equal (*attr_names, "id")(strcmp ((const char *) (*attr_names), (const char *) ("id"))
== 0)
) {
846 /* skip if empty */
847 if (**attr_values) {
848 if (strlen (*attr_values) != 2 &&
849 strlen (*attr_values) != 3) {
850 return;
851 }
852 ccode_id = *attr_values;
853 }
854 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
855 lang_name = *attr_values;
856 }
857
858 ++attr_names;
859 ++attr_values;
860 }
861
862 if (lang_name == NULL((void*)0)) {
863 return;
864 }
865
866 if (ccode != NULL((void*)0)) {
867 g_hash_table_insert (cafe_languages_map,
868 g_strdup (ccode)g_strdup_inline (ccode),
869 g_strdup (lang_name)g_strdup_inline (lang_name));
870 }
871 if (ccode_longB != NULL((void*)0)) {
872 g_hash_table_insert (cafe_languages_map,
873 g_strdup (ccode_longB)g_strdup_inline (ccode_longB),
874 g_strdup (lang_name)g_strdup_inline (lang_name));
875 }
876 if (ccode_longT != NULL((void*)0)) {
877 g_hash_table_insert (cafe_languages_map,
878 g_strdup (ccode_longT)g_strdup_inline (ccode_longT),
879 g_strdup (lang_name)g_strdup_inline (lang_name));
880 }
881 if (ccode_id != NULL((void*)0)) {
882 g_hash_table_insert (cafe_languages_map,
883 g_strdup (ccode_id)g_strdup_inline (ccode_id),
884 g_strdup (lang_name)g_strdup_inline (lang_name));
885 }
886}
887
888static void
889territories_parse_start_tag (GMarkupParseContext *ctx G_GNUC_UNUSED__attribute__ ((__unused__)),
890 const char *element_name,
891 const char **attr_names,
892 const char **attr_values,
893 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)),
894 GError **error G_GNUC_UNUSED__attribute__ ((__unused__)))
895{
896 const char *acode_2;
897 const char *acode_3;
898 const char *ncode;
899 const char *territory_common_name;
900 const char *territory_name;
901
902 if (! g_str_equal (element_name, "iso_3166_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_3166_entry"
)) == 0)
|| attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
903 return;
904 }
905
906 acode_2 = NULL((void*)0);
907 acode_3 = NULL((void*)0);
908 ncode = NULL((void*)0);
909 territory_common_name = NULL((void*)0);
910 territory_name = NULL((void*)0);
911
912 while (*attr_names && *attr_values) {
913 if (g_str_equal (*attr_names, "alpha_2_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_2_code"
)) == 0)
) {
914 /* skip if empty */
915 if (**attr_values) {
916 if (strlen (*attr_values) != 2) {
917 return;
918 }
919 acode_2 = *attr_values;
920 }
921 } else if (g_str_equal (*attr_names, "alpha_3_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_3_code"
)) == 0)
) {
922 /* skip if empty */
923 if (**attr_values) {
924 if (strlen (*attr_values) != 3) {
925 return;
926 }
927 acode_3 = *attr_values;
928 }
929 } else if (g_str_equal (*attr_names, "numeric_code")(strcmp ((const char *) (*attr_names), (const char *) ("numeric_code"
)) == 0)
) {
930 /* skip if empty */
931 if (**attr_values) {
932 if (strlen (*attr_values) != 3) {
933 return;
934 }
935 ncode = *attr_values;
936 }
937 } else if (g_str_equal (*attr_names, "common_name")(strcmp ((const char *) (*attr_names), (const char *) ("common_name"
)) == 0)
) {
938 /* skip if empty */
939 if (**attr_values) {
940 territory_common_name = *attr_values;
941 }
942 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
943 territory_name = *attr_values;
944 }
945
946 ++attr_names;
947 ++attr_values;
948 }
949
950 if (territory_common_name != NULL((void*)0)) {
951 territory_name = territory_common_name;
952 }
953
954 if (territory_name == NULL((void*)0)) {
955 return;
956 }
957
958 if (acode_2 != NULL((void*)0)) {
959 g_hash_table_insert (cafe_territories_map,
960 g_strdup (acode_2)g_strdup_inline (acode_2),
961 g_strdup (territory_name)g_strdup_inline (territory_name));
962 }
963 if (acode_3 != NULL((void*)0)) {
964 g_hash_table_insert (cafe_territories_map,
965 g_strdup (acode_3)g_strdup_inline (acode_3),
966 g_strdup (territory_name)g_strdup_inline (territory_name));
967 }
968 if (ncode != NULL((void*)0)) {
969 g_hash_table_insert (cafe_territories_map,
970 g_strdup (ncode)g_strdup_inline (ncode),
971 g_strdup (territory_name)g_strdup_inline (territory_name));
972 }
973}
974
975static void
976languages_variant_init (const char *variant)
977{
978 gboolean res;
979 gsize buf_len;
980 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
981 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *filename = NULL((void*)0);
982 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
983
984 bindtextdomain (variant, ISO_CODES_LOCALESDIR"/usr" "/share/locale");
985 bind_textdomain_codeset (variant, "UTF-8");
986
987 error = NULL((void*)0);
988 filename = g_strdup_printf (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/%s.xml", variant);
989 res = g_file_get_contents (filename,
990 &buf,
991 &buf_len,
992 &error);
993 if (res) {
994 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
995 GMarkupParser parser = { languages_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
996
997 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
998
999 error = NULL((void*)0);
1000 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1001
1002 if (! res) {
1003 g_warning ("Failed to parse '%s': %s\n",
1004 filename,
1005 error->message);
1006 }
1007 } else {
1008 g_warning ("Failed to load '%s': %s\n",
1009 filename,
1010 error->message);
1011 }
1012}
1013
1014static void
1015languages_init (void)
1016{
1017 if (cafe_languages_map)
1018 return;
1019
1020 cafe_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1021
1022 languages_variant_init ("iso_639");
1023 languages_variant_init ("iso_639_3");
1024}
1025
1026static void
1027territories_init (void)
1028{
1029 gboolean res;
1030 gsize buf_len;
1031 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
1032 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1033
1034 if (cafe_territories_map)
1035 return;
1036
1037 bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1038 bind_textdomain_codeset ("iso_3166", "UTF-8");
1039
1040 cafe_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1041
1042 error = NULL((void*)0);
1043 res = g_file_get_contents (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1044 &buf,
1045 &buf_len,
1046 &error);
1047 if (res) {
1048 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1049 GMarkupParser parser = { territories_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1050
1051 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1052
1053 error = NULL((void*)0);
1054 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1055
1056 if (! res) {
1057 g_warning ("Failed to parse '%s': %s\n",
1058 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1059 error->message);
1060 }
1061 } else {
1062 g_warning ("Failed to load '%s': %s\n",
1063 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1064 error->message);
1065 }
1066}
1067
1068/**
1069 * cafe_get_language_from_locale:
1070 * @locale: a locale string
1071 * @translation: (allow-none): a locale string
1072 *
1073 * Gets the language description for @locale. If @translation is
1074 * provided the returned string is translated accordingly.
1075 *
1076 * Return value: (transfer full): the language description. Caller
1077 * takes ownership.
1078 *
1079 * Since: 1.22
1080 */
1081char *
1082cafe_get_language_from_locale (const char *locale,
1083 const char *translation)
1084{
1085 GString *full_language;
1086 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1087 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1088 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1089 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1090 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1091 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1092 gboolean is_utf8 = TRUE(!(0));
1093
1094 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1095 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1096
1097 full_language = g_string_new (NULL((void*)0));
1098
1099 languages_init ();
1100 territories_init ();
1101
1102 cafe_parse_locale (locale,
1103 &language_code,
1104 &territory_code,
1105 &codeset_code,
1106 NULL((void*)0));
1107
1108 if (language_code == NULL((void*)0)) {
1109 goto out;
1110 }
1111
1112 translated_language = get_translated_language (language_code, translation);
1113 if (translated_language == NULL((void*)0)) {
1114 goto out;
1115 }
1116
1117 full_language = g_string_append (full_language, translated_language)(__builtin_constant_p (translated_language) ? __extension__ (
{ const char * const __val = (translated_language); g_string_append_len_inline
(full_language, __val, (__val != ((void*)0)) ? (gssize) strlen
(((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_language, translated_language, (gssize) -1))
;
1118
1119 if (is_unique_language (language_code)) {
1120 goto out;
This statement is never executed
1121 }
1122
1123 if (territory_code != NULL((void*)0)) {
1124 translated_territory = get_translated_territory (territory_code, translation);
1125 }
1126 if (translated_territory != NULL((void*)0)) {
1127 g_string_append_printf (full_language,
1128 " (%s)",
1129 translated_territory);
1130 }
1131
1132 language_name_get_codeset_details (locale, &langinfo_codeset, &is_utf8);
1133
1134 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1135 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1136 }
1137
1138 if (!is_utf8 && codeset_code) {
1139 g_string_append_printf (full_language,
1140 " [%s]",
1141 codeset_code);
1142 }
1143
1144 out:
1145 if (full_language->len == 0) {
1146 g_string_free (full_language, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_language), ((!(0)))) : g_string_free_and_steal (full_language
)) : (g_string_free) ((full_language), ((!(0)))))
;
1147 return NULL((void*)0);
1148 }
1149
1150 return g_string_free (full_language, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_language
), ((0))) : g_string_free_and_steal (full_language)) : (g_string_free
) ((full_language), ((0))))
;
1151}
1152
1153/**
1154 * cafe_get_country_from_locale:
1155 * @locale: a locale string
1156 * @translation: (allow-none): a locale string
1157 *
1158 * Gets the country description for @locale. If @translation is
1159 * provided the returned string is translated accordingly.
1160 *
1161 * Return value: (transfer full): the country description. Caller
1162 * takes ownership.
1163 *
1164 * Since: 1.22
1165 */
1166char *
1167cafe_get_country_from_locale (const char *locale,
1168 const char *translation)
1169{
1170 GString *full_name;
1171 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1172 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1173 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1174 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1175 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1176 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1177 gboolean is_utf8 = TRUE(!(0));
1178
1179 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1180 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1181
1182 full_name = g_string_new (NULL((void*)0));
1183
1184 languages_init ();
1185 territories_init ();
1186
1187 cafe_parse_locale (locale,
1188 &language_code,
1189 &territory_code,
1190 &codeset_code,
1191 NULL((void*)0));
1192
1193 if (territory_code == NULL((void*)0)) {
1194 goto out;
1195 }
1196
1197 translated_territory = get_translated_territory (territory_code, translation);
1198 g_string_append (full_name, translated_territory)(__builtin_constant_p (translated_territory) ? __extension__ (
{ const char * const __val = (translated_territory); g_string_append_len_inline
(full_name, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_name, translated_territory, (gssize) -1))
;
1199
1200 if (is_unique_territory (territory_code)) {
1201 goto out;
1202 }
1203
1204 if (language_code != NULL((void*)0)) {
1205 translated_language = get_translated_language (language_code, translation);
1206 }
1207 if (translated_language != NULL((void*)0)) {
1208 g_string_append_printf (full_name,
1209 " (%s)",
1210 translated_language);
1211 }
1212
1213 language_name_get_codeset_details (translation, &langinfo_codeset, &is_utf8);
1214
1215 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1216 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1217 }
1218
1219 if (!is_utf8 && codeset_code) {
1220 g_string_append_printf (full_name,
1221 " [%s]",
1222 codeset_code);
1223 }
1224
1225 out:
1226 if (full_name->len == 0) {
1227 g_string_free (full_name, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_name), ((!(0)))) : g_string_free_and_steal (full_name))
: (g_string_free) ((full_name), ((!(0)))))
;
1228 return NULL((void*)0);
1229 }
1230
1231 return g_string_free (full_name, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_name
), ((0))) : g_string_free_and_steal (full_name)) : (g_string_free
) ((full_name), ((0))))
;
1232}
1233
1234/**
1235 * cafe_get_all_locales:
1236 *
1237 * Gets all locales.
1238 *
1239 * Return value: (array zero-terminated=1) (element-type utf8) (transfer full):
1240 * a newly allocated %NULL-terminated string array containing the
1241 * all locales. Free with g_strfreev().
1242 *
1243 * Since: 1.22
1244 */
1245char **
1246cafe_get_all_locales (void)
1247{
1248 GHashTableIter iter;
1249 gpointer key, value;
1250 GPtrArray *array;
1251
1252 if (cafe_available_locales_map == NULL((void*)0)) {
1253 collect_locales ();
1254 }
1255
1256 array = g_ptr_array_new ();
1257 g_hash_table_iter_init (&iter, cafe_available_locales_map);
1258 while (g_hash_table_iter_next (&iter, &key, &value)) {
1259 CafeLocale *locale;
1260
1261 locale = (CafeLocale *) value;
1262
1263 g_ptr_array_add (array, g_strdup (locale->name)g_strdup_inline (locale->name));
1264 }
1265 g_ptr_array_add (array, NULL((void*)0));
1266
1267 return (char **) g_ptr_array_free (array, FALSE(0));
1268}
1269
1270/**
1271 * cafe_get_language_from_code:
1272 * @code: an ISO 639 code string
1273 * @translation: (allow-none): a locale string
1274 *
1275 * Gets the language name for @code. If @locale is provided the
1276 * returned string is translated accordingly.
1277 *
1278 * Return value: (transfer full): the language name. Caller takes
1279 * ownership.
1280 *
1281 * Since: 1.22
1282 */
1283char *
1284cafe_get_language_from_code (const char *code,
1285 const char *translation)
1286{
1287 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1288
1289 languages_init ();
1290
1291 return get_translated_language (code, translation);
1292}
1293
1294/**
1295 * cafe_get_country_from_code:
1296 * @code: an ISO 3166 code string
1297 * @translation: (allow-none): a locale string
1298 *
1299 * Gets the country name for @code. If @locale is provided the
1300 * returned string is translated accordingly.
1301 *
1302 * Return value: (transfer full): the country name. Caller takes
1303 * ownership.
1304 *
1305 * Since: 1.22
1306 */
1307char *
1308cafe_get_country_from_code (const char *code,
1309 const char *translation)
1310{
1311 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("CafeDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1312
1313 territories_init ();
1314
1315 return get_translated_territory (code, translation);
1316}