Blame intl/dcigettext.c

Packit Service 82fcde
/* Implementation of the internal dcigettext function.
Packit Service 82fcde
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
Packit Service 82fcde
   This program is free software: you can redistribute it and/or modify
Packit Service 82fcde
   it under the terms of the GNU Lesser General Public License as published by
Packit Service 82fcde
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service 82fcde
   (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   This program is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 82fcde
   GNU Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public License
Packit Service 82fcde
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
/* Tell glibc's <string.h> to provide a prototype for mempcpy().
Packit Service 82fcde
   This must come before <config.h> because <config.h> may include
Packit Service 82fcde
   <features.h>, and once <features.h> has been included, it's too late.  */
Packit Service 82fcde
#ifndef _GNU_SOURCE
Packit Service 82fcde
# define _GNU_SOURCE	1
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef HAVE_CONFIG_H
Packit Service 82fcde
# include <config.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
Packit Service 82fcde
#ifdef __GNUC__
Packit Service 82fcde
# define alloca __builtin_alloca
Packit Service 82fcde
# define HAVE_ALLOCA 1
Packit Service 82fcde
#else
Packit Service 82fcde
# ifdef _MSC_VER
Packit Service 82fcde
#  include <malloc.h>
Packit Service 82fcde
#  define alloca _alloca
Packit Service 82fcde
# else
Packit Service 82fcde
#  if defined HAVE_ALLOCA_H || defined _LIBC
Packit Service 82fcde
#   include <alloca.h>
Packit Service 82fcde
#  else
Packit Service 82fcde
#   ifdef _AIX
Packit Service 82fcde
 #pragma alloca
Packit Service 82fcde
#   else
Packit Service 82fcde
#    ifndef alloca
Packit Service 82fcde
char *alloca ();
Packit Service 82fcde
#    endif
Packit Service 82fcde
#   endif
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#ifndef errno
Packit Service 82fcde
extern int errno;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifndef __set_errno
Packit Service 82fcde
# define __set_errno(val) errno = (val)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
Packit Service 82fcde
#if defined HAVE_UNISTD_H || defined _LIBC
Packit Service 82fcde
# include <unistd.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include <locale.h>
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  /* Guess whether integer division by zero raises signal SIGFPE.
Packit Service 82fcde
     Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
Packit Service 82fcde
# if defined __alpha__ || defined __arm__ || defined __i386__ \
Packit Service 82fcde
     || defined __m68k__ || defined __s390__
Packit Service 82fcde
#  define INTDIV0_RAISES_SIGFPE 1
Packit Service 82fcde
# else
Packit Service 82fcde
#  define INTDIV0_RAISES_SIGFPE 0
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
#if !INTDIV0_RAISES_SIGFPE
Packit Service 82fcde
# include <signal.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if defined HAVE_SYS_PARAM_H || defined _LIBC
Packit Service 82fcde
# include <sys/param.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !defined _LIBC
Packit Service 82fcde
# include "localcharset.h"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include "gettextP.h"
Packit Service 82fcde
#include "plural-exp.h"
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# include <libintl.h>
Packit Service 82fcde
#else
Packit Service 82fcde
# ifdef IN_LIBGLOCALE
Packit Service 82fcde
#  include <libintl.h>
Packit Service 82fcde
# endif
Packit Service 82fcde
# include "libgnuintl.h"
Packit Service 82fcde
#endif
Packit Service 82fcde
#include "hash-string.h"
Packit Service 82fcde
Packit Service 82fcde
/* Handle multi-threaded applications.  */
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# include <libc-lock.h>
Packit Service 82fcde
# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
Packit Service 82fcde
# define gl_rwlock_rdlock __libc_rwlock_rdlock
Packit Service 82fcde
# define gl_rwlock_wrlock __libc_rwlock_wrlock
Packit Service 82fcde
# define gl_rwlock_unlock __libc_rwlock_unlock
Packit Service 82fcde
#else
Packit Service 82fcde
# include "lock.h"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Alignment of types.  */
Packit Service 82fcde
#if defined __GNUC__ && __GNUC__ >= 2
Packit Service 82fcde
# define alignof(TYPE) __alignof__ (TYPE)
Packit Service 82fcde
#else
Packit Service 82fcde
# define alignof(TYPE) \
Packit Service 82fcde
    ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
Packit Service 82fcde
#ifndef offsetof
Packit Service 82fcde
# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* @@ end of prolog @@ */
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
/* Rename the non ANSI C functions.  This is required by the standard
Packit Service 82fcde
   because some ANSI C functions will require linking with this object
Packit Service 82fcde
   file and the name space must not be polluted.  */
Packit Service 82fcde
# define strdup __strdup
Packit Service 82fcde
# define getcwd __getcwd
Packit Service 82fcde
# ifndef stpcpy
Packit Service 82fcde
#  define stpcpy __stpcpy
Packit Service 82fcde
# endif
Packit Service 82fcde
# define tfind __tfind
Packit Service 82fcde
#else
Packit Service 82fcde
# if !defined HAVE_GETCWD
Packit Service 82fcde
char *getwd ();
Packit Service 82fcde
#  define getcwd(buf, max) getwd (buf)
Packit Service 82fcde
# else
Packit Service 82fcde
#  if VMS
Packit Service 82fcde
#   define getcwd(buf, max) (getcwd) (buf, max, 0)
Packit Service 82fcde
#  else
Packit Service 82fcde
char *getcwd ();
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
# ifndef HAVE_STPCPY
Packit Service 82fcde
static char *stpcpy (char *dest, const char *src);
Packit Service 82fcde
# endif
Packit Service 82fcde
# ifndef HAVE_MEMPCPY
Packit Service 82fcde
static void *mempcpy (void *dest, const void *src, size_t n);
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Use a replacement if the system does not provide the `tsearch' function
Packit Service 82fcde
   family.  */
Packit Service 82fcde
#if defined HAVE_TSEARCH || defined _LIBC
Packit Service 82fcde
# include <search.h>
Packit Service 82fcde
#else
Packit Service 82fcde
# define tsearch libintl_tsearch
Packit Service 82fcde
# define tfind libintl_tfind
Packit Service 82fcde
# define tdelete libintl_tdelete
Packit Service 82fcde
# define twalk libintl_twalk
Packit Service 82fcde
# include "tsearch.h"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# define tsearch __tsearch
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Amount to increase buffer size by in each try.  */
Packit Service 82fcde
#define PATH_INCR 32
Packit Service 82fcde
Packit Service 82fcde
/* The following is from pathmax.h.  */
Packit Service 82fcde
/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
Packit Service 82fcde
   PATH_MAX but might cause redefinition warnings when sys/param.h is
Packit Service 82fcde
   later included (as on MORE/BSD 4.3).  */
Packit Service 82fcde
#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
Packit Service 82fcde
# include <limits.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef _POSIX_PATH_MAX
Packit Service 82fcde
# define _POSIX_PATH_MAX 255
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !defined PATH_MAX && defined _PC_PATH_MAX
Packit Service 82fcde
# define PATH_MAX (__pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : __pathconf ("/", _PC_PATH_MAX))
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Don't include sys/param.h if it already has been.  */
Packit Service 82fcde
#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
Packit Service 82fcde
# include <sys/param.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !defined PATH_MAX && defined MAXPATHLEN
Packit Service 82fcde
# define PATH_MAX MAXPATHLEN
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef PATH_MAX
Packit Service 82fcde
# define PATH_MAX _POSIX_PATH_MAX
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Pathname support.
Packit Service 82fcde
   ISSLASH(C)           tests whether C is a directory separator character.
Packit Service 82fcde
   IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
Packit Service 82fcde
                        it may be concatenated to a directory pathname.
Packit Service 82fcde
   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
Packit Service 82fcde
 */
Packit Service 82fcde
#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
Packit Service 82fcde
  /* Win32, Cygwin, OS/2, DOS */
Packit Service 82fcde
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
Packit Service 82fcde
# define HAS_DEVICE(P) \
Packit Service 82fcde
    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
Packit Service 82fcde
     && (P)[1] == ':')
Packit Service 82fcde
# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
Packit Service 82fcde
# define IS_PATH_WITH_DIR(P) \
Packit Service 82fcde
    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
Packit Service 82fcde
#else
Packit Service 82fcde
  /* Unix */
Packit Service 82fcde
# define ISSLASH(C) ((C) == '/')
Packit Service 82fcde
# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
Packit Service 82fcde
# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Whether to support different locales in different threads.  */
Packit Service 82fcde
#if defined _LIBC || HAVE_USELOCALE || defined IN_LIBGLOCALE
Packit Service 82fcde
# define HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* This is the type used for the search tree where known translations
Packit Service 82fcde
   are stored.  */
Packit Service 82fcde
struct known_translation_t
Packit Service 82fcde
{
Packit Service 82fcde
  /* Domain in which to search.  */
Packit Service 82fcde
  const char *domainname;
Packit Service 82fcde
Packit Service 82fcde
  /* The category.  */
Packit Service 82fcde
  int category;
Packit Service 82fcde
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
  /* Name of the relevant locale category, or "" for the global locale.  */
Packit Service 82fcde
  const char *localename;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
  /* The character encoding.  */
Packit Service 82fcde
  const char *encoding;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* State of the catalog counter at the point the string was found.  */
Packit Service 82fcde
  int counter;
Packit Service 82fcde
Packit Service 82fcde
  /* Catalog where the string was found.  */
Packit Service 82fcde
  struct loaded_l10nfile *domain;
Packit Service 82fcde
Packit Service 82fcde
  /* And finally the translation.  */
Packit Service 82fcde
  const char *translation;
Packit Service 82fcde
  size_t translation_length;
Packit Service 82fcde
Packit Service 82fcde
  /* Pointer to the string in question.  */
Packit Service 82fcde
  union
Packit Service 82fcde
    {
Packit Service 82fcde
      char appended[ZERO];  /* used if domain != NULL */
Packit Service 82fcde
      const char *ptr;      /* used if domain == NULL */
Packit Service 82fcde
    }
Packit Service 82fcde
  msgid;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
gl_rwlock_define_initialized (static, tree_lock)
Packit Service 82fcde
Packit Service 82fcde
/* Root of the search tree with known translations.  */
Packit Service 82fcde
static void *root;
Packit Service 82fcde
Packit Service 82fcde
/* Function to compare two entries in the table of known translations.  */
Packit Service 82fcde
static int
Packit Service 82fcde
transcmp (const void *p1, const void *p2)
Packit Service 82fcde
{
Packit Service 82fcde
  const struct known_translation_t *s1;
Packit Service 82fcde
  const struct known_translation_t *s2;
Packit Service 82fcde
  int result;
Packit Service 82fcde
Packit Service 82fcde
  s1 = (const struct known_translation_t *) p1;
Packit Service 82fcde
  s2 = (const struct known_translation_t *) p2;
Packit Service 82fcde
Packit Service 82fcde
  result = strcmp (s1->domain != NULL ? s1->msgid.appended : s1->msgid.ptr,
Packit Service 82fcde
		   s2->domain != NULL ? s2->msgid.appended : s2->msgid.ptr);
Packit Service 82fcde
  if (result == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      result = strcmp (s1->domainname, s2->domainname);
Packit Service 82fcde
      if (result == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
	  result = strcmp (s1->localename, s2->localename);
Packit Service 82fcde
	  if (result == 0)
Packit Service 82fcde
#endif
Packit Service 82fcde
	    {
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
	      result = strcmp (s1->encoding, s2->encoding);
Packit Service 82fcde
	      if (result == 0)
Packit Service 82fcde
#endif
Packit Service 82fcde
		/* We compare the category last (though this is the cheapest
Packit Service 82fcde
		   operation) since it is hopefully always the same (namely
Packit Service 82fcde
		   LC_MESSAGES).  */
Packit Service 82fcde
		result = s1->category - s2->category;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Name of the default domain used for gettext(3) prior any call to
Packit Service 82fcde
   textdomain(3).  The default value for this is "messages".  */
Packit Service 82fcde
const char _nl_default_default_domain[] attribute_hidden = "messages";
Packit Service 82fcde
Packit Service 82fcde
#ifndef IN_LIBGLOCALE
Packit Service 82fcde
/* Value used as the default domain for gettext(3).  */
Packit Service 82fcde
const char *_nl_current_default_domain attribute_hidden
Packit Service 82fcde
     = _nl_default_default_domain;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Contains the default location of the message catalogs.  */
Packit Service 82fcde
#if defined __EMX__
Packit Service 82fcde
extern const char _nl_default_dirname[];
Packit Service 82fcde
#else
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
extern const char _nl_default_dirname[];
Packit Service 82fcde
libc_hidden_proto (_nl_default_dirname)
Packit Service 82fcde
# endif
Packit Service 82fcde
const char _nl_default_dirname[] = LOCALEDIR;
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
libc_hidden_data_def (_nl_default_dirname)
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifndef IN_LIBGLOCALE
Packit Service 82fcde
/* List with bindings of specific domains created by bindtextdomain()
Packit Service 82fcde
   calls.  */
Packit Service 82fcde
struct binding *_nl_domain_bindings;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Prototypes for local functions.  */
Packit Service 82fcde
static char *plural_lookup (struct loaded_l10nfile *domain,
Packit Service 82fcde
			    unsigned long int n,
Packit Service 82fcde
			    const char *translation, size_t translation_len);
Packit Service 82fcde
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
static const char *guess_category_value (int category,
Packit Service 82fcde
					 const char *categoryname,
Packit Service 82fcde
					 const char *localename);
Packit Service 82fcde
#else
Packit Service 82fcde
static const char *guess_category_value (int category,
Packit Service 82fcde
					 const char *categoryname);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# include "../locale/localeinfo.h"
Packit Service 82fcde
# define category_to_name(category) \
Packit Service 82fcde
  _nl_category_names.str + _nl_category_name_idxs[category]
Packit Service 82fcde
#else
Packit Service 82fcde
static const char *category_to_name (int category);
Packit Service 82fcde
#endif
Packit Service 82fcde
#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
Packit Service 82fcde
static const char *get_output_charset (struct binding *domainbinding);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* For those losing systems which don't have `alloca' we have to add
Packit Service 82fcde
   some additional code emulating it.  */
Packit Service 82fcde
#ifdef HAVE_ALLOCA
Packit Service 82fcde
/* Nothing has to be done.  */
Packit Service 82fcde
# define freea(p) /* nothing */
Packit Service 82fcde
# define ADD_BLOCK(list, address) /* nothing */
Packit Service 82fcde
# define FREE_BLOCKS(list) /* nothing */
Packit Service 82fcde
#else
Packit Service 82fcde
struct block_list
Packit Service 82fcde
{
Packit Service 82fcde
  void *address;
Packit Service 82fcde
  struct block_list *next;
Packit Service 82fcde
};
Packit Service 82fcde
# define ADD_BLOCK(list, addr)						      \
Packit Service 82fcde
  do {									      \
Packit Service 82fcde
    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
Packit Service 82fcde
    /* If we cannot get a free block we cannot add the new element to	      \
Packit Service 82fcde
       the list.  */							      \
Packit Service 82fcde
    if (newp != NULL) {							      \
Packit Service 82fcde
      newp->address = (addr);						      \
Packit Service 82fcde
      newp->next = (list);						      \
Packit Service 82fcde
      (list) = newp;							      \
Packit Service 82fcde
    }									      \
Packit Service 82fcde
  } while (0)
Packit Service 82fcde
# define FREE_BLOCKS(list)						      \
Packit Service 82fcde
  do {									      \
Packit Service 82fcde
    while (list != NULL) {						      \
Packit Service 82fcde
      struct block_list *old = list;					      \
Packit Service 82fcde
      list = list->next;						      \
Packit Service 82fcde
      free (old->address);						      \
Packit Service 82fcde
      free (old);							      \
Packit Service 82fcde
    }									      \
Packit Service 82fcde
  } while (0)
Packit Service 82fcde
# undef alloca
Packit Service 82fcde
# define alloca(size) (malloc (size))
Packit Service 82fcde
# define freea(p) free (p)
Packit Service 82fcde
#endif	/* have alloca */
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
/* List of blocks allocated for translations.  */
Packit Service 82fcde
typedef struct transmem_list
Packit Service 82fcde
{
Packit Service 82fcde
  struct transmem_list *next;
Packit Service 82fcde
  char data[ZERO];
Packit Service 82fcde
} transmem_block_t;
Packit Service 82fcde
static struct transmem_list *transmem_list;
Packit Service 82fcde
#else
Packit Service 82fcde
typedef unsigned char transmem_block_t;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Names for the libintl functions are a problem.  They must not clash
Packit Service 82fcde
   with existing names and they should follow ANSI C.  But this source
Packit Service 82fcde
   code is also used in GNU C Library where the names have a __
Packit Service 82fcde
   prefix.  So we have to make a difference here.  */
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# define DCIGETTEXT __dcigettext
Packit Service 82fcde
#else
Packit Service 82fcde
# define DCIGETTEXT libintl_dcigettext
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Lock variable to protect the global data in the gettext implementation.  */
Packit Service 82fcde
gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
Packit Service 82fcde
Packit Service 82fcde
/* Checking whether the binaries runs SUID must be done and glibc provides
Packit Service 82fcde
   easier methods therefore we make a difference here.  */
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
# define ENABLE_SECURE __libc_enable_secure
Packit Service 82fcde
# define DETERMINE_SECURE
Packit Service 82fcde
#else
Packit Service 82fcde
# ifndef HAVE_GETUID
Packit Service 82fcde
#  define getuid() 0
Packit Service 82fcde
# endif
Packit Service 82fcde
# ifndef HAVE_GETGID
Packit Service 82fcde
#  define getgid() 0
Packit Service 82fcde
# endif
Packit Service 82fcde
# ifndef HAVE_GETEUID
Packit Service 82fcde
#  define geteuid() getuid()
Packit Service 82fcde
# endif
Packit Service 82fcde
# ifndef HAVE_GETEGID
Packit Service 82fcde
#  define getegid() getgid()
Packit Service 82fcde
# endif
Packit Service 82fcde
static int enable_secure;
Packit Service 82fcde
# define ENABLE_SECURE (enable_secure == 1)
Packit Service 82fcde
# define DETERMINE_SECURE \
Packit Service 82fcde
  if (enable_secure == 0)						      \
Packit Service 82fcde
    {									      \
Packit Service 82fcde
      if (getuid () != geteuid () || getgid () != getegid ())		      \
Packit Service 82fcde
	enable_secure = 1;						      \
Packit Service 82fcde
      else								      \
Packit Service 82fcde
	enable_secure = -1;						      \
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Get the function to evaluate the plural expression.  */
Packit Service 82fcde
#include "eval-plural.h"
Packit Service 82fcde
Packit Service 82fcde
/* Look up MSGID in the DOMAINNAME message catalog for the current
Packit Service 82fcde
   CATEGORY locale and, if PLURAL is nonzero, search over string
Packit Service 82fcde
   depending on the plural form determined by N.  */
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
char *
Packit Service 82fcde
gl_dcigettext (const char *domainname,
Packit Service 82fcde
	       const char *msgid1, const char *msgid2,
Packit Service 82fcde
	       int plural, unsigned long int n,
Packit Service 82fcde
	       int category,
Packit Service 82fcde
	       const char *localename, const char *encoding)
Packit Service 82fcde
#else
Packit Service 82fcde
char *
Packit Service 82fcde
DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
Packit Service 82fcde
	    int plural, unsigned long int n, int category)
Packit Service 82fcde
#endif
Packit Service 82fcde
{
Packit Service 82fcde
#ifndef HAVE_ALLOCA
Packit Service 82fcde
  struct block_list *block_list = NULL;
Packit Service 82fcde
#endif
Packit Service 82fcde
  struct loaded_l10nfile *domain;
Packit Service 82fcde
  struct binding *binding;
Packit Service 82fcde
  const char *categoryname;
Packit Service 82fcde
  const char *categoryvalue;
Packit Service 82fcde
  const char *dirname;
Packit Service 82fcde
  char *xdirname = NULL;
Packit Service 82fcde
  char *xdomainname;
Packit Service 82fcde
  char *single_locale;
Packit Service 82fcde
  char *retval;
Packit Service 82fcde
  size_t retlen;
Packit Service 82fcde
  int saved_errno;
Packit Service 82fcde
  struct known_translation_t search;
Packit Service 82fcde
  struct known_translation_t **foundp = NULL;
Packit Service 82fcde
#if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
Packit Service 82fcde
  const char *localename;
Packit Service 82fcde
#endif
Packit Service 82fcde
  size_t domainname_len;
Packit Service 82fcde
Packit Service 82fcde
  /* If no real MSGID is given return NULL.  */
Packit Service 82fcde
  if (msgid1 == NULL)
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  if (category < 0 || category >= __LC_LAST || category == LC_ALL)
Packit Service 82fcde
    /* Bogus.  */
Packit Service 82fcde
    return (plural == 0
Packit Service 82fcde
	    ? (char *) msgid1
Packit Service 82fcde
	    /* Use the Germanic plural rule.  */
Packit Service 82fcde
	    : n == 1 ? (char *) msgid1 : (char *) msgid2);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Preserve the `errno' value.  */
Packit Service 82fcde
  saved_errno = errno;
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
Packit Service 82fcde
  __libc_rwlock_rdlock (__libc_setlocale_lock);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  gl_rwlock_rdlock (_nl_state_lock);
Packit Service 82fcde
Packit Service 82fcde
  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
Packit Service 82fcde
     CATEGORY is not LC_MESSAGES this might not make much sense but the
Packit Service 82fcde
     definition left this undefined.  */
Packit Service 82fcde
  if (domainname == NULL)
Packit Service 82fcde
    domainname = _nl_current_default_domain;
Packit Service 82fcde
Packit Service 82fcde
  /* OS/2 specific: backward compatibility with older libintl versions  */
Packit Service 82fcde
#ifdef LC_MESSAGES_COMPAT
Packit Service 82fcde
  if (category == LC_MESSAGES_COMPAT)
Packit Service 82fcde
    category = LC_MESSAGES;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Try to find the translation among those which we found at
Packit Service 82fcde
     some time.  */
Packit Service 82fcde
  search.domain = NULL;
Packit Service 82fcde
  search.msgid.ptr = msgid1;
Packit Service 82fcde
  search.domainname = domainname;
Packit Service 82fcde
  search.category = category;
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
# ifndef IN_LIBGLOCALE
Packit Service 82fcde
#  ifdef _LIBC
Packit Service 82fcde
  localename = __current_locale_name (category);
Packit Service 82fcde
#  else
Packit Service 82fcde
  categoryname = category_to_name (category);
Packit Service 82fcde
#   define CATEGORYNAME_INITIALIZED
Packit Service 82fcde
  localename = _nl_locale_name_thread_unsafe (category, categoryname);
Packit Service 82fcde
  if (localename == NULL)
Packit Service 82fcde
    localename = "";
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
  search.localename = localename;
Packit Service 82fcde
# ifdef IN_LIBGLOCALE
Packit Service 82fcde
  search.encoding = encoding;
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
  /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
Packit Service 82fcde
     tsearch calls can be fatal.  */
Packit Service 82fcde
  gl_rwlock_rdlock (tree_lock);
Packit Service 82fcde
Packit Service 82fcde
  foundp = (struct known_translation_t **) tfind (&search, &root, transcmp);
Packit Service 82fcde
Packit Service 82fcde
  gl_rwlock_unlock (tree_lock);
Packit Service 82fcde
Packit Service 82fcde
  if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Now deal with plural.  */
Packit Service 82fcde
      if (plural)
Packit Service 82fcde
	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
Packit Service 82fcde
				(*foundp)->translation_length);
Packit Service 82fcde
      else
Packit Service 82fcde
	retval = (char *) (*foundp)->translation;
Packit Service 82fcde
Packit Service 82fcde
      gl_rwlock_unlock (_nl_state_lock);
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
      __libc_rwlock_unlock (__libc_setlocale_lock);
Packit Service 82fcde
# endif
Packit Service 82fcde
      __set_errno (saved_errno);
Packit Service 82fcde
      return retval;
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* See whether this is a SUID binary or not.  */
Packit Service 82fcde
  DETERMINE_SECURE;
Packit Service 82fcde
Packit Service 82fcde
  /* First find matching binding.  */
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
  /* We can use a trivial binding, since _nl_find_msg will ignore it anyway,
Packit Service 82fcde
     and _nl_load_domain and _nl_find_domain just pass it through.  */
Packit Service 82fcde
  binding = NULL;
Packit Service 82fcde
  dirname = bindtextdomain (domainname, NULL);
Packit Service 82fcde
#else
Packit Service 82fcde
  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
Packit Service 82fcde
    {
Packit Service 82fcde
      int compare = strcmp (domainname, binding->domainname);
Packit Service 82fcde
      if (compare == 0)
Packit Service 82fcde
	/* We found it!  */
Packit Service 82fcde
	break;
Packit Service 82fcde
      if (compare < 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* It is not in the list.  */
Packit Service 82fcde
	  binding = NULL;
Packit Service 82fcde
	  break;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (binding == NULL)
Packit Service 82fcde
    dirname = _nl_default_dirname;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      dirname = binding->dirname;
Packit Service 82fcde
#endif
Packit Service 82fcde
      if (!IS_ABSOLUTE_PATH (dirname))
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We have a relative path.  Make it absolute now.  */
Packit Service 82fcde
	  char *cwd = getcwd (NULL, 0);
Packit Service 82fcde
	  if (cwd == NULL)
Packit Service 82fcde
	    /* We cannot get the current working directory.  Don't
Packit Service 82fcde
	       signal an error but simply return the default
Packit Service 82fcde
	       string.  */
Packit Service 82fcde
	    goto return_untranslated;
Packit Service 82fcde
	  int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname);
Packit Service 82fcde
	  free (cwd);
Packit Service 82fcde
	  if (ret < 0)
Packit Service 1c5418
	      return NULL;
Packit Service 82fcde
	  dirname = xdirname;
Packit Service 82fcde
	}
Packit Service 82fcde
#ifndef IN_LIBGLOCALE
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Now determine the symbolic name of CATEGORY and its value.  */
Packit Service 82fcde
#ifndef CATEGORYNAME_INITIALIZED
Packit Service 82fcde
  categoryname = category_to_name (category);
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
  categoryvalue = guess_category_value (category, categoryname, localename);
Packit Service 82fcde
#else
Packit Service 82fcde
  categoryvalue = guess_category_value (category, categoryname);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  domainname_len = strlen (domainname);
Packit Service 82fcde
  xdomainname = (char *) alloca (strlen (categoryname)
Packit Service 82fcde
				 + domainname_len + 5);
Packit Service 82fcde
  ADD_BLOCK (block_list, xdomainname);
Packit Service 82fcde
Packit Service 82fcde
  stpcpy ((char *) mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
Packit Service 82fcde
			    domainname, domainname_len),
Packit Service 82fcde
	  ".mo");
Packit Service 82fcde
Packit Service 82fcde
  /* Creating working area.  */
Packit Service 82fcde
  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
Packit Service 82fcde
  ADD_BLOCK (block_list, single_locale);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
  /* Search for the given string.  This is a loop because we perhaps
Packit Service 82fcde
     got an ordered list of languages to consider for the translation.  */
Packit Service 82fcde
  while (1)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Make CATEGORYVALUE point to the next element of the list.  */
Packit Service 82fcde
      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
Packit Service 82fcde
	++categoryvalue;
Packit Service 82fcde
      if (categoryvalue[0] == '\0')
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* The whole contents of CATEGORYVALUE has been searched but
Packit Service 82fcde
	     no valid entry has been found.  We solve this situation
Packit Service 82fcde
	     by implicitly appending a "C" entry, i.e. no translation
Packit Service 82fcde
	     will take place.  */
Packit Service 82fcde
	  single_locale[0] = 'C';
Packit Service 82fcde
	  single_locale[1] = '\0';
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  char *cp = single_locale;
Packit Service 82fcde
	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
Packit Service 82fcde
	    *cp++ = *categoryvalue++;
Packit Service 82fcde
	  *cp = '\0';
Packit Service 82fcde
Packit Service 82fcde
	  /* When this is a SUID binary we must not allow accessing files
Packit Service 82fcde
	     outside the dedicated directories.  */
Packit Service 82fcde
	  if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
Packit Service 82fcde
	    /* Ingore this entry.  */
Packit Service 82fcde
	    continue;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* If the current locale value is C (or POSIX) we don't load a
Packit Service 82fcde
	 domain.  Return the MSGID.  */
Packit Service 82fcde
      if (strcmp (single_locale, "C") == 0
Packit Service 82fcde
	  || strcmp (single_locale, "POSIX") == 0)
Packit Service 82fcde
	break;
Packit Service 82fcde
Packit Service 82fcde
      /* Find structure describing the message catalog matching the
Packit Service 82fcde
	 DOMAINNAME and CATEGORY.  */
Packit Service 82fcde
      domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
Packit Service 82fcde
Packit Service 82fcde
      if (domain != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
#if defined IN_LIBGLOCALE
Packit Service 82fcde
	  retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
Packit Service 82fcde
#else
Packit Service 82fcde
	  retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
	  if (retval == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      int cnt;
Packit Service 82fcde
Packit Service 82fcde
	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
Packit Service 82fcde
		{
Packit Service 82fcde
#if defined IN_LIBGLOCALE
Packit Service 82fcde
		  retval = _nl_find_msg (domain->successor[cnt], binding,
Packit Service 82fcde
					 encoding, msgid1, &retlen);
Packit Service 82fcde
#else
Packit Service 82fcde
		  retval = _nl_find_msg (domain->successor[cnt], binding,
Packit Service 82fcde
					 msgid1, 1, &retlen);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
		  /* Resource problems are not fatal, instead we return no
Packit Service 82fcde
		     translation.  */
Packit Service 82fcde
		  if (__builtin_expect (retval == (char *) -1, 0))
Packit Service 82fcde
		    goto return_untranslated;
Packit Service 82fcde
Packit Service 82fcde
		  if (retval != NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      domain = domain->successor[cnt];
Packit Service 82fcde
		      break;
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Returning -1 means that some resource problem exists
Packit Service 82fcde
	     (likely memory) and that the strings could not be
Packit Service 82fcde
	     converted.  Return the original strings.  */
Packit Service 82fcde
	  if (__builtin_expect (retval == (char *) -1, 0))
Packit Service 82fcde
	    break;
Packit Service 82fcde
Packit Service 82fcde
	  if (retval != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Found the translation of MSGID1 in domain DOMAIN:
Packit Service 82fcde
		 starting at RETVAL, RETLEN bytes.  */
Packit Service 82fcde
	      free (xdirname);
Packit Service 82fcde
	      FREE_BLOCKS (block_list);
Packit Service 82fcde
	      if (foundp == NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Create a new entry and add it to the search tree.  */
Packit Service 82fcde
		  size_t msgid_len;
Packit Service 82fcde
		  size_t size;
Packit Service 82fcde
		  struct known_translation_t *newp;
Packit Service 82fcde
Packit Service 82fcde
		  msgid_len = strlen (msgid1) + 1;
Packit Service 82fcde
		  size = offsetof (struct known_translation_t, msgid)
Packit Service 82fcde
			 + msgid_len + domainname_len + 1;
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
		  size += strlen (localename) + 1;
Packit Service 82fcde
#endif
Packit Service 82fcde
		  newp = (struct known_translation_t *) malloc (size);
Packit Service 82fcde
		  if (newp != NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      char *new_domainname;
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
		      char *new_localename;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
		      new_domainname =
Packit Service 82fcde
			(char *) mempcpy (newp->msgid.appended, msgid1,
Packit Service 82fcde
					  msgid_len);
Packit Service 82fcde
		      memcpy (new_domainname, domainname, domainname_len + 1);
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
		      new_localename = new_domainname + domainname_len + 1;
Packit Service 82fcde
		      strcpy (new_localename, localename);
Packit Service 82fcde
#endif
Packit Service 82fcde
		      newp->domainname = new_domainname;
Packit Service 82fcde
		      newp->category = category;
Packit Service 82fcde
#ifdef HAVE_PER_THREAD_LOCALE
Packit Service 82fcde
		      newp->localename = new_localename;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
		      newp->encoding = encoding;
Packit Service 82fcde
#endif
Packit Service 82fcde
		      newp->counter = _nl_msg_cat_cntr;
Packit Service 82fcde
		      newp->domain = domain;
Packit Service 82fcde
		      newp->translation = retval;
Packit Service 82fcde
		      newp->translation_length = retlen;
Packit Service 82fcde
Packit Service 82fcde
		      gl_rwlock_wrlock (tree_lock);
Packit Service 82fcde
Packit Service 82fcde
		      /* Insert the entry in the search tree.  */
Packit Service 82fcde
		      foundp = (struct known_translation_t **)
Packit Service 82fcde
			tsearch (newp, &root, transcmp);
Packit Service 82fcde
Packit Service 82fcde
		      gl_rwlock_unlock (tree_lock);
Packit Service 82fcde
Packit Service 82fcde
		      if (foundp == NULL
Packit Service 82fcde
			  || __builtin_expect (*foundp != newp, 0))
Packit Service 82fcde
			/* The insert failed.  */
Packit Service 82fcde
			free (newp);
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* We can update the existing entry.  */
Packit Service 82fcde
		  (*foundp)->counter = _nl_msg_cat_cntr;
Packit Service 82fcde
		  (*foundp)->domain = domain;
Packit Service 82fcde
		  (*foundp)->translation = retval;
Packit Service 82fcde
		  (*foundp)->translation_length = retlen;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      __set_errno (saved_errno);
Packit Service 82fcde
Packit Service 82fcde
	      /* Now deal with plural.  */
Packit Service 82fcde
	      if (plural)
Packit Service 82fcde
		retval = plural_lookup (domain, n, retval, retlen);
Packit Service 82fcde
Packit Service 82fcde
	      gl_rwlock_unlock (_nl_state_lock);
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
	      __libc_rwlock_unlock (__libc_setlocale_lock);
Packit Service 82fcde
#endif
Packit Service 82fcde
	      return retval;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
 return_untranslated:
Packit Service 82fcde
  /* Return the untranslated MSGID.  */
Packit Service 82fcde
  free (xdirname);
Packit Service 82fcde
  FREE_BLOCKS (block_list);
Packit Service 82fcde
  gl_rwlock_unlock (_nl_state_lock);
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
  __libc_rwlock_unlock (__libc_setlocale_lock);
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifndef _LIBC
Packit Service 82fcde
  if (!ENABLE_SECURE)
Packit Service 82fcde
    {
Packit Service 82fcde
      extern void _nl_log_untranslated (const char *logfilename,
Packit Service 82fcde
					const char *domainname,
Packit Service 82fcde
					const char *msgid1, const char *msgid2,
Packit Service 82fcde
					int plural);
Packit Service 82fcde
      const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
Packit Service 82fcde
Packit Service 82fcde
      if (logfilename != NULL && logfilename[0] != '\0')
Packit Service 82fcde
	_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
Packit Service 82fcde
    }
Packit Service 82fcde
#endif
Packit Service 82fcde
  __set_errno (saved_errno);
Packit Service 82fcde
  return (plural == 0
Packit Service 82fcde
	  ? (char *) msgid1
Packit Service 82fcde
	  /* Use the Germanic plural rule.  */
Packit Service 82fcde
	  : n == 1 ? (char *) msgid1 : (char *) msgid2);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING.
Packit Service 82fcde
   Return it if found.  Return NULL if not found or in case of a conversion
Packit Service 82fcde
   failure (problem in the particular message catalog).  Return (char *) -1
Packit Service 82fcde
   in case of a memory allocation failure during conversion (only if
Packit Service 82fcde
   ENCODING != NULL resp. CONVERT == true).  */
Packit Service 82fcde
char *
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
_nl_find_msg (struct loaded_l10nfile *domain_file,
Packit Service 82fcde
	      struct binding *domainbinding, const char *encoding,
Packit Service 82fcde
	      const char *msgid,
Packit Service 82fcde
	      size_t *lengthp)
Packit Service 82fcde
#else
Packit Service 82fcde
_nl_find_msg (struct loaded_l10nfile *domain_file,
Packit Service 82fcde
	      struct binding *domainbinding,
Packit Service 82fcde
	      const char *msgid, int convert,
Packit Service 82fcde
	      size_t *lengthp)
Packit Service 82fcde
#endif
Packit Service 82fcde
{
Packit Service 82fcde
  struct loaded_domain *domain;
Packit Service 82fcde
  nls_uint32 nstrings;
Packit Service 82fcde
  size_t act;
Packit Service 82fcde
  char *result;
Packit Service 82fcde
  size_t resultlen;
Packit Service 82fcde
Packit Service 82fcde
  if (domain_file->decided <= 0)
Packit Service 82fcde
    _nl_load_domain (domain_file, domainbinding);
Packit Service 82fcde
Packit Service 82fcde
  if (domain_file->data == NULL)
Packit Service 82fcde
    return NULL;
Packit Service 82fcde
Packit Service 82fcde
  domain = (struct loaded_domain *) domain_file->data;
Packit Service 82fcde
Packit Service 82fcde
  nstrings = domain->nstrings;
Packit Service 82fcde
Packit Service 82fcde
  /* Locate the MSGID and its translation.  */
Packit Service 82fcde
  if (domain->hash_tab != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Use the hashing table.  */
Packit Service 82fcde
      nls_uint32 len = strlen (msgid);
Packit Service 82fcde
      nls_uint32 hash_val = __hash_string (msgid);
Packit Service 82fcde
      nls_uint32 idx = hash_val % domain->hash_size;
Packit Service 82fcde
      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
Packit Service 82fcde
Packit Service 82fcde
      while (1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  nls_uint32 nstr =
Packit Service 82fcde
	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
Packit Service 82fcde
Packit Service 82fcde
	  if (nstr == 0)
Packit Service 82fcde
	    /* Hash table entry is empty.  */
Packit Service 82fcde
	    return NULL;
Packit Service 82fcde
Packit Service 82fcde
	  nstr--;
Packit Service 82fcde
Packit Service 82fcde
	  /* Compare msgid with the original string at index nstr.
Packit Service 82fcde
	     We compare the lengths with >=, not ==, because plural entries
Packit Service 82fcde
	     are represented by strings with an embedded NUL.  */
Packit Service 82fcde
	  if (nstr < nstrings
Packit Service 82fcde
	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
Packit Service 82fcde
		&& (strcmp (msgid,
Packit Service 82fcde
			    domain->data + W (domain->must_swap,
Packit Service 82fcde
					      domain->orig_tab[nstr].offset))
Packit Service 82fcde
		    == 0)
Packit Service 82fcde
	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
Packit Service 82fcde
		&& (strcmp (msgid,
Packit Service 82fcde
			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
Packit Service 82fcde
		    == 0))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      act = nstr;
Packit Service 82fcde
	      goto found;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  if (idx >= domain->hash_size - incr)
Packit Service 82fcde
	    idx -= domain->hash_size - incr;
Packit Service 82fcde
	  else
Packit Service 82fcde
	    idx += incr;
Packit Service 82fcde
	}
Packit Service 82fcde
      /* NOTREACHED */
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Try the default method:  binary search in the sorted array of
Packit Service 82fcde
	 messages.  */
Packit Service 82fcde
      size_t top, bottom;
Packit Service 82fcde
Packit Service 82fcde
      bottom = 0;
Packit Service 82fcde
      top = nstrings;
Packit Service 82fcde
      while (bottom < top)
Packit Service 82fcde
	{
Packit Service 82fcde
	  int cmp_val;
Packit Service 82fcde
Packit Service 82fcde
	  act = (bottom + top) / 2;
Packit Service 82fcde
	  cmp_val = strcmp (msgid, (domain->data
Packit Service 82fcde
				    + W (domain->must_swap,
Packit Service 82fcde
					 domain->orig_tab[act].offset)));
Packit Service 82fcde
	  if (cmp_val < 0)
Packit Service 82fcde
	    top = act;
Packit Service 82fcde
	  else if (cmp_val > 0)
Packit Service 82fcde
	    bottom = act + 1;
Packit Service 82fcde
	  else
Packit Service 82fcde
	    goto found;
Packit Service 82fcde
	}
Packit Service 82fcde
      /* No translation was found.  */
Packit Service 82fcde
      return NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
 found:
Packit Service 82fcde
  /* The translation was found at index ACT.  If we have to convert the
Packit Service 82fcde
     string to use a different character set, this is the time.  */
Packit Service 82fcde
  if (act < nstrings)
Packit Service 82fcde
    {
Packit Service 82fcde
      result = (char *)
Packit Service 82fcde
	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
Packit Service 82fcde
      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
Packit Service 82fcde
      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
#if defined _LIBC || HAVE_ICONV
Packit Service 82fcde
# ifdef IN_LIBGLOCALE
Packit Service 82fcde
  if (encoding != NULL)
Packit Service 82fcde
# else
Packit Service 82fcde
  if (convert)
Packit Service 82fcde
# endif
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We are supposed to do a conversion.  */
Packit Service 82fcde
# ifndef IN_LIBGLOCALE
Packit Service 82fcde
      const char *encoding = get_output_charset (domainbinding);
Packit Service 82fcde
# endif
Packit Service 82fcde
      size_t nconversions;
Packit Service 82fcde
      struct converted_domain *convd;
Packit Service 82fcde
      size_t i;
Packit Service 82fcde
Packit Service 82fcde
      /* Protect against reallocation of the table.  */
Packit Service 82fcde
      gl_rwlock_rdlock (domain->conversions_lock);
Packit Service 82fcde
Packit Service 82fcde
      /* Search whether a table with converted translations for this
Packit Service 82fcde
	 encoding has already been allocated.  */
Packit Service 82fcde
      nconversions = domain->nconversions;
Packit Service 82fcde
      convd = NULL;
Packit Service 82fcde
Packit Service 82fcde
      for (i = nconversions; i > 0; )
Packit Service 82fcde
	{
Packit Service 82fcde
	  i--;
Packit Service 82fcde
	  if (strcmp (domain->conversions[i].encoding, encoding) == 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      convd = &domain->conversions[i];
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      gl_rwlock_unlock (domain->conversions_lock);
Packit Service 82fcde
Packit Service 82fcde
      if (convd == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We have to allocate a new conversions table.  */
Packit Service 82fcde
	  gl_rwlock_wrlock (domain->conversions_lock);
Packit Service 82fcde
	  nconversions = domain->nconversions;
Packit Service 82fcde
Packit Service 82fcde
	  /* Maybe in the meantime somebody added the translation.
Packit Service 82fcde
	     Recheck.  */
Packit Service 82fcde
	  for (i = nconversions; i > 0; )
Packit Service 82fcde
	    {
Packit Service 82fcde
	      i--;
Packit Service 82fcde
	      if (strcmp (domain->conversions[i].encoding, encoding) == 0)
Packit Service 82fcde
		{
Packit Service 82fcde
		  convd = &domain->conversions[i];
Packit Service 82fcde
		  goto found_convd;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  {
Packit Service 82fcde
	    /* Allocate a table for the converted translations for this
Packit Service 82fcde
	       encoding.  */
Packit Service 82fcde
	    struct converted_domain *new_conversions =
Packit Service 82fcde
	      (struct converted_domain *)
Packit Service 82fcde
	      (domain->conversions != NULL
Packit Service 82fcde
	       ? realloc (domain->conversions,
Packit Service 82fcde
			  (nconversions + 1) * sizeof (struct converted_domain))
Packit Service 82fcde
	       : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
Packit Service 82fcde
Packit Service 82fcde
	    if (__builtin_expect (new_conversions == NULL, 0))
Packit Service 82fcde
	      {
Packit Service 82fcde
		/* Nothing we can do, no more memory.  We cannot use the
Packit Service 82fcde
		   translation because it might be encoded incorrectly.  */
Packit Service 82fcde
	      unlock_fail:
Packit Service 82fcde
		gl_rwlock_unlock (domain->conversions_lock);
Packit Service 82fcde
		return (char *) -1;
Packit Service 82fcde
	      }
Packit Service 82fcde
Packit Service 82fcde
	    domain->conversions = new_conversions;
Packit Service 82fcde
Packit Service 82fcde
	    /* Copy the 'encoding' string to permanent storage.  */
Packit Service 82fcde
	    encoding = strdup (encoding);
Packit Service 82fcde
	    if (__builtin_expect (encoding == NULL, 0))
Packit Service 82fcde
	      /* Nothing we can do, no more memory.  We cannot use the
Packit Service 82fcde
		 translation because it might be encoded incorrectly.  */
Packit Service 82fcde
	      goto unlock_fail;
Packit Service 82fcde
Packit Service 82fcde
	    convd = &new_conversions[nconversions];
Packit Service 82fcde
	    convd->encoding = encoding;
Packit Service 82fcde
Packit Service 82fcde
	    /* Find out about the character set the file is encoded with.
Packit Service 82fcde
	       This can be found (in textual form) in the entry "".  If this
Packit Service 82fcde
	       entry does not exist or if this does not contain the 'charset='
Packit Service 82fcde
	       information, we will assume the charset matches the one the
Packit Service 82fcde
	       current locale and we don't have to perform any conversion.  */
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
	    convd->conv = (__gconv_t) -1;
Packit Service 82fcde
# else
Packit Service 82fcde
#  if HAVE_ICONV
Packit Service 82fcde
	    convd->conv = (iconv_t) -1;
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
	    {
Packit Service 82fcde
	      char *nullentry;
Packit Service 82fcde
	      size_t nullentrylen;
Packit Service 82fcde
Packit Service 82fcde
	      /* Get the header entry.  This is a recursion, but it doesn't
Packit Service 82fcde
		 reallocate domain->conversions because we pass
Packit Service 82fcde
		 encoding = NULL or convert = 0, respectively.  */
Packit Service 82fcde
	      nullentry =
Packit Service 82fcde
# ifdef IN_LIBGLOCALE
Packit Service 82fcde
		_nl_find_msg (domain_file, domainbinding, NULL, "",
Packit Service 82fcde
			      &nullentrylen);
Packit Service 82fcde
# else
Packit Service 82fcde
		_nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
	      /* Resource problems are fatal.  If we continue onwards we will
Packit Service 82fcde
	         only attempt to calloc a new conv_tab and fail later.  */
Packit Service 82fcde
	      if (__builtin_expect (nullentry == (char *) -1, 0))
Packit Service 82fcde
	        return (char *) -1;
Packit Service 82fcde
Packit Service 82fcde
	      if (nullentry != NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  const char *charsetstr;
Packit Service 82fcde
Packit Service 82fcde
		  charsetstr = strstr (nullentry, "charset=");
Packit Service 82fcde
		  if (charsetstr != NULL)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      size_t len;
Packit Service 82fcde
		      char *charset;
Packit Service 82fcde
		      const char *outcharset;
Packit Service 82fcde
Packit Service 82fcde
		      charsetstr += strlen ("charset=");
Packit Service 82fcde
		      len = strcspn (charsetstr, " \t\n");
Packit Service 82fcde
Packit Service 82fcde
		      charset = (char *) alloca (len + 1);
Packit Service 82fcde
# if defined _LIBC || HAVE_MEMPCPY
Packit Service 82fcde
		      *((char *) mempcpy (charset, charsetstr, len)) = '\0';
Packit Service 82fcde
# else
Packit Service 82fcde
		      memcpy (charset, charsetstr, len);
Packit Service 82fcde
		      charset[len] = '\0';
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
		      outcharset = encoding;
Packit Service 82fcde
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
		      /* We always want to use transliteration.  */
Packit Service 82fcde
		      outcharset = norm_add_slashes (outcharset, "TRANSLIT");
Packit Service 82fcde
		      charset = norm_add_slashes (charset, "");
Packit Service 82fcde
		      int r = __gconv_open (outcharset, charset, &convd->conv,
Packit Service 82fcde
					    GCONV_AVOID_NOCONV);
Packit Service 82fcde
		      if (__builtin_expect (r != __GCONV_OK, 0))
Packit Service 82fcde
			{
Packit Service 82fcde
			  /* If the output encoding is the same there is
Packit Service 82fcde
			     nothing to do.  Otherwise do not use the
Packit Service 82fcde
			     translation at all.  */
Packit Service 82fcde
			  if (__builtin_expect (r != __GCONV_NULCONV, 1))
Packit Service 82fcde
			    {
Packit Service 82fcde
			      gl_rwlock_unlock (domain->conversions_lock);
Packit Service 82fcde
			      free ((char *) encoding);
Packit Service 82fcde
			      return NULL;
Packit Service 82fcde
			    }
Packit Service 82fcde
Packit Service 82fcde
			  convd->conv = (__gconv_t) -1;
Packit Service 82fcde
			}
Packit Service 82fcde
# else
Packit Service 82fcde
#  if HAVE_ICONV
Packit Service 82fcde
		      /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
Packit Service 82fcde
			 we want to use transliteration.  */
Packit Service 82fcde
#   if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \
Packit Service 82fcde
	&& !defined __UCLIBC__) \
Packit Service 82fcde
       || _LIBICONV_VERSION >= 0x0105
Packit Service 82fcde
		      if (strchr (outcharset, '/') == NULL)
Packit Service 82fcde
			{
Packit Service 82fcde
			  char *tmp;
Packit Service 82fcde
Packit Service 82fcde
			  len = strlen (outcharset);
Packit Service 82fcde
			  tmp = (char *) alloca (len + 10 + 1);
Packit Service 82fcde
			  memcpy (tmp, outcharset, len);
Packit Service 82fcde
			  memcpy (tmp + len, "//TRANSLIT", 10 + 1);
Packit Service 82fcde
			  outcharset = tmp;
Packit Service 82fcde
Packit Service 82fcde
			  convd->conv = iconv_open (outcharset, charset);
Packit Service 82fcde
Packit Service 82fcde
			  freea (outcharset);
Packit Service 82fcde
			}
Packit Service 82fcde
		      else
Packit Service 82fcde
#   endif
Packit Service 82fcde
			convd->conv = iconv_open (outcharset, charset);
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
		      freea (charset);
Packit Service 82fcde
		    }
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
	    convd->conv_tab = NULL;
Packit Service 82fcde
	    /* Here domain->conversions is still == new_conversions.  */
Packit Service 82fcde
	    domain->nconversions++;
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
	found_convd:
Packit Service 82fcde
	  gl_rwlock_unlock (domain->conversions_lock);
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
	  convd->conv != (__gconv_t) -1
Packit Service 82fcde
# else
Packit Service 82fcde
#  if HAVE_ICONV
Packit Service 82fcde
	  convd->conv != (iconv_t) -1
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
	  )
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We are supposed to do a conversion.  First allocate an
Packit Service 82fcde
	     appropriate table with the same structure as the table
Packit Service 82fcde
	     of translations in the file, where we can put the pointers
Packit Service 82fcde
	     to the converted strings in.
Packit Service 82fcde
	     There is a slight complication with plural entries.  They
Packit Service 82fcde
	     are represented by consecutive NUL terminated strings.  We
Packit Service 82fcde
	     handle this case by converting RESULTLEN bytes, including
Packit Service 82fcde
	     NULs.  */
Packit Service 82fcde
Packit Service 82fcde
	  /* This lock primarily protects the memory management variables
Packit Service 82fcde
	     freemem, freemem_size.  It also protects write accesses to
Packit Service 82fcde
	     convd->conv_tab.  It's not worth using a separate lock (such
Packit Service 82fcde
	     as domain->conversions_lock) for this purpose, because when
Packit Service 82fcde
	     modifying convd->conv_tab, we also need to lock freemem,
Packit Service 82fcde
	     freemem_size for most of the time.  */
Packit Service 82fcde
	  __libc_lock_define_initialized (static, lock)
Packit Service 82fcde
Packit Service 82fcde
	  if (__builtin_expect (convd->conv_tab == NULL, 0))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      __libc_lock_lock (lock);
Packit Service 82fcde
	      if (convd->conv_tab == NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  convd->conv_tab =
Packit Service 82fcde
		    (char **) calloc (nstrings + domain->n_sysdep_strings,
Packit Service 82fcde
				      sizeof (char *));
Packit Service 82fcde
		  if (convd->conv_tab != NULL)
Packit Service 82fcde
		    goto not_translated_yet;
Packit Service 82fcde
		  /* Mark that we didn't succeed allocating a table.  */
Packit Service 82fcde
		  convd->conv_tab = (char **) -1;
Packit Service 82fcde
		}
Packit Service 82fcde
	      __libc_lock_unlock (lock);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
Packit Service 82fcde
	    /* Nothing we can do, no more memory.  We cannot use the
Packit Service 82fcde
	       translation because it might be encoded incorrectly.  */
Packit Service 82fcde
	    return (char *) -1;
Packit Service 82fcde
Packit Service 82fcde
	  if (convd->conv_tab[act] == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* We haven't used this string so far, so it is not
Packit Service 82fcde
		 translated yet.  Do this now.  */
Packit Service 82fcde
	      /* We use a bit more efficient memory handling.
Packit Service 82fcde
		 We allocate always larger blocks which get used over
Packit Service 82fcde
		 time.  This is faster than many small allocations.   */
Packit Service 82fcde
# define INITIAL_BLOCK_SIZE	4080
Packit Service 82fcde
	      static unsigned char *freemem;
Packit Service 82fcde
	      static size_t freemem_size;
Packit Service 82fcde
Packit Service 82fcde
	      const unsigned char *inbuf;
Packit Service 82fcde
	      unsigned char *outbuf;
Packit Service 82fcde
	      int malloc_count;
Packit Service 82fcde
# ifndef _LIBC
Packit Service 82fcde
	      transmem_block_t *transmem_list;
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
	      __libc_lock_lock (lock);
Packit Service 82fcde
	    not_translated_yet:
Packit Service 82fcde
Packit Service 82fcde
	      inbuf = (const unsigned char *) result;
Packit Service 82fcde
	      outbuf = freemem + sizeof (size_t);
Packit Service 82fcde
# ifndef _LIBC
Packit Service 82fcde
	      transmem_list = NULL;
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
	      malloc_count = 0;
Packit Service 82fcde
	      while (1)
Packit Service 82fcde
		{
Packit Service 82fcde
		  transmem_block_t *newmem;
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
		  size_t non_reversible;
Packit Service 82fcde
		  int res;
Packit Service 82fcde
Packit Service 82fcde
		  if (freemem_size < sizeof (size_t))
Packit Service 82fcde
		    goto resize_freemem;
Packit Service 82fcde
Packit Service 82fcde
		  res = __gconv (convd->conv,
Packit Service 82fcde
				 &inbuf, inbuf + resultlen,
Packit Service 82fcde
				 &outbuf,
Packit Service 82fcde
				 outbuf + freemem_size - sizeof (size_t),
Packit Service 82fcde
				 &non_reversible);
Packit Service 82fcde
Packit Service 82fcde
		  if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
Packit Service 82fcde
		    break;
Packit Service 82fcde
Packit Service 82fcde
		  if (res != __GCONV_FULL_OUTPUT)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* We should not use the translation at all, it
Packit Service 82fcde
			 is incorrectly encoded.  */
Packit Service 82fcde
		      __libc_lock_unlock (lock);
Packit Service 82fcde
		      return NULL;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  inbuf = (const unsigned char *) result;
Packit Service 82fcde
# else
Packit Service 82fcde
#  if HAVE_ICONV
Packit Service 82fcde
		  const char *inptr = (const char *) inbuf;
Packit Service 82fcde
		  size_t inleft = resultlen;
Packit Service 82fcde
		  char *outptr = (char *) outbuf;
Packit Service 82fcde
		  size_t outleft;
Packit Service 82fcde
Packit Service 82fcde
		  if (freemem_size < sizeof (size_t))
Packit Service 82fcde
		    goto resize_freemem;
Packit Service 82fcde
Packit Service 82fcde
		  outleft = freemem_size - sizeof (size_t);
Packit Service 82fcde
		  if (iconv (convd->conv,
Packit Service 82fcde
			     (ICONV_CONST char **) &inptr, &inleft,
Packit Service 82fcde
			     &outptr, &outleft)
Packit Service 82fcde
		      != (size_t) (-1))
Packit Service 82fcde
		    {
Packit Service 82fcde
		      outbuf = (unsigned char *) outptr;
Packit Service 82fcde
		      break;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  if (errno != E2BIG)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      __libc_lock_unlock (lock);
Packit Service 82fcde
		      return NULL;
Packit Service 82fcde
		    }
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
		resize_freemem:
Packit Service 82fcde
		  /* We must allocate a new buffer or resize the old one.  */
Packit Service 82fcde
		  if (malloc_count > 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      ++malloc_count;
Packit Service 82fcde
		      freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
Packit Service 82fcde
		      newmem = (transmem_block_t *) realloc (transmem_list,
Packit Service 82fcde
							     freemem_size);
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
		      if (newmem != NULL)
Packit Service 82fcde
			transmem_list = newmem;
Packit Service 82fcde
		      else
Packit Service 82fcde
			{
Packit Service 82fcde
			  struct transmem_list *old = transmem_list;
Packit Service 82fcde
Packit Service 82fcde
			  transmem_list = transmem_list->next;
Packit Service 82fcde
			  free (old);
Packit Service 82fcde
			}
Packit Service 82fcde
# endif
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else
Packit Service 82fcde
		    {
Packit Service 82fcde
		      malloc_count = 1;
Packit Service 82fcde
		      freemem_size = INITIAL_BLOCK_SIZE;
Packit Service 82fcde
		      newmem = (transmem_block_t *) malloc (freemem_size);
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
		      if (newmem != NULL)
Packit Service 82fcde
			{
Packit Service 82fcde
			  /* Add the block to the list of blocks we have to free
Packit Service 82fcde
			     at some point.  */
Packit Service 82fcde
			  newmem->next = transmem_list;
Packit Service 82fcde
			  transmem_list = newmem;
Packit Service 82fcde
			}
Packit Service 82fcde
		      /* Fall through and return -1.  */
Packit Service 82fcde
# endif
Packit Service 82fcde
		    }
Packit Service 82fcde
		  if (__builtin_expect (newmem == NULL, 0))
Packit Service 82fcde
		    {
Packit Service 82fcde
		      freemem = NULL;
Packit Service 82fcde
		      freemem_size = 0;
Packit Service 82fcde
		      __libc_lock_unlock (lock);
Packit Service 82fcde
		      return (char *) -1;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
		  freemem = (unsigned char *) newmem->data;
Packit Service 82fcde
		  freemem_size -= offsetof (struct transmem_list, data);
Packit Service 82fcde
# else
Packit Service 82fcde
		  transmem_list = newmem;
Packit Service 82fcde
		  freemem = newmem;
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
		  outbuf = freemem + sizeof (size_t);
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      /* We have now in our buffer a converted string.  Put this
Packit Service 82fcde
		 into the table of conversions.  */
Packit Service 82fcde
	      *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
Packit Service 82fcde
	      convd->conv_tab[act] = (char *) freemem;
Packit Service 82fcde
	      /* Shrink freemem, but keep it aligned.  */
Packit Service 82fcde
	      freemem_size -= outbuf - freemem;
Packit Service 82fcde
	      freemem = outbuf;
Packit Service 82fcde
	      freemem += freemem_size & (alignof (size_t) - 1);
Packit Service 82fcde
	      freemem_size = freemem_size & ~ (alignof (size_t) - 1);
Packit Service 82fcde
Packit Service 82fcde
	      __libc_lock_unlock (lock);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Now convd->conv_tab[act] contains the translation of all
Packit Service 82fcde
	     the plural variants.  */
Packit Service 82fcde
	  result = convd->conv_tab[act] + sizeof (size_t);
Packit Service 82fcde
	  resultlen = *(size_t *) convd->conv_tab[act];
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* The result string is converted.  */
Packit Service 82fcde
Packit Service 82fcde
#endif /* _LIBC || HAVE_ICONV */
Packit Service 82fcde
Packit Service 82fcde
  *lengthp = resultlen;
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Look up a plural variant.  */
Packit Service 82fcde
static char *
Packit Service 82fcde
plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
Packit Service 82fcde
	       const char *translation, size_t translation_len)
Packit Service 82fcde
{
Packit Service 82fcde
  struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
Packit Service 82fcde
  unsigned long int index;
Packit Service 82fcde
  const char *p;
Packit Service 82fcde
Packit Service 82fcde
  index = plural_eval (domaindata->plural, n);
Packit Service 82fcde
  if (index >= domaindata->nplurals)
Packit Service 82fcde
    /* This should never happen.  It means the plural expression and the
Packit Service 82fcde
       given maximum value do not match.  */
Packit Service 82fcde
    index = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Skip INDEX strings at TRANSLATION.  */
Packit Service 82fcde
  p = translation;
Packit Service 82fcde
  while (index-- > 0)
Packit Service 82fcde
    {
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
      p = __rawmemchr (p, '\0');
Packit Service 82fcde
#else
Packit Service 82fcde
      p = strchr (p, '\0');
Packit Service 82fcde
#endif
Packit Service 82fcde
      /* And skip over the NUL byte.  */
Packit Service 82fcde
      p++;
Packit Service 82fcde
Packit Service 82fcde
      if (p >= translation + translation_len)
Packit Service 82fcde
	/* This should never happen.  It means the plural expression
Packit Service 82fcde
	   evaluated to a value larger than the number of variants
Packit Service 82fcde
	   available for MSGID1.  */
Packit Service 82fcde
	return (char *) translation;
Packit Service 82fcde
    }
Packit Service 82fcde
  return (char *) p;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#ifndef _LIBC
Packit Service 82fcde
/* Return string representation of locale CATEGORY.  */
Packit Service 82fcde
static const char *
Packit Service 82fcde
category_to_name (int category)
Packit Service 82fcde
{
Packit Service 82fcde
  const char *retval;
Packit Service 82fcde
Packit Service 82fcde
  switch (category)
Packit Service 82fcde
  {
Packit Service 82fcde
#ifdef LC_COLLATE
Packit Service 82fcde
  case LC_COLLATE:
Packit Service 82fcde
    retval = "LC_COLLATE";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_CTYPE
Packit Service 82fcde
  case LC_CTYPE:
Packit Service 82fcde
    retval = "LC_CTYPE";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_MONETARY
Packit Service 82fcde
  case LC_MONETARY:
Packit Service 82fcde
    retval = "LC_MONETARY";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_NUMERIC
Packit Service 82fcde
  case LC_NUMERIC:
Packit Service 82fcde
    retval = "LC_NUMERIC";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_TIME
Packit Service 82fcde
  case LC_TIME:
Packit Service 82fcde
    retval = "LC_TIME";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_MESSAGES
Packit Service 82fcde
  case LC_MESSAGES:
Packit Service 82fcde
    retval = "LC_MESSAGES";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_RESPONSE
Packit Service 82fcde
  case LC_RESPONSE:
Packit Service 82fcde
    retval = "LC_RESPONSE";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef LC_ALL
Packit Service 82fcde
  case LC_ALL:
Packit Service 82fcde
    /* This might not make sense but is perhaps better than any other
Packit Service 82fcde
       value.  */
Packit Service 82fcde
    retval = "LC_ALL";
Packit Service 82fcde
    break;
Packit Service 82fcde
#endif
Packit Service 82fcde
  default:
Packit Service 82fcde
    /* If you have a better idea for a default value let me know.  */
Packit Service 82fcde
    retval = "LC_XXX";
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  return retval;
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Guess value of current locale from value of the environment variables
Packit Service 82fcde
   or system-dependent defaults.  */
Packit Service 82fcde
static const char *
Packit Service 82fcde
#ifdef IN_LIBGLOCALE
Packit Service 82fcde
guess_category_value (int category, const char *categoryname,
Packit Service 82fcde
		      const char *locale)
Packit Service 82fcde
Packit Service 82fcde
#else
Packit Service 82fcde
guess_category_value (int category, const char *categoryname)
Packit Service 82fcde
#endif
Packit Service 82fcde
{
Packit Service 82fcde
  const char *language;
Packit Service 82fcde
#ifndef IN_LIBGLOCALE
Packit Service 82fcde
  const char *locale;
Packit Service 82fcde
# ifndef _LIBC
Packit Service 82fcde
  const char *language_default;
Packit Service 82fcde
  int locale_defaulted;
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* We use the settings in the following order:
Packit Service 82fcde
     1. The value of the environment variable 'LANGUAGE'.  This is a GNU
Packit Service 82fcde
        extension.  Its value can be a colon-separated list of locale names.
Packit Service 82fcde
     2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
Packit Service 82fcde
        More precisely, the first among these that is set to a non-empty value.
Packit Service 82fcde
        This is how POSIX specifies it.  The value is a single locale name.
Packit Service 82fcde
     3. A system-dependent preference list of languages.  Its value can be a
Packit Service 82fcde
        colon-separated list of locale names.
Packit Service 82fcde
     4. A system-dependent default locale name.
Packit Service 82fcde
     This way:
Packit Service 82fcde
       - System-dependent settings can be overridden by environment variables.
Packit Service 82fcde
       - If the system provides both a list of languages and a default locale,
Packit Service 82fcde
         the former is used.  */
Packit Service 82fcde
Packit Service 82fcde
#ifndef IN_LIBGLOCALE
Packit Service 82fcde
  /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
Packit Service 82fcde
     `LC_xxx', and `LANG'.  On some systems this can be done by the
Packit Service 82fcde
     `setlocale' function itself.  */
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
  locale = __current_locale_name (category);
Packit Service 82fcde
# else
Packit Service 82fcde
  locale_defaulted = 0;
Packit Service 82fcde
#  if HAVE_USELOCALE
Packit Service 82fcde
  locale = _nl_locale_name_thread_unsafe (category, categoryname);
Packit Service 82fcde
  if (locale == NULL)
Packit Service 82fcde
#  endif
Packit Service 82fcde
    {
Packit Service 82fcde
      locale = _nl_locale_name_posix (category, categoryname);
Packit Service 82fcde
      if (locale == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  locale = _nl_locale_name_default ();
Packit Service 82fcde
	  locale_defaulted = 1;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
Packit Service 82fcde
     to "C" because
Packit Service 82fcde
     1. "C" locale usually uses the ASCII encoding, and most international
Packit Service 82fcde
	messages use non-ASCII characters. These characters get displayed
Packit Service 82fcde
	as question marks (if using glibc's iconv()) or as invalid 8-bit
Packit Service 82fcde
	characters (because other iconv()s refuse to convert most non-ASCII
Packit Service 82fcde
	characters to ASCII). In any case, the output is ugly.
Packit Service 82fcde
     2. The precise output of some programs in the "C" locale is specified
Packit Service 82fcde
	by POSIX and should not depend on environment variables like
Packit Service 82fcde
	"LANGUAGE" or system-dependent information.  We allow such programs
Packit Service 82fcde
        to use gettext().  */
Packit Service 82fcde
  if (strcmp (locale, "C") == 0)
Packit Service 82fcde
    return locale;
Packit Service 82fcde
Packit Service 82fcde
  /* The highest priority value is the value of the 'LANGUAGE' environment
Packit Service 82fcde
     variable.  */
Packit Service 82fcde
  language = getenv ("LANGUAGE");
Packit Service 82fcde
  if (language != NULL && language[0] != '\0')
Packit Service 82fcde
    return language;
Packit Service 82fcde
#if !defined IN_LIBGLOCALE && !defined _LIBC
Packit Service 82fcde
  /* The next priority value is the locale name, if not defaulted.  */
Packit Service 82fcde
  if (locale_defaulted)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The next priority value is the default language preferences list. */
Packit Service 82fcde
      language_default = _nl_language_preferences_default ();
Packit Service 82fcde
      if (language_default != NULL)
Packit Service 82fcde
        return language_default;
Packit Service 82fcde
    }
Packit Service 82fcde
  /* The least priority value is the locale name, if defaulted.  */
Packit Service 82fcde
#endif
Packit Service 82fcde
  return locale;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
Packit Service 82fcde
/* Returns the output charset.  */
Packit Service 82fcde
static const char *
Packit Service 82fcde
get_output_charset (struct binding *domainbinding)
Packit Service 82fcde
{
Packit Service 82fcde
  /* The output charset should normally be determined by the locale.  But
Packit Service 82fcde
     sometimes the locale is not used or not correctly set up, so we provide
Packit Service 82fcde
     a possibility for the user to override this: the OUTPUT_CHARSET
Packit Service 82fcde
     environment variable.  Moreover, the value specified through
Packit Service 82fcde
     bind_textdomain_codeset overrides both.  */
Packit Service 82fcde
  if (domainbinding != NULL && domainbinding->codeset != NULL)
Packit Service 82fcde
    return domainbinding->codeset;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* For speed reasons, we look at the value of OUTPUT_CHARSET only
Packit Service 82fcde
	 once.  This is a user variable that is not supposed to change
Packit Service 82fcde
	 during a program run.  */
Packit Service 82fcde
      static char *output_charset_cache;
Packit Service 82fcde
      static int output_charset_cached;
Packit Service 82fcde
Packit Service 82fcde
      if (!output_charset_cached)
Packit Service 82fcde
	{
Packit Service 82fcde
	  const char *value = getenv ("OUTPUT_CHARSET");
Packit Service 82fcde
Packit Service 82fcde
	  if (value != NULL && value[0] != '\0')
Packit Service 82fcde
	    {
Packit Service 82fcde
	      size_t len = strlen (value) + 1;
Packit Service 82fcde
	      char *value_copy = (char *) malloc (len);
Packit Service 82fcde
Packit Service 82fcde
	      if (value_copy != NULL)
Packit Service 82fcde
		memcpy (value_copy, value, len);
Packit Service 82fcde
	      output_charset_cache = value_copy;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  output_charset_cached = 1;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (output_charset_cache != NULL)
Packit Service 82fcde
	return output_charset_cache;
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
# ifdef _LIBC
Packit Service 82fcde
	  return _NL_CURRENT (LC_CTYPE, CODESET);
Packit Service 82fcde
# else
Packit Service 82fcde
#  if HAVE_ICONV
Packit Service 82fcde
	  return locale_charset ();
Packit Service 82fcde
#  endif
Packit Service 82fcde
# endif
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* @@ begin of epilog @@ */
Packit Service 82fcde
Packit Service 82fcde
/* We don't want libintl.a to depend on any other library.  So we
Packit Service 82fcde
   avoid the non-standard function stpcpy.  In GNU C Library this
Packit Service 82fcde
   function is available, though.  Also allow the symbol HAVE_STPCPY
Packit Service 82fcde
   to be defined.  */
Packit Service 82fcde
#if !_LIBC && !HAVE_STPCPY
Packit Service 82fcde
static char *
Packit Service 82fcde
stpcpy (char *dest, const char *src)
Packit Service 82fcde
{
Packit Service 82fcde
  while ((*dest++ = *src++) != '\0')
Packit Service 82fcde
    /* Do nothing. */ ;
Packit Service 82fcde
  return dest - 1;
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !_LIBC && !HAVE_MEMPCPY
Packit Service 82fcde
static void *
Packit Service 82fcde
mempcpy (void *dest, const void *src, size_t n)
Packit Service 82fcde
{
Packit Service 82fcde
  return (void *) ((char *) memcpy (dest, src, n) + n);
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if !_LIBC && !HAVE_TSEARCH
Packit Service 82fcde
# include "tsearch.c"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#ifdef _LIBC
Packit Service 82fcde
/* If we want to free all resources we have to do some work at
Packit Service 82fcde
   program's end.  */
Packit Service 82fcde
libc_freeres_fn (free_mem)
Packit Service 82fcde
{
Packit Service 82fcde
  void *old;
Packit Service 82fcde
Packit Service 82fcde
  while (_nl_domain_bindings != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct binding *oldp = _nl_domain_bindings;
Packit Service 82fcde
      _nl_domain_bindings = _nl_domain_bindings->next;
Packit Service 82fcde
      if (oldp->dirname != _nl_default_dirname)
Packit Service 82fcde
	/* Yes, this is a pointer comparison.  */
Packit Service 82fcde
	free (oldp->dirname);
Packit Service 82fcde
      free (oldp->codeset);
Packit Service 82fcde
      free (oldp);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (_nl_current_default_domain != _nl_default_default_domain)
Packit Service 82fcde
    /* Yes, again a pointer comparison.  */
Packit Service 82fcde
    free ((char *) _nl_current_default_domain);
Packit Service 82fcde
Packit Service 82fcde
  /* Remove the search tree with the known translations.  */
Packit Service 82fcde
  __tdestroy (root, free);
Packit Service 82fcde
  root = NULL;
Packit Service 82fcde
Packit Service 82fcde
  while (transmem_list != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      old = transmem_list;
Packit Service 82fcde
      transmem_list = transmem_list->next;
Packit Service 82fcde
      free (old);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
#endif