source: trunk/third/gettext/lib/localcharset.c @ 16931

Revision 16931, 6.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16930, which included commits to RCS files with non-trunk default branches.
Line 
1/* Determine a canonical name for the current locale's character encoding.
2
3   Copyright (C) 2000-2001 Free Software Foundation, Inc.
4
5   This program is free software; you can redistribute it and/or modify it
6   under the terms of the GNU Library General Public License as published
7   by the Free Software Foundation; either version 2, or (at your option)
8   any later version.
9
10   This program 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   Library General Public License for more details.
14
15   You should have received a copy of the GNU Library General Public
16   License along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18   USA.  */
19
20/* Written by Bruno Haible <haible@clisp.cons.org>.  */
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
25
26#if HAVE_STDDEF_H
27# include <stddef.h>
28#endif
29
30#include <stdio.h>
31#if HAVE_STRING_H
32# include <string.h>
33#else
34# include <strings.h>
35#endif
36#if HAVE_STDLIB_H
37# include <stdlib.h>
38#endif
39
40#if defined _WIN32 || defined __WIN32__
41# undef WIN32   /* avoid warning on mingw32 */
42# define WIN32
43#endif
44
45#ifndef WIN32
46# if HAVE_LANGINFO_CODESET
47#  include <langinfo.h>
48# else
49#  if HAVE_SETLOCALE
50#   include <locale.h>
51#  endif
52# endif
53#else /* WIN32 */
54# define WIN32_LEAN_AND_MEAN
55# include <windows.h>
56#endif
57
58#ifndef DIRECTORY_SEPARATOR
59# define DIRECTORY_SEPARATOR '/'
60#endif
61
62#ifndef ISSLASH
63# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
64#endif
65
66/* The following static variable is declared 'volatile' to avoid a
67   possible multithread problem in the function get_charset_aliases. If we
68   are running in a threaded environment, and if two threads initialize
69   'charset_aliases' simultaneously, both will produce the same value,
70   and everything will be ok if the two assignments to 'charset_aliases'
71   are atomic. But I don't know what will happen if the two assignments mix.  */
72#if __STDC__ != 1
73# define volatile /* empty */
74#endif
75/* Pointer to the contents of the charset.alias file, if it has already been
76   read, else NULL.  Its format is:
77   ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0'  */
78static const char * volatile charset_aliases;
79
80/* Return a pointer to the contents of the charset.alias file.  */
81static const char *
82get_charset_aliases ()
83{
84  const char *cp;
85
86  cp = charset_aliases;
87  if (cp == NULL)
88    {
89#ifndef WIN32
90      FILE *fp;
91      const char *dir = LIBDIR;
92      const char *base = "charset.alias";
93      char *file_name;
94
95      /* Concatenate dir and base into freshly allocated file_name.  */
96      {
97        size_t dir_len = strlen (dir);
98        size_t base_len = strlen (base);
99        int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
100        file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
101        if (file_name != NULL)
102          {
103            memcpy (file_name, dir, dir_len);
104            if (add_slash)
105              file_name[dir_len] = DIRECTORY_SEPARATOR;
106            memcpy (file_name + dir_len + add_slash, base, base_len + 1);
107          }
108      }
109
110      if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
111        /* Out of memory or file not found, treat it as empty.  */
112        cp = "";
113      else
114        {
115          /* Parse the file's contents.  */
116          int c;
117          char buf1[50+1];
118          char buf2[50+1];
119          char *res_ptr = NULL;
120          size_t res_size = 0;
121          size_t l1, l2;
122
123          for (;;)
124            {
125              c = getc (fp);
126              if (c == EOF)
127                break;
128              if (c == '\n' || c == ' ' || c == '\t')
129                continue;
130              if (c == '#')
131                {
132                  /* Skip comment, to end of line.  */
133                  do
134                    c = getc (fp);
135                  while (!(c == EOF || c == '\n'));
136                  if (c == EOF)
137                    break;
138                  continue;
139                }
140              ungetc (c, fp);
141              if (fscanf(fp, "%50s %50s", buf1, buf2) < 2)
142                break;
143              l1 = strlen (buf1);
144              l2 = strlen (buf2);
145              if (res_size == 0)
146                {
147                  res_size = l1 + 1 + l2 + 1;
148                  res_ptr = malloc (res_size + 1);
149                }
150              else
151                {
152                  res_size += l1 + 1 + l2 + 1;
153                  res_ptr = realloc (res_ptr, res_size + 1);
154                }
155              if (res_ptr == NULL)
156                {
157                  /* Out of memory. */
158                  res_size = 0;
159                  break;
160                }
161              strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
162              strcpy (res_ptr + res_size - (l2 + 1), buf2);
163            }
164          fclose (fp);
165          if (res_size == 0)
166            cp = "";
167          else
168            {
169              *(res_ptr + res_size) = '\0';
170              cp = res_ptr;
171            }
172        }
173
174      if (file_name != NULL)
175        free (file_name);
176
177#else /* WIN32 */
178
179      /* To avoid the troubles of installing a separate file in the same
180         directory as the DLL and of retrieving the DLL's directory at
181         runtime, simply inline the aliases here.  */
182
183      cp = "CP936" "\0" "GBK" "\0"
184           "CP1361" "\0" "JOHAB" "\0";
185#endif
186
187      charset_aliases = cp;
188    }
189
190  return cp;
191}
192
193/* Determine the current locale's character encoding, and canonicalize it
194   into one of the canonical names listed in config.charset.
195   The result must not be freed; it is statically allocated.
196   If the canonical name cannot be determined, the result is a non-canonical
197   name.  */
198
199#ifdef STATIC
200STATIC
201#endif
202const char *
203locale_charset ()
204{
205  const char *codeset;
206  const char *aliases;
207
208#ifndef WIN32
209
210# if HAVE_LANGINFO_CODESET
211
212  /* Most systems support nl_langinfo (CODESET) nowadays.  */
213  codeset = nl_langinfo (CODESET);
214
215# else
216
217  /* On old systems which lack it, use setlocale or getenv.  */
218  const char *locale = NULL;
219
220  /* But most old systems don't have a complete set of locales.  Some
221     (like SunOS 4 or DJGPP) have only the C locale.  Therefore we don't
222     use setlocale here; it would return "C" when it doesn't support the
223     locale name the user has set.  */
224#  if HAVE_SETLOCALE && 0
225  locale = setlocale (LC_CTYPE, NULL);
226#  endif
227  if (locale == NULL || locale[0] == '\0')
228    {
229      locale = getenv ("LC_ALL");
230      if (locale == NULL || locale[0] == '\0')
231        {
232          locale = getenv ("LC_CTYPE");
233          if (locale == NULL || locale[0] == '\0')
234            locale = getenv ("LANG");
235        }
236    }
237
238  /* On some old systems, one used to set locale = "iso8859_1". On others,
239     you set it to "language_COUNTRY.charset". In any case, we resolve it
240     through the charset.alias file.  */
241  codeset = locale;
242
243# endif
244
245#else /* WIN32 */
246
247  static char buf[2 + 10 + 1];
248
249  /* Win32 has a function returning the locale's codepage as a number.  */
250  sprintf (buf, "CP%u", GetACP ());
251  codeset = buf;
252
253#endif
254
255  if (codeset == NULL)
256    /* The canonical name cannot be determined.  */
257    codeset = "";
258
259  /* Resolve alias. */
260  for (aliases = get_charset_aliases ();
261       *aliases != '\0';
262       aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
263    if (strcmp (codeset, aliases) == 0
264        || (aliases[0] == '*' && aliases[1] == '\0'))
265      {
266        codeset = aliases + strlen (aliases) + 1;
267        break;
268      }
269
270  return codeset;
271}
Note: See TracBrowser for help on using the repository browser.