Blame lib/localcharset.c

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