Imported Upstream version 0.2.0
[debian/lxdm.git] / src / gdm / gdm-languages.c
CommitLineData
eea1c851
AL
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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Written by : William Jon McCann <mccann@jhu.edu>
21 * Ray Strode <rstrode@redhat.com>
22 */
23
24#include "config.h"
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <string.h>
30#include <errno.h>
31#include <dirent.h>
32#include <locale.h>
33#include <langinfo.h>
34#include <sys/stat.h>
35
36#include <glib.h>
37#include <glib/gi18n.h>
38#include <glib/gstdio.h>
39
40#include "gdm-languages.h"
41
42#include <langinfo.h>
43#ifndef __LC_LAST
44#define __LC_LAST 13
45#endif
46#include "locarchive.h"
47
48#define ALIASES_FILE LIBLOCALEDIR "/locale.alias"
49#define ARCHIVE_FILE LIBLOCALEDIR "/locale-archive"
50#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
51#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
52
53typedef struct _GdmLocale {
54 char *id;
55 char *name;
56 char *language_code;
57 char *territory_code;
58 char *codeset;
59 char *modifier;
60} GdmLocale;
61
62static GHashTable *gdm_languages_map;
63static GHashTable *gdm_territories_map;
64static GHashTable *gdm_available_locales_map;
65
66static void
67gdm_locale_free (GdmLocale *locale)
68{
69 if (locale == NULL) {
70 return;
71 }
72
73 g_free (locale->id);
74 g_free (locale->name);
75 g_free (locale->codeset);
76 g_free (locale->modifier);
77 g_free (locale);
78}
79
80static char *
81normalize_codeset (const char *codeset)
82{
83 char *normalized_codeset;
84 const char *p;
85 char *q;
86
87 normalized_codeset = g_strdup (codeset);
88
89 if (codeset != NULL) {
90 for (p = codeset, q = normalized_codeset;
91 *p != '\0'; p++) {
92
93 if (*p == '-' || *p == '_') {
94 continue;
95 }
96
97 *q = g_ascii_tolower (*p);
98 q++;
99 }
100 *q = '\0';
101 }
102
103 return normalized_codeset;
104}
105
106/*
107 * According to http://en.wikipedia.org/wiki/Locale
108 * locale names are of the form:
109 * [language[_territory][.codeset][@modifier]]
110 */
111void
112gdm_parse_language_name (const char *name,
113 char **language_codep,
114 char **territory_codep,
115 char **codesetp,
116 char **modifierp)
117{
118 GRegex *re;
119 GMatchInfo *match_info;
120 gboolean res;
121 GError *error;
122
123 error = NULL;
124 re = g_regex_new ("^(?P<language>[^_.@[:space:]]+)"
125 "(_(?P<territory>[[:upper:]]+))?"
126 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
127 "(@(?P<modifier>[[:ascii:]]+))?$",
128 0, 0, &error);
129 if (re == NULL) {
130 g_critical ("%s", error->message);
131 return;
132 }
133
134 if (!g_regex_match (re, name, 0, &match_info) ||
135 g_match_info_is_partial_match (match_info)) {
136 g_match_info_free (match_info);
137 g_regex_unref (re);
138 g_warning ("locale %s isn't valid\n", name);
139 return;
140 }
141
142 res = g_match_info_matches (match_info);
143 if (! res) {
144 g_warning ("Unable to parse locale: %s", name);
145 return;
146 }
147
148 if (language_codep != NULL) {
149 *language_codep = g_match_info_fetch_named (match_info, "language");
150 }
151
152 if (territory_codep != NULL) {
153 *territory_codep = g_match_info_fetch_named (match_info, "territory");
154
155 if (*territory_codep != NULL &&
156 *territory_codep[0] == '\0') {
157 g_free (*territory_codep);
158 *territory_codep = NULL;
159 }
160 }
161
162 if (codesetp != NULL) {
163 *codesetp = g_match_info_fetch_named (match_info, "codeset");
164
165 if (*codesetp != NULL &&
166 *codesetp[0] == '\0') {
167 g_free (*codesetp);
168 *codesetp = NULL;
169 }
170
171 if (*codesetp != NULL) {
172 char *codeset;
173
174 codeset = normalize_codeset (*codesetp);
175 g_free (*codesetp);
176 *codesetp = codeset;
177 }
178 }
179
180 if (modifierp != NULL) {
181 *modifierp = g_match_info_fetch_named (match_info, "modifier");
182
183 if (*modifierp != NULL &&
184 *modifierp[0] == '\0') {
185 g_free (*modifierp);
186 *modifierp = NULL;
187 }
188 }
189
190 g_match_info_free (match_info);
191 g_regex_unref (re);
192}
193
194static char *
195construct_language_name (const char *language,
196 const char *territory,
197 const char *codeset,
198 const char *modifier)
199{
200 char *name;
201
202 g_assert (language[0] != 0);
203 g_assert (territory == NULL || territory[0] != 0);
204 g_assert (codeset == NULL || codeset[0] != 0);
205 g_assert (modifier == NULL || modifier[0] != 0);
206
207 name = g_strdup_printf ("%s%s%s%s%s%s%s",
208 language,
209 territory != NULL? "_" : "",
210 territory != NULL? territory : "",
211 codeset != NULL? "." : "",
212 codeset != NULL? codeset : "",
213 modifier != NULL? "@" : "",
214 modifier != NULL? modifier : "");
215
216 return name;
217}
218
219static void
220make_codeset_canonical_for_locale (const char *name,
221 char **codeset)
222{
223 char *old_locale;
224
225 old_locale = setlocale (LC_CTYPE, name);
226
227 if (old_locale == NULL) {
228 return;
229 }
230
231 g_free (*codeset);
232 *codeset = g_strdup (nl_langinfo (CODESET));
233
234 setlocale (LC_CTYPE, old_locale);
235}
236
237char *
238gdm_normalize_language_name (const char *name)
239{
240 char *normalized_name;
241 char *language_code;
242 char *territory_code;
243 char *codeset;
244 char *modifier;
245
246 if (name[0] == '\0') {
247 return NULL;
248 }
249
250 gdm_parse_language_name (name,
251 &language_code,
252 &territory_code,
253 &codeset, &modifier);
254
255 if (codeset != NULL) {
256 make_codeset_canonical_for_locale (name, &codeset);
257 }
258
259 normalized_name = construct_language_name (language_code,
260 territory_code,
261 codeset, modifier);
262 g_free (language_code);
263 g_free (territory_code);
264 g_free (codeset);
265 g_free (modifier);
266
267 return normalized_name;
268}
269
270static gboolean
271language_name_is_valid (const char *language_name)
272{
273 char *old_locale;
274 gboolean is_valid;
275
276 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
277 is_valid = setlocale (LC_MESSAGES, language_name) != NULL;
278 setlocale (LC_MESSAGES, old_locale);
279 g_free (old_locale);
280
281 return is_valid;
282}
283
284static gboolean
285language_name_is_utf8 (const char *language_name)
286{
287 char *old_locale;
288 char *codeset;
289 gboolean is_utf8;
290
291 old_locale = g_strdup (setlocale (LC_CTYPE, NULL));
292
293 if (setlocale (LC_CTYPE, language_name) == NULL) {
294 g_free (old_locale);
295 return FALSE;
296 }
297
298 codeset = normalize_codeset (nl_langinfo (CODESET));
299
300 is_utf8 = strcmp (codeset, "utf8") == 0;
301 g_free (codeset);
302
303 setlocale (LC_CTYPE, old_locale);
304 g_free (old_locale);
305
306 return is_utf8;
307}
308
309static gboolean
310language_name_has_translations (const char *language_name)
311{
312 GDir *dir;
313 char *path;
314 const char *name;
315 gboolean has_translations;
316
317 path = g_build_filename (GNOMELOCALEDIR, language_name, "LC_MESSAGES", NULL);
318
319 has_translations = FALSE;
320 dir = g_dir_open (path, 0, NULL);
321 g_free (path);
322
323 if (dir == NULL) {
324 goto out;
325 }
326
327 do {
328 name = g_dir_read_name (dir);
329
330 if (name == NULL) {
331 break;
332 }
333
334 if (g_str_has_suffix (name, ".mo")) {
335 has_translations = TRUE;
336 break;
337 }
338 } while (name != NULL);
339 g_dir_close (dir);
340
341out:
342 return has_translations;
343}
344
345static gboolean
346add_locale (const char *language_name)
347{
348 GdmLocale *locale;
349 GdmLocale *old_locale;
350 char *name;
351
352 if (language_name_is_utf8 (language_name)) {
353 name = g_strdup (language_name);
354 } else {
355 name = g_strdup_printf ("%s.utf8", language_name);
356
357 if (!language_name_is_utf8 (name)) {
358 g_free (name);
359 return FALSE;
360 }
361 }
362
363 if (!language_name_is_valid (name)) {
364 g_free (name);
365 return FALSE;
366 }
367
368
369 locale = g_new0 (GdmLocale, 1);
370 gdm_parse_language_name (name,
371 &locale->language_code,
372 &locale->territory_code,
373 &locale->codeset,
374 &locale->modifier);
375 g_free (name);
376 name = NULL;
377
378 locale->id = construct_language_name (locale->language_code, locale->territory_code,
379 NULL, locale->modifier);
380 locale->name = construct_language_name (locale->language_code, locale->territory_code,
381 locale->codeset, locale->modifier);
382
383 if (!language_name_has_translations (locale->name) &&
384 !language_name_has_translations (locale->id) &&
385 !language_name_has_translations (locale->language_code)) {
386 gdm_locale_free (locale);
387 return FALSE;
388 }
389
390 old_locale = g_hash_table_lookup (gdm_available_locales_map, locale->id);
391 if (old_locale != NULL) {
392 if (strlen (old_locale->name) > strlen (locale->name)) {
393 gdm_locale_free (locale);
394 return FALSE;
395 }
396 }
397
398 g_hash_table_insert (gdm_available_locales_map, g_strdup (locale->id), locale);
399
400 return TRUE;
401}
402
403struct nameent
404{
405 char *name;
406 uint32_t locrec_offset;
407};
408
409static gboolean
410collect_locales_from_archive (void)
411{
412 GMappedFile *mapped;
413 GError *error;
414 char *addr;
415 struct locarhead *head;
416 struct namehashent *namehashtab;
417 struct nameent *names;
418 uint32_t used;
419 uint32_t cnt;
420 gsize len;
421 gboolean locales_collected;
422
423 error = NULL;
424 mapped = g_mapped_file_new (ARCHIVE_FILE, FALSE, &error);
425 if (mapped == NULL) {
426 g_warning ("Mapping failed for %s: %s", ARCHIVE_FILE, error->message);
427 g_error_free (error);
428 return FALSE;
429 }
430
431 locales_collected = FALSE;
432
433 addr = g_mapped_file_get_contents (mapped);
434 len = g_mapped_file_get_length (mapped);
435
436 head = (struct locarhead *) addr;
437 if (head->namehash_offset + head->namehash_size > len
438 || head->string_offset + head->string_size > len
439 || head->locrectab_offset + head->locrectab_size > len
440 || head->sumhash_offset + head->sumhash_size > len) {
441 goto out;
442 }
443
444 namehashtab = (struct namehashent *) (addr + head->namehash_offset);
445
446 names = (struct nameent *) g_new0 (struct nameent, head->namehash_used);
447 for (cnt = used = 0; cnt < head->namehash_size; ++cnt) {
448 if (namehashtab[cnt].locrec_offset != 0) {
449 names[used].name = addr + namehashtab[cnt].name_offset;
450 names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
451 }
452 }
453
454 for (cnt = 0; cnt < used; ++cnt) {
455 add_locale (names[cnt].name);
456 }
457
458 g_free (names);
459
460 locales_collected = TRUE;
461 out:
462
463 g_mapped_file_free (mapped);
464 return locales_collected;
465}
466
467static int
468select_dirs (const struct dirent *dirent)
469{
470 int result = 0;
471
472 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
473 mode_t mode = 0;
474
475#ifdef _DIRENT_HAVE_D_TYPE
476 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK) {
477 mode = DTTOIF (dirent->d_type);
478 } else
479#endif
480 {
481 struct stat st;
482 char *path;
483
484 path = g_build_filename (LIBLOCALEDIR, dirent->d_name, NULL);
485 if (g_stat (path, &st) == 0) {
486 mode = st.st_mode;
487 }
488 g_free (path);
489 }
490
491 result = S_ISDIR (mode);
492 }
493
494 return result;
495}
496
497static void
498collect_locales_from_directory (void)
499{
500 struct dirent **dirents;
501 int ndirents;
502 int cnt;
503
faee902e 504 ndirents = scandir (ISO_CODES_LOCALESDIR, &dirents, select_dirs, alphasort);
eea1c851
AL
505
506 for (cnt = 0; cnt < ndirents; ++cnt) {
507 add_locale (dirents[cnt]->d_name);
508 }
509
510 if (ndirents > 0) {
511 free (dirents);
512 }
513}
514
515static void
516collect_locales (void)
517{
518
519 if (gdm_available_locales_map == NULL) {
520 gdm_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gdm_locale_free);
521 }
522
523 if (collect_locales_from_archive ()) {
524 return;
525 } else {
526 g_warning ("Could not read list of available locales from libc, "
527 "guessing possible locales from available translations, "
528 "but list may be incomplete!");
529
530 collect_locales_from_directory ();
531 }
faee902e 532
eea1c851
AL
533}
534
535static gboolean
536is_fallback_language (const char *code)
537{
538 const char *fallback_language_names[] = { "C", "POSIX", NULL };
539 int i;
540
541 for (i = 0; fallback_language_names[i] != NULL; i++) {
542 if (strcmp (code, fallback_language_names[i]) == 0) {
543 return TRUE;
544 }
545 }
546
547 return FALSE;
548}
549
550static const char *
551get_language (const char *code)
552{
553 const char *name;
554 int len;
555
556 g_assert (code != NULL);
557
558 if (is_fallback_language (code)) {
559 return "Unspecified";
560 }
561
562 len = strlen (code);
563 if (len != 2 && len != 3) {
564 return NULL;
565 }
566
567 name = (const char *) g_hash_table_lookup (gdm_languages_map, code);
568
569 return name;
570}
571
572static char *
573get_first_item_in_semicolon_list (const char *list)
574{
575 char **items;
576 char *item;
577
578 /* Some entries in iso codes have multiple values, separated
579 * by semicolons. Not really sure which one to pick, so
580 * we just arbitrarily pick the first one.
581 */
582 items = g_strsplit (list, "; ", 2);
583
584 item = g_strdup (items[0]);
585 g_strfreev (items);
586
587 return item;
588}
589
590static char *
591get_translated_language (const char *code,
592 const char *locale)
593{
594 const char *language;
595 char *name;
596
597 language = get_language (code);
598
599 name = NULL;
600 if (language != NULL) {
601 const char *translated_name;
602 char *old_locale;
603
604 if (locale != NULL) {
605 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
606 setlocale (LC_MESSAGES, locale);
607 }
608
609 if (is_fallback_language (code)) {
610 name = _("Unspecified");
611 } else {
612 translated_name = dgettext ("iso_639", language);
613 name = get_first_item_in_semicolon_list (translated_name);
614 }
615
616 if (locale != NULL) {
617 setlocale (LC_MESSAGES, old_locale);
618 g_free (old_locale);
619 }
620 }
621
622 return name;
623}
624
625static const char *
626get_territory (const char *code)
627{
628 const char *name;
629 int len;
630
631 g_assert (code != NULL);
632
633 len = strlen (code);
634 if (len != 2 && len != 3) {
635 return NULL;
636 }
637
638 name = (const char *) g_hash_table_lookup (gdm_territories_map, code);
639
640 return name;
641}
642
643static const char *
644get_translated_territory (const char *code,
645 const char *locale)
646{
647 const char *territory;
648 char *name;
649
650 territory = get_territory (code);
651
652 name = NULL;
653 if (territory != NULL) {
654 const char *translated_territory;
655 char *old_locale;
656
657 if (locale != NULL) {
658 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
659 setlocale (LC_MESSAGES, locale);
660 }
661
662 translated_territory = dgettext ("iso_3166", territory);
663 name = get_first_item_in_semicolon_list (translated_territory);
664
665 if (locale != NULL) {
666 setlocale (LC_MESSAGES, old_locale);
667 g_free (old_locale);
668 }
669 }
670
671 return name;
672}
673
674static void
675languages_parse_start_tag (GMarkupParseContext *ctx,
676 const char *element_name,
677 const char **attr_names,
678 const char **attr_values,
679 gpointer user_data,
680 GError **error)
681{
682 const char *ccode_longB;
683 const char *ccode_longT;
684 const char *ccode;
685 const char *lang_name;
686
687 if (! g_str_equal (element_name, "iso_639_entry") || attr_names == NULL || attr_values == NULL) {
688 return;
689 }
690
691 ccode = NULL;
692 ccode_longB = NULL;
693 ccode_longT = NULL;
694 lang_name = NULL;
695
696 while (*attr_names && *attr_values) {
697 if (g_str_equal (*attr_names, "iso_639_1_code")) {
698 /* skip if empty */
699 if (**attr_values) {
700 if (strlen (*attr_values) != 2) {
701 return;
702 }
703 ccode = *attr_values;
704 }
705 } else if (g_str_equal (*attr_names, "iso_639_2B_code")) {
706 /* skip if empty */
707 if (**attr_values) {
708 if (strlen (*attr_values) != 3) {
709 return;
710 }
711 ccode_longB = *attr_values;
712 }
713 } else if (g_str_equal (*attr_names, "iso_639_2T_code")) {
714 /* skip if empty */
715 if (**attr_values) {
716 if (strlen (*attr_values) != 3) {
717 return;
718 }
719 ccode_longT = *attr_values;
720 }
721 } else if (g_str_equal (*attr_names, "name")) {
722 lang_name = *attr_values;
723 }
724
725 ++attr_names;
726 ++attr_values;
727 }
728
729 if (lang_name == NULL) {
730 return;
731 }
732
733 if (ccode != NULL) {
734 g_hash_table_insert (gdm_languages_map,
735 g_strdup (ccode),
736 g_strdup (lang_name));
737 }
738 if (ccode_longB != NULL) {
739 g_hash_table_insert (gdm_languages_map,
740 g_strdup (ccode_longB),
741 g_strdup (lang_name));
742 }
743 if (ccode_longT != NULL) {
744 g_hash_table_insert (gdm_languages_map,
745 g_strdup (ccode_longT),
746 g_strdup (lang_name));
747 }
748}
749
750static void
751territories_parse_start_tag (GMarkupParseContext *ctx,
752 const char *element_name,
753 const char **attr_names,
754 const char **attr_values,
755 gpointer user_data,
756 GError **error)
757{
758 const char *acode_2;
759 const char *acode_3;
760 const char *ncode;
761 const char *territory_common_name;
762 const char *territory_name;
763
764 if (! g_str_equal (element_name, "iso_3166_entry") || attr_names == NULL || attr_values == NULL) {
765 return;
766 }
767
768 acode_2 = NULL;
769 acode_3 = NULL;
770 ncode = NULL;
771 territory_common_name = NULL;
772 territory_name = NULL;
773
774 while (*attr_names && *attr_values) {
775 if (g_str_equal (*attr_names, "alpha_2_code")) {
776 /* skip if empty */
777 if (**attr_values) {
778 if (strlen (*attr_values) != 2) {
779 return;
780 }
781 acode_2 = *attr_values;
782 }
783 } else if (g_str_equal (*attr_names, "alpha_3_code")) {
784 /* skip if empty */
785 if (**attr_values) {
786 if (strlen (*attr_values) != 3) {
787 return;
788 }
789 acode_3 = *attr_values;
790 }
791 } else if (g_str_equal (*attr_names, "numeric_code")) {
792 /* skip if empty */
793 if (**attr_values) {
794 if (strlen (*attr_values) != 3) {
795 return;
796 }
797 ncode = *attr_values;
798 }
799 } else if (g_str_equal (*attr_names, "common_name")) {
800 /* skip if empty */
801 if (**attr_values) {
802 territory_common_name = *attr_values;
803 }
804 } else if (g_str_equal (*attr_names, "name")) {
805 territory_name = *attr_values;
806 }
807
808 ++attr_names;
809 ++attr_values;
810 }
811
812 if (territory_common_name != NULL) {
813 territory_name = territory_common_name;
814 }
815
816 if (territory_name == NULL) {
817 return;
818 }
819
820 if (acode_2 != NULL) {
821 g_hash_table_insert (gdm_territories_map,
822 g_strdup (acode_2),
823 g_strdup (territory_name));
824 }
825 if (acode_3 != NULL) {
826 g_hash_table_insert (gdm_territories_map,
827 g_strdup (acode_3),
828 g_strdup (territory_name));
829 }
830 if (ncode != NULL) {
831 g_hash_table_insert (gdm_territories_map,
832 g_strdup (ncode),
833 g_strdup (territory_name));
834 }
835}
836
837static void
838languages_init (void)
839{
840 GError *error;
841 gboolean res;
842 char *buf;
843 gsize buf_len;
844
845 bindtextdomain ("iso_639", ISO_CODES_LOCALESDIR);
846 bind_textdomain_codeset ("iso_639", "UTF-8");
847
848 gdm_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
849
850 error = NULL;
851 res = g_file_get_contents (ISO_CODES_DATADIR "/iso_639.xml",
852 &buf,
853 &buf_len,
854 &error);
855 if (res) {
856 GMarkupParseContext *ctx;
857 GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
858
859 ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
860
861 error = NULL;
862 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
863
864 if (! res) {
865 g_warning ("Failed to parse '%s': %s\n",
866 ISO_CODES_DATADIR "/iso_639.xml",
867 error->message);
868 g_error_free (error);
869 }
870
871 g_markup_parse_context_free (ctx);
872 g_free (buf);
873 } else {
874 g_warning ("Failed to load '%s': %s\n",
875 ISO_CODES_DATADIR "/iso_639.xml",
876 error->message);
877 g_error_free (error);
878 }
879}
880
881static void
882territories_init (void)
883{
884 GError *error;
885 gboolean res;
886 char *buf;
887 gsize buf_len;
888
889 bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR);
890 bind_textdomain_codeset ("iso_3166", "UTF-8");
891
892 gdm_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
893
894 error = NULL;
895 res = g_file_get_contents (ISO_CODES_DATADIR "/iso_3166.xml",
896 &buf,
897 &buf_len,
898 &error);
899 if (res) {
900 GMarkupParseContext *ctx;
901 GMarkupParser parser = { territories_parse_start_tag, NULL, NULL, NULL, NULL };
902
903 ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
904
905 error = NULL;
906 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
907
908 if (! res) {
909 g_warning ("Failed to parse '%s': %s\n",
910 ISO_CODES_DATADIR "/iso_3166.xml",
911 error->message);
912 g_error_free (error);
913 }
914
915 g_markup_parse_context_free (ctx);
916 g_free (buf);
917 } else {
918 g_warning ("Failed to load '%s': %s\n",
919 ISO_CODES_DATADIR "/iso_3166.xml",
920 error->message);
921 g_error_free (error);
922 }
923}
924
925char *
926gdm_get_language_from_name (const char *name,
927 const char *locale)
928{
929 char *full_language;
930 char *language_code;
931 char *territory_code;
932 const char *language;
933 const char *territory;
934
935 if (gdm_languages_map == NULL) {
936 languages_init ();
937 }
938
939 if (gdm_territories_map == NULL) {
940 territories_init ();
941 }
942
943 language_code = NULL;
944 territory_code = NULL;
945 full_language = NULL;
946
947 gdm_parse_language_name (name, &language_code, &territory_code,
948 NULL, NULL);
949
950 if (language_code == NULL) {
951 goto out;
952 }
953
954 language = get_translated_language (language_code, locale);
955
956 if (territory_code != NULL) {
957 territory = get_translated_territory (territory_code, locale);
958 } else {
959 territory = NULL;
960 }
961
962 if (territory != NULL) {
963 full_language = g_strdup_printf ("%s (%s)",
964 language ? language : "",
965 territory ? territory : "");
966 } else {
967 full_language = g_strdup (language);
968 }
969
970out:
971 g_free (language_code);
972 g_free (territory_code);
973
974 return full_language;
975}
976
977char **
978gdm_get_all_language_names (void)
979{
980 GHashTableIter iter;
981 gpointer key, value;
982 GPtrArray *array;
983
984 if (gdm_available_locales_map == NULL) {
985 collect_locales ();
986 }
987
988 array = g_ptr_array_new ();
989 g_hash_table_iter_init (&iter, gdm_available_locales_map);
990 while (g_hash_table_iter_next (&iter, &key, &value)) {
991 GdmLocale *locale;
992
993 locale = (GdmLocale *) value;
994
995 g_ptr_array_add (array, g_strdup (locale->name));
996 }
997 g_ptr_array_add (array, NULL);
998
999 return (char **) g_ptr_array_free (array, FALSE);
1000}