localcharset.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:9k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /* Determine a canonical name for the current locale's character encoding.
  2.    Copyright (C) 2000-2002 Free Software Foundation, Inc.
  3.    This program is free software; you can redistribute it and/or modify it
  4.    under the terms of the GNU Library General Public License as published
  5.    by the Free Software Foundation; either version 2, or (at your option)
  6.    any later version.
  7.    This program is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10.    Library General Public License for more details.
  11.    You should have received a copy of the GNU Library General Public
  12.    License along with this program; if not, write to the Free Software
  13.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  14.    USA.  */
  15. /* Written by Bruno Haible <bruno@clisp.org>.  */
  16. #ifdef HAVE_CONFIG_H
  17. # include <config.h>
  18. #endif
  19. #if HAVE_STDDEF_H
  20. # include <stddef.h>
  21. #endif
  22. #include <stdio.h>
  23. #if HAVE_STRING_H
  24. # include <string.h>
  25. #else
  26. # include <strings.h>
  27. #endif
  28. #if HAVE_STDLIB_H
  29. # include <stdlib.h>
  30. #endif
  31. #if defined _WIN32 || defined __WIN32__
  32. # undef WIN32   /* avoid warning on mingw32 */
  33. # define WIN32
  34. #endif
  35. #if defined __EMX__
  36. /* Assume EMX program runs on OS/2, even if compiled under DOS.  */
  37. # define OS2
  38. #endif
  39. #if !defined WIN32
  40. # if HAVE_LANGINFO_CODESET
  41. #  include <langinfo.h>
  42. # else
  43. #  if HAVE_SETLOCALE
  44. #   include <locale.h>
  45. #  endif
  46. # endif
  47. #elif defined WIN32
  48. # define WIN32_LEAN_AND_MEAN
  49. # include <windows.h>
  50. #endif
  51. #if defined OS2
  52. # define INCL_DOS
  53. # include <os2.h>
  54. #endif
  55. #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
  56.   /* Win32, OS/2, DOS */
  57. # define ISSLASH(C) ((C) == '/' || (C) == '\')
  58. #endif
  59. #ifndef DIRECTORY_SEPARATOR
  60. # define DIRECTORY_SEPARATOR '/'
  61. #endif
  62. #ifndef ISSLASH
  63. # define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
  64. #endif
  65. #ifdef HAVE_GETC_UNLOCKED
  66. # undef getc
  67. # define getc getc_unlocked
  68. #endif
  69. #ifdef __cplusplus
  70. /* When compiling with "gcc -x c++", produce a function with C linkage.  */
  71. extern "C" const char * locale_charset (void);
  72. #endif
  73. /* The following static variable is declared 'volatile' to avoid a
  74.    possible multithread problem in the function get_charset_aliases. If we
  75.    are running in a threaded environment, and if two threads initialize
  76.    'charset_aliases' simultaneously, both will produce the same value,
  77.    and everything will be ok if the two assignments to 'charset_aliases'
  78.    are atomic. But I don't know what will happen if the two assignments mix.  */
  79. #if __STDC__ != 1
  80. # define volatile /* empty */
  81. #endif
  82. /* Pointer to the contents of the charset.alias file, if it has already been
  83.    read, else NULL.  Its format is:
  84.    ALIAS_1 '' CANONICAL_1 '' ... ALIAS_n '' CANONICAL_n '' ''  */
  85. static const char * volatile charset_aliases;
  86. /* Return a pointer to the contents of the charset.alias file.  */
  87. static const char *
  88. get_charset_aliases ()
  89. {
  90.   const char *cp;
  91.   cp = charset_aliases;
  92.   if (cp == NULL)
  93.     {
  94. #if !defined WIN32
  95.       FILE *fp;
  96.       const char *dir = LIBDIR;
  97.       const char *base = "charset.alias";
  98.       char *file_name;
  99.       /* Concatenate dir and base into freshly allocated file_name.  */
  100.       {
  101. size_t dir_len = strlen (dir);
  102. size_t base_len = strlen (base);
  103. int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
  104. file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
  105. if (file_name != NULL)
  106.   {
  107.     memcpy (file_name, dir, dir_len);
  108.     if (add_slash)
  109.       file_name[dir_len] = DIRECTORY_SEPARATOR;
  110.     memcpy (file_name + dir_len + add_slash, base, base_len + 1);
  111.   }
  112.       }
  113.       if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
  114. /* Out of memory or file not found, treat it as empty.  */
  115. cp = "";
  116.       else
  117. {
  118.   /* Parse the file's contents.  */
  119.   int c;
  120.   char buf1[50+1];
  121.   char buf2[50+1];
  122.   char *res_ptr = NULL;
  123.   size_t res_size = 0;
  124.   size_t l1, l2;
  125.   for (;;)
  126.     {
  127.       c = getc (fp);
  128.       if (c == EOF)
  129. break;
  130.       if (c == 'n' || c == ' ' || c == 't')
  131. continue;
  132.       if (c == '#')
  133. {
  134.   /* Skip comment, to end of line.  */
  135.   do
  136.     c = getc (fp);
  137.   while (!(c == EOF || c == 'n'));
  138.   if (c == EOF)
  139.     break;
  140.   continue;
  141. }
  142.       ungetc (c, fp);
  143.       if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
  144. break;
  145.       l1 = strlen (buf1);
  146.       l2 = strlen (buf2);
  147.       if (res_size == 0)
  148. {
  149.   res_size = l1 + 1 + l2 + 1;
  150.   res_ptr = (char *) malloc (res_size + 1);
  151. }
  152.       else
  153. {
  154.   res_size += l1 + 1 + l2 + 1;
  155.   res_ptr = (char *) realloc (res_ptr, res_size + 1);
  156. }
  157.       if (res_ptr == NULL)
  158. {
  159.   /* Out of memory. */
  160.   res_size = 0;
  161.   break;
  162. }
  163.       strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
  164.       strcpy (res_ptr + res_size - (l2 + 1), buf2);
  165.     }
  166.   fclose (fp);
  167.   if (res_size == 0)
  168.     cp = "";
  169.   else
  170.     {
  171.       *(res_ptr + res_size) = '';
  172.       cp = res_ptr;
  173.     }
  174. }
  175.       if (file_name != NULL)
  176. free (file_name);
  177. #else
  178.       /* To avoid the troubles of installing a separate file in the same
  179.  directory as the DLL and of retrieving the DLL's directory at
  180.  runtime, simply inline the aliases here.  */
  181. # if defined WIN32
  182.       cp = "CP936" "" "GBK" ""
  183.    "CP1361" "" "JOHAB" ""
  184.    "CP20127" "" "ASCII" ""
  185.    "CP20866" "" "KOI8-R" ""
  186.    "CP21866" "" "KOI8-RU" ""
  187.    "CP28591" "" "ISO-8859-1" ""
  188.    "CP28592" "" "ISO-8859-2" ""
  189.    "CP28593" "" "ISO-8859-3" ""
  190.    "CP28594" "" "ISO-8859-4" ""
  191.    "CP28595" "" "ISO-8859-5" ""
  192.    "CP28596" "" "ISO-8859-6" ""
  193.    "CP28597" "" "ISO-8859-7" ""
  194.    "CP28598" "" "ISO-8859-8" ""
  195.    "CP28599" "" "ISO-8859-9" ""
  196.    "CP28605" "" "ISO-8859-15" "";
  197. # endif
  198. #endif
  199.       charset_aliases = cp;
  200.     }
  201.   return cp;
  202. }
  203. /* Determine the current locale's character encoding, and canonicalize it
  204.    into one of the canonical names listed in config.charset.
  205.    The result must not be freed; it is statically allocated.
  206.    If the canonical name cannot be determined, the result is a non-canonical
  207.    name.  */
  208. #ifdef STATIC
  209. STATIC
  210. #endif
  211. const char *
  212. locale_charset ()
  213. {
  214.   const char *codeset;
  215.   const char *aliases;
  216. #if !(defined WIN32 || defined OS2)
  217. # if HAVE_LANGINFO_CODESET
  218.   /* Most systems support nl_langinfo (CODESET) nowadays.  */
  219.   codeset = nl_langinfo (CODESET);
  220. # else
  221.   /* On old systems which lack it, use setlocale or getenv.  */
  222.   const char *locale = NULL;
  223.   /* But most old systems don't have a complete set of locales.  Some
  224.      (like SunOS 4 or DJGPP) have only the C locale.  Therefore we don't
  225.      use setlocale here; it would return "C" when it doesn't support the
  226.      locale name the user has set.  */
  227. #  if HAVE_SETLOCALE && 0
  228.   locale = setlocale (LC_CTYPE, NULL);
  229. #  endif
  230.   if (locale == NULL || locale[0] == '')
  231.     {
  232.       locale = getenv ("LC_ALL");
  233.       if (locale == NULL || locale[0] == '')
  234. {
  235.   locale = getenv ("LC_CTYPE");
  236.   if (locale == NULL || locale[0] == '')
  237.     locale = getenv ("LANG");
  238. }
  239.     }
  240.   /* On some old systems, one used to set locale = "iso8859_1". On others,
  241.      you set it to "language_COUNTRY.charset". In any case, we resolve it
  242.      through the charset.alias file.  */
  243.   codeset = locale;
  244. # endif
  245. #elif defined WIN32
  246.   static char buf[2 + 10 + 1];
  247.   /* Woe32 has a function returning the locale's codepage as a number.  */
  248.   sprintf (buf, "CP%u", GetACP ());
  249.   codeset = buf;
  250. #elif defined OS2
  251.   const char *locale;
  252.   static char buf[2 + 10 + 1];
  253.   ULONG cp[3];
  254.   ULONG cplen;
  255.   /* Allow user to override the codeset, as set in the operating system,
  256.      with standard language environment variables.  */
  257.   locale = getenv ("LC_ALL");
  258.   if (locale == NULL || locale[0] == '')
  259.     {
  260.       locale = getenv ("LC_CTYPE");
  261.       if (locale == NULL || locale[0] == '')
  262. locale = getenv ("LANG");
  263.     }
  264.   if (locale != NULL && locale[0] != '')
  265.     {
  266.       /* If the locale name contains an encoding after the dot, return it.  */
  267.       const char *dot = strchr (locale, '.');
  268.       if (dot != NULL)
  269. {
  270.   const char *modifier;
  271.   dot++;
  272.   /* Look for the possible @... trailer and remove it, if any.  */
  273.   modifier = strchr (dot, '@');
  274.   if (modifier == NULL)
  275.     return dot;
  276.   if (modifier - dot < sizeof (buf))
  277.     {
  278.       memcpy (buf, dot, modifier - dot);
  279.       buf [modifier - dot] = '';
  280.       return buf;
  281.     }
  282. }
  283.       /* Resolve through the charset.alias file.  */
  284.       codeset = locale;
  285.     }
  286.   else
  287.     {
  288.       /* OS/2 has a function returning the locale's codepage as a number.  */
  289.       if (DosQueryCp (sizeof (cp), cp, &cplen))
  290. codeset = "";
  291.       else
  292. {
  293.   sprintf (buf, "CP%u", cp[0]);
  294.   codeset = buf;
  295. }
  296.     }
  297. #endif
  298.   if (codeset == NULL)
  299.     /* The canonical name cannot be determined.  */
  300.     codeset = "";
  301.   /* Resolve alias. */
  302.   for (aliases = get_charset_aliases ();
  303.        *aliases != '';
  304.        aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
  305.     if (strcmp (codeset, aliases) == 0
  306. || (aliases[0] == '*' && aliases[1] == ''))
  307.       {
  308. codeset = aliases + strlen (aliases) + 1;
  309. break;
  310.       }
  311.   /* Don't return an empty string.  GNU libc and GNU libiconv interpret
  312.      the empty string as denoting "the locale's character encoding",
  313.      thus GNU libiconv would call this function a second time.  */
  314.   if (codeset[0] == '')
  315.     codeset = "ASCII";
  316.   return codeset;
  317. }