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