Blame lib/localcharset.c

Packit Service fdd496
/* Determine a canonical name for the current locale's character encoding.
Packit Service fdd496
Packit Service fdd496
   Copyright (C) 2000-2006, 2008-2017 Free Software Foundation, Inc.
Packit Service fdd496
Packit Service fdd496
   This program is free software; you can redistribute it and/or modify
Packit Service fdd496
   it under the terms of the GNU General Public License as published by
Packit Service fdd496
   the Free Software Foundation; either version 3, or (at your option)
Packit Service fdd496
   any later version.
Packit Service fdd496
Packit Service fdd496
   This program is distributed in the hope that it will be useful,
Packit Service fdd496
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fdd496
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service fdd496
   GNU General Public License for more details.
Packit Service fdd496
Packit Service fdd496
   You should have received a copy of the GNU General Public License along
Packit Service fdd496
   with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit Service fdd496
Packit Service fdd496
/* Written by Bruno Haible <bruno@clisp.org>.  */
Packit Service fdd496
Packit Service fdd496
#include <config.h>
Packit Service fdd496
Packit Service fdd496
/* Specification.  */
Packit Service fdd496
#include "localcharset.h"
Packit Service fdd496
Packit Service fdd496
#include <fcntl.h>
Packit Service fdd496
#include <stddef.h>
Packit Service fdd496
#include <stdio.h>
Packit Service fdd496
#include <string.h>
Packit Service fdd496
#include <stdlib.h>
Packit Service fdd496
Packit Service fdd496
#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
Packit Service fdd496
# define DARWIN7 /* Darwin 7 or newer, i.e. Mac OS X 10.3 or newer */
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
Packit Service fdd496
# define WINDOWS_NATIVE
Packit Service fdd496
# include <locale.h>
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#if defined __EMX__
Packit Service fdd496
/* Assume EMX program runs on OS/2, even if compiled under DOS.  */
Packit Service fdd496
# ifndef OS2
Packit Service fdd496
#  define OS2
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#if !defined WINDOWS_NATIVE
Packit Service fdd496
# include <unistd.h>
Packit Service fdd496
# if HAVE_LANGINFO_CODESET
Packit Service fdd496
#  include <langinfo.h>
Packit Service fdd496
# else
Packit Service fdd496
#  if 0 /* see comment below */
Packit Service fdd496
#   include <locale.h>
Packit Service fdd496
#  endif
Packit Service fdd496
# endif
Packit Service fdd496
# ifdef __CYGWIN__
Packit Service fdd496
#  define WIN32_LEAN_AND_MEAN
Packit Service fdd496
#  include <windows.h>
Packit Service fdd496
# endif
Packit Service fdd496
#elif defined WINDOWS_NATIVE
Packit Service fdd496
# define WIN32_LEAN_AND_MEAN
Packit Service fdd496
# include <windows.h>
Packit Service fdd496
#endif
Packit Service fdd496
#if defined OS2
Packit Service fdd496
# define INCL_DOS
Packit Service fdd496
# include <os2.h>
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* For MB_CUR_MAX_L */
Packit Service fdd496
#if defined DARWIN7
Packit Service fdd496
# include <xlocale.h>
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#if ENABLE_RELOCATABLE
Packit Service fdd496
# include "relocatable.h"
Packit Service fdd496
#else
Packit Service fdd496
# define relocate(pathname) (pathname)
Packit Service fdd496
# define relocate2(pathname,allocatedp) (*(allocatedp) = NULL, (pathname))
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* Get LIBDIR.  */
Packit Service fdd496
#ifndef LIBDIR
Packit Service fdd496
# include "configmake.h"
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* Define O_NOFOLLOW to 0 on platforms where it does not exist.  */
Packit Service fdd496
#ifndef O_NOFOLLOW
Packit Service fdd496
# define O_NOFOLLOW 0
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
Packit Service fdd496
  /* Native Windows, Cygwin, OS/2, DOS */
Packit Service fdd496
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#ifndef DIRECTORY_SEPARATOR
Packit Service fdd496
# define DIRECTORY_SEPARATOR '/'
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#ifndef ISSLASH
Packit Service fdd496
# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
#if HAVE_DECL_GETC_UNLOCKED
Packit Service fdd496
# undef getc
Packit Service fdd496
# define getc getc_unlocked
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
/* The following static variable is declared 'volatile' to avoid a
Packit Service fdd496
   possible multithread problem in the function get_charset_aliases. If we
Packit Service fdd496
   are running in a threaded environment, and if two threads initialize
Packit Service fdd496
   'charset_aliases' simultaneously, both will produce the same value,
Packit Service fdd496
   and everything will be ok if the two assignments to 'charset_aliases'
Packit Service fdd496
   are atomic. But I don't know what will happen if the two assignments mix.  */
Packit Service fdd496
#if __STDC__ != 1
Packit Service fdd496
# define volatile /* empty */
Packit Service fdd496
#endif
Packit Service fdd496
/* Pointer to the contents of the charset.alias file, if it has already been
Packit Service fdd496
   read, else NULL.  Its format is:
Packit Service fdd496
   ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0'  */
Packit Service fdd496
static const char * volatile charset_aliases;
Packit Service fdd496
Packit Service fdd496
/* Return a pointer to the contents of the charset.alias file.  */
Packit Service fdd496
static const char *
Packit Service fdd496
get_charset_aliases (void)
Packit Service fdd496
{
Packit Service fdd496
  const char *cp;
Packit Service fdd496
Packit Service fdd496
  cp = charset_aliases;
Packit Service fdd496
  if (cp == NULL)
Packit Service fdd496
    {
Packit Service fdd496
#if !(defined DARWIN7 || defined VMS || defined WINDOWS_NATIVE || defined __CYGWIN__ || defined OS2)
Packit Service fdd496
      char *malloc_dir = NULL;
Packit Service fdd496
      const char *dir;
Packit Service fdd496
      const char *base = "charset.alias";
Packit Service fdd496
      char *file_name;
Packit Service fdd496
Packit Service fdd496
      /* Make it possible to override the charset.alias location.  This is
Packit Service fdd496
         necessary for running the testsuite before "make install".  */
Packit Service fdd496
      dir = getenv ("CHARSETALIASDIR");
Packit Service fdd496
      if (dir == NULL || dir[0] == '\0')
Packit Service fdd496
        dir = relocate2 (LIBDIR, &malloc_dir);
Packit Service fdd496
Packit Service fdd496
      /* Concatenate dir and base into freshly allocated file_name.  */
Packit Service fdd496
      {
Packit Service fdd496
        size_t dir_len = strlen (dir);
Packit Service fdd496
        size_t base_len = strlen (base);
Packit Service fdd496
        int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
Packit Service fdd496
        file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
Packit Service fdd496
        if (file_name != NULL)
Packit Service fdd496
          {
Packit Service fdd496
            memcpy (file_name, dir, dir_len);
Packit Service fdd496
            if (add_slash)
Packit Service fdd496
              file_name[dir_len] = DIRECTORY_SEPARATOR;
Packit Service fdd496
            memcpy (file_name + dir_len + add_slash, base, base_len + 1);
Packit Service fdd496
          }
Packit Service fdd496
      }
Packit Service fdd496
Packit Service fdd496
      free (malloc_dir);
Packit Service fdd496
Packit Service fdd496
      if (file_name == NULL)
Packit Service fdd496
        /* Out of memory.  Treat the file as empty.  */
Packit Service fdd496
        cp = "";
Packit Service fdd496
      else
Packit Service fdd496
        {
Packit Service fdd496
          int fd;
Packit Service fdd496
Packit Service fdd496
          /* Open the file.  Reject symbolic links on platforms that support
Packit Service fdd496
             O_NOFOLLOW.  This is a security feature.  Without it, an attacker
Packit Service fdd496
             could retrieve parts of the contents (namely, the tail of the
Packit Service fdd496
             first line that starts with "* ") of an arbitrary file by placing
Packit Service fdd496
             a symbolic link to that file under the name "charset.alias" in
Packit Service fdd496
             some writable directory and defining the environment variable
Packit Service fdd496
             CHARSETALIASDIR to point to that directory.  */
Packit Service fdd496
          fd = open (file_name,
Packit Service fdd496
                     O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0));
Packit Service fdd496
          if (fd < 0)
Packit Service fdd496
            /* File not found.  Treat it as empty.  */
Packit Service fdd496
            cp = "";
Packit Service fdd496
          else
Packit Service fdd496
            {
Packit Service fdd496
              FILE *fp;
Packit Service fdd496
Packit Service fdd496
              fp = fdopen (fd, "r");
Packit Service fdd496
              if (fp == NULL)
Packit Service fdd496
                {
Packit Service fdd496
                  /* Out of memory.  Treat the file as empty.  */
Packit Service fdd496
                  close (fd);
Packit Service fdd496
                  cp = "";
Packit Service fdd496
                }
Packit Service fdd496
              else
Packit Service fdd496
                {
Packit Service fdd496
                  /* Parse the file's contents.  */
Packit Service fdd496
                  char *res_ptr = NULL;
Packit Service fdd496
                  size_t res_size = 0;
Packit Service fdd496
Packit Service fdd496
                  for (;;)
Packit Service fdd496
                    {
Packit Service fdd496
                      int c;
Packit Service fdd496
                      char buf1[50+1];
Packit Service fdd496
                      char buf2[50+1];
Packit Service fdd496
                      size_t l1, l2;
Packit Service fdd496
                      char *old_res_ptr;
Packit Service fdd496
Packit Service fdd496
                      c = getc (fp);
Packit Service fdd496
                      if (c == EOF)
Packit Service fdd496
                        break;
Packit Service fdd496
                      if (c == '\n' || c == ' ' || c == '\t')
Packit Service fdd496
                        continue;
Packit Service fdd496
                      if (c == '#')
Packit Service fdd496
                        {
Packit Service fdd496
                          /* Skip comment, to end of line.  */
Packit Service fdd496
                          do
Packit Service fdd496
                            c = getc (fp);
Packit Service fdd496
                          while (!(c == EOF || c == '\n'));
Packit Service fdd496
                          if (c == EOF)
Packit Service fdd496
                            break;
Packit Service fdd496
                          continue;
Packit Service fdd496
                        }
Packit Service fdd496
                      ungetc (c, fp);
Packit Service fdd496
                      if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
Packit Service fdd496
                        break;
Packit Service fdd496
                      l1 = strlen (buf1);
Packit Service fdd496
                      l2 = strlen (buf2);
Packit Service fdd496
                      old_res_ptr = res_ptr;
Packit Service fdd496
                      if (res_size == 0)
Packit Service fdd496
                        {
Packit Service fdd496
                          res_size = l1 + 1 + l2 + 1;
Packit Service fdd496
                          res_ptr = (char *) malloc (res_size + 1);
Packit Service fdd496
                        }
Packit Service fdd496
                      else
Packit Service fdd496
                        {
Packit Service fdd496
                          res_size += l1 + 1 + l2 + 1;
Packit Service fdd496
                          res_ptr = (char *) realloc (res_ptr, res_size + 1);
Packit Service fdd496
                        }
Packit Service fdd496
                      if (res_ptr == NULL)
Packit Service fdd496
                        {
Packit Service fdd496
                          /* Out of memory. */
Packit Service fdd496
                          res_size = 0;
Packit Service fdd496
                          free (old_res_ptr);
Packit Service fdd496
                          break;
Packit Service fdd496
                        }
Packit Service fdd496
                      strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
Packit Service fdd496
                      strcpy (res_ptr + res_size - (l2 + 1), buf2);
Packit Service fdd496
                    }
Packit Service fdd496
                  fclose (fp);
Packit Service fdd496
                  if (res_size == 0)
Packit Service fdd496
                    cp = "";
Packit Service fdd496
                  else
Packit Service fdd496
                    {
Packit Service fdd496
                      *(res_ptr + res_size) = '\0';
Packit Service fdd496
                      cp = res_ptr;
Packit Service fdd496
                    }
Packit Service fdd496
                }
Packit Service fdd496
            }
Packit Service fdd496
Packit Service fdd496
          free (file_name);
Packit Service fdd496
        }
Packit Service fdd496
Packit Service fdd496
#else
Packit Service fdd496
Packit Service fdd496
# if defined DARWIN7
Packit Service fdd496
      /* To avoid the trouble of installing a file that is shared by many
Packit Service fdd496
         GNU packages -- many packaging systems have problems with this --,
Packit Service fdd496
         simply inline the aliases here.  */
Packit Service fdd496
      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
Packit Service fdd496
           "ISO8859-2" "\0" "ISO-8859-2" "\0"
Packit Service fdd496
           "ISO8859-4" "\0" "ISO-8859-4" "\0"
Packit Service fdd496
           "ISO8859-5" "\0" "ISO-8859-5" "\0"
Packit Service fdd496
           "ISO8859-7" "\0" "ISO-8859-7" "\0"
Packit Service fdd496
           "ISO8859-9" "\0" "ISO-8859-9" "\0"
Packit Service fdd496
           "ISO8859-13" "\0" "ISO-8859-13" "\0"
Packit Service fdd496
           "ISO8859-15" "\0" "ISO-8859-15" "\0"
Packit Service fdd496
           "KOI8-R" "\0" "KOI8-R" "\0"
Packit Service fdd496
           "KOI8-U" "\0" "KOI8-U" "\0"
Packit Service fdd496
           "CP866" "\0" "CP866" "\0"
Packit Service fdd496
           "CP949" "\0" "CP949" "\0"
Packit Service fdd496
           "CP1131" "\0" "CP1131" "\0"
Packit Service fdd496
           "CP1251" "\0" "CP1251" "\0"
Packit Service fdd496
           "eucCN" "\0" "GB2312" "\0"
Packit Service fdd496
           "GB2312" "\0" "GB2312" "\0"
Packit Service fdd496
           "eucJP" "\0" "EUC-JP" "\0"
Packit Service fdd496
           "eucKR" "\0" "EUC-KR" "\0"
Packit Service fdd496
           "Big5" "\0" "BIG5" "\0"
Packit Service fdd496
           "Big5HKSCS" "\0" "BIG5-HKSCS" "\0"
Packit Service fdd496
           "GBK" "\0" "GBK" "\0"
Packit Service fdd496
           "GB18030" "\0" "GB18030" "\0"
Packit Service fdd496
           "SJIS" "\0" "SHIFT_JIS" "\0"
Packit Service fdd496
           "ARMSCII-8" "\0" "ARMSCII-8" "\0"
Packit Service fdd496
           "PT154" "\0" "PT154" "\0"
Packit Service fdd496
         /*"ISCII-DEV" "\0" "?" "\0"*/
Packit Service fdd496
           "*" "\0" "UTF-8" "\0";
Packit Service fdd496
# endif
Packit Service fdd496
Packit Service fdd496
# if defined VMS
Packit Service fdd496
      /* To avoid the troubles of an extra file charset.alias_vms in the
Packit Service fdd496
         sources of many GNU packages, simply inline the aliases here.  */
Packit Service fdd496
      /* The list of encodings is taken from the OpenVMS 7.3-1 documentation
Packit Service fdd496
         "Compaq C Run-Time Library Reference Manual for OpenVMS systems"
Packit Service fdd496
         section 10.7 "Handling Different Character Sets".  */
Packit Service fdd496
      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
Packit Service fdd496
           "ISO8859-2" "\0" "ISO-8859-2" "\0"
Packit Service fdd496
           "ISO8859-5" "\0" "ISO-8859-5" "\0"
Packit Service fdd496
           "ISO8859-7" "\0" "ISO-8859-7" "\0"
Packit Service fdd496
           "ISO8859-8" "\0" "ISO-8859-8" "\0"
Packit Service fdd496
           "ISO8859-9" "\0" "ISO-8859-9" "\0"
Packit Service fdd496
           /* Japanese */
Packit Service fdd496
           "eucJP" "\0" "EUC-JP" "\0"
Packit Service fdd496
           "SJIS" "\0" "SHIFT_JIS" "\0"
Packit Service fdd496
           "DECKANJI" "\0" "DEC-KANJI" "\0"
Packit Service fdd496
           "SDECKANJI" "\0" "EUC-JP" "\0"
Packit Service fdd496
           /* Chinese */
Packit Service fdd496
           "eucTW" "\0" "EUC-TW" "\0"
Packit Service fdd496
           "DECHANYU" "\0" "DEC-HANYU" "\0"
Packit Service fdd496
           "DECHANZI" "\0" "GB2312" "\0"
Packit Service fdd496
           /* Korean */
Packit Service fdd496
           "DECKOREAN" "\0" "EUC-KR" "\0";
Packit Service fdd496
# endif
Packit Service fdd496
Packit Service fdd496
# if defined WINDOWS_NATIVE || defined __CYGWIN__
Packit Service fdd496
      /* To avoid the troubles of installing a separate file in the same
Packit Service fdd496
         directory as the DLL and of retrieving the DLL's directory at
Packit Service fdd496
         runtime, simply inline the aliases here.  */
Packit Service fdd496
Packit Service fdd496
      cp = "CP936" "\0" "GBK" "\0"
Packit Service fdd496
           "CP1361" "\0" "JOHAB" "\0"
Packit Service fdd496
           "CP20127" "\0" "ASCII" "\0"
Packit Service fdd496
           "CP20866" "\0" "KOI8-R" "\0"
Packit Service fdd496
           "CP20936" "\0" "GB2312" "\0"
Packit Service fdd496
           "CP21866" "\0" "KOI8-RU" "\0"
Packit Service fdd496
           "CP28591" "\0" "ISO-8859-1" "\0"
Packit Service fdd496
           "CP28592" "\0" "ISO-8859-2" "\0"
Packit Service fdd496
           "CP28593" "\0" "ISO-8859-3" "\0"
Packit Service fdd496
           "CP28594" "\0" "ISO-8859-4" "\0"
Packit Service fdd496
           "CP28595" "\0" "ISO-8859-5" "\0"
Packit Service fdd496
           "CP28596" "\0" "ISO-8859-6" "\0"
Packit Service fdd496
           "CP28597" "\0" "ISO-8859-7" "\0"
Packit Service fdd496
           "CP28598" "\0" "ISO-8859-8" "\0"
Packit Service fdd496
           "CP28599" "\0" "ISO-8859-9" "\0"
Packit Service fdd496
           "CP28605" "\0" "ISO-8859-15" "\0"
Packit Service fdd496
           "CP38598" "\0" "ISO-8859-8" "\0"
Packit Service fdd496
           "CP51932" "\0" "EUC-JP" "\0"
Packit Service fdd496
           "CP51936" "\0" "GB2312" "\0"
Packit Service fdd496
           "CP51949" "\0" "EUC-KR" "\0"
Packit Service fdd496
           "CP51950" "\0" "EUC-TW" "\0"
Packit Service fdd496
           "CP54936" "\0" "GB18030" "\0"
Packit Service fdd496
           "CP65001" "\0" "UTF-8" "\0";
Packit Service fdd496
# endif
Packit Service fdd496
# if defined OS2
Packit Service fdd496
      /* To avoid the troubles of installing a separate file in the same
Packit Service fdd496
         directory as the DLL and of retrieving the DLL's directory at
Packit Service fdd496
         runtime, simply inline the aliases here.  */
Packit Service fdd496
Packit Service fdd496
      /* The list of encodings is taken from "List of OS/2 Codepages"
Packit Service fdd496
         by Alex Taylor:
Packit Service fdd496
         <http://altsan.org/os2/toolkits/uls/index.html#codepages>.
Packit Service fdd496
         See also "IBM Globalization - Code page identifiers":
Packit Service fdd496
         <http://www-01.ibm.com/software/globalization/cp/cp_cpgid.html>.  */
Packit Service fdd496
      cp = "CP813" "\0" "ISO-8859-7" "\0"
Packit Service fdd496
           "CP878" "\0" "KOI8-R" "\0"
Packit Service fdd496
           "CP819" "\0" "ISO-8859-1" "\0"
Packit Service fdd496
           "CP912" "\0" "ISO-8859-2" "\0"
Packit Service fdd496
           "CP913" "\0" "ISO-8859-3" "\0"
Packit Service fdd496
           "CP914" "\0" "ISO-8859-4" "\0"
Packit Service fdd496
           "CP915" "\0" "ISO-8859-5" "\0"
Packit Service fdd496
           "CP916" "\0" "ISO-8859-8" "\0"
Packit Service fdd496
           "CP920" "\0" "ISO-8859-9" "\0"
Packit Service fdd496
           "CP921" "\0" "ISO-8859-13" "\0"
Packit Service fdd496
           "CP923" "\0" "ISO-8859-15" "\0"
Packit Service fdd496
           "CP954" "\0" "EUC-JP" "\0"
Packit Service fdd496
           "CP964" "\0" "EUC-TW" "\0"
Packit Service fdd496
           "CP970" "\0" "EUC-KR" "\0"
Packit Service fdd496
           "CP1089" "\0" "ISO-8859-6" "\0"
Packit Service fdd496
           "CP1208" "\0" "UTF-8" "\0"
Packit Service fdd496
           "CP1381" "\0" "GB2312" "\0"
Packit Service fdd496
           "CP1386" "\0" "GBK" "\0"
Packit Service fdd496
           "CP3372" "\0" "EUC-JP" "\0";
Packit Service fdd496
# endif
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
      charset_aliases = cp;
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  return cp;
Packit Service fdd496
}
Packit Service fdd496
Packit Service fdd496
/* Determine the current locale's character encoding, and canonicalize it
Packit Service fdd496
   into one of the canonical names listed in config.charset.
Packit Service fdd496
   The result must not be freed; it is statically allocated.
Packit Service fdd496
   If the canonical name cannot be determined, the result is a non-canonical
Packit Service fdd496
   name.  */
Packit Service fdd496
Packit Service fdd496
#ifdef STATIC
Packit Service fdd496
STATIC
Packit Service fdd496
#endif
Packit Service fdd496
const char *
Packit Service fdd496
locale_charset (void)
Packit Service fdd496
{
Packit Service fdd496
  const char *codeset;
Packit Service fdd496
  const char *aliases;
Packit Service fdd496
Packit Service fdd496
#if !(defined WINDOWS_NATIVE || defined OS2)
Packit Service fdd496
Packit Service fdd496
# if HAVE_LANGINFO_CODESET
Packit Service fdd496
Packit Service fdd496
  /* Most systems support nl_langinfo (CODESET) nowadays.  */
Packit Service fdd496
  codeset = nl_langinfo (CODESET);
Packit Service fdd496
Packit Service fdd496
#  ifdef __CYGWIN__
Packit Service fdd496
  /* Cygwin < 1.7 does not have locales.  nl_langinfo (CODESET) always
Packit Service fdd496
     returns "US-ASCII".  Return the suffix of the locale name from the
Packit Service fdd496
     environment variables (if present) or the codepage as a number.  */
Packit Service fdd496
  if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
Packit Service fdd496
    {
Packit Service fdd496
      const char *locale;
Packit Service fdd496
      static char buf[2 + 10 + 1];
Packit Service fdd496
Packit Service fdd496
      locale = getenv ("LC_ALL");
Packit Service fdd496
      if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
        {
Packit Service fdd496
          locale = getenv ("LC_CTYPE");
Packit Service fdd496
          if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
            locale = getenv ("LANG");
Packit Service fdd496
        }
Packit Service fdd496
      if (locale != NULL && locale[0] != '\0')
Packit Service fdd496
        {
Packit Service fdd496
          /* If the locale name contains an encoding after the dot, return
Packit Service fdd496
             it.  */
Packit Service fdd496
          const char *dot = strchr (locale, '.');
Packit Service fdd496
Packit Service fdd496
          if (dot != NULL)
Packit Service fdd496
            {
Packit Service fdd496
              const char *modifier;
Packit Service fdd496
Packit Service fdd496
              dot++;
Packit Service fdd496
              /* Look for the possible @... trailer and remove it, if any.  */
Packit Service fdd496
              modifier = strchr (dot, '@');
Packit Service fdd496
              if (modifier == NULL)
Packit Service fdd496
                return dot;
Packit Service fdd496
              if (modifier - dot < sizeof (buf))
Packit Service fdd496
                {
Packit Service fdd496
                  memcpy (buf, dot, modifier - dot);
Packit Service fdd496
                  buf [modifier - dot] = '\0';
Packit Service fdd496
                  return buf;
Packit Service fdd496
                }
Packit Service fdd496
            }
Packit Service fdd496
        }
Packit Service fdd496
Packit Service fdd496
      /* The Windows API has a function returning the locale's codepage as a
Packit Service fdd496
         number: GetACP().  This encoding is used by Cygwin, unless the user
Packit Service fdd496
         has set the environment variable CYGWIN=codepage:oem (which very few
Packit Service fdd496
         people do).
Packit Service fdd496
         Output directed to console windows needs to be converted (to
Packit Service fdd496
         GetOEMCP() if the console is using a raster font, or to
Packit Service fdd496
         GetConsoleOutputCP() if it is using a TrueType font).  Cygwin does
Packit Service fdd496
         this conversion transparently (see winsup/cygwin/fhandler_console.cc),
Packit Service fdd496
         converting to GetConsoleOutputCP().  This leads to correct results,
Packit Service fdd496
         except when SetConsoleOutputCP has been called and a raster font is
Packit Service fdd496
         in use.  */
Packit Service fdd496
      sprintf (buf, "CP%u", GetACP ());
Packit Service fdd496
      codeset = buf;
Packit Service fdd496
    }
Packit Service fdd496
#  endif
Packit Service fdd496
Packit Service fdd496
# else
Packit Service fdd496
Packit Service fdd496
  /* On old systems which lack it, use setlocale or getenv.  */
Packit Service fdd496
  const char *locale = NULL;
Packit Service fdd496
Packit Service fdd496
  /* But most old systems don't have a complete set of locales.  Some
Packit Service fdd496
     (like SunOS 4 or DJGPP) have only the C locale.  Therefore we don't
Packit Service fdd496
     use setlocale here; it would return "C" when it doesn't support the
Packit Service fdd496
     locale name the user has set.  */
Packit Service fdd496
#  if 0
Packit Service fdd496
  locale = setlocale (LC_CTYPE, NULL);
Packit Service fdd496
#  endif
Packit Service fdd496
  if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
    {
Packit Service fdd496
      locale = getenv ("LC_ALL");
Packit Service fdd496
      if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
        {
Packit Service fdd496
          locale = getenv ("LC_CTYPE");
Packit Service fdd496
          if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
            locale = getenv ("LANG");
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  /* On some old systems, one used to set locale = "iso8859_1". On others,
Packit Service fdd496
     you set it to "language_COUNTRY.charset". In any case, we resolve it
Packit Service fdd496
     through the charset.alias file.  */
Packit Service fdd496
  codeset = locale;
Packit Service fdd496
Packit Service fdd496
# endif
Packit Service fdd496
Packit Service fdd496
#elif defined WINDOWS_NATIVE
Packit Service fdd496
Packit Service fdd496
  static char buf[2 + 10 + 1];
Packit Service fdd496
Packit Service fdd496
  /* The Windows API has a function returning the locale's codepage as
Packit Service fdd496
     a number, but the value doesn't change according to what the
Packit Service fdd496
     'setlocale' call specified.  So we use it as a last resort, in
Packit Service fdd496
     case the string returned by 'setlocale' doesn't specify the
Packit Service fdd496
     codepage.  */
Packit Service fdd496
  char *current_locale = setlocale (LC_ALL, NULL);
Packit Service fdd496
  char *pdot;
Packit Service fdd496
Packit Service fdd496
  /* If they set different locales for different categories,
Packit Service fdd496
     'setlocale' will return a semi-colon separated list of locale
Packit Service fdd496
     values.  To make sure we use the correct one, we choose LC_CTYPE.  */
Packit Service fdd496
  if (strchr (current_locale, ';'))
Packit Service fdd496
    current_locale = setlocale (LC_CTYPE, NULL);
Packit Service fdd496
Packit Service fdd496
  pdot = strrchr (current_locale, '.');
Packit Service fdd496
  if (pdot && 2 + strlen (pdot + 1) + 1 <= sizeof (buf))
Packit Service fdd496
    sprintf (buf, "CP%s", pdot + 1);
Packit Service fdd496
  else
Packit Service fdd496
    {
Packit Service fdd496
      /* The Windows API has a function returning the locale's codepage as a
Packit Service fdd496
        number: GetACP().
Packit Service fdd496
        When the output goes to a console window, it needs to be provided in
Packit Service fdd496
        GetOEMCP() encoding if the console is using a raster font, or in
Packit Service fdd496
        GetConsoleOutputCP() encoding if it is using a TrueType font.
Packit Service fdd496
        But in GUI programs and for output sent to files and pipes, GetACP()
Packit Service fdd496
        encoding is the best bet.  */
Packit Service fdd496
      sprintf (buf, "CP%u", GetACP ());
Packit Service fdd496
    }
Packit Service fdd496
  codeset = buf;
Packit Service fdd496
Packit Service fdd496
#elif defined OS2
Packit Service fdd496
Packit Service fdd496
  const char *locale;
Packit Service fdd496
  static char buf[2 + 10 + 1];
Packit Service fdd496
  ULONG cp[3];
Packit Service fdd496
  ULONG cplen;
Packit Service fdd496
Packit Service fdd496
  codeset = NULL;
Packit Service fdd496
Packit Service fdd496
  /* Allow user to override the codeset, as set in the operating system,
Packit Service fdd496
     with standard language environment variables.  */
Packit Service fdd496
  locale = getenv ("LC_ALL");
Packit Service fdd496
  if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
    {
Packit Service fdd496
      locale = getenv ("LC_CTYPE");
Packit Service fdd496
      if (locale == NULL || locale[0] == '\0')
Packit Service fdd496
        locale = getenv ("LANG");
Packit Service fdd496
    }
Packit Service fdd496
  if (locale != NULL && locale[0] != '\0')
Packit Service fdd496
    {
Packit Service fdd496
      /* If the locale name contains an encoding after the dot, return it.  */
Packit Service fdd496
      const char *dot = strchr (locale, '.');
Packit Service fdd496
Packit Service fdd496
      if (dot != NULL)
Packit Service fdd496
        {
Packit Service fdd496
          const char *modifier;
Packit Service fdd496
Packit Service fdd496
          dot++;
Packit Service fdd496
          /* Look for the possible @... trailer and remove it, if any.  */
Packit Service fdd496
          modifier = strchr (dot, '@');
Packit Service fdd496
          if (modifier == NULL)
Packit Service fdd496
            return dot;
Packit Service fdd496
          if (modifier - dot < sizeof (buf))
Packit Service fdd496
            {
Packit Service fdd496
              memcpy (buf, dot, modifier - dot);
Packit Service fdd496
              buf [modifier - dot] = '\0';
Packit Service fdd496
              return buf;
Packit Service fdd496
            }
Packit Service fdd496
        }
Packit Service fdd496
Packit Service fdd496
      /* For the POSIX locale, don't use the system's codepage.  */
Packit Service fdd496
      if (strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0)
Packit Service fdd496
        codeset = "";
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
  if (codeset == NULL)
Packit Service fdd496
    {
Packit Service fdd496
      /* OS/2 has a function returning the locale's codepage as a number.  */
Packit Service fdd496
      if (DosQueryCp (sizeof (cp), cp, &cplen))
Packit Service fdd496
        codeset = "";
Packit Service fdd496
      else
Packit Service fdd496
        {
Packit Service fdd496
          sprintf (buf, "CP%u", cp[0]);
Packit Service fdd496
          codeset = buf;
Packit Service fdd496
        }
Packit Service fdd496
    }
Packit Service fdd496
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  if (codeset == NULL)
Packit Service fdd496
    /* The canonical name cannot be determined.  */
Packit Service fdd496
    codeset = "";
Packit Service fdd496
Packit Service fdd496
  /* Resolve alias. */
Packit Service fdd496
  for (aliases = get_charset_aliases ();
Packit Service fdd496
       *aliases != '\0';
Packit Service fdd496
       aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
Packit Service fdd496
    if (strcmp (codeset, aliases) == 0
Packit Service fdd496
        || (aliases[0] == '*' && aliases[1] == '\0'))
Packit Service fdd496
      {
Packit Service fdd496
        codeset = aliases + strlen (aliases) + 1;
Packit Service fdd496
        break;
Packit Service fdd496
      }
Packit Service fdd496
Packit Service fdd496
  /* Don't return an empty string.  GNU libc and GNU libiconv interpret
Packit Service fdd496
     the empty string as denoting "the locale's character encoding",
Packit Service fdd496
     thus GNU libiconv would call this function a second time.  */
Packit Service fdd496
  if (codeset[0] == '\0')
Packit Service fdd496
    codeset = "ASCII";
Packit Service fdd496
Packit Service fdd496
#ifdef DARWIN7
Packit Service fdd496
  /* Mac OS X sets MB_CUR_MAX to 1 when LC_ALL=C, and "UTF-8"
Packit Service fdd496
     (the default codeset) does not work when MB_CUR_MAX is 1.  */
Packit Service fdd496
  if (strcmp (codeset, "UTF-8") == 0 && MB_CUR_MAX_L (uselocale (NULL)) <= 1)
Packit Service fdd496
    codeset = "ASCII";
Packit Service fdd496
#endif
Packit Service fdd496
Packit Service fdd496
  return codeset;
Packit Service fdd496
}