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