1 #include "config.h"
2 
3 #include <stdlib.h>
4 #include <stdio.h>
5 
6 #ifdef HAVE_UNISTD_H
7 #include <unistd.h>
8 #endif
9 
10 #include <string.h>
11 #include <errno.h>
12 #include <locale.h>
13 #include <sys/stat.h>
14 
15 #include <glib.h>
16 #include <glib/gi18n.h>
17 #include <glib/gstdio.h>
18 #include <hb-ot.h>
19 
20 #include "language-names.h"
21 
22 #ifndef ISO_CODES_PREFIX
23 #define ISO_CODES_PREFIX "/usr"
24 #endif
25 
26 #define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
27 #define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
28 
29 static GHashTable *language_map;
30 
31 static char *
get_first_item_in_semicolon_list(const char * list)32 get_first_item_in_semicolon_list (const char *list)
33 {
34   char **items;
35   char  *item;
36 
37   items = g_strsplit (list, "; ", 2);
38 
39   item = g_strdup (items[0]);
40   g_strfreev (items);
41 
42   return item;
43 }
44 
45 static char *
capitalize_utf8_string(const char * str)46 capitalize_utf8_string (const char *str)
47 {
48   char first[8] = { 0 };
49 
50   if (!str)
51     return NULL;
52 
53   g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
54 
55   return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL);
56 }
57 
58 static char *
get_display_name(const char * language)59 get_display_name (const char *language)
60 {
61   const char  *translated;
62   char *tmp;
63   char *name;
64 
65   translated = dgettext ("iso_639", language);
66 
67   tmp = get_first_item_in_semicolon_list (translated);
68   name = capitalize_utf8_string (tmp);
69   g_free (tmp);
70 
71   return name;
72 }
73 
74 static void
languages_parse_start_tag(GMarkupParseContext * ctx,const char * element_name,const char ** attr_names,const char ** attr_values,gpointer user_data,GError ** error)75 languages_parse_start_tag (GMarkupParseContext  *ctx,
76                            const char           *element_name,
77                            const char          **attr_names,
78                            const char          **attr_values,
79                            gpointer              user_data,
80                            GError              **error)
81 {
82   const char *ccode_longB;
83   const char *ccode_longT;
84   const char *ccode;
85   const char *ccode_id;
86   const char *lang_name;
87   char *display_name;
88   const char *long_names[] = {
89     "Dogri",
90     "Greek, Modern",
91     "Interlingua",
92     "Konkani",
93     "Tonga",
94     "Turkish, Ottoman",
95   };
96   int i;
97 
98   if (!(g_str_equal (element_name, "iso_639_entry") ||
99         g_str_equal (element_name, "iso_639_3_entry")) ||
100         attr_names == NULL ||
101         attr_values == NULL)
102     return;
103 
104   ccode = NULL;
105   ccode_longB = NULL;
106   ccode_longT = NULL;
107   ccode_id = NULL;
108   lang_name = NULL;
109 
110   while (*attr_names && *attr_values)
111     {
112       if (g_str_equal (*attr_names, "iso_639_1_code"))
113         {
114           if (**attr_values)
115             {
116               if (strlen (*attr_values) != 2)
117                 return;
118               ccode = *attr_values;
119             }
120         }
121       else if (g_str_equal (*attr_names, "iso_639_2B_code"))
122         {
123           if (**attr_values)
124             {
125               if (strlen (*attr_values) != 3)
126                 return;
127               ccode_longB = *attr_values;
128             }
129         }
130       else if (g_str_equal (*attr_names, "iso_639_2T_code"))
131         {
132           if (**attr_values)
133             {
134               if (strlen (*attr_values) != 3)
135                 return;
136               ccode_longT = *attr_values;
137             }
138         }
139       else if (g_str_equal (*attr_names, "id"))
140         {
141           if (**attr_values)
142             {
143               if (strlen (*attr_values) != 2 &&
144                   strlen (*attr_values) != 3)
145                 return;
146               ccode_id = *attr_values;
147             }
148         }
149       else if (g_str_equal (*attr_names, "name"))
150         {
151           lang_name = *attr_values;
152         }
153 
154       ++attr_names;
155       ++attr_values;
156     }
157 
158   if (lang_name == NULL)
159     return;
160 
161   display_name = get_display_name (lang_name);
162 
163   /* Fix up some egregious names */
164   for (i = 0; i < G_N_ELEMENTS (long_names); i++)
165     {
166       if (g_str_has_prefix (display_name, long_names[i]))
167         display_name[strlen (long_names[i])] = '\0';
168     }
169 
170 
171   if (ccode != NULL)
172     g_hash_table_insert (language_map,
173                          pango_language_from_string (ccode),
174                          g_strdup (display_name));
175 
176   if (ccode_longB != NULL)
177     g_hash_table_insert (language_map,
178                          pango_language_from_string (ccode_longB),
179                          g_strdup (display_name));
180 
181   if (ccode_longT != NULL)
182     g_hash_table_insert (language_map,
183                          pango_language_from_string (ccode_longT),
184                          g_strdup (display_name));
185 
186   if (ccode_id != NULL)
187     g_hash_table_insert (language_map,
188                          pango_language_from_string (ccode_id),
189                          g_strdup (display_name));
190 
191   g_free (display_name);
192 }
193 
194 static void
languages_variant_init(const char * variant)195 languages_variant_init (const char *variant)
196 {
197   gboolean res;
198   gsize    buf_len;
199   char *buf;
200   char *filename;
201   GError *error;
202 
203   bindtextdomain (variant, ISO_CODES_LOCALESDIR);
204   bind_textdomain_codeset (variant, "UTF-8");
205 
206   error = NULL;
207   filename = g_strconcat (ISO_CODES_DATADIR, "/", variant, ".xml", NULL);
208   res = g_file_get_contents (filename, &buf, &buf_len, &error);
209   if (res)
210     {
211       GMarkupParseContext *ctx = NULL;
212       GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
213 
214       ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
215 
216       res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
217       g_free (ctx);
218 
219       if (!res)
220         {
221           g_warning ("Failed to parse '%s': %s\n", filename, error->message);
222           g_error_free (error);
223         }
224     }
225   else
226     {
227       g_warning ("Failed to load '%s': %s\n", filename, error->message);
228       g_error_free (error);
229     }
230 
231   g_free (filename);
232   g_free (buf);
233 }
234 
235 static void
languages_init(void)236 languages_init (void)
237 {
238   if (language_map)
239     return;
240 
241   language_map = g_hash_table_new_full (NULL, NULL, NULL, g_free);
242   languages_variant_init ("iso_639");
243   languages_variant_init ("iso_639_3");
244 }
245 
246 const char *
get_language_name(PangoLanguage * language)247 get_language_name (PangoLanguage *language)
248 {
249   languages_init ();
250 
251   return (const char *) g_hash_table_lookup (language_map, language);
252 }
253 
254 const char *
get_language_name_for_tag(guint32 tag)255 get_language_name_for_tag (guint32 tag)
256 {
257   hb_language_t lang;
258   const char *s;
259 
260   lang = hb_ot_tag_to_language (tag);
261   s = hb_language_to_string (lang);
262 
263   return get_language_name (pango_language_from_string (s));
264 }
265