[Android] Add in a static libiconv library so non English games don't crash Dolphin Mobile.

This commit is contained in:
Ryan Houdek
2013-08-29 04:43:31 -05:00
parent c5a886100c
commit 160d72a9ae
247 changed files with 108640 additions and 6 deletions

View File

@ -0,0 +1,550 @@
/* 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>. */
/* 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
/* Get LIBDIR. */
#ifndef LIBDIR
#define LIBDIR ""
#endif
/* Define O_NOFOLLOW to 0 on platforms where it does not exist. */
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif
#ifndef HAVE_WORKING_O_NOFOLLOW
#define HAVE_WORKING_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 defined DARWIN7
/* To avoid the trouble of installing a file that is shared by many
GNU packages -- many packaging systems have problems with this --,
simply inline the aliases here. */
cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
"ISO8859-2" "\0" "ISO-8859-2" "\0"
"ISO8859-4" "\0" "ISO-8859-4" "\0"
"ISO8859-5" "\0" "ISO-8859-5" "\0"
"ISO8859-7" "\0" "ISO-8859-7" "\0"
"ISO8859-9" "\0" "ISO-8859-9" "\0"
"ISO8859-13" "\0" "ISO-8859-13" "\0"
"ISO8859-15" "\0" "ISO-8859-15" "\0"
"KOI8-R" "\0" "KOI8-R" "\0"
"KOI8-U" "\0" "KOI8-U" "\0"
"CP866" "\0" "CP866" "\0"
"CP949" "\0" "CP949" "\0"
"CP1131" "\0" "CP1131" "\0"
"CP1251" "\0" "CP1251" "\0"
"eucCN" "\0" "GB2312" "\0"
"GB2312" "\0" "GB2312" "\0"
"eucJP" "\0" "EUC-JP" "\0"
"eucKR" "\0" "EUC-KR" "\0"
"Big5" "\0" "BIG5" "\0"
"Big5HKSCS" "\0" "BIG5-HKSCS" "\0"
"GBK" "\0" "GBK" "\0"
"GB18030" "\0" "GB18030" "\0"
"SJIS" "\0" "SHIFT_JIS" "\0"
"ARMSCII-8" "\0" "ARMSCII-8" "\0"
"PT154" "\0" "PT154" "\0"
/*"ISCII-DEV" "\0" "?" "\0"*/
"*" "\0" "UTF-8" "\0";
# endif
# if defined VMS
/* To avoid the troubles of an extra file charset.alias_vms in the
sources of many GNU packages, simply inline the aliases here. */
/* The list of encodings is taken from the OpenVMS 7.3-1 documentation
"Compaq C Run-Time Library Reference Manual for OpenVMS systems"
section 10.7 "Handling Different Character Sets". */
cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
"ISO8859-2" "\0" "ISO-8859-2" "\0"
"ISO8859-5" "\0" "ISO-8859-5" "\0"
"ISO8859-7" "\0" "ISO-8859-7" "\0"
"ISO8859-8" "\0" "ISO-8859-8" "\0"
"ISO8859-9" "\0" "ISO-8859-9" "\0"
/* Japanese */
"eucJP" "\0" "EUC-JP" "\0"
"SJIS" "\0" "SHIFT_JIS" "\0"
"DECKANJI" "\0" "DEC-KANJI" "\0"
"SDECKANJI" "\0" "EUC-JP" "\0"
/* Chinese */
"eucTW" "\0" "EUC-TW" "\0"
"DECHANYU" "\0" "DEC-HANYU" "\0"
"DECHANZI" "\0" "GB2312" "\0"
/* Korean */
"DECKOREAN" "\0" "EUC-KR" "\0";
# endif
# if defined WIN32_NATIVE || defined __CYGWIN__
/* To avoid the troubles of installing a separate file in the same
directory as the DLL and of retrieving the DLL's directory at
runtime, simply inline the aliases here. */
cp = "CP936" "\0" "GBK" "\0"
"CP1361" "\0" "JOHAB" "\0"
"CP20127" "\0" "ASCII" "\0"
"CP20866" "\0" "KOI8-R" "\0"
"CP20936" "\0" "GB2312" "\0"
"CP21866" "\0" "KOI8-RU" "\0"
"CP28591" "\0" "ISO-8859-1" "\0"
"CP28592" "\0" "ISO-8859-2" "\0"
"CP28593" "\0" "ISO-8859-3" "\0"
"CP28594" "\0" "ISO-8859-4" "\0"
"CP28595" "\0" "ISO-8859-5" "\0"
"CP28596" "\0" "ISO-8859-6" "\0"
"CP28597" "\0" "ISO-8859-7" "\0"
"CP28598" "\0" "ISO-8859-8" "\0"
"CP28599" "\0" "ISO-8859-9" "\0"
"CP28605" "\0" "ISO-8859-15" "\0"
"CP38598" "\0" "ISO-8859-8" "\0"
"CP51932" "\0" "EUC-JP" "\0"
"CP51936" "\0" "GB2312" "\0"
"CP51949" "\0" "EUC-KR" "\0"
"CP51950" "\0" "EUC-TW" "\0"
"CP54936" "\0" "GB18030" "\0"
"CP65001" "\0" "UTF-8" "\0";
# endif
#endif
charset_aliases = cp;
}
return cp;
}
/* Determine the current locale's character encoding, and canonicalize it
into one of the canonical names listed in config.charset.
The result must not be freed; it is statically allocated.
If the canonical name cannot be determined, the result is a non-canonical
name. */
#ifdef STATIC
STATIC
#endif
const char *
locale_charset (void)
{
const char *codeset;
const char *aliases;
#if !(defined WIN32_NATIVE || defined OS2)
# if HAVE_LANGINFO_CODESET
/* Most systems support nl_langinfo (CODESET) nowadays. */
codeset = nl_langinfo (CODESET);
# ifdef __CYGWIN__
/* Cygwin < 1.7 does not have locales. nl_langinfo (CODESET) always
returns "US-ASCII". Return the suffix of the locale name from the
environment variables (if present) or the codepage as a number. */
if (codeset != NULL && strcmp (codeset, "US-ASCII") == 0)
{
const char *locale;
static char buf[2 + 10 + 1];
locale = getenv ("LC_ALL");
if (locale == NULL || locale[0] == '\0')
{
locale = getenv ("LC_CTYPE");
if (locale == NULL || locale[0] == '\0')
locale = getenv ("LANG");
}
if (locale != NULL && locale[0] != '\0')
{
/* If the locale name contains an encoding after the dot, return
it. */
const char *dot = strchr (locale, '.');
if (dot != NULL)
{
const char *modifier;
dot++;
/* Look for the possible @... trailer and remove it, if any. */
modifier = strchr (dot, '@');
if (modifier == NULL)
return dot;
if (modifier - dot < sizeof (buf))
{
memcpy (buf, dot, modifier - dot);
buf [modifier - dot] = '\0';
return buf;
}
}
}
/* Woe32 has a function returning the locale's codepage as a number:
GetACP(). This encoding is used by Cygwin, unless the user has set
the environment variable CYGWIN=codepage:oem (which very few people
do).
Output directed to console windows needs to be converted (to
GetOEMCP() if the console is using a raster font, or to
GetConsoleOutputCP() if it is using a TrueType font). Cygwin does
this conversion transparently (see winsup/cygwin/fhandler_console.cc),
converting to GetConsoleOutputCP(). This leads to correct results,
except when SetConsoleOutputCP has been called and a raster font is
in use. */
sprintf (buf, "CP%u", GetACP ());
codeset = buf;
}
# endif
# else
/* On old systems which lack it, use setlocale or getenv. */
const char *locale = NULL;
/* But most old systems don't have a complete set of locales. Some
(like SunOS 4 or DJGPP) have only the C locale. Therefore we don't
use setlocale here; it would return "C" when it doesn't support the
locale name the user has set. */
# if 0
locale = setlocale (LC_CTYPE, NULL);
# endif
if (locale == NULL || locale[0] == '\0')
{
locale = getenv ("LC_ALL");
if (locale == NULL || locale[0] == '\0')
{
locale = getenv ("LC_CTYPE");
if (locale == NULL || locale[0] == '\0')
locale = getenv ("LANG");
}
}
/* On some old systems, one used to set locale = "iso8859_1". On others,
you set it to "language_COUNTRY.charset". In any case, we resolve it
through the charset.alias file. */
codeset = locale;
# endif
#elif defined WIN32_NATIVE
static char buf[2 + 10 + 1];
/* Woe32 has a function returning the locale's codepage as a number:
GetACP().
When the output goes to a console window, it needs to be provided in
GetOEMCP() encoding if the console is using a raster font, or in
GetConsoleOutputCP() encoding if it is using a TrueType font.
But in GUI programs and for output sent to files and pipes, GetACP()
encoding is the best bet. */
sprintf (buf, "CP%u", GetACP ());
codeset = buf;
#elif defined OS2
const char *locale;
static char buf[2 + 10 + 1];
ULONG cp[3];
ULONG cplen;
/* Allow user to override the codeset, as set in the operating system,
with standard language environment variables. */
locale = getenv ("LC_ALL");
if (locale == NULL || locale[0] == '\0')
{
locale = getenv ("LC_CTYPE");
if (locale == NULL || locale[0] == '\0')
locale = getenv ("LANG");
}
if (locale != NULL && locale[0] != '\0')
{
/* If the locale name contains an encoding after the dot, return it. */
const char *dot = strchr (locale, '.');
if (dot != NULL)
{
const char *modifier;
dot++;
/* Look for the possible @... trailer and remove it, if any. */
modifier = strchr (dot, '@');
if (modifier == NULL)
return dot;
if (modifier - dot < sizeof (buf))
{
memcpy (buf, dot, modifier - dot);
buf [modifier - dot] = '\0';
return buf;
}
}
/* Resolve through the charset.alias file. */
codeset = locale;
}
else
{
/* OS/2 has a function returning the locale's codepage as a number. */
if (DosQueryCp (sizeof (cp), cp, &cplen))
codeset = "";
else
{
sprintf (buf, "CP%u", cp[0]);
codeset = buf;
}
}
#endif
if (codeset == NULL)
/* The canonical name cannot be determined. */
codeset = "";
/* Resolve alias. */
for (aliases = get_charset_aliases ();
*aliases != '\0';
aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
if (strcmp (codeset, aliases) == 0
|| (aliases[0] == '*' && aliases[1] == '\0'))
{
codeset = aliases + strlen (aliases) + 1;
break;
}
/* Don't return an empty string. GNU libc and GNU libiconv interpret
the empty string as denoting "the locale's character encoding",
thus GNU libiconv would call this function a second time. */
if (codeset[0] == '\0')
codeset = "ASCII";
return codeset;
}

View File

@ -0,0 +1,483 @@
/* Provide relocatable packages.
Copyright (C) 2003-2006, 2008-2011 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2003.
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. */
/* Tell glibc's <stdio.h> to provide a prototype for getline().
This must come before <config.h> because <config.h> may include
<features.h>, and once <features.h> has been included, it's too late. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#define _GL_USE_STDLIB_ALLOC 1
#include <config.h>
/* Specification. */
#include "relocatable.h"
#if ENABLE_RELOCATABLE
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef NO_XMALLOC
# define xmalloc malloc
#else
# include "xalloc.h"
#endif
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#if DEPENDS_ON_LIBCHARSET
# include <libcharset.h>
#endif
#if DEPENDS_ON_LIBICONV && HAVE_ICONV
# include <iconv.h>
#endif
#if DEPENDS_ON_LIBINTL && ENABLE_NLS
# include <libintl.h>
#endif
/* Faked cheap 'bool'. */
#undef bool
#undef false
#undef true
#define bool int
#define false 0
#define true 1
/* Pathname support.
ISSLASH(C) tests whether C is a directory separator character.
IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
*/
#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
/* Win32, OS/2, DOS */
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
# define HAS_DEVICE(P) \
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
&& (P)[1] == ':')
# define IS_PATH_WITH_DIR(P) \
(strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
#else
/* Unix */
# define ISSLASH(C) ((C) == '/')
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
# define FILE_SYSTEM_PREFIX_LEN(P) 0
#endif
/* Original installation prefix. */
static char *orig_prefix;
static size_t orig_prefix_len;
/* Current installation prefix. */
static char *curr_prefix;
static size_t curr_prefix_len;
/* These prefixes do not end in a slash. Anything that will be concatenated
to them must start with a slash. */
/* Sets the original and the current installation prefix of this module.
Relocation simply replaces a pathname starting with the original prefix
by the corresponding pathname with the current prefix instead. Both
prefixes should be directory names without trailing slash (i.e. use ""
instead of "/"). */
static void
set_this_relocation_prefix (const char *orig_prefix_arg,
const char *curr_prefix_arg)
{
if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
/* Optimization: if orig_prefix and curr_prefix are equal, the
relocation is a nop. */
&& strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
{
/* Duplicate the argument strings. */
char *memory;
orig_prefix_len = strlen (orig_prefix_arg);
curr_prefix_len = strlen (curr_prefix_arg);
memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
#ifdef NO_XMALLOC
if (memory != NULL)
#endif
{
memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
orig_prefix = memory;
memory += orig_prefix_len + 1;
memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
curr_prefix = memory;
return;
}
}
orig_prefix = NULL;
curr_prefix = NULL;
/* Don't worry about wasted memory here - this function is usually only
called once. */
}
/* Sets the original and the current installation prefix of the package.
Relocation simply replaces a pathname starting with the original prefix
by the corresponding pathname with the current prefix instead. Both
prefixes should be directory names without trailing slash (i.e. use ""
instead of "/"). */
void
set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
{
set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
/* Now notify all dependent libraries. */
#if DEPENDS_ON_LIBCHARSET
libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
#endif
#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
#endif
#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
#endif
}
#if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
/* Convenience function:
Computes the current installation prefix, based on the original
installation prefix, the original installation directory of a particular
file, and the current pathname of this file.
Returns it, freshly allocated. Returns NULL upon failure. */
#ifdef IN_LIBRARY
#define compute_curr_prefix local_compute_curr_prefix
static
#endif
char *
compute_curr_prefix (const char *orig_installprefix,
const char *orig_installdir,
const char *curr_pathname)
{
char *curr_installdir;
const char *rel_installdir;
if (curr_pathname == NULL)
return NULL;
/* Determine the relative installation directory, relative to the prefix.
This is simply the difference between orig_installprefix and
orig_installdir. */
if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
!= 0)
/* Shouldn't happen - nothing should be installed outside $(prefix). */
return NULL;
rel_installdir = orig_installdir + strlen (orig_installprefix);
/* Determine the current installation directory. */
{
const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
const char *p = curr_pathname + strlen (curr_pathname);
char *q;
while (p > p_base)
{
p--;
if (ISSLASH (*p))
break;
}
q = (char *) xmalloc (p - curr_pathname + 1);
#ifdef NO_XMALLOC
if (q == NULL)
return NULL;
#endif
memcpy (q, curr_pathname, p - curr_pathname);
q[p - curr_pathname] = '\0';
curr_installdir = q;
}
/* Compute the current installation prefix by removing the trailing
rel_installdir from it. */
{
const char *rp = rel_installdir + strlen (rel_installdir);
const char *cp = curr_installdir + strlen (curr_installdir);
const char *cp_base =
curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
while (rp > rel_installdir && cp > cp_base)
{
bool same = false;
const char *rpi = rp;
const char *cpi = cp;
while (rpi > rel_installdir && cpi > cp_base)
{
rpi--;
cpi--;
if (ISSLASH (*rpi) || ISSLASH (*cpi))
{
if (ISSLASH (*rpi) && ISSLASH (*cpi))
same = true;
break;
}
/* Do case-insensitive comparison if the file system is always or
often case-insensitive. It's better to accept the comparison
if the difference is only in case, rather than to fail. */
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
/* Win32, Cygwin, OS/2, DOS - case insignificant file system */
if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
!= (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
break;
#else
if (*rpi != *cpi)
break;
#endif
}
if (!same)
break;
/* The last pathname component was the same. opi and cpi now point
to the slash before it. */
rp = rpi;
cp = cpi;
}
if (rp > rel_installdir)
{
/* Unexpected: The curr_installdir does not end with rel_installdir. */
free (curr_installdir);
return NULL;
}
{
size_t curr_prefix_len = cp - curr_installdir;
char *curr_prefix;
curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
#ifdef NO_XMALLOC
if (curr_prefix == NULL)
{
free (curr_installdir);
return NULL;
}
#endif
memcpy (curr_prefix, curr_installdir, curr_prefix_len);
curr_prefix[curr_prefix_len] = '\0';
free (curr_installdir);
return curr_prefix;
}
}
}
#endif /* !IN_LIBRARY || PIC */
#if defined PIC && defined INSTALLDIR
/* Full pathname of shared library, or NULL. */
static char *shared_library_fullname;
#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
/* Native Win32 only.
On Cygwin, it is better to use the Cygwin provided /proc interface, than
to use native Win32 API and cygwin_conv_to_posix_path, because it supports
longer file names
(see <http://cygwin.com/ml/cygwin/2011-01/msg00410.html>). */
/* Determine the full pathname of the shared library when it is loaded. */
BOOL WINAPI
DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
{
(void) reserved;
if (event == DLL_PROCESS_ATTACH)
{
/* The DLL is being loaded into an application's address range. */
static char location[MAX_PATH];
if (!GetModuleFileName (module_handle, location, sizeof (location)))
/* Shouldn't happen. */
return FALSE;
if (!IS_PATH_WITH_DIR (location))
/* Shouldn't happen. */
return FALSE;
shared_library_fullname = strdup (location);
}
return TRUE;
}
#else /* Unix */
static void
find_shared_library_fullname ()
{
#if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
/* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
function.
Cygwin >= 1.5 has /proc/self/maps and the getline() function too. */
FILE *fp;
/* Open the current process' maps file. It describes one VMA per line. */
fp = fopen ("/proc/self/maps", "r");
if (fp)
{
unsigned long address = (unsigned long) &find_shared_library_fullname;
for (;;)
{
unsigned long start, end;
int c;
if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
break;
if (address >= start && address <= end - 1)
{
/* Found it. Now see if this line contains a filename. */
while (c = getc (fp), c != EOF && c != '\n' && c != '/')
continue;
if (c == '/')
{
size_t size;
int len;
ungetc (c, fp);
shared_library_fullname = NULL; size = 0;
len = getline (&shared_library_fullname, &size, fp);
if (len >= 0)
{
/* Success: filled shared_library_fullname. */
if (len > 0 && shared_library_fullname[len - 1] == '\n')
shared_library_fullname[len - 1] = '\0';
}
}
break;
}
while (c = getc (fp), c != EOF && c != '\n')
continue;
}
fclose (fp);
}
#endif
}
#endif /* WIN32 / Unix */
/* Return the full pathname of the current shared library.
Return NULL if unknown.
Guaranteed to work only on Linux, Cygwin and Woe32. */
static char *
get_shared_library_fullname ()
{
#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
static bool tried_find_shared_library_fullname;
if (!tried_find_shared_library_fullname)
{
find_shared_library_fullname ();
tried_find_shared_library_fullname = true;
}
#endif
return shared_library_fullname;
}
#endif /* PIC */
/* Returns the pathname, relocated according to the current installation
directory.
The returned string is either PATHNAME unmodified or a freshly allocated
string that you can free with free() after casting it to 'char *'. */
const char *
relocate (const char *pathname)
{
#if defined PIC && defined INSTALLDIR
static int initialized;
/* Initialization code for a shared library. */
if (!initialized)
{
/* At this point, orig_prefix and curr_prefix likely have already been
set through the main program's set_program_name_and_installdir
function. This is sufficient in the case that the library has
initially been installed in the same orig_prefix. But we can do
better, to also cover the cases that 1. it has been installed
in a different prefix before being moved to orig_prefix and (later)
to curr_prefix, 2. unlike the program, it has not moved away from
orig_prefix. */
const char *orig_installprefix = INSTALLPREFIX;
const char *orig_installdir = INSTALLDIR;
char *curr_prefix_better;
curr_prefix_better =
compute_curr_prefix (orig_installprefix, orig_installdir,
get_shared_library_fullname ());
set_relocation_prefix (orig_installprefix,
curr_prefix_better != NULL
? curr_prefix_better
: curr_prefix);
if (curr_prefix_better != NULL)
free (curr_prefix_better);
initialized = 1;
}
#endif
/* Note: It is not necessary to perform case insensitive comparison here,
even for DOS-like file systems, because the pathname argument was
typically created from the same Makefile variable as orig_prefix came
from. */
if (orig_prefix != NULL && curr_prefix != NULL
&& strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
{
if (pathname[orig_prefix_len] == '\0')
{
/* pathname equals orig_prefix. */
char *result = (char *) xmalloc (strlen (curr_prefix) + 1);
#ifdef NO_XMALLOC
if (result != NULL)
#endif
{
strcpy (result, curr_prefix);
return result;
}
}
else if (ISSLASH (pathname[orig_prefix_len]))
{
/* pathname starts with orig_prefix. */
const char *pathname_tail = &pathname[orig_prefix_len];
char *result =
(char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
#ifdef NO_XMALLOC
if (result != NULL)
#endif
{
memcpy (result, curr_prefix, curr_prefix_len);
strcpy (result + curr_prefix_len, pathname_tail);
return result;
}
}
}
/* Nothing to relocate. */
return pathname;
}
#endif

View File

@ -0,0 +1,83 @@
/* Provide relocatable packages.
Copyright (C) 2003, 2005, 2008-2011 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2003.
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. */
#ifndef _RELOCATABLE_H
#define _RELOCATABLE_H
#ifdef __cplusplus
extern "C" {
#endif
/* This can be enabled through the configure --enable-relocatable option. */
#if ENABLE_RELOCATABLE
/* When building a DLL, we must export some functions. Note that because
this is a private .h file, we don't need to use __declspec(dllimport)
in any case. */
#if HAVE_VISIBILITY && BUILDING_DLL
# define RELOCATABLE_DLL_EXPORTED __attribute__((__visibility__("default")))
#elif defined _MSC_VER && BUILDING_DLL
# define RELOCATABLE_DLL_EXPORTED __declspec(dllexport)
#else
# define RELOCATABLE_DLL_EXPORTED
#endif
/* Sets the original and the current installation prefix of the package.
Relocation simply replaces a pathname starting with the original prefix
by the corresponding pathname with the current prefix instead. Both
prefixes should be directory names without trailing slash (i.e. use ""
instead of "/"). */
extern RELOCATABLE_DLL_EXPORTED void
set_relocation_prefix (const char *orig_prefix,
const char *curr_prefix);
/* Returns the pathname, relocated according to the current installation
directory.
The returned string is either PATHNAME unmodified or a freshly allocated
string that you can free with free() after casting it to 'char *'. */
extern const char * relocate (const char *pathname);
/* Memory management: relocate() potentially allocates memory, because it has
to construct a fresh pathname. If this is a problem because your program
calls relocate() frequently, think about caching the result. Or free the
return value if it was different from the argument pathname. */
/* Convenience function:
Computes the current installation prefix, based on the original
installation prefix, the original installation directory of a particular
file, and the current pathname of this file.
Returns it, freshly allocated. Returns NULL upon failure. */
extern char * compute_curr_prefix (const char *orig_installprefix,
const char *orig_installdir,
const char *curr_pathname);
#else
/* By default, we use the hardwired pathnames. */
#define relocate(pathname) (pathname)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _RELOCATABLE_H */