Trivial typo fix
[platform/upstream/glib.git] / glib / gcharset.c
1 /* gcharset.c - Charset information
2  *
3  * Copyright (C) 2011 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include "gcharsetprivate.h"
24
25 #include "garray.h"
26 #include "genviron.h"
27 #include "ghash.h"
28 #include "gmessages.h"
29 #include "gstrfuncs.h"
30 #include "gthread.h"
31 #ifdef G_OS_WIN32
32 #include "gwin32.h"
33 #endif
34
35 #include "libcharset/libcharset.h"
36
37 #include <string.h>
38 #include <stdio.h>
39
40 G_LOCK_DEFINE_STATIC (aliases);
41
42 static GHashTable *
43 get_alias_hash (void)
44 {
45   static GHashTable *alias_hash = NULL;
46   const char *aliases;
47
48   G_LOCK (aliases);
49
50   if (!alias_hash)
51     {
52       alias_hash = g_hash_table_new (g_str_hash, g_str_equal);
53
54       aliases = _g_locale_get_charset_aliases ();
55       while (*aliases != '\0')
56         {
57           const char *canonical;
58           const char *alias;
59           const char **alias_array;
60           int count = 0;
61
62           alias = aliases;
63           aliases += strlen (aliases) + 1;
64           canonical = aliases;
65           aliases += strlen (aliases) + 1;
66
67           alias_array = g_hash_table_lookup (alias_hash, canonical);
68           if (alias_array)
69             {
70               while (alias_array[count])
71                 count++;
72             }
73
74           alias_array = g_renew (const char *, alias_array, count + 2);
75           alias_array[count] = alias;
76           alias_array[count + 1] = NULL;
77
78           g_hash_table_insert (alias_hash, (char *)canonical, alias_array);
79         }
80     }
81
82   G_UNLOCK (aliases);
83
84   return alias_hash;
85 }
86
87 /* As an abuse of the alias table, the following routines gets
88  * the charsets that are aliases for the canonical name.
89  */
90 const char **
91 _g_charset_get_aliases (const char *canonical_name)
92 {
93   GHashTable *alias_hash = get_alias_hash ();
94
95   return g_hash_table_lookup (alias_hash, canonical_name);
96 }
97
98 static gboolean
99 g_utf8_get_charset_internal (const char  *raw_data,
100                              const char **a)
101 {
102   const char *charset = g_getenv ("CHARSET");
103
104   if (charset && *charset)
105     {
106       *a = charset;
107
108       if (charset && strstr (charset, "UTF-8"))
109         return TRUE;
110       else
111         return FALSE;
112     }
113
114   /* The libcharset code tries to be thread-safe without
115    * a lock, but has a memory leak and a missing memory
116    * barrier, so we lock for it
117    */
118   G_LOCK (aliases);
119   charset = _g_locale_charset_unalias (raw_data);
120   G_UNLOCK (aliases);
121
122   if (charset && *charset)
123     {
124       *a = charset;
125
126       if (charset && strstr (charset, "UTF-8"))
127         return TRUE;
128       else
129         return FALSE;
130     }
131
132   /* Assume this for compatibility at present.  */
133   *a = "US-ASCII";
134
135   return FALSE;
136 }
137
138 typedef struct _GCharsetCache GCharsetCache;
139
140 struct _GCharsetCache {
141   gboolean is_utf8;
142   gchar *raw;
143   gchar *charset;
144 };
145
146 static void
147 charset_cache_free (gpointer data)
148 {
149   GCharsetCache *cache = data;
150   g_free (cache->raw);
151   g_free (cache->charset);
152   g_free (cache);
153 }
154
155 /**
156  * g_get_charset:
157  * @charset: return location for character set name
158  *
159  * Obtains the character set for the <link linkend="setlocale">current
160  * locale</link>; you might use this character set as an argument to
161  * g_convert(), to convert from the current locale's encoding to some
162  * other encoding. (Frequently g_locale_to_utf8() and g_locale_from_utf8()
163  * are nice shortcuts, though.)
164  *
165  * On Windows the character set returned by this function is the
166  * so-called system default ANSI code-page. That is the character set
167  * used by the "narrow" versions of C library and Win32 functions that
168  * handle file names. It might be different from the character set
169  * used by the C library's current locale.
170  *
171  * The return value is %TRUE if the locale's encoding is UTF-8, in that
172  * case you can perhaps avoid calling g_convert().
173  *
174  * The string returned in @charset is not allocated, and should not be
175  * freed.
176  *
177  * Return value: %TRUE if the returned charset is UTF-8
178  */
179 gboolean
180 g_get_charset (const char **charset)
181 {
182   static GPrivate cache_private = G_PRIVATE_INIT (charset_cache_free);
183   GCharsetCache *cache = g_private_get (&cache_private);
184   const gchar *raw;
185
186   if (!cache)
187     {
188       cache = g_new0 (GCharsetCache, 1);
189       g_private_set (&cache_private, cache);
190     }
191
192   G_LOCK (aliases);
193   raw = _g_locale_charset_raw ();
194   G_UNLOCK (aliases);
195
196   if (!(cache->raw && strcmp (cache->raw, raw) == 0))
197     {
198       const gchar *new_charset;
199
200       g_free (cache->raw);
201       g_free (cache->charset);
202       cache->raw = g_strdup (raw);
203       cache->is_utf8 = g_utf8_get_charset_internal (raw, &new_charset);
204       cache->charset = g_strdup (new_charset);
205     }
206
207   if (charset)
208     *charset = cache->charset;
209
210   return cache->is_utf8;
211 }
212
213 /**
214  * g_get_codeset:
215  *
216  * Gets the character set for the current locale.
217  *
218  * Return value: a newly allocated string containing the name
219  *     of the character set. This string must be freed with g_free().
220  */
221 gchar *
222 g_get_codeset (void)
223 {
224   const gchar *charset;
225
226   g_get_charset (&charset);
227
228   return g_strdup (charset);
229 }
230
231 #ifndef G_OS_WIN32
232
233 static GHashTable *alias_table = NULL;
234
235 /* read an alias file for the locales */
236 static void
237 read_aliases (gchar *file)
238 {
239   FILE *fp;
240   char buf[256];
241
242   if (!alias_table)
243     alias_table = g_hash_table_new (g_str_hash, g_str_equal);
244   fp = fopen (file,"r");
245   if (!fp)
246     return;
247   while (fgets (buf, 256, fp))
248     {
249       char *p, *q;
250
251       g_strstrip (buf);
252
253       /* Line is a comment */
254       if ((buf[0] == '#') || (buf[0] == '\0'))
255         continue;
256
257       /* Reads first column */
258       for (p = buf, q = NULL; *p; p++) {
259         if ((*p == '\t') || (*p == ' ') || (*p == ':')) {
260           *p = '\0';
261           q = p+1;
262           while ((*q == '\t') || (*q == ' ')) {
263             q++;
264           }
265           break;
266         }
267       }
268       /* The line only had one column */
269       if (!q || *q == '\0')
270         continue;
271
272       /* Read second column */
273       for (p = q; *p; p++) {
274         if ((*p == '\t') || (*p == ' ')) {
275           *p = '\0';
276           break;
277         }
278       }
279
280       /* Add to alias table if necessary */
281       if (!g_hash_table_lookup (alias_table, buf)) {
282         g_hash_table_insert (alias_table, g_strdup (buf), g_strdup (q));
283       }
284     }
285   fclose (fp);
286 }
287
288 #endif
289
290 static char *
291 unalias_lang (char *lang)
292 {
293 #ifndef G_OS_WIN32
294   char *p;
295   int i;
296
297   if (!alias_table)
298     read_aliases ("/usr/share/locale/locale.alias");
299
300   i = 0;
301   while ((p = g_hash_table_lookup (alias_table, lang)) && (strcmp (p, lang) != 0))
302     {
303       lang = p;
304       if (i++ == 30)
305         {
306           static gboolean said_before = FALSE;
307           if (!said_before)
308             g_warning ("Too many alias levels for a locale, "
309                        "may indicate a loop");
310           said_before = TRUE;
311           return lang;
312         }
313     }
314 #endif
315   return lang;
316 }
317
318 /* Mask for components of locale spec. The ordering here is from
319  * least significant to most significant
320  */
321 enum
322 {
323   COMPONENT_CODESET =   1 << 0,
324   COMPONENT_TERRITORY = 1 << 1,
325   COMPONENT_MODIFIER =  1 << 2
326 };
327
328 /* Break an X/Open style locale specification into components
329  */
330 static guint
331 explode_locale (const gchar *locale,
332                 gchar      **language,
333                 gchar      **territory,
334                 gchar      **codeset,
335                 gchar      **modifier)
336 {
337   const gchar *uscore_pos;
338   const gchar *at_pos;
339   const gchar *dot_pos;
340
341   guint mask = 0;
342
343   uscore_pos = strchr (locale, '_');
344   dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
345   at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
346
347   if (at_pos)
348     {
349       mask |= COMPONENT_MODIFIER;
350       *modifier = g_strdup (at_pos);
351     }
352   else
353     at_pos = locale + strlen (locale);
354
355   if (dot_pos)
356     {
357       mask |= COMPONENT_CODESET;
358       *codeset = g_strndup (dot_pos, at_pos - dot_pos);
359     }
360   else
361     dot_pos = at_pos;
362
363   if (uscore_pos)
364     {
365       mask |= COMPONENT_TERRITORY;
366       *territory = g_strndup (uscore_pos, dot_pos - uscore_pos);
367     }
368   else
369     uscore_pos = dot_pos;
370
371   *language = g_strndup (locale, uscore_pos - locale);
372
373   return mask;
374 }
375
376 /*
377  * Compute all interesting variants for a given locale name -
378  * by stripping off different components of the value.
379  *
380  * For simplicity, we assume that the locale is in
381  * X/Open format: language[_territory][.codeset][@modifier]
382  *
383  * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
384  *       as well. We could just copy the code from glibc wholesale
385  *       but it is big, ugly, and complicated, so I'm reluctant
386  *       to do so when this should handle 99% of the time...
387  */
388 static void
389 append_locale_variants (GPtrArray *array,
390                         const gchar *locale)
391 {
392   gchar *language = NULL;
393   gchar *territory = NULL;
394   gchar *codeset = NULL;
395   gchar *modifier = NULL;
396
397   guint mask;
398   guint i, j;
399
400   g_return_if_fail (locale != NULL);
401
402   mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
403
404   /* Iterate through all possible combinations, from least attractive
405    * to most attractive.
406    */
407   for (j = 0; j <= mask; ++j)
408     {
409       i = mask - j;
410
411       if ((i & ~mask) == 0)
412         {
413           gchar *val = g_strconcat (language,
414                                     (i & COMPONENT_TERRITORY) ? territory : "",
415                                     (i & COMPONENT_CODESET) ? codeset : "",
416                                     (i & COMPONENT_MODIFIER) ? modifier : "",
417                                     NULL);
418           g_ptr_array_add (array, val);
419         }
420     }
421
422   g_free (language);
423   if (mask & COMPONENT_CODESET)
424     g_free (codeset);
425   if (mask & COMPONENT_TERRITORY)
426     g_free (territory);
427   if (mask & COMPONENT_MODIFIER)
428     g_free (modifier);
429 }
430
431 /**
432  * g_get_locale_variants:
433  * @locale: a locale identifier
434  *
435  * Returns a list of derived variants of @locale, which can be used to
436  * e.g. construct locale-dependent filenames or search paths. The returned
437  * list is sorted from most desirable to least desirable.
438  * This function handles territory, charset and extra locale modifiers.
439  *
440  * For example, if @locale is "fr_BE", then the returned list
441  * is "fr_BE", "fr".
442  *
443  * If you need the list of variants for the <emphasis>current locale</emphasis>,
444  * use g_get_language_names().
445  *
446  * Returns: (transfer full) (array zero-terminated=1) (element-type utf8): a newly
447  *   allocated array of newly allocated strings with the locale variants. Free with
448  *   g_strfreev().
449  *
450  * Since: 2.28
451  */
452 gchar **
453 g_get_locale_variants (const gchar *locale)
454 {
455   GPtrArray *array;
456
457   g_return_val_if_fail (locale != NULL, NULL);
458
459   array = g_ptr_array_sized_new (8);
460   append_locale_variants (array, locale);
461   g_ptr_array_add (array, NULL);
462
463   return (gchar **) g_ptr_array_free (array, FALSE);
464 }
465
466 /* The following is (partly) taken from the gettext package.
467    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.  */
468
469 static const gchar *
470 guess_category_value (const gchar *category_name)
471 {
472   const gchar *retval;
473
474   /* The highest priority value is the 'LANGUAGE' environment
475      variable.  This is a GNU extension.  */
476   retval = g_getenv ("LANGUAGE");
477   if ((retval != NULL) && (retval[0] != '\0'))
478     return retval;
479
480   /* 'LANGUAGE' is not set.  So we have to proceed with the POSIX
481      methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.  On some
482      systems this can be done by the 'setlocale' function itself.  */
483
484   /* Setting of LC_ALL overwrites all other.  */
485   retval = g_getenv ("LC_ALL");
486   if ((retval != NULL) && (retval[0] != '\0'))
487     return retval;
488
489   /* Next comes the name of the desired category.  */
490   retval = g_getenv (category_name);
491   if ((retval != NULL) && (retval[0] != '\0'))
492     return retval;
493
494   /* Last possibility is the LANG environment variable.  */
495   retval = g_getenv ("LANG");
496   if ((retval != NULL) && (retval[0] != '\0'))
497     return retval;
498
499 #ifdef G_PLATFORM_WIN32
500   /* g_win32_getlocale() first checks for LC_ALL, LC_MESSAGES and
501    * LANG, which we already did above. Oh well. The main point of
502    * calling g_win32_getlocale() is to get the thread's locale as used
503    * by Windows and the Microsoft C runtime (in the "English_United
504    * States" format) translated into the Unixish format.
505    */
506   {
507     char *locale = g_win32_getlocale ();
508     retval = g_intern_string (locale);
509     g_free (locale);
510     return retval;
511   }
512 #endif
513
514   return NULL;
515 }
516
517 typedef struct _GLanguageNamesCache GLanguageNamesCache;
518
519 struct _GLanguageNamesCache {
520   gchar *languages;
521   gchar **language_names;
522 };
523
524 static void
525 language_names_cache_free (gpointer data)
526 {
527   GLanguageNamesCache *cache = data;
528   g_free (cache->languages);
529   g_strfreev (cache->language_names);
530   g_free (cache);
531 }
532
533 /**
534  * g_get_language_names:
535  *
536  * Computes a list of applicable locale names, which can be used to
537  * e.g. construct locale-dependent filenames or search paths. The returned
538  * list is sorted from most desirable to least desirable and always contains
539  * the default locale "C".
540  *
541  * For example, if LANGUAGE=de:en_US, then the returned list is
542  * "de", "en_US", "en", "C".
543  *
544  * This function consults the environment variables <envar>LANGUAGE</envar>,
545  * <envar>LC_ALL</envar>, <envar>LC_MESSAGES</envar> and <envar>LANG</envar>
546  * to find the list of locales specified by the user.
547  *
548  * Return value: (array zero-terminated=1) (transfer none): a %NULL-terminated array of strings owned by GLib
549  *    that must not be modified or freed.
550  *
551  * Since: 2.6
552  **/
553 const gchar * const *
554 g_get_language_names (void)
555 {
556   static GPrivate cache_private = G_PRIVATE_INIT (language_names_cache_free);
557   GLanguageNamesCache *cache = g_private_get (&cache_private);
558   const gchar *value;
559
560   if (!cache)
561     {
562       cache = g_new0 (GLanguageNamesCache, 1);
563       g_private_set (&cache_private, cache);
564     }
565
566   value = guess_category_value ("LC_MESSAGES");
567   if (!value)
568     value = "C";
569
570   if (!(cache->languages && strcmp (cache->languages, value) == 0))
571     {
572       GPtrArray *array;
573       gchar **alist, **a;
574
575       g_free (cache->languages);
576       g_strfreev (cache->language_names);
577       cache->languages = g_strdup (value);
578
579       array = g_ptr_array_sized_new (8);
580
581       alist = g_strsplit (value, ":", 0);
582       for (a = alist; *a; a++)
583         append_locale_variants (array, unalias_lang (*a));
584       g_strfreev (alist);
585       g_ptr_array_add (array, g_strdup ("C"));
586       g_ptr_array_add (array, NULL);
587
588       cache->language_names = (gchar **) g_ptr_array_free (array, FALSE);
589     }
590
591   return (const gchar * const *) cache->language_names;
592 }