1a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Implementation of the internal dcigettext function.
2b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o   Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
3a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
4a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   This program is free software; you can redistribute it and/or modify it
5a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   under the terms of the GNU Library General Public License as published
6a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   by the Free Software Foundation; either version 2, or (at your option)
7a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   any later version.
8a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
9a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   This program is distributed in the hope that it will be useful,
10a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   but WITHOUT ANY WARRANTY; without even the implied warranty of
11a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   Library General Public License for more details.
13a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
14a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   You should have received a copy of the GNU Library General Public
15a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   License along with this program; if not, write to the Free Software
16a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   USA.  */
18a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
19a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Tell glibc's <string.h> to provide a prototype for mempcpy().
20a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   This must come before <config.h> because <config.h> may include
21a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   <features.h>, and once <features.h> has been included, it's too late.  */
22a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef _GNU_SOURCE
23a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _GNU_SOURCE	1
24a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
25a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
26a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef HAVE_CONFIG_H
27a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <config.h>
28a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
29a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
30a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <sys/types.h>
31a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
32a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef __GNUC__
33a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define alloca __builtin_alloca
34a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define HAVE_ALLOCA 1
35a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
36b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# ifdef _MSC_VER
37b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  include <malloc.h>
38b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  define alloca _alloca
39a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# else
40b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  if defined HAVE_ALLOCA_H || defined _LIBC
41b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   include <alloca.h>
42a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  else
43b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   ifdef _AIX
44b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o #pragma alloca
45b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   else
46b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#    ifndef alloca
47a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ochar *alloca ();
48b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#    endif
49a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#   endif
50a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  endif
51a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
52a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
53a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
54a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <errno.h>
55a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef errno
56a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'oextern int errno;
57a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
58a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef __set_errno
59a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __set_errno(val) errno = (val)
60a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
61a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
62a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <stddef.h>
63a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <stdlib.h>
64a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <string.h>
65a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
66a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_UNISTD_H || defined _LIBC
67a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <unistd.h>
68a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
69a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
70a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <locale.h>
71a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
72a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
73a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Guess whether integer division by zero raises signal SIGFPE.
74a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     Set to 1 only if you know for sure.  In case of doubt, set to 0.  */
75a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# if defined __alpha__ || defined __arm__ || defined __i386__ \
76a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     || defined __m68k__ || defined __s390__
77a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define INTDIV0_RAISES_SIGFPE 1
78a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# else
79a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define INTDIV0_RAISES_SIGFPE 0
80a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
81a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
82a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if !INTDIV0_RAISES_SIGFPE
83a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <signal.h>
84a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
85a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
86a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_SYS_PARAM_H || defined _LIBC
87a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <sys/param.h>
88a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
89a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
90a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include "gettextP.h"
91a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include "plural-exp.h"
92a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
93a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <libintl.h>
94a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
95a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include "libgnuintl.h"
96a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
97a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include "hash-string.h"
98a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
99a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Thread safetyness.  */
100a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
101a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <bits/libc-lock.h>
102a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
103a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Provide dummy implementation if this is outside glibc.  */
104a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __libc_lock_define_initialized(CLASS, NAME)
105a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __libc_lock_lock(NAME)
106a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __libc_lock_unlock(NAME)
107a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __libc_rwlock_define_initialized(CLASS, NAME)
108a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __libc_rwlock_rdlock(NAME)
109a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define __libc_rwlock_unlock(NAME)
110a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
111a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
112a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Alignment of types.  */
113a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined __GNUC__ && __GNUC__ >= 2
114a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define alignof(TYPE) __alignof__ (TYPE)
115a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
116a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define alignof(TYPE) \
117a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
118a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
119a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
120a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* The internal variables in the standalone libintl.a must have different
121a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   names than the internal variables in GNU libc, otherwise programs
122a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   using libintl.a cannot be linked statically.  */
123a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if !defined _LIBC
124a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _nl_default_default_domain libintl_nl_default_default_domain
125a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _nl_current_default_domain libintl_nl_current_default_domain
126a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _nl_default_dirname libintl_nl_default_dirname
127a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _nl_domain_bindings libintl_nl_domain_bindings
128a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
129a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
130a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
131a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef offsetof
132a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
133a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
134a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
135a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* @@ end of prolog @@ */
136a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
137a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
138a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Rename the non ANSI C functions.  This is required by the standard
139a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   because some ANSI C functions will require linking with this object
140a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   file and the name space must not be polluted.  */
141a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define getcwd __getcwd
142a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef stpcpy
143a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define stpcpy __stpcpy
144a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
145a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define tfind __tfind
146a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
147a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# if !defined HAVE_GETCWD
148a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ochar *getwd ();
149a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define getcwd(buf, max) getwd (buf)
150a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# else
151b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  if VMS
152b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   define getcwd(buf, max) (getcwd) (buf, max, 0)
153b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  else
154a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ochar *getcwd ();
155b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  endif
156a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
157a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef HAVE_STPCPY
1580eeec8ac61bf1eaa31533b2be825cd75580829c9Theodore Ts'o#define stpcpy(dest, src) my_stpcpy(dest, src)
159b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic char *stpcpy (char *dest, const char *src);
160a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
161a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef HAVE_MEMPCPY
162b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic void *mempcpy (void *dest, const void *src, size_t n);
163a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
164a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
165a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
166a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Amount to increase buffer size by in each try.  */
167a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#define PATH_INCR 32
168a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
169a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* The following is from pathmax.h.  */
170a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
171a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   PATH_MAX but might cause redefinition warnings when sys/param.h is
172a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   later included (as on MORE/BSD 4.3).  */
173a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
174a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <limits.h>
175a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
176a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
177a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef _POSIX_PATH_MAX
178a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _POSIX_PATH_MAX 255
179a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
180a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
181a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if !defined PATH_MAX && defined _PC_PATH_MAX
182a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
183a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
184a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
185a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Don't include sys/param.h if it already has been.  */
186a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
187a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <sys/param.h>
188a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
189a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
190a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if !defined PATH_MAX && defined MAXPATHLEN
191a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define PATH_MAX MAXPATHLEN
192a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
193a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
194a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef PATH_MAX
195a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define PATH_MAX _POSIX_PATH_MAX
196a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
197a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
198a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Pathname support.
199a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   ISSLASH(C)           tests whether C is a directory separator character.
200a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
201a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o                        it may be concatenated to a directory pathname.
202a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
203a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o */
204a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
205a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Win32, OS/2, DOS */
206a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define ISSLASH(C) ((C) == '/' || (C) == '\\')
207a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define HAS_DEVICE(P) \
208a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
209a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     && (P)[1] == ':')
210a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
211a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define IS_PATH_WITH_DIR(P) \
212a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
213a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
214a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Unix */
215a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define ISSLASH(C) ((C) == '/')
216a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
217a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
218a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
219a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
220a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* This is the type used for the search tree where known translations
221a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   are stored.  */
222a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostruct known_translation_t
223a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
224a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Domain in which to search.  */
225a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char *domainname;
226a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
227a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* The category.  */
228a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  int category;
229a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
230a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* State of the catalog counter at the point the string was found.  */
231a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  int counter;
232a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
233a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Catalog where the string was found.  */
234a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct loaded_l10nfile *domain;
235a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
236a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* And finally the translation.  */
237a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *translation;
238a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  size_t translation_length;
239a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
240a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Pointer to the string in question.  */
241a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char msgid[ZERO];
242a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o};
243a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
244a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Root of the search tree with known translations.  We can use this
245a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   only if the system provides the `tsearch' function family.  */
246a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_TSEARCH || defined _LIBC
247a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <search.h>
248a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
249a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic void *root;
250a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
251a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifdef _LIBC
252a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define tsearch __tsearch
253a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
254a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
255a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Function to compare two entries in the table of known translations.  */
256a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic int
257b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'otranscmp (const void *p1, const void *p2)
258a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
259a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const struct known_translation_t *s1;
260a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const struct known_translation_t *s2;
261a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  int result;
262a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
263a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  s1 = (const struct known_translation_t *) p1;
264a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  s2 = (const struct known_translation_t *) p2;
265a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
266a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  result = strcmp (s1->msgid, s2->msgid);
267a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (result == 0)
268a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
269a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      result = strcmp (s1->domainname, s2->domainname);
270a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (result == 0)
271a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	/* We compare the category last (though this is the cheapest
272a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	   operation) since it is hopefully always the same (namely
273a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	   LC_MESSAGES).  */
274a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	result = s1->category - s2->category;
275a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
276a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
277a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return result;
278a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
279a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
280a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
281b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifndef INTVARDEF
282b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# define INTVARDEF(name)
283b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
284b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifndef INTUSE
285b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# define INTUSE(name) name
286b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
287b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
288a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Name of the default domain used for gettext(3) prior any call to
289a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   textdomain(3).  The default value for this is "messages".  */
290a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'oconst char _nl_default_default_domain[] attribute_hidden = "messages";
291a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
292a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Value used as the default domain for gettext(3).  */
293a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'oconst char *_nl_current_default_domain attribute_hidden
294a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     = _nl_default_default_domain;
295a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
296a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Contains the default location of the message catalogs.  */
297a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined __EMX__
298a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'oextern const char _nl_default_dirname[];
299a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
300a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'oconst char _nl_default_dirname[] = LOCALEDIR;
301b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'oINTVARDEF (_nl_default_dirname)
302a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
303a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
304a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* List with bindings of specific domains created by bindtextdomain()
305a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   calls.  */
306a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostruct binding *_nl_domain_bindings;
307a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
308a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Prototypes for local functions.  */
309b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic char *plural_lookup (struct loaded_l10nfile *domain,
310b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o			    unsigned long int n,
311b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o			    const char *translation, size_t translation_len)
312a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     internal_function;
313b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic const char *guess_category_value (int category,
314b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o					 const char *categoryname)
315a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     internal_function;
316b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifdef _LIBC
317b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# include "../locale/localeinfo.h"
318b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# define category_to_name(category)	_nl_category_names[category]
319b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#else
320b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic const char *category_to_name (int category) internal_function;
321b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
322a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
323a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
324a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* For those loosing systems which don't have `alloca' we have to add
325a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   some additional code emulating it.  */
326a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef HAVE_ALLOCA
327a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Nothing has to be done.  */
328a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define freea(p) /* nothing */
329a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define ADD_BLOCK(list, address) /* nothing */
330a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define FREE_BLOCKS(list) /* nothing */
331a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
332a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostruct block_list
333a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
334a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  void *address;
335a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct block_list *next;
336a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o};
337a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define ADD_BLOCK(list, addr)						      \
338a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  do {									      \
339a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
340a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    /* If we cannot get a free block we cannot add the new element to	      \
341a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o       the list.  */							      \
342a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    if (newp != NULL) {							      \
343a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      newp->address = (addr);						      \
344a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      newp->next = (list);						      \
345a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      (list) = newp;							      \
346a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }									      \
347a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  } while (0)
348a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define FREE_BLOCKS(list)						      \
349a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  do {									      \
350a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    while (list != NULL) {						      \
351a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      struct block_list *old = list;					      \
352a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      list = list->next;						      \
353a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      free (old->address);						      \
354a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      free (old);							      \
355a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }									      \
356a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  } while (0)
357a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# undef alloca
358a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define alloca(size) (malloc (size))
359a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define freea(p) free (p)
360a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif	/* have alloca */
361a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
362a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
363a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
364a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* List of blocks allocated for translations.  */
365a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'otypedef struct transmem_list
366a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
367a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct transmem_list *next;
368a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char data[ZERO];
369a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o} transmem_block_t;
370a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic struct transmem_list *transmem_list;
371a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
372a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'otypedef unsigned char transmem_block_t;
373a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
374a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
375a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
376a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Names for the libintl functions are a problem.  They must not clash
377a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   with existing names and they should follow ANSI C.  But this source
378a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   code is also used in GNU C Library where the names have a __
379a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   prefix.  So we have to make a difference here.  */
380a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
381a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define DCIGETTEXT __dcigettext
382a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
383a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define DCIGETTEXT libintl_dcigettext
384a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
385a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
386a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Lock variable to protect the global data in the gettext implementation.  */
387a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
388a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
389a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
390a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
391a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Checking whether the binaries runs SUID must be done and glibc provides
392a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   easier methods therefore we make a difference here.  */
393a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
394a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define ENABLE_SECURE __libc_enable_secure
395a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define DETERMINE_SECURE
396a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
397a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef HAVE_GETUID
398a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define getuid() 0
399a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
400a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef HAVE_GETGID
401a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define getgid() 0
402a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
403a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef HAVE_GETEUID
404a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define geteuid() getuid()
405a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
406a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef HAVE_GETEGID
407a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define getegid() getgid()
408a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
409a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic int enable_secure;
410a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define ENABLE_SECURE (enable_secure == 1)
411a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define DETERMINE_SECURE \
412a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (enable_secure == 0)						      \
413a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {									      \
414a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (getuid () != geteuid () || getgid () != getegid ())		      \
415a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	enable_secure = 1;						      \
416a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      else								      \
417a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	enable_secure = -1;						      \
418a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
419a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
420a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
421a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Get the function to evaluate the plural expression.  */
422a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include "eval-plural.h"
423a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
424a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Look up MSGID in the DOMAINNAME message catalog for the current
425a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   CATEGORY locale and, if PLURAL is nonzero, search over string
426a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   depending on the plural form determined by N.  */
427a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ochar *
428b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'oDCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
429b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	    int plural, unsigned long int n, int category)
430a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
431a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef HAVE_ALLOCA
432a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct block_list *block_list = NULL;
433a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
434a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct loaded_l10nfile *domain;
435a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct binding *binding;
436a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *categoryname;
437a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *categoryvalue;
438a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char *dirname, *xdomainname;
439a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char *single_locale;
440a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char *retval;
441a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  size_t retlen;
442a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  int saved_errno;
443a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_TSEARCH || defined _LIBC
444a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct known_translation_t *search;
445a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct known_translation_t **foundp = NULL;
446a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  size_t msgid_len;
447a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
448a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  size_t domainname_len;
449a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
450a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* If no real MSGID is given return NULL.  */
451a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (msgid1 == NULL)
452a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    return NULL;
453a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
454b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifdef _LIBC
455b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  if (category < 0 || category >= __LC_LAST || category == LC_ALL)
456b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o    /* Bogus.  */
457b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o    return (plural == 0
458b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	    ? (char *) msgid1
459b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	    /* Use the Germanic plural rule.  */
460b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	    : n == 1 ? (char *) msgid1 : (char *) msgid2);
461b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
462b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
463a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  __libc_rwlock_rdlock (_nl_state_lock);
464a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
465a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
466a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     CATEGORY is not LC_MESSAGES this might not make much sense but the
467a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     definition left this undefined.  */
468a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (domainname == NULL)
469a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    domainname = _nl_current_default_domain;
470a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
471a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* OS/2 specific: backward compatibility with older libintl versions  */
472a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_MESSAGES_COMPAT
473a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (category == LC_MESSAGES_COMPAT)
474a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    category = LC_MESSAGES;
475a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
476a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
477a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_TSEARCH || defined _LIBC
478a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  msgid_len = strlen (msgid1) + 1;
479a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
480a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Try to find the translation among those which we found at
481a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     some time.  */
482a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  search = (struct known_translation_t *)
483a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	   alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
484a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  memcpy (search->msgid, msgid1, msgid_len);
485a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  search->domainname = (char *) domainname;
486a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  search->category = category;
487a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
488a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
489a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  freea (search);
490a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
491a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
492a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* Now deal with plural.  */
493a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (plural)
494a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
495a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o				(*foundp)->translation_length);
496a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      else
497a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	retval = (char *) (*foundp)->translation;
498a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
499a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      __libc_rwlock_unlock (_nl_state_lock);
500a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      return retval;
501a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
502a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
503a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
504a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Preserve the `errno' value.  */
505a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  saved_errno = errno;
506a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
507a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* See whether this is a SUID binary or not.  */
508a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  DETERMINE_SECURE;
509a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
510a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* First find matching binding.  */
511a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
512a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
513a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      int compare = strcmp (domainname, binding->domainname);
514a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (compare == 0)
515a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	/* We found it!  */
516a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	break;
517a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (compare < 0)
518a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
519a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* It is not in the list.  */
520a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  binding = NULL;
521a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  break;
522a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
523a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
524a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
525a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (binding == NULL)
526b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o    dirname = (char *) INTUSE(_nl_default_dirname);
527a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  else if (IS_ABSOLUTE_PATH (binding->dirname))
528a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    dirname = binding->dirname;
529a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  else
530a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
531a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* We have a relative path.  Make it absolute now.  */
532a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      size_t dirname_len = strlen (binding->dirname) + 1;
533a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      size_t path_max;
534a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      char *ret;
535a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
536a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      path_max = (unsigned int) PATH_MAX;
537a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      path_max += 2;		/* The getcwd docs say to do this.  */
538a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
539a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      for (;;)
540a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
541a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  dirname = (char *) alloca (path_max + dirname_len);
542a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  ADD_BLOCK (block_list, dirname);
543a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
544a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  __set_errno (0);
545a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  ret = getcwd (dirname, path_max);
546a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (ret != NULL || errno != ERANGE)
547a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    break;
548a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
549a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  path_max += path_max / 2;
550a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  path_max += PATH_INCR;
551a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
552a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
553a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (ret == NULL)
554b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	/* We cannot get the current working directory.  Don't signal an
555b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	   error but simply return the default string.  */
556b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	goto return_untranslated;
557a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
558a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
559a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
560a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
561a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Now determine the symbolic name of CATEGORY and its value.  */
562a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  categoryname = category_to_name (category);
563a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  categoryvalue = guess_category_value (category, categoryname);
564a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
565a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  domainname_len = strlen (domainname);
566a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  xdomainname = (char *) alloca (strlen (categoryname)
567a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o				 + domainname_len + 5);
568a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  ADD_BLOCK (block_list, xdomainname);
569a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
570a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
571a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  domainname, domainname_len),
572a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  ".mo");
573a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
574a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Creating working area.  */
575a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
576a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  ADD_BLOCK (block_list, single_locale);
577a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
578a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
579a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Search for the given string.  This is a loop because we perhaps
580a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     got an ordered list of languages to consider for the translation.  */
581a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  while (1)
582a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
583a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* Make CATEGORYVALUE point to the next element of the list.  */
584a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
585a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	++categoryvalue;
586a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (categoryvalue[0] == '\0')
587a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
588a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* The whole contents of CATEGORYVALUE has been searched but
589a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     no valid entry has been found.  We solve this situation
590a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     by implicitly appending a "C" entry, i.e. no translation
591a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     will take place.  */
592a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  single_locale[0] = 'C';
593a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  single_locale[1] = '\0';
594a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
595a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      else
596a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
597a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  char *cp = single_locale;
598a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
599a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    *cp++ = *categoryvalue++;
600a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  *cp = '\0';
601a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
602a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* When this is a SUID binary we must not allow accessing files
603a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     outside the dedicated directories.  */
604a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
605a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    /* Ingore this entry.  */
606a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    continue;
607a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
608a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
609a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* If the current locale value is C (or POSIX) we don't load a
610a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 domain.  Return the MSGID.  */
611a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (strcmp (single_locale, "C") == 0
612a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  || strcmp (single_locale, "POSIX") == 0)
613b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	break;
614a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
615a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* Find structure describing the message catalog matching the
616a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 DOMAINNAME and CATEGORY.  */
617a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
618a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
619a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (domain != NULL)
620a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
621a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  retval = _nl_find_msg (domain, binding, msgid1, &retlen);
622a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
623a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (retval == NULL)
624a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    {
625a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      int cnt;
626a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
627a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
628a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
629a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  retval = _nl_find_msg (domain->successor[cnt], binding,
630a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o					 msgid1, &retlen);
631a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
632a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  if (retval != NULL)
633a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    {
634a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      domain = domain->successor[cnt];
635a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      break;
636a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    }
637a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
638a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    }
639a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
640a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (retval != NULL)
641a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    {
642a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      /* Found the translation of MSGID1 in domain DOMAIN:
643a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		 starting at RETVAL, RETLEN bytes.  */
644a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      FREE_BLOCKS (block_list);
645a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined HAVE_TSEARCH || defined _LIBC
646a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (foundp == NULL)
647a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
648a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  /* Create a new entry and add it to the search tree.  */
649a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  struct known_translation_t *newp;
650a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
651a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  newp = (struct known_translation_t *)
652a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    malloc (offsetof (struct known_translation_t, msgid)
653a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			    + msgid_len + domainname_len + 1);
654a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  if (newp != NULL)
655a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    {
656a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      newp->domainname =
657a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			mempcpy (newp->msgid, msgid1, msgid_len);
658a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      memcpy (newp->domainname, domainname, domainname_len + 1);
659a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      newp->category = category;
660a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      newp->counter = _nl_msg_cat_cntr;
661a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      newp->domain = domain;
662a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      newp->translation = retval;
663a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      newp->translation_length = retlen;
664a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
665a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      /* Insert the entry in the search tree.  */
666a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      foundp = (struct known_translation_t **)
667a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			tsearch (newp, &root, transcmp);
668a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      if (foundp == NULL
669a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			  || __builtin_expect (*foundp != newp, 0))
670a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			/* The insert failed.  */
671a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			free (newp);
672a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    }
673a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
674a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      else
675a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
676a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  /* We can update the existing entry.  */
677a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  (*foundp)->counter = _nl_msg_cat_cntr;
678a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  (*foundp)->domain = domain;
679a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  (*foundp)->translation = retval;
680a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  (*foundp)->translation_length = retlen;
681a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
682a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
683b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	      __set_errno (saved_errno);
684b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
685a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      /* Now deal with plural.  */
686a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (plural)
687a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		retval = plural_lookup (domain, n, retval, retlen);
688a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
689a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      __libc_rwlock_unlock (_nl_state_lock);
690a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      return retval;
691a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    }
692a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
693a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
694b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
695b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o return_untranslated:
696b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  /* Return the untranslated MSGID.  */
697b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  FREE_BLOCKS (block_list);
698b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  __libc_rwlock_unlock (_nl_state_lock);
699b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#if 0				/* Doesn't work with diet libc -- TYT */
700b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifndef _LIBC
701b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  if (!ENABLE_SECURE)
702b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o    {
703b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      extern void _nl_log_untranslated (const char *logfilename,
704b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o					const char *domainname,
705b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o					const char *msgid1, const char *msgid2,
706b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o					int plural);
707b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
708b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
709b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      if (logfilename != NULL && logfilename[0] != '\0')
710b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
711b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o    }
712b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
713b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
714b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  __set_errno (saved_errno);
715b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  return (plural == 0
716b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	  ? (char *) msgid1
717b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	  /* Use the Germanic plural rule.  */
718b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	  : n == 1 ? (char *) msgid1 : (char *) msgid2);
719a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
720a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
721a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
722a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ochar *
723a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ointernal_function
724b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o_nl_find_msg (struct loaded_l10nfile *domain_file,
725b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	      struct binding *domainbinding, const char *msgid,
726b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	      size_t *lengthp)
727a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
728a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct loaded_domain *domain;
729a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  nls_uint32 nstrings;
730a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  size_t act;
731a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  char *result;
732a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  size_t resultlen;
733a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
734a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (domain_file->decided == 0)
735a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    _nl_load_domain (domain_file, domainbinding);
736a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
737a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (domain_file->data == NULL)
738a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    return NULL;
739a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
740a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  domain = (struct loaded_domain *) domain_file->data;
741a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
742a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  nstrings = domain->nstrings;
743a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
744a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Locate the MSGID and its translation.  */
745a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (domain->hash_tab != NULL)
746a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
747a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* Use the hashing table.  */
748a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      nls_uint32 len = strlen (msgid);
749a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      nls_uint32 hash_val = hash_string (msgid);
750a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      nls_uint32 idx = hash_val % domain->hash_size;
751a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
752a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
753a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      while (1)
754a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
755a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  nls_uint32 nstr =
756a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
757a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
758a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (nstr == 0)
759a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    /* Hash table entry is empty.  */
760a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    return NULL;
761a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
762a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  nstr--;
763a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
764a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* Compare msgid with the original string at index nstr.
765a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     We compare the lengths with >=, not ==, because plural entries
766a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     are represented by strings with an embedded NUL.  */
767a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (nstr < nstrings
768a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
769a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		&& (strcmp (msgid,
770a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			    domain->data + W (domain->must_swap,
771a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o					      domain->orig_tab[nstr].offset))
772a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    == 0)
773a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      : domain->orig_sysdep_tab[nstr - nstrings].length > len
774a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		&& (strcmp (msgid,
775a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			    domain->orig_sysdep_tab[nstr - nstrings].pointer)
776a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    == 0))
777a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    {
778a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      act = nstr;
779a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      goto found;
780a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    }
781a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
782a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (idx >= domain->hash_size - incr)
783a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    idx -= domain->hash_size - incr;
784a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  else
785a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    idx += incr;
786a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
787a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* NOTREACHED */
788a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
789a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  else
790a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
791a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* Try the default method:  binary search in the sorted array of
792a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 messages.  */
793a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      size_t top, bottom;
794a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
795a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      bottom = 0;
796a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      top = nstrings;
797a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      while (bottom < top)
798a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
799a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  int cmp_val;
800a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
801a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  act = (bottom + top) / 2;
802a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  cmp_val = strcmp (msgid, (domain->data
803a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o				    + W (domain->must_swap,
804a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o					 domain->orig_tab[act].offset)));
805a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  if (cmp_val < 0)
806a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    top = act;
807a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  else if (cmp_val > 0)
808a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    bottom = act + 1;
809a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  else
810a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    goto found;
811a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
812a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* No translation was found.  */
813a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      return NULL;
814a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
815a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
816a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o found:
817a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* The translation was found at index ACT.  If we have to convert the
818a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     string to use a different character set, this is the time.  */
819a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (act < nstrings)
820a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
821a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      result = (char *)
822a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	(domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
823a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
824a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
825a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  else
826a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
827a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
828a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      resultlen = domain->trans_sysdep_tab[act - nstrings].length;
829a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
830a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
831a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined _LIBC || HAVE_ICONV
832a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (domain->codeset_cntr
833a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
834a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
835a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* The domain's codeset has changed through bind_textdomain_codeset()
836a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 since the message catalog was initialized or last accessed.  We
837a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 have to reinitialize the converter.  */
838a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      _nl_free_domain_conv (domain);
839a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      _nl_init_domain_conv (domain_file, domain, domainbinding);
840a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
841a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
842a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (
843a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifdef _LIBC
844a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      domain->conv != (__gconv_t) -1
845a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# else
846a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  if HAVE_ICONV
847a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      domain->conv != (iconv_t) -1
848a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  endif
849a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
850a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      )
851a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
852a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* We are supposed to do a conversion.  First allocate an
853a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 appropriate table with the same structure as the table
854a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 of translations in the file, where we can put the pointers
855a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 to the converted strings in.
856a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 There is a slight complication with plural entries.  They
857a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 are represented by consecutive NUL terminated strings.  We
858a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 handle this case by converting RESULTLEN bytes, including
859a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 NULs.  */
860a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
861a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (domain->conv_tab == NULL
862a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  && ((domain->conv_tab =
863a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		 (char **) calloc (nstrings + domain->n_sysdep_strings,
864a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o				   sizeof (char *)))
865a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      == NULL))
866a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	/* Mark that we didn't succeed allocating a table.  */
867a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	domain->conv_tab = (char **) -1;
868a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
869a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
870a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	/* Nothing we can do, no more memory.  */
871a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	goto converted;
872a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
873a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (domain->conv_tab[act] == NULL)
874a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	{
875a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* We haven't used this string so far, so it is not
876a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     translated yet.  Do this now.  */
877a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* We use a bit more efficient memory handling.
878a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     We allocate always larger blocks which get used over
879a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     time.  This is faster than many small allocations.   */
880a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  __libc_lock_define_initialized (static, lock)
881a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define INITIAL_BLOCK_SIZE	4080
882a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  static unsigned char *freemem;
883a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  static size_t freemem_size;
884a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
885a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  const unsigned char *inbuf;
886a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  unsigned char *outbuf;
887a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  int malloc_count;
888a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef _LIBC
889a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  transmem_block_t *transmem_list = NULL;
890a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
891a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
892a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  __libc_lock_lock (lock);
893a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
894a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  inbuf = (const unsigned char *) result;
895a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  outbuf = freemem + sizeof (size_t);
896a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
897a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  malloc_count = 0;
898a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  while (1)
899a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    {
900a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      transmem_block_t *newmem;
901a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifdef _LIBC
902a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      size_t non_reversible;
903a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      int res;
904a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
905a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (freemem_size < sizeof (size_t))
906a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		goto resize_freemem;
907a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
908a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      res = __gconv (domain->conv,
909a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			     &inbuf, inbuf + resultlen,
910a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			     &outbuf,
911a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			     outbuf + freemem_size - sizeof (size_t),
912a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			     &non_reversible);
913a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
914a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
915a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		break;
916a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
917a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (res != __GCONV_FULL_OUTPUT)
918a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
919a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  __libc_lock_unlock (lock);
920a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  goto converted;
921a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
922a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
923a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      inbuf = result;
924a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# else
925a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  if HAVE_ICONV
926a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      const char *inptr = (const char *) inbuf;
927a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      size_t inleft = resultlen;
928a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      char *outptr = (char *) outbuf;
929a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      size_t outleft;
930a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
931a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (freemem_size < sizeof (size_t))
932a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		goto resize_freemem;
933a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
934a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      outleft = freemem_size - sizeof (size_t);
935a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (iconv (domain->conv,
936a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			 (ICONV_CONST char **) &inptr, &inleft,
937a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			 &outptr, &outleft)
938a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  != (size_t) (-1))
939a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
940a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  outbuf = (unsigned char *) outptr;
941a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  break;
942a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
943a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (errno != E2BIG)
944a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
945a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  __libc_lock_unlock (lock);
946a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  goto converted;
947a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
948a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  endif
949a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
950a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
951a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    resize_freemem:
952a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      /* We must allocate a new buffer or resize the old one.  */
953a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (malloc_count > 0)
954a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
955a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  ++malloc_count;
956a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
957a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  newmem = (transmem_block_t *) realloc (transmem_list,
958a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o							 freemem_size);
959a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifdef _LIBC
960a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  if (newmem != NULL)
961a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    transmem_list = transmem_list->next;
962a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  else
963a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    {
964a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      struct transmem_list *old = transmem_list;
965a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
966a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      transmem_list = transmem_list->next;
967a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      free (old);
968a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    }
969a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
970a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
971a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      else
972a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
973a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  malloc_count = 1;
974a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  freemem_size = INITIAL_BLOCK_SIZE;
975a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  newmem = (transmem_block_t *) malloc (freemem_size);
976a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
977a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      if (__builtin_expect (newmem == NULL, 0))
978a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		{
979a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  freemem = NULL;
980a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  freemem_size = 0;
981a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  __libc_lock_unlock (lock);
982a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  goto converted;
983a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		}
984a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
985a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifdef _LIBC
986a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      /* Add the block to the list of blocks we have to free
987a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o                 at some point.  */
988a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      newmem->next = transmem_list;
989a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      transmem_list = newmem;
990a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
991a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      freemem = newmem->data;
992a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      freemem_size -= offsetof (struct transmem_list, data);
993a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# else
994a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      transmem_list = newmem;
995a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      freemem = newmem;
996a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
997a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
998a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      outbuf = freemem + sizeof (size_t);
999a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	    }
1000a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1001a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* We have now in our buffer a converted string.  Put this
1002a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	     into the table of conversions.  */
1003a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
1004a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  domain->conv_tab[act] = (char *) freemem;
1005a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  /* Shrink freemem, but keep it aligned.  */
1006a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  freemem_size -= outbuf - freemem;
1007a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  freemem = outbuf;
1008a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  freemem += freemem_size & (alignof (size_t) - 1);
1009a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  freemem_size = freemem_size & ~ (alignof (size_t) - 1);
1010a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1011a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  __libc_lock_unlock (lock);
1012a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	}
1013a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1014a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* Now domain->conv_tab[act] contains the translation of all
1015a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	 the plural variants.  */
1016a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      result = domain->conv_tab[act] + sizeof (size_t);
1017a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      resultlen = *(size_t *) domain->conv_tab[act];
1018a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
1019a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1020a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o converted:
1021a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* The result string is converted.  */
1022a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1023a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif /* _LIBC || HAVE_ICONV */
1024a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1025a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  *lengthp = resultlen;
1026a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return result;
1027a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1028a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1029a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1030a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Look up a plural variant.  */
1031a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic char *
1032a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ointernal_function
1033b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'oplural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
1034b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	       const char *translation, size_t translation_len)
1035a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
1036a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
1037a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  unsigned long int index;
1038a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *p;
1039a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1040a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  index = plural_eval (domaindata->plural, n);
1041a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (index >= domaindata->nplurals)
1042a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    /* This should never happen.  It means the plural expression and the
1043a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o       given maximum value do not match.  */
1044a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    index = 0;
1045a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1046a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Skip INDEX strings at TRANSLATION.  */
1047a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  p = translation;
1048a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  while (index-- > 0)
1049a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
1050a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
1051a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      p = __rawmemchr (p, '\0');
1052a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
1053a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      p = strchr (p, '\0');
1054a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1055a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      /* And skip over the NUL byte.  */
1056a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      p++;
1057a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1058a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (p >= translation + translation_len)
1059a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	/* This should never happen.  It means the plural expression
1060a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	   evaluated to a value larger than the number of variants
1061a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	   available for MSGID1.  */
1062a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	return (char *) translation;
1063a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
1064a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return (char *) p;
1065a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1066a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1067b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifndef _LIBC
1068a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Return string representation of locale CATEGORY.  */
1069a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic const char *
1070a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ointernal_function
1071b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ocategory_to_name (int category)
1072a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
1073a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *retval;
1074a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1075a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  switch (category)
1076a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  {
1077a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_COLLATE
1078a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_COLLATE:
1079a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_COLLATE";
1080a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1081a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1082a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_CTYPE
1083a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_CTYPE:
1084a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_CTYPE";
1085a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1086a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1087a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_MONETARY
1088a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_MONETARY:
1089a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_MONETARY";
1090a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1091a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1092a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_NUMERIC
1093a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_NUMERIC:
1094a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_NUMERIC";
1095a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1096a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1097a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_TIME
1098a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_TIME:
1099a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_TIME";
1100a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1101a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1102a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_MESSAGES
1103a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_MESSAGES:
1104a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_MESSAGES";
1105a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1106a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1107a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_RESPONSE
1108a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_RESPONSE:
1109a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_RESPONSE";
1110a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1111a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1112a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef LC_ALL
1113a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  case LC_ALL:
1114a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    /* This might not make sense but is perhaps better than any other
1115a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o       value.  */
1116a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_ALL";
1117a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    break;
1118a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1119a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  default:
1120a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    /* If you have a better idea for a default value let me know.  */
1121a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    retval = "LC_XXX";
1122a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  }
1123a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1124a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return retval;
1125a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1126b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
1127a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1128a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Guess value of current locale from value of the environment variables.  */
1129a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic const char *
1130a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ointernal_function
1131b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'oguess_category_value (int category, const char *categoryname)
1132a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
1133a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *language;
1134a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  const char *retval;
1135a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1136a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* The highest priority value is the `LANGUAGE' environment
1137a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     variable.  But we don't use the value if the currently selected
1138a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     locale is the C locale.  This is a GNU extension.  */
1139a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  language = getenv ("LANGUAGE");
1140a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (language != NULL && language[0] == '\0')
1141a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    language = NULL;
1142a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1143a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* We have to proceed with the POSIX methods of looking to `LC_ALL',
1144a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     `LC_xxx', and `LANG'.  On some systems this can be done by the
1145a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     `setlocale' function itself.  */
1146a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
1147b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  retval = __current_locale_name (category);
1148a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
1149a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  retval = _nl_locale_name (category, categoryname);
1150a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1151a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1152a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Ignore LANGUAGE if the locale is set to "C" because
1153a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     1. "C" locale usually uses the ASCII encoding, and most international
1154a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	messages use non-ASCII characters. These characters get displayed
1155a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	as question marks (if using glibc's iconv()) or as invalid 8-bit
1156a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	characters (because other iconv()s refuse to convert most non-ASCII
1157a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	characters to ASCII). In any case, the output is ugly.
1158a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o     2. The precise output of some programs in the "C" locale is specified
1159a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	by POSIX and should not depend on environment variables like
1160a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	"LANGUAGE".  We allow such programs to use gettext().  */
1161a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
1162a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1163a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1164a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* @@ begin of epilog @@ */
1165a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1166a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* We don't want libintl.a to depend on any other library.  So we
1167a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   avoid the non-standard function stpcpy.  In GNU C Library this
1168a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   function is available, though.  Also allow the symbol HAVE_STPCPY
1169a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   to be defined.  */
1170a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if !_LIBC && !HAVE_STPCPY
1171a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic char *
1172b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostpcpy (char *dest, const char *src)
1173a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
1174a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  while ((*dest++ = *src++) != '\0')
1175a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    /* Do nothing. */ ;
1176a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return dest - 1;
1177a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1178a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1179a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1180a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if !_LIBC && !HAVE_MEMPCPY
1181a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic void *
1182b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'omempcpy (void *dest, const void *src, size_t n)
1183a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
1184a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return (void *) ((char *) memcpy (dest, src, n) + n);
1185a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1186a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1187a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1188a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1189a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
1190a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* If we want to free all resources we have to do some work at
1191a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   program's end.  */
1192b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'olibc_freeres_fn (free_mem)
1193a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o{
1194a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  void *old;
1195a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1196a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  while (_nl_domain_bindings != NULL)
1197a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
1198a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      struct binding *oldp = _nl_domain_bindings;
1199a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      _nl_domain_bindings = _nl_domain_bindings->next;
1200b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      if (oldp->dirname != INTUSE(_nl_default_dirname))
1201a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	/* Yes, this is a pointer comparison.  */
1202a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	free (oldp->dirname);
1203a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      free (oldp->codeset);
1204a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      free (oldp);
1205a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
1206a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1207a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (_nl_current_default_domain != _nl_default_default_domain)
1208a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    /* Yes, again a pointer comparison.  */
1209a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    free ((char *) _nl_current_default_domain);
1210a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1211a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* Remove the search tree with the known translations.  */
1212a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  __tdestroy (root, free);
1213a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  root = NULL;
1214a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1215a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  while (transmem_list != NULL)
1216a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    {
1217a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      old = transmem_list;
1218a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      transmem_list = transmem_list->next;
1219a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      free (old);
1220a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    }
1221a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o}
1222a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1223