source: trunk/third/bonobo-activation/bonobo-activation/bonobo-activation-get-language-list.c @ 18563

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