/* Determine a canonical name for the current locale's character encoding.
Copyright (C) 2000-2006, 2008-2010 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA. */
/* Written by Bruno Haible <bruno@clisp.org>. */
#include <config.h>
/* Specification. */
#include "localcharset.h"
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
# define DARWIN7 /* Darwin 7 or newer, i.e. MacOS X 10.3 or newer */
#endif
#if defined _WIN32 || defined __WIN32__
# define WIN32_NATIVE
#endif
#if defined __EMX__
/* Assume EMX program runs on OS/2, even if compiled under DOS. */
# ifndef OS2
# define OS2
# endif
#endif
#if !defined WIN32_NATIVE
# include <unistd.h>
# if HAVE_LANGINFO_CODESET
# include <langinfo.h>
# else
# if 0 /* see comment below */
# include <locale.h>
# endif
# endif
# ifdef __CYGWIN__
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# endif
#elif defined WIN32_NATIVE
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#if defined OS2
# define INCL_DOS
# include <os2.h>
#endif
#if ENABLE_RELOCATABLE
# include "relocatable.h"
#else
# define relocate(pathname) (pathname)
#endif
/* Define O_NOFOLLOW to 0 on platforms where it does not exist. */
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
/* Win32, Cygwin, OS/2, DOS */
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
#endif
#ifndef DIRECTORY_SEPARATOR
# define DIRECTORY_SEPARATOR '/'
#endif
#ifndef ISSLASH
# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
#endif
#if HAVE_DECL_GETC_UNLOCKED
# undef getc
# define getc getc_unlocked
#endif
/* The following static variable is declared 'volatile' to avoid a
possible multithread problem in the function get_charset_aliases. If we
are running in a threaded environment, and if two threads initialize
'charset_aliases' simultaneously, both will produce the same value,
and everything will be ok if the two assignments to 'charset_aliases'
are atomic. But I don't know what will happen if the two assignments mix. */
#if __STDC__ != 1
# define volatile /* empty */
#endif
/* Pointer to the contents of the charset.alias file, if it has already been
read, else NULL. Its format is:
ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */
static const char * volatile charset_aliases;
/* Return a pointer to the contents of the charset.alias file. */
static const char *
get_charset_aliases (void)
{
const char *cp;
cp = charset_aliases;
if (cp == NULL)
{
#if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
const char *dir;
const char *base = "charset.alias";
char *file_name;
/* Make it possible to override the charset.alias location. This is
necessary for running the testsuite before "make install". */
dir = getenv ("CHARSETALIASDIR");
if (dir == NULL || dir[0] == '\0')
dir = relocate (LIBDIR);
/* Concatenate dir and base into freshly allocated file_name. */
{
size_t dir_len = strlen (dir);
size_t base_len = strlen (base);
int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
if (file_name != NULL)
{
memcpy (file_name, dir, dir_len);
if (add_slash)
file_name[dir_len] = DIRECTORY_SEPARATOR;
memcpy (file_name + dir_len + add_slash, base, base_len + 1);
}
}
if (file_name == NULL)
/* Out of memory. Treat the file as empty. */
cp = "";
else
{
int fd;
/* Open the file. Reject symbolic links on platforms that support
O_NOFOLLOW. This is a security feature. Without it, an attacker
could retrieve parts of the contents (namely, the tail of the
first line that starts with "* ") of an arbitrary file by placing
a symbolic link to that file under the name "charset.alias" in
some writable directory and defining the environment variable
CHARSETALIASDIR to point to that directory. */
fd = open (file_name,
O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
/* File not found. Treat it as empty. */
cp = "";
else
{
FILE *fp;
fp = fdopen (fd, "r");
if (fp == NULL)
{
/* Out of memory. Treat the file as empty. */
close (fd);
cp = "";
}
else
{
/* Parse the file's contents. */
char *res_ptr = NULL;
size_t res_size = 0;
for (;;)
{
int c;
char buf1[50+1];
char buf2[50+1];
size_t l1, l2;
char *old_res_ptr;
c = getc (fp);
if (c == EOF)
break;
if (c == '\n' || c == ' ' || c == '\t')
continue;
if (c == '#')
{
/* Skip comment, to end of line. */
do
c = getc (fp);
while (!(c == EOF || c == '\n'));
if (c == EOF)
break;
continue;
}
ungetc (c, fp);
if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
break;
l1 = strlen (buf1);
l2 = strlen (buf2);
old_res_ptr = res_ptr;
if (res_size == 0)
{
res_size = l1 + 1 + l2 + 1;
res_ptr = (char *) malloc (res_size + 1);
}
else
{
res_size += l1 + 1 + l2 + 1;
res_ptr = (char *) realloc (res_ptr, res_size + 1);
}
if (res_ptr == NULL)
{
/* Out of memory. */
res_size = 0;
free (old_res_ptr);
break;
}
strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
strcpy (res_ptr + res_size - (l2 + 1), buf2);
}
fclose (fp);
if (res_size == 0)
cp = "";
else
{
*(res_ptr + res_size) = '\0';
cp = res_ptr;
}
}
}
free (file_name);
}
#else
# if d
评论4
最新资源