105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Determine a canonical name for the current locale's character encoding.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2000-2006, 2008-2012 Free Software Foundation, Inc.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software; you can redistribute it and/or modify
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3, or (at your option)
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License along
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   with this program; if not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Written by Bruno Haible <bruno@clisp.org>.  */
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "localcharset.h"
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <fcntl.h>
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stddef.h>
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdio.h>
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <string.h>
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DARWIN7 /* Darwin 7 or newer, i.e. Mac OS X 10.3 or newer */
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined _WIN32 || defined __WIN32__
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define WINDOWS_NATIVE
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined __EMX__
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Assume EMX program runs on OS/2, even if compiled under DOS.  */
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# ifndef OS2
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define OS2
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !defined WINDOWS_NATIVE
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <unistd.h>
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if HAVE_LANGINFO_CODESET
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  include <langinfo.h>
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if 0 /* see comment below */
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   include <locale.h>
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# ifdef __CYGWIN__
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define WIN32_LEAN_AND_MEAN
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  include <windows.h>
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif defined WINDOWS_NATIVE
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define WIN32_LEAN_AND_MEAN
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <windows.h>
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined OS2
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define INCL_DOS
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <os2.h>
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if ENABLE_RELOCATABLE
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "relocatable.h"
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define relocate(pathname) (pathname)
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get LIBDIR.  */
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef LIBDIR
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "configmake.h"
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Define O_NOFOLLOW to 0 on platforms where it does not exist.  */
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef O_NOFOLLOW
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define O_NOFOLLOW 0
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Native Windows, Cygwin, OS/2, DOS */
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define ISSLASH(C) ((C) == '/' || (C) == '\\')
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef DIRECTORY_SEPARATOR
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DIRECTORY_SEPARATOR '/'
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef ISSLASH
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_DECL_GETC_UNLOCKED
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# undef getc
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define getc getc_unlocked
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The following static variable is declared 'volatile' to avoid a
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   possible multithread problem in the function get_charset_aliases. If we
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   are running in a threaded environment, and if two threads initialize
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   'charset_aliases' simultaneously, both will produce the same value,
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   and everything will be ok if the two assignments to 'charset_aliases'
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   are atomic. But I don't know what will happen if the two assignments mix.  */
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if __STDC__ != 1
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define volatile /* empty */
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Pointer to the contents of the charset.alias file, if it has already been
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   read, else NULL.  Its format is:
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0'  */
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic const char * volatile charset_aliases;
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Return a pointer to the contents of the charset.alias file.  */
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic const char *
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wangget_charset_aliases (void)
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  const char *cp;
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  cp = charset_aliases;
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (cp == NULL)
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !(defined DARWIN7 || defined VMS || defined WINDOWS_NATIVE || defined __CYGWIN__)
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      const char *dir;
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      const char *base = "charset.alias";
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      char *file_name;
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Make it possible to override the charset.alias location.  This is
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         necessary for running the testsuite before "make install".  */
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      dir = getenv ("CHARSETALIASDIR");
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (dir == NULL || dir[0] == '\0')
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        dir = relocate (LIBDIR);
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Concatenate dir and base into freshly allocated file_name.  */
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        size_t dir_len = strlen (dir);
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        size_t base_len = strlen (base);
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (file_name != NULL)
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          {
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            memcpy (file_name, dir, dir_len);
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (add_slash)
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              file_name[dir_len] = DIRECTORY_SEPARATOR;
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            memcpy (file_name + dir_len + add_slash, base, base_len + 1);
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          }
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (file_name == NULL)
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Out of memory.  Treat the file as empty.  */
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        cp = "";
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          int fd;
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Open the file.  Reject symbolic links on platforms that support
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang             O_NOFOLLOW.  This is a security feature.  Without it, an attacker
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang             could retrieve parts of the contents (namely, the tail of the
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang             first line that starts with "* ") of an arbitrary file by placing
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang             a symbolic link to that file under the name "charset.alias" in
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang             some writable directory and defining the environment variable
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang             CHARSETALIASDIR to point to that directory.  */
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          fd = open (file_name,
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0));
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (fd < 0)
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            /* File not found.  Treat it as empty.  */
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            cp = "";
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          else
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              FILE *fp;
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              fp = fdopen (fd, "r");
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (fp == NULL)
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* Out of memory.  Treat the file as empty.  */
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  close (fd);
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp = "";
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* Parse the file's contents.  */
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  char *res_ptr = NULL;
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  size_t res_size = 0;
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  for (;;)
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      int c;
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      char buf1[50+1];
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      char buf2[50+1];
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      size_t l1, l2;
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      char *old_res_ptr;
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      c = getc (fp);
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (c == EOF)
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        break;
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (c == '\n' || c == ' ' || c == '\t')
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        continue;
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (c == '#')
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* Skip comment, to end of line.  */
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          do
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            c = getc (fp);
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          while (!(c == EOF || c == '\n'));
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          if (c == EOF)
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            break;
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          continue;
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      ungetc (c, fp);
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        break;
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      l1 = strlen (buf1);
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      l2 = strlen (buf2);
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      old_res_ptr = res_ptr;
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (res_size == 0)
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          res_size = l1 + 1 + l2 + 1;
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          res_ptr = (char *) malloc (res_size + 1);
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          res_size += l1 + 1 + l2 + 1;
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          res_ptr = (char *) realloc (res_ptr, res_size + 1);
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (res_ptr == NULL)
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* Out of memory. */
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          res_size = 0;
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          free (old_res_ptr);
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          break;
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      strcpy (res_ptr + res_size - (l2 + 1), buf2);
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  fclose (fp);
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (res_size == 0)
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    cp = "";
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      *(res_ptr + res_size) = '\0';
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp = res_ptr;
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          free (file_name);
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined DARWIN7
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* To avoid the trouble of installing a file that is shared by many
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang         GNU packages -- many packaging systems have problems with this --,
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang         simply inline the aliases here.  */
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-2" "\0" "ISO-8859-2" "\0"
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-4" "\0" "ISO-8859-4" "\0"
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-5" "\0" "ISO-8859-5" "\0"
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-7" "\0" "ISO-8859-7" "\0"
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-9" "\0" "ISO-8859-9" "\0"
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-13" "\0" "ISO-8859-13" "\0"
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-15" "\0" "ISO-8859-15" "\0"
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "KOI8-R" "\0" "KOI8-R" "\0"
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "KOI8-U" "\0" "KOI8-U" "\0"
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP866" "\0" "CP866" "\0"
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP949" "\0" "CP949" "\0"
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP1131" "\0" "CP1131" "\0"
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP1251" "\0" "CP1251" "\0"
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "eucCN" "\0" "GB2312" "\0"
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "GB2312" "\0" "GB2312" "\0"
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "eucJP" "\0" "EUC-JP" "\0"
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "eucKR" "\0" "EUC-KR" "\0"
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "Big5" "\0" "BIG5" "\0"
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "Big5HKSCS" "\0" "BIG5-HKSCS" "\0"
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "GBK" "\0" "GBK" "\0"
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "GB18030" "\0" "GB18030" "\0"
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "SJIS" "\0" "SHIFT_JIS" "\0"
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ARMSCII-8" "\0" "ARMSCII-8" "\0"
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "PT154" "\0" "PT154" "\0"
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         /*"ISCII-DEV" "\0" "?" "\0"*/
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "*" "\0" "UTF-8" "\0";
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined VMS
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* To avoid the troubles of an extra file charset.alias_vms in the
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang         sources of many GNU packages, simply inline the aliases here.  */
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* The list of encodings is taken from the OpenVMS 7.3-1 documentation
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang         "Compaq C Run-Time Library Reference Manual for OpenVMS systems"
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang         section 10.7 "Handling Different Character Sets".  */
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-2" "\0" "ISO-8859-2" "\0"
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-5" "\0" "ISO-8859-5" "\0"
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-7" "\0" "ISO-8859-7" "\0"
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-8" "\0" "ISO-8859-8" "\0"
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "ISO8859-9" "\0" "ISO-8859-9" "\0"
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           /* Japanese */
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "eucJP" "\0" "EUC-JP" "\0"
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "SJIS" "\0" "SHIFT_JIS" "\0"
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "DECKANJI" "\0" "DEC-KANJI" "\0"
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "SDECKANJI" "\0" "EUC-JP" "\0"
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           /* Chinese */
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "eucTW" "\0" "EUC-TW" "\0"
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "DECHANYU" "\0" "DEC-HANYU" "\0"
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "DECHANZI" "\0" "GB2312" "\0"
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           /* Korean */
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "DECKOREAN" "\0" "EUC-KR" "\0";
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if defined WINDOWS_NATIVE || defined __CYGWIN__
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* To avoid the troubles of installing a separate file in the same
31205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         directory as the DLL and of retrieving the DLL's directory at
31305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         runtime, simply inline the aliases here.  */
31405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
31505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      cp = "CP936" "\0" "GBK" "\0"
31605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP1361" "\0" "JOHAB" "\0"
31705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP20127" "\0" "ASCII" "\0"
31805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP20866" "\0" "KOI8-R" "\0"
31905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP20936" "\0" "GB2312" "\0"
32005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP21866" "\0" "KOI8-RU" "\0"
32105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28591" "\0" "ISO-8859-1" "\0"
32205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28592" "\0" "ISO-8859-2" "\0"
32305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28593" "\0" "ISO-8859-3" "\0"
32405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28594" "\0" "ISO-8859-4" "\0"
32505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28595" "\0" "ISO-8859-5" "\0"
32605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28596" "\0" "ISO-8859-6" "\0"
32705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28597" "\0" "ISO-8859-7" "\0"
32805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28598" "\0" "ISO-8859-8" "\0"
32905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28599" "\0" "ISO-8859-9" "\0"
33005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP28605" "\0" "ISO-8859-15" "\0"
33105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP38598" "\0" "ISO-8859-8" "\0"
33205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP51932" "\0" "EUC-JP" "\0"
33305436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP51936" "\0" "GB2312" "\0"
33405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP51949" "\0" "EUC-KR" "\0"
33505436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP51950" "\0" "EUC-TW" "\0"
33605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP54936" "\0" "GB18030" "\0"
33705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           "CP65001" "\0" "UTF-8" "\0";
33805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
33905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
34005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      charset_aliases = cp;
34205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
34305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return cp;
34505436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
34605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Determine the current locale's character encoding, and canonicalize it
34805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   into one of the canonical names listed in config.charset.
34905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   The result must not be freed; it is statically allocated.
35005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   If the canonical name cannot be determined, the result is a non-canonical
35105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   name.  */
35205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
35305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef STATIC
35405436638acc7c010349a69c3395f1a57c642dc62Ying WangSTATIC
35505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
35605436638acc7c010349a69c3395f1a57c642dc62Ying Wangconst char *
35705436638acc7c010349a69c3395f1a57c642dc62Ying Wanglocale_charset (void)
35805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
35905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  const char *codeset;
36005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  const char *aliases;
36105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
36205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !(defined WINDOWS_NATIVE || defined OS2)
36305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
36405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if HAVE_LANGINFO_CODESET
36505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
36605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Most systems support nl_langinfo (CODESET) nowadays.  */
36705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  codeset = nl_langinfo (CODESET);
36805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
36905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  ifdef __CYGWIN__
37005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Cygwin < 1.7 does not have locales.  nl_langinfo (CODESET) always
37105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     returns "US-ASCII".  Return the suffix of the locale name from the
37205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     environment variables (if present) or the codepage as a number.  */
37305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
37405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
37505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      const char *locale;
37605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      static char buf[2 + 10 + 1];
37705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
37805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      locale = getenv ("LC_ALL");
37905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (locale == NULL || locale[0] == '\0')
38005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
38105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          locale = getenv ("LC_CTYPE");
38205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (locale == NULL || locale[0] == '\0')
38305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            locale = getenv ("LANG");
38405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
38505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (locale != NULL && locale[0] != '\0')
38605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
38705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* If the locale name contains an encoding after the dot, return
38805436638acc7c010349a69c3395f1a57c642dc62Ying Wang             it.  */
38905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          const char *dot = strchr (locale, '.');
39005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
39105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (dot != NULL)
39205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
39305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              const char *modifier;
39405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
39505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              dot++;
39605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Look for the possible @... trailer and remove it, if any.  */
39705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              modifier = strchr (dot, '@');
39805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (modifier == NULL)
39905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                return dot;
40005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (modifier - dot < sizeof (buf))
40105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
40205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  memcpy (buf, dot, modifier - dot);
40305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  buf [modifier - dot] = '\0';
40405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  return buf;
40505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
40605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
40705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
40805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
40905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* The Windows API has a function returning the locale's codepage as a
41005436638acc7c010349a69c3395f1a57c642dc62Ying Wang         number: GetACP().  This encoding is used by Cygwin, unless the user
41105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         has set the environment variable CYGWIN=codepage:oem (which very few
41205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         people do).
41305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         Output directed to console windows needs to be converted (to
41405436638acc7c010349a69c3395f1a57c642dc62Ying Wang         GetOEMCP() if the console is using a raster font, or to
41505436638acc7c010349a69c3395f1a57c642dc62Ying Wang         GetConsoleOutputCP() if it is using a TrueType font).  Cygwin does
41605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         this conversion transparently (see winsup/cygwin/fhandler_console.cc),
41705436638acc7c010349a69c3395f1a57c642dc62Ying Wang         converting to GetConsoleOutputCP().  This leads to correct results,
41805436638acc7c010349a69c3395f1a57c642dc62Ying Wang         except when SetConsoleOutputCP has been called and a raster font is
41905436638acc7c010349a69c3395f1a57c642dc62Ying Wang         in use.  */
42005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      sprintf (buf, "CP%u", GetACP ());
42105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      codeset = buf;
42205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
42305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
42405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
42505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
42605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
42705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* On old systems which lack it, use setlocale or getenv.  */
42805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  const char *locale = NULL;
42905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
43005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* But most old systems don't have a complete set of locales.  Some
43105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     (like SunOS 4 or DJGPP) have only the C locale.  Therefore we don't
43205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     use setlocale here; it would return "C" when it doesn't support the
43305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     locale name the user has set.  */
43405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if 0
43505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  locale = setlocale (LC_CTYPE, NULL);
43605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
43705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (locale == NULL || locale[0] == '\0')
43805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
43905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      locale = getenv ("LC_ALL");
44005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (locale == NULL || locale[0] == '\0')
44105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
44205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          locale = getenv ("LC_CTYPE");
44305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (locale == NULL || locale[0] == '\0')
44405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            locale = getenv ("LANG");
44505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
44605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
44705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
44805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* On some old systems, one used to set locale = "iso8859_1". On others,
44905436638acc7c010349a69c3395f1a57c642dc62Ying Wang     you set it to "language_COUNTRY.charset". In any case, we resolve it
45005436638acc7c010349a69c3395f1a57c642dc62Ying Wang     through the charset.alias file.  */
45105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  codeset = locale;
45205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
45405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif defined WINDOWS_NATIVE
45605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  static char buf[2 + 10 + 1];
45805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
45905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* The Windows API has a function returning the locale's codepage as a
46005436638acc7c010349a69c3395f1a57c642dc62Ying Wang     number: GetACP().
46105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     When the output goes to a console window, it needs to be provided in
46205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     GetOEMCP() encoding if the console is using a raster font, or in
46305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     GetConsoleOutputCP() encoding if it is using a TrueType font.
46405436638acc7c010349a69c3395f1a57c642dc62Ying Wang     But in GUI programs and for output sent to files and pipes, GetACP()
46505436638acc7c010349a69c3395f1a57c642dc62Ying Wang     encoding is the best bet.  */
46605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  sprintf (buf, "CP%u", GetACP ());
46705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  codeset = buf;
46805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
46905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif defined OS2
47005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
47105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  const char *locale;
47205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  static char buf[2 + 10 + 1];
47305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  ULONG cp[3];
47405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  ULONG cplen;
47505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
47605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Allow user to override the codeset, as set in the operating system,
47705436638acc7c010349a69c3395f1a57c642dc62Ying Wang     with standard language environment variables.  */
47805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  locale = getenv ("LC_ALL");
47905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (locale == NULL || locale[0] == '\0')
48005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
48105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      locale = getenv ("LC_CTYPE");
48205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (locale == NULL || locale[0] == '\0')
48305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        locale = getenv ("LANG");
48405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
48505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (locale != NULL && locale[0] != '\0')
48605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
48705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* If the locale name contains an encoding after the dot, return it.  */
48805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      const char *dot = strchr (locale, '.');
48905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
49005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (dot != NULL)
49105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
49205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          const char *modifier;
49305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
49405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dot++;
49505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Look for the possible @... trailer and remove it, if any.  */
49605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          modifier = strchr (dot, '@');
49705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (modifier == NULL)
49805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            return dot;
49905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (modifier - dot < sizeof (buf))
50005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
50105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              memcpy (buf, dot, modifier - dot);
50205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              buf [modifier - dot] = '\0';
50305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              return buf;
50405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
50505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
50605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
50705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Resolve through the charset.alias file.  */
50805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      codeset = locale;
50905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
51005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
51105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
51205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* OS/2 has a function returning the locale's codepage as a number.  */
51305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (DosQueryCp (sizeof (cp), cp, &cplen))
51405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        codeset = "";
51505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else
51605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
51705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          sprintf (buf, "CP%u", cp[0]);
51805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          codeset = buf;
51905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
52005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
52105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
52305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (codeset == NULL)
52505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* The canonical name cannot be determined.  */
52605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    codeset = "";
52705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
52805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Resolve alias. */
52905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  for (aliases = get_charset_aliases ();
53005436638acc7c010349a69c3395f1a57c642dc62Ying Wang       *aliases != '\0';
53105436638acc7c010349a69c3395f1a57c642dc62Ying Wang       aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
53205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (strcmp (codeset, aliases) == 0
53305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        || (aliases[0] == '*' && aliases[1] == '\0'))
53405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
53505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        codeset = aliases + strlen (aliases) + 1;
53605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
53705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
53805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
53905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Don't return an empty string.  GNU libc and GNU libiconv interpret
54005436638acc7c010349a69c3395f1a57c642dc62Ying Wang     the empty string as denoting "the locale's character encoding",
54105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     thus GNU libiconv would call this function a second time.  */
54205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (codeset[0] == '\0')
54305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    codeset = "ASCII";
54405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
54505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef DARWIN7
54605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Mac OS X sets MB_CUR_MAX to 1 when LC_ALL=C, and "UTF-8"
54705436638acc7c010349a69c3395f1a57c642dc62Ying Wang     (the default codeset) does not work when MB_CUR_MAX is 1.  */
54805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (strcmp (codeset, "UTF-8") == 0 && MB_CUR_MAX <= 1)
54905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    codeset = "ASCII";
55005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
55105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
55205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return codeset;
55305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
554