source: trunk/third/gnome-vfs/libgnomevfs/gnome-vfs-i18n.c @ 17128

Revision 17128, 8.6 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17127, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
3 * All rights reserved.
4 *
5 * This file is part of the Gnome Library.
6 *
7 * The Gnome Library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * The Gnome Library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with the Gnome Library; see the file COPYING.LIB.  If not,
19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <errno.h>
28#include <glib.h>
29#include <signal.h>
30#include <string.h>
31#include <sys/types.h>
32#include <sys/wait.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <stdio.h>
37#include <ctype.h>
38
39#include <stdlib.h> /* for mkstemp */
40#include <unistd.h> /* for close */
41
42#include "gnome-vfs.h"
43#include "gnome-vfs-private.h"
44
45static GHashTable *alias_table = NULL;
46static GHashTable *category_table = NULL;
47
48/*read an alias file for the locales*/
49static void
50read_aliases (char *file)
51{
52  FILE *fp;
53  char buf[256];
54
55  if (!alias_table)
56    alias_table = g_hash_table_new (g_str_hash, g_str_equal);
57  fp = fopen (file,"r");
58  if (!fp)
59    return;
60  while (fgets (buf, 256, fp))
61    {
62      char *p, *q, *r;
63
64      g_strstrip (buf);
65      if ((buf[0] == '#') || (buf[0] == '\0'))
66        continue;
67      for (p = buf, q = NULL; *p; p++)
68        if ((*p == '\t') || (*p == ' ')) {
69          *p = '\0'; q = p;
70          break;
71        }
72      if (!q)
73        continue;
74      for (p = q, r = NULL; *p; p++)
75        if ((*p == '\t') || (*p == ' ')) {
76          *p = '\0'; r = p;
77          break;
78        }
79      if(!r)
80        continue;
81      if (!g_hash_table_lookup (alias_table, buf))
82        g_hash_table_insert (alias_table, g_strdup (buf), g_strdup (r));
83    }
84  fclose (fp);
85}
86
87static char *
88unalias_lang (char *lang)
89{
90  char *p;
91  int i;
92
93  if (!alias_table)
94    {
95      read_aliases ("/usr/share/locale/locale.alias");
96      read_aliases ("/usr/local/share/locale/locale.alias");
97      read_aliases ("/usr/lib/X11/locale/locale.alias");
98      read_aliases ("/usr/openwin/lib/locale/locale.alias");
99    }
100  i = 0;
101  while ((p = g_hash_table_lookup (alias_table, lang)) && (strcmp (p, lang) != 0))
102    {
103      lang = p;
104      if (i++ == 30)
105        {
106          static gboolean said_before = FALSE;
107          if (!said_before)
108            g_warning ("Too many alias levels for a locale, "
109                       "may indicate a loop");
110          said_before = TRUE;
111          return lang;
112        }
113    }
114  return lang;
115}
116
117/* Mask for components of locale spec. The ordering here is from
118 * least significant to most significant
119 */
120enum
121{
122  COMPONENT_CODESET =   1 << 0,
123  COMPONENT_TERRITORY = 1 << 1,
124  COMPONENT_MODIFIER =  1 << 2
125};
126
127/* Break an X/Open style locale specification into components
128 */
129static guint
130explode_locale (const gchar *locale,
131                gchar **language,
132                gchar **territory,
133                gchar **codeset,
134                gchar **modifier)
135{
136  const gchar *uscore_pos;
137  const gchar *at_pos;
138  const gchar *dot_pos;
139
140  guint mask = 0;
141
142  uscore_pos = strchr (locale, '_');
143  dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
144  at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
145
146  if (at_pos)
147    {
148      mask |= COMPONENT_MODIFIER;
149      *modifier = g_strdup (at_pos);
150    }
151  else
152    at_pos = locale + strlen (locale);
153
154  if (dot_pos)
155    {
156      mask |= COMPONENT_CODESET;
157      *codeset = g_strndup (dot_pos, at_pos - dot_pos);
158    }
159  else
160    dot_pos = at_pos;
161
162  if (uscore_pos)
163    {
164      mask |= COMPONENT_TERRITORY;
165      *territory = g_strndup (uscore_pos, dot_pos - uscore_pos);
166    }
167  else
168    uscore_pos = dot_pos;
169
170  *language = g_strndup (locale, uscore_pos - locale);
171
172  return mask;
173}
174
175/*
176 * Compute all interesting variants for a given locale name -
177 * by stripping off different components of the value.
178 *
179 * For simplicity, we assume that the locale is in
180 * X/Open format: language[_territory][.codeset][@modifier]
181 *
182 * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
183 *       as well. We could just copy the code from glibc wholesale
184 *       but it is big, ugly, and complicated, so I'm reluctant
185 *       to do so when this should handle 99% of the time...
186 */
187static GList *
188compute_locale_variants (const gchar *locale)
189{
190  GList *retval = NULL;
191
192  gchar *language;
193  gchar *territory;
194  gchar *codeset;
195  gchar *modifier;
196
197  guint mask;
198  guint i;
199
200  g_return_val_if_fail (locale != NULL, NULL);
201
202  mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
203
204  /* Iterate through all possible combinations, from least attractive
205   * to most attractive.
206   */
207  for (i = 0; i <= mask; i++)
208    if ((i & ~mask) == 0)
209      {
210        gchar *val = g_strconcat (language,
211                                  (i & COMPONENT_TERRITORY) ? territory : "",
212                                  (i & COMPONENT_CODESET) ? codeset : "",
213                                  (i & COMPONENT_MODIFIER) ? modifier : "",
214                                  NULL);
215        retval = g_list_prepend (retval, val);
216      }
217
218  g_free (language);
219  if (mask & COMPONENT_CODESET)
220    g_free (codeset);
221  if (mask & COMPONENT_TERRITORY)
222    g_free (territory);
223  if (mask & COMPONENT_MODIFIER)
224    g_free (modifier);
225
226  return retval;
227}
228
229/* The following is (partly) taken from the gettext package.
230   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.  */
231
232static const gchar *
233guess_category_value (const gchar *categoryname)
234{
235  const gchar *retval;
236
237  /* The highest priority value is the `LANGUAGE' environment
238     variable.  This is a GNU extension.  */
239  retval = g_getenv ("LANGUAGE");
240  if ((retval != NULL) && (retval[0] != '\0'))
241    return retval;
242
243  /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
244     methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
245     systems this can be done by the `setlocale' function itself.  */
246
247  /* Setting of LC_ALL overwrites all other.  */
248  retval = g_getenv ("LC_ALL"); 
249  if ((retval != NULL) && (retval[0] != '\0'))
250    return retval;
251
252  /* Next comes the name of the desired category.  */
253  retval = g_getenv (categoryname);
254  if ((retval != NULL) && (retval[0] != '\0'))
255    return retval;
256
257  /* Last possibility is the LANG environment variable.  */
258  retval = g_getenv ("LANG");
259  if ((retval != NULL) && (retval[0] != '\0'))
260    return retval;
261
262  return NULL;
263}
264
265/**
266 * gnome_vfs_i18n_get_language_list:
267 * @category_name: Name of category to look up, e.g. "LC_MESSAGES".
268 *
269 * This computes a list of language strings.  It searches in the
270 * standard environment variables to find the list, which is sorted
271 * in order from most desirable to least desirable.  The `C' locale
272 * is appended to the list if it does not already appear (other
273 * routines depend on this behaviour).
274 * If @category_name is %NULL, then LC_ALL is assumed.
275 *
276 * Return value: a copy of the list of languages (which you need to free).
277 **/
278GList *
279gnome_vfs_i18n_get_language_list (const gchar *category_name)
280{
281  GList *list;
282
283  if (!category_name)
284    category_name = "LC_ALL";
285
286  if (category_table)
287    {
288      list = g_hash_table_lookup (category_table, (const gpointer) category_name);
289    }
290  else
291    {
292      category_table = g_hash_table_new (g_str_hash, g_str_equal);
293      list = NULL;
294    }
295
296  if (!list)
297    {
298      gint c_locale_defined = FALSE;
299 
300      const gchar *category_value;
301      gchar *category_memory, *orig_category_memory;
302
303      category_value = guess_category_value (category_name);
304      if (!category_value)
305        category_value = "C";
306      orig_category_memory = category_memory =
307        g_malloc (strlen (category_value)+1);
308     
309      while (category_value[0] != '\0')
310        {
311          while ((category_value[0] != '\0') && (category_value[0] == ':'))
312            ++category_value;
313         
314          if (category_value[0] != '\0')
315            {
316              char *cp = category_memory;
317             
318              while ((category_value[0] != '\0') && (category_value[0] != ':'))
319                *category_memory++ = *category_value++;
320             
321              category_memory[0] = '\0';
322              category_memory++;
323             
324              cp = unalias_lang (cp);
325             
326              if (strcmp (cp, "C") == 0)
327                c_locale_defined = TRUE;
328             
329              list = g_list_concat (list, compute_locale_variants (cp));
330            }
331        }
332
333      g_free (orig_category_memory);
334     
335      if (!c_locale_defined)
336        list= g_list_append (list, "C");
337
338      g_hash_table_insert (category_table, (gpointer) category_name, list);
339    }
340
341  return g_list_copy (list);
342}
Note: See TracBrowser for help on using the repository browser.