#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#ifdef __GNUC__
# define alloca __builtin_alloca
# define HAVE_ALLOCA 1
#else
# ifdef _MSC_VER
# include <malloc.h>
# define alloca _alloca
# else
# if defined HAVE_ALLOCA_H || defined _LIBC
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca
char *alloca ();
# endif
# endif
# endif
# endif
#endif
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#ifndef __set_errno
# define __set_errno(val) errno = (val)
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#if defined HAVE_UNISTD_H || defined _LIBC
# include <unistd.h>
#endif
#include <locale.h>
#ifdef _LIBC
# if defined __alpha__ || defined __arm__ || defined __i386__ \
|| defined __m68k__ || defined __s390__
# define INTDIV0_RAISES_SIGFPE 1
# else
# define INTDIV0_RAISES_SIGFPE 0
# endif
#endif
#if !INTDIV0_RAISES_SIGFPE
# include <signal.h>
#endif
#if defined HAVE_SYS_PARAM_H || defined _LIBC
# include <sys/param.h>
#endif
#if !defined _LIBC
# include "localcharset.h"
#endif
#include "gettextP.h"
#include "plural-exp.h"
#ifdef _LIBC
# include <libintl.h>
#else
# ifdef IN_LIBGLOCALE
# include <libintl.h>
# endif
# include "libgnuintl.h"
#endif
#include "hash-string.h"
#ifdef _LIBC
# include <bits/libc-lock.h>
# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
# define gl_rwlock_rdlock __libc_rwlock_rdlock
# define gl_rwlock_wrlock __libc_rwlock_wrlock
# define gl_rwlock_unlock __libc_rwlock_unlock
#else
# include "lock.h"
#endif
#if defined __GNUC__ && __GNUC__ >= 2
# define alignof(TYPE) __alignof__ (TYPE)
#else
# define alignof(TYPE) \
((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
#endif
#ifndef offsetof
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
#endif
#ifdef _LIBC
# define getcwd __getcwd
# ifndef stpcpy
# define stpcpy __stpcpy
# endif
# define tfind __tfind
#else
# if !defined HAVE_GETCWD
char *getwd ();
# define getcwd(buf, max) getwd (buf)
# else
# if VMS
# define getcwd(buf, max) (getcwd) (buf, max, 0)
# else
char *getcwd (char *, size_t);
# endif
# endif
# ifndef HAVE_STPCPY
static char *stpcpy (char *dest, const char *src);
# endif
# ifndef HAVE_MEMPCPY
static void *mempcpy (void *dest, const void *src, size_t n);
# endif
#endif
#if defined HAVE_TSEARCH || defined _LIBC
# include <search.h>
#else
# define tsearch libintl_tsearch
# define tfind libintl_tfind
# define tdelete libintl_tdelete
# define twalk libintl_twalk
# include "tsearch.h"
#endif
#ifdef _LIBC
# define tsearch __tsearch
#endif
#define PATH_INCR 32
#include <limits.h>
#ifndef _POSIX_PATH_MAX
# define _POSIX_PATH_MAX 255
#endif
#if !defined PATH_MAX && defined _PC_PATH_MAX
# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
#endif
#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
# include <sys/param.h>
#endif
#if !defined PATH_MAX && defined MAXPATHLEN
# define PATH_MAX MAXPATHLEN
#endif
#ifndef PATH_MAX
# define PATH_MAX _POSIX_PATH_MAX
#endif
#ifdef _LIBC
# define IS_ABSOLUTE_FILE_NAME(P) ((P)[0] == '/')
# define IS_RELATIVE_FILE_NAME(P) (! IS_ABSOLUTE_FILE_NAME (P))
# define IS_FILE_NAME_WITH_DIR(P) (strchr ((P), '/') != NULL)
#else
# include "filename.h"
#endif
#if defined _LIBC || HAVE_USELOCALE || defined IN_LIBGLOCALE
# define HAVE_PER_THREAD_LOCALE
#endif
struct known_translation_t
{
const char *domainname;
int category;
#ifdef HAVE_PER_THREAD_LOCALE
const char *localename;
#endif
#ifdef IN_LIBGLOCALE
const char *encoding;
#endif
int counter;
struct loaded_l10nfile *domain;
const char *translation;
size_t translation_length;
union
{
char appended[ZERO];
const char *ptr;
}
msgid;
};
gl_rwlock_define_initialized (static, tree_lock)
static void *root;
static int
transcmp (const void *p1, const void *p2)
{
const struct known_translation_t *s1;
const struct known_translation_t *s2;
int result;
s1 = (const struct known_translation_t *) p1;
s2 = (const struct known_translation_t *) p2;
result = strcmp (s1->domain != NULL ? s1->msgid.appended : s1->msgid.ptr,
s2->domain != NULL ? s2->msgid.appended : s2->msgid.ptr);
if (result == 0)
{
result = strcmp (s1->domainname, s2->domainname);
if (result == 0)
{
#ifdef HAVE_PER_THREAD_LOCALE
result = strcmp (s1->localename, s2->localename);
if (result == 0)
#endif
{
#ifdef IN_LIBGLOCALE
result = strcmp (s1->encoding, s2->encoding);
if (result == 0)
#endif
result = s1->category - s2->category;
}
}
}
return result;
}
const char _nl_default_default_domain[] attribute_hidden = "messages";
#ifndef IN_LIBGLOCALE
const char *_nl_current_default_domain attribute_hidden
= _nl_default_default_domain;
#endif
#if defined __EMX__ && !defined __KLIBC__
extern const char _nl_default_dirname[];
#else
# ifdef _LIBC
extern const char _nl_default_dirname[];
libc_hidden_proto (_nl_default_dirname)
# endif
const char _nl_default_dirname[] = LOCALEDIR;
# ifdef _LIBC
libc_hidden_data_def (_nl_default_dirname)
# endif
#endif
#ifndef IN_LIBGLOCALE
struct binding *_nl_domain_bindings;
#endif
static char *plural_lookup (struct loaded_l10nfile *domain,
unsigned long int n,
const char *translation, size_t translation_len)
internal_function;
#ifdef IN_LIBGLOCALE
static const char *guess_category_value (int category,
const char *categoryname,
const char *localename)
internal_function;
#else
static const char *guess_category_value (int category,
const char *categoryname)
internal_function;
#endif
#ifdef _LIBC
# include "../locale/localeinfo.h"
# define category_to_name(category) \
_nl_category_names.str + _nl_category_name_idxs[category]
#else
static const char *category_to_name (int category) internal_function;
#endif
#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
static const char *get_output_charset (struct binding *domainbinding)
internal_function;
#endif
#ifdef HAVE_ALLOCA
# define freea(p)
# define ADD_BLOCK(list, address)
# define FREE_BLOCKS(list)
#else
struct block_list
{
void *address;
struct block_list *next;
};
# define ADD_BLOCK(list, addr) \
do { \
struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
\
if (newp != NULL) { \
newp->address = (addr); \
newp->next = (list); \
(list) = newp; \
} \
} while (0)
# define FREE_BLOCKS(list) \
do { \
while (list != NULL) { \
struct block_list *old = list; \
list = list->next; \
free (old->address); \
free (old); \
} \
} while (0)
# undef alloca
# define alloca(size) (malloc (size))
# define freea(p) free (p)
#endif
#ifdef _LIBC
typedef struct transmem_list
{
struct transmem_list *next;
char data[ZERO];
} transmem_block_t;
static struct transmem_list *transmem_list;
#else
typedef unsigned char transmem_block_t;
#endif
#ifdef _LIBC
# define DCIGETTEXT __dcigettext
#else
# define DCIGETTEXT libintl_dcigettext
#endif
gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
#ifdef _LIBC
# define ENABLE_SECURE __libc_enable_secure
# define DETERMINE_SECURE
#else
# ifndef HAVE_GETUID
# define getuid() 0
# endif
# ifndef HAVE_GETGID
# define getgid() 0
# endif
# ifndef HAVE_GETEUID
# define geteuid() getuid()
# endif
# ifndef HAVE_GETEGID
# define getegid() getgid()
# endif
static int enable_secure;
# define ENABLE_SECURE (enable_secure == 1)
# define DETERMINE_SECURE \
if (enable_secure == 0) \
{ \
if (getuid () != geteuid () || getgid () != getegid ()) \
enable_secure = 1; \
else \
enable_secure = -1; \
}
#endif
#include "eval-plural.h"
#ifdef IN_LIBGLOCALE
char *
gl_dcigettext (const char *domainname,
const char *msgid1, const char *msgid2,
int plural, unsigned long int n,
int category,
const char *localename, const char *encoding)
#else
char *
DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
int plural, unsigned long int n, int category)
#endif
{
#ifndef HAVE_ALLOCA
struct block_list *block_list = NULL;
#endif
struct loaded_l10nfile *domain;
struct binding *binding;
const char *categoryname;
const char *categoryvalue;
const char *dirname;
#if defined _WIN32 && !defined __CYGWIN__
const wchar_t *wdirname;
#endif
char *xdomainname;
char *single_locale;
char *retval;
size_t retlen;
int saved_errno;
struct known_translation_t search;
struct known_translation_t **foundp = NULL;
#if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
const char *localename;
#endif
size_t domainname_len;
if (msgid1 == NULL)
return NULL;
#ifdef _LIBC
if (category < 0 || category >= __LC_LAST || category == LC_ALL)
return (plural == 0
? (char *) msgid1
: n == 1 ? (char *) msgid1 : (char *) msgid2);
#endif
saved_errno = errno;
#ifdef _LIBC
__libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
__libc_rwlock_rdlock (__libc_setlocale_lock);
#endif
gl_rwlock_rdlock (_nl_state_lock);
if (domainname == NULL)
domainname = _nl_current_default_domain;
#ifdef LC_MESSAGES_COMPAT
if (category == LC_MESSAGES_COMPAT)
category = LC_MESSAGES;
#endif
search.domain = NULL;
search.msgid.ptr = msgid1;
search.domainname = domainname;
search.category = category;
#ifdef HAVE_PER_THREAD_LOCALE
# ifndef IN_LIBGLOCALE
# ifdef _LIBC
localename = strdupa (__current_locale_name (category));
# else
categoryname = category_to_name (category);
# define CATEGORYNAME_INITIALIZED
localename = _nl_locale_name_thread_unsafe (category, categoryname);
if (localename == NULL)
localename = "";
# endif
# endif
search.localename = localename;
#endif
#ifdef IN_LIBGLOCALE
search.encoding = encoding;
#endif
gl_rwlock_rdlock (tree_lock);
foundp = (struct known_translation_t **) tfind (&search, &root, transcmp);
gl_rwlock_unlock (tree_lock);
if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
{
if (plural)
retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
(*foundp)->translation_length);
else
retval = (char *) (*foundp)->translation;
gl_rwlock_unlock (_nl_state_lock);
# ifdef _LIBC
__libc_rwlock_unlock (__libc_setlocale_lock);
# endif
__set_errno (saved_errno);
return retval;
}
DETERMINE_SECURE;
#ifdef IN_LIBGLOCALE
binding = NULL;
dirname = bindtextdomain (domainname, NULL);
# if defined _WIN32 && !defined __CYGWIN__
wdirname = wbindtextdomain (domainname, NULL);
# endif
#else
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
{
int compare = strcmp (domainname, binding->domainname);
if (compare == 0)
break;
if (compare < 0)
{
binding = NULL;
break;
}
}
if (binding == NULL)
{
dirname = _nl_default_dirname;
# if defined _WIN32 && !defined __CYGWIN__
wdirname = NULL;
# endif
}
else
{
dirname = binding->dirname;
# if defined _WIN32 && !defined __CYGWIN__
wdirname = binding->wdirname;
# endif
#endif
#if defined _WIN32 && !defined __CYGWIN__
if (wdirname != NULL
? IS_RELATIVE_FILE_NAME (wdirname)
: IS_RELATIVE_FILE_NAME (dirname))
{
size_t wdirname_len;
size_t path_max;
wchar_t *resolved_wdirname;
wchar_t *ret;
wchar_t *p;
if (wdirname != NULL)
wdirname_len = wcslen (wdirname);
else
{
wdirname_len = mbstowcs (NULL, dirname, 0);
if (wdirname_len == (size_t)(-1))
goto return_untranslated;
}
wdirname_len++;
path_max = (unsigned int) PATH_MAX;
path_max += 2;
for (;;)
{
resolved_wdirname =
(wchar_t *)
alloca ((path_max + wdirname_len) * sizeof (wchar_t));
ADD_BLOCK (block_list, resolved_wdirname);
__set_errno (0);
ret = _wgetcwd (resolved_wdirname, path_max);
if (ret != NULL || errno != ERANGE)
break;
path_max += path_max / 2;
path_max += PATH_INCR;
}
if (ret == NULL)
goto return_untranslated;
p = wcschr (resolved_wdirname, L'\0');
*p++ = L'/';
if (wdirname != NULL)
wcscpy (p, wdirname);
else
mbstowcs (p, dirname, wdirname_len);
wdirname = resolved_wdirname;
dirname = NULL;
}
#else
if (IS_RELATIVE_FILE_NAME (dirname))
{
size_t dirname_len = strlen (dirname) + 1;
size_t path_max;
char *resolved_dirname;
char *ret;
path_max = (unsigned int) PATH_MAX;
path_max += 2;
for (;;)
{
resolved_dirname = (char *) alloca (path_max + dirname_len);
ADD_BLOCK (block_list, resolved_dirname);
__set_errno (0);
ret = getcwd (resolved_dirname, path_max);
if (ret != NULL || errno != ERANGE)
break;
path_max += path_max / 2;
path_max += PATH_INCR;
}
if (ret == NULL)
goto return_untranslated;
stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname);
dirname = resolved_dirname;
}
#endif
#ifndef IN_LIBGLOCALE
}
#endif
#ifndef CATEGORYNAME_INITIALIZED
categoryname = category_to_name (category);
#endif
#ifdef IN_LIBGLOCALE
categoryvalue = guess_category_value (category, categoryname, localename);
#else
categoryvalue = guess_category_value (category, categoryname);
#endif
domainname_len = strlen (domainname);
xdomainname = (char *) alloca (strlen (categoryname)
+ domainname_len + 5);
ADD_BLOCK (block_list, xdomainname);
stpcpy ((char *) mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
domainname, domainname_len),
".mo");
single_locale = (char *) alloca (strlen (categoryvalue) + 1);
ADD_BLOCK (block_list, single_locale);
while (1)
{
while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
++categoryvalue;
if (categoryvalue[0] == '\0')
{
single_locale[0] = 'C';
single_locale[1] = '\0';
}
else
{
char *cp = single_locale;
while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
*cp++ = *categoryvalue++;
*cp = '\0';
if (ENABLE_SECURE && IS_FILE_NAME_WITH_DIR (single_locale))
continue;
}
if (strcmp (single_locale, "C") == 0
|| strcmp (single_locale, "POSIX") == 0)
break;
domain = _nl_find_domain (dirname,
#if defined _WIN32 && !defined __CYGWIN__
wdirname,
#endif
single_locale, xdomainname, binding);
if (domain != NULL)
{
#if defined IN_LIBGLOCALE
retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
#else
retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
#endif
if (retval == NULL)
{
int cnt;
for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
{
#if defined IN_LIBGLOCALE
retval = _nl_find_msg (domain->successor[cnt], binding,
encoding, msgid1, &retlen);
#else
retval = _nl_find_msg (domain->successor[cnt], binding,
msgid1, 1, &retlen);
#endif
if (__builtin_expect (retval == (char *) -1, 0))
goto return_untranslated;
if (retval != NULL)
{
domain = domain->successor[cnt];
break;
}
}
}
if (__builtin_expect (retval == (char *) -1, 0))
break;
if (retval != NULL)
{
FREE_BLOCKS (block_list);
if (foundp == NULL)
{
size_t msgid_len;
size_t size;
struct known_translation_t *newp;
msgid_len = strlen (msgid1) + 1;
size = offsetof (struct known_translation_t, msgid)
+ msgid_len + domainname_len + 1;
#ifdef HAVE_PER_THREAD_LOCALE
size += strlen (localename) + 1;
#endif
newp = (struct known_translation_t *) malloc (size);
if (newp != NULL)
{
char *new_domainname;
#ifdef HAVE_PER_THREAD_LOCALE
char *new_localename;
#endif
new_domainname =
(char *) mempcpy (newp->msgid.appended, msgid1,
msgid_len);
memcpy (new_domainname, domainname, domainname_len + 1);
#ifdef HAVE_PER_THREAD_LOCALE
new_localename = new_domainname + domainname_len + 1;
strcpy (new_localename, localename);
#endif
newp->domainname = new_domainname;
newp->category = category;
#ifdef HAVE_PER_THREAD_LOCALE
newp->localename = new_localename;
#endif
#ifdef IN_LIBGLOCALE
newp->encoding = encoding;
#endif
newp->counter = _nl_msg_cat_cntr;
newp->domain = domain;
newp->translation = retval;
newp->translation_length = retlen;
gl_rwlock_wrlock (tree_lock);
foundp = (struct known_translation_t **)
tsearch (newp, &root, transcmp);
gl_rwlock_unlock (tree_lock);
if (foundp == NULL
|| __builtin_expect (*foundp != newp, 0))
free (newp);
}
}
else
{
(*foundp)->counter = _nl_msg_cat_cntr;
(*foundp)->domain = domain;
(*foundp)->translation = retval;
(*foundp)->translation_length = retlen;
}
__set_errno (saved_errno);
if (plural)
retval = plural_lookup (domain, n, retval, retlen);
gl_rwlock_unlock (_nl_state_lock);
#ifdef _LIBC
__libc_rwlock_unlock (__libc_setlocale_lock);
#endif
return retval;
}
}
}
return_untranslated:
FREE_BLOCKS (block_list);
gl_rwlock_unlock (_nl_state_lock);
#ifdef _LIBC
__libc_rwlock_unlock (__libc_setlocale_lock);
#endif
#ifndef _LIBC
if (!ENABLE_SECURE)
{
extern void _nl_log_untranslated (const char *logfilename,
const char *domainname,
const char *msgid1, const char *msgid2,
int plural);
const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
if (logfilename != NULL && logfilename[0] != '\0')
_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
}
#endif
__set_errno (saved_errno);
return (plural == 0
? (char *) msgid1
: n == 1 ? (char *) msgid1 : (char *) msgid2);
}
#ifdef _LIBC
__libc_lock_define_initialized (static, lock)
#endif
char *
internal_function
#ifdef IN_LIBGLOCALE
_nl_find_msg (struct loaded_l10nfile *domain_file,
struct binding *domainbinding, const char *encoding,
const char *msgid,
size_t *lengthp)
#else
_nl_find_msg (struct loaded_l10nfile *domain_file,
struct binding *domainbinding,
const char *msgid, int convert,
size_t *lengthp)
#endif
{
struct loaded_domain *domain;
nls_uint32 nstrings;
size_t act;
char *result;
size_t resultlen;
if (domain_file->decided <= 0)
_nl_load_domain (domain_file, domainbinding);
if (domain_file->data == NULL)
return NULL;
domain = (struct loaded_domain *) domain_file->data;
nstrings = domain->nstrings;
if (domain->hash_tab != NULL)
{
nls_uint32 len = strlen (msgid);
nls_uint32 hash_val = __hash_string (msgid);
nls_uint32 idx = hash_val % domain->hash_size;
nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
while (1)
{
nls_uint32 nstr =
W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
if (nstr == 0)
return NULL;
nstr--;
if (nstr < nstrings
? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
&& (strcmp (msgid,
domain->data + W (domain->must_swap,
domain->orig_tab[nstr].offset))
== 0)
: domain->orig_sysdep_tab[nstr - nstrings].length > len
&& (strcmp (msgid,
domain->orig_sysdep_tab[nstr - nstrings].pointer)
== 0))
{
act = nstr;
goto found;
}
if (idx >= domain->hash_size - incr)
idx -= domain->hash_size - incr;
else
idx += incr;
}
}
else
{
size_t top, bottom;
bottom = 0;
top = nstrings;
while (bottom < top)
{
int cmp_val;
act = (bottom + top) / 2;
cmp_val = strcmp (msgid, (domain->data
+ W (domain->must_swap,
domain->orig_tab[act].offset)));
if (cmp_val < 0)
top = act;
else if (cmp_val > 0)
bottom = act + 1;
else
goto found;
}
return NULL;
}
found:
if (act < nstrings)
{
result = (char *)
(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
}
else
{
result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
resultlen = domain->trans_sysdep_tab[act - nstrings].length;
}
#if defined _LIBC || HAVE_ICONV
# ifdef IN_LIBGLOCALE
if (encoding != NULL)
# else
if (convert)
# endif
{
# ifndef IN_LIBGLOCALE
const char *encoding = get_output_charset (domainbinding);
# endif
size_t nconversions;
struct converted_domain *convd;
size_t i;
gl_rwlock_rdlock (domain->conversions_lock);
nconversions = domain->nconversions;
convd = NULL;
for (i = nconversions; i > 0; )
{
i--;
if (strcmp (domain->conversions[i].encoding, encoding) == 0)
{
convd = &domain->conversions[i];
break;
}
}
gl_rwlock_unlock (domain->conversions_lock);
if (convd == NULL)
{
gl_rwlock_wrlock (domain->conversions_lock);
nconversions = domain->nconversions;
for (i = nconversions; i > 0; )
{
i--;
if (strcmp (domain->conversions[i].encoding, encoding) == 0)
{
convd = &domain->conversions[i];
goto found_convd;
}
}
{
struct converted_domain *new_conversions =
(struct converted_domain *)
(domain->conversions != NULL
? realloc (domain->conversions,
(nconversions + 1) * sizeof (struct converted_domain))
: malloc ((nconversions + 1) * sizeof (struct converted_domain)));
if (__builtin_expect (new_conversions == NULL, 0))
{
unlock_fail:
gl_rwlock_unlock (domain->conversions_lock);
return (char *) -1;
}
domain->conversions = new_conversions;
encoding = strdup (encoding);
if (__builtin_expect (encoding == NULL, 0))
goto unlock_fail;
convd = &new_conversions[nconversions];
convd->encoding = encoding;
# ifdef _LIBC
convd->conv = (__gconv_t) -1;
# else
# if HAVE_ICONV
convd->conv = (iconv_t) -1;
# endif
# endif
{
char *nullentry;
size_t nullentrylen;
nullentry =
# ifdef IN_LIBGLOCALE
_nl_find_msg (domain_file, domainbinding, NULL, "",
&nullentrylen);
# else
_nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
# endif
if (__builtin_expect (nullentry == (char *) -1, 0))
{
# ifndef IN_LIBGLOCALE
free ((char *) encoding);
# endif
goto unlock_fail;
}
if (nullentry != NULL)
{
const char *charsetstr;
charsetstr = strstr (nullentry, "charset=");
if (charsetstr != NULL)
{
size_t len;
char *charset;
const char *outcharset;
charsetstr += strlen ("charset=");
len = strcspn (charsetstr, " \t\n");
charset = (char *) alloca (len + 1);
# if defined _LIBC || HAVE_MEMPCPY
*((char *) mempcpy (charset, charsetstr, len)) = '\0';
# else
memcpy (charset, charsetstr, len);
charset[len] = '\0';
# endif
outcharset = encoding;
# ifdef _LIBC
outcharset = norm_add_slashes (outcharset, "TRANSLIT");
charset = norm_add_slashes (charset, "");
int r = __gconv_open (outcharset, charset, &convd->conv,
GCONV_AVOID_NOCONV);
if (__builtin_expect (r != __GCONV_OK, 0))
{
if (__builtin_expect (r != __GCONV_NULCONV, 1))
{
gl_rwlock_unlock (domain->conversions_lock);
free ((char *) encoding);
return NULL;
}
convd->conv = (__gconv_t) -1;
}
# else
# if HAVE_ICONV
# if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \
&& !defined __UCLIBC__) \
|| _LIBICONV_VERSION >= 0x0105
if (strchr (outcharset, '/') == NULL)
{
char *tmp;
len = strlen (outcharset);
tmp = (char *) alloca (len + 10 + 1);
memcpy (tmp, outcharset, len);
memcpy (tmp + len, "//TRANSLIT", 10 + 1);
outcharset = tmp;
convd->conv = iconv_open (outcharset, charset);
freea (outcharset);
}
else
# endif
convd->conv = iconv_open (outcharset, charset);
# endif
# endif
freea (charset);
}
}
}
convd->conv_tab = NULL;
domain->nconversions++;
}
found_convd:
gl_rwlock_unlock (domain->conversions_lock);
}
if (
# ifdef _LIBC
convd->conv != (__gconv_t) -1
# else
# if HAVE_ICONV
convd->conv != (iconv_t) -1
# endif
# endif
)
{
if (__builtin_expect (convd->conv_tab == NULL, 0))
{
#ifdef _LIBC
__libc_lock_lock (lock);
#endif
if (convd->conv_tab == NULL)
{
convd->conv_tab =
(char **) calloc (nstrings + domain->n_sysdep_strings,
sizeof (char *));
if (convd->conv_tab != NULL)
goto not_translated_yet;
convd->conv_tab = (char **) -1;
}
#ifdef _LIBC
__libc_lock_unlock (lock);
#endif
}
if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
return (char *) -1;
if (convd->conv_tab[act] == NULL)
{
# define INITIAL_BLOCK_SIZE 4080
static unsigned char *freemem;
static size_t freemem_size;
const unsigned char *inbuf;
unsigned char *outbuf;
int malloc_count;
# ifndef _LIBC
transmem_block_t *transmem_list;
# endif
#ifdef _LIBC
__libc_lock_lock (lock);
#endif
not_translated_yet:
inbuf = (const unsigned char *) result;
outbuf = freemem + sizeof (size_t);
# ifndef _LIBC
transmem_list = NULL;
# endif
malloc_count = 0;
while (1)
{
transmem_block_t *newmem;
# ifdef _LIBC
size_t non_reversible;
int res;
if (freemem_size < sizeof (size_t))
goto resize_freemem;
res = __gconv (convd->conv,
&inbuf, inbuf + resultlen,
&outbuf,
outbuf + freemem_size - sizeof (size_t),
&non_reversible);
if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
break;
if (res != __GCONV_FULL_OUTPUT)
{
#ifdef _LIBC
__libc_lock_unlock (lock);
#endif
return NULL;
}
inbuf = (const unsigned char *) result;
# else
# if HAVE_ICONV
const char *inptr = (const char *) inbuf;
size_t inleft = resultlen;
char *outptr = (char *) outbuf;
size_t outleft;
if (freemem_size < sizeof (size_t))
goto resize_freemem;
outleft = freemem_size - sizeof (size_t);
if (iconv (convd->conv,
(ICONV_CONST char **) &inptr, &inleft,
&outptr, &outleft)
!= (size_t) (-1))
{
outbuf = (unsigned char *) outptr;
break;
}
if (errno != E2BIG)
{
#ifdef _LIBC
__libc_lock_unlock (lock);
#endif
return NULL;
}
# endif
# endif
resize_freemem:
if (malloc_count > 0)
{
++malloc_count;
freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
newmem = (transmem_block_t *) realloc (transmem_list,
freemem_size);
# ifdef _LIBC
if (newmem != NULL)
transmem_list = newmem;
else
{
struct transmem_list *old = transmem_list;
transmem_list = transmem_list->next;
free (old);
}
# endif
}
else
{
malloc_count = 1;
freemem_size = INITIAL_BLOCK_SIZE;
newmem = (transmem_block_t *) malloc (freemem_size);
# ifdef _LIBC
if (newmem != NULL)
{
newmem->next = transmem_list;
transmem_list = newmem;
}
# endif
}
if (__builtin_expect (newmem == NULL, 0))
{
freemem = NULL;
freemem_size = 0;
#ifdef _LIBC
__libc_lock_unlock (lock);
#endif
return (char *) -1;
}
# ifdef _LIBC
freemem = (unsigned char *) newmem->data;
freemem_size -= offsetof (struct transmem_list, data);
# else
transmem_list = newmem;
freemem = newmem;
# endif
outbuf = freemem + sizeof (size_t);
}
*(size_t *) freemem = outbuf - freemem - sizeof (size_t);
convd->conv_tab[act] = (char *) freemem;
freemem_size -= outbuf - freemem;
freemem = outbuf;
freemem += freemem_size & (alignof (size_t) - 1);
freemem_size = freemem_size & ~ (alignof (size_t) - 1);
#ifdef _LIBC
__libc_lock_unlock (lock);
#endif
}
result = convd->conv_tab[act] + sizeof (size_t);
resultlen = *(size_t *) convd->conv_tab[act];
}
}
#endif
*lengthp = resultlen;
return result;
}
static char *
internal_function
plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
const char *translation, size_t translation_len)
{
struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
unsigned long int index;
const char *p;
index = plural_eval (domaindata->plural, n);
if (index >= domaindata->nplurals)
index = 0;
p = translation;
while (index-- > 0)
{
#ifdef _LIBC
p = __rawmemchr (p, '\0');
#else
p = strchr (p, '\0');
#endif
p++;
if (p >= translation + translation_len)
return (char *) translation;
}
return (char *) p;
}
#ifndef _LIBC
static const char *
internal_function
category_to_name (int category)
{
const char *retval;
switch (category)
{
#ifdef LC_COLLATE
case LC_COLLATE:
retval = "LC_COLLATE";
break;
#endif
#ifdef LC_CTYPE
case LC_CTYPE:
retval = "LC_CTYPE";
break;
#endif
#ifdef LC_MONETARY
case LC_MONETARY:
retval = "LC_MONETARY";
break;
#endif
#ifdef LC_NUMERIC
case LC_NUMERIC:
retval = "LC_NUMERIC";
break;
#endif
#ifdef LC_TIME
case LC_TIME:
retval = "LC_TIME";
break;
#endif
#ifdef LC_MESSAGES
case LC_MESSAGES:
retval = "LC_MESSAGES";
break;
#endif
#ifdef LC_RESPONSE
case LC_RESPONSE:
retval = "LC_RESPONSE";
break;
#endif
#ifdef LC_ALL
case LC_ALL:
retval = "LC_ALL";
break;
#endif
default:
retval = "LC_XXX";
}
return retval;
}
#endif
static const char *
internal_function
#ifdef IN_LIBGLOCALE
guess_category_value (int category, const char *categoryname,
const char *locale)
#else
guess_category_value (int category, const char *categoryname)
#endif
{
const char *language;
#ifndef IN_LIBGLOCALE
const char *locale;
# ifndef _LIBC
const char *language_default;
int locale_defaulted;
# endif
#endif
#ifndef IN_LIBGLOCALE
# ifdef _LIBC
locale = __current_locale_name (category);
# else
locale_defaulted = 0;
# if HAVE_USELOCALE
locale = _nl_locale_name_thread_unsafe (category, categoryname);
if (locale == NULL)
# endif
{
locale = _nl_locale_name_posix (category, categoryname);
if (locale == NULL)
{
locale = _nl_locale_name_default ();
locale_defaulted = 1;
}
}
# endif
#endif
if (strcmp (locale, "C") == 0)
return locale;
language = getenv ("LANGUAGE");
if (language != NULL && language[0] != '\0')
return language;
#if !defined IN_LIBGLOCALE && !defined _LIBC
if (locale_defaulted)
{
language_default = _nl_language_preferences_default ();
if (language_default != NULL)
return language_default;
}
#endif
return locale;
}
#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
static const char *
internal_function
get_output_charset (struct binding *domainbinding)
{
if (domainbinding != NULL && domainbinding->codeset != NULL)
return domainbinding->codeset;
else
{
static char *output_charset_cache;
static int output_charset_cached;
if (!output_charset_cached)
{
const char *value = getenv ("OUTPUT_CHARSET");
if (value != NULL && value[0] != '\0')
{
size_t len = strlen (value) + 1;
char *value_copy = (char *) malloc (len);
if (value_copy != NULL)
memcpy (value_copy, value, len);
output_charset_cache = value_copy;
}
output_charset_cached = 1;
}
if (output_charset_cache != NULL)
return output_charset_cache;
else
{
# ifdef _LIBC
return _NL_CURRENT (LC_CTYPE, CODESET);
# else
# if HAVE_ICONV
return locale_charset ();
# endif
# endif
}
}
}
#endif
#if !_LIBC && !HAVE_STPCPY
static char *
stpcpy (char *dest, const char *src)
{
while ((*dest++ = *src++) != '\0')
;
return dest - 1;
}
#endif
#if !_LIBC && !HAVE_MEMPCPY
static void *
mempcpy (void *dest, const void *src, size_t n)
{
return (void *) ((char *) memcpy (dest, src, n) + n);
}
#endif
#if !_LIBC && !HAVE_TSEARCH
# include "tsearch.c"
#endif
#ifdef _LIBC
libc_freeres_fn (free_mem)
{
void *old;
while (_nl_domain_bindings != NULL)
{
struct binding *oldp = _nl_domain_bindings;
_nl_domain_bindings = _nl_domain_bindings->next;
if (oldp->dirname != _nl_default_dirname)
free (oldp->dirname);
free (oldp->codeset);
free (oldp);
}
if (_nl_current_default_domain != _nl_default_default_domain)
free ((char *) _nl_current_default_domain);
__tdestroy (root, free);
root = NULL;
while (transmem_list != NULL)
{
old = transmem_list;
transmem_list = transmem_list->next;
free (old);
}
}
#endif