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