Updated from ../gpl2lgpl.sed
[kopensolaris-gnu/glibc.git] / intl / dcgettext.c
1 /* dcgettext.c -- implementation of the dcgettext(3) function
2    Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3
4 This file is part of the GNU C Library.  Its master source is NOT part of
5 the C library, however.  The master source lives in /gd/gnu/lib.
6
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB.  If
19 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
20 Cambridge, MA 02139, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <sys/types.h>
27
28 #ifdef __GNUC__
29 # define alloca __builtin_alloca
30 #else
31 # if defined HAVE_ALLOCA_H || defined _LIBC
32 #  include <alloca.h>
33 # else
34 #  ifdef _AIX
35  #pragma alloca
36 #  else
37 #   ifndef alloca
38 char *alloca ();
39 #   endif
40 #  endif
41 # endif
42 #endif
43
44 #include <errno.h>
45 #ifndef errno
46 extern int errno;
47 #endif
48
49 #if defined STDC_HEADERS || defined _LIBC
50 # include <stdlib.h>
51 #else
52 char *getenv ();
53 # ifdef HAVE_MALLOC_H
54 #  include <malloc.h>
55 # else
56 void free ();
57 # endif
58 #endif
59
60 #if defined HAVE_STRING_H || defined _LIBC
61 # include <string.h>
62 #else
63 # include <strings.h>
64 #endif
65 #if !HAVE_STRCHR && !defined _LIBC
66 # ifndef strchr
67 #  define strchr index
68 # endif
69 #endif
70
71 #if defined HAVE_UNISTD_H || defined _LIBC
72 # include <unistd.h>
73 #endif
74
75 #include "gettext.h"
76 #include "gettextP.h"
77 #ifdef _LIBC
78 # include <libintl.h>
79 #else
80 # include "libgettext.h"
81 #endif
82 #include "hash-string.h"
83
84 /* @@ end of prolog @@ */
85
86 #ifdef _LIBC
87 /* Rename the non ANSI C functions.  This is required by the standard
88    because some ANSI C functions will require linking with this object
89    file and the name space must not be polluted.  */
90 # define getcwd __getcwd
91 # define stpcpy __stpcpy
92 #else
93 # if !defined HAVE_GETCWD
94 char *getwd ();
95 #  define getcwd(buf, max) getwd (buf)
96 # else
97 char *getcwd ();
98 # endif
99 #endif
100
101 /* Amount to increase buffer size by in each try.  */
102 #define PATH_INCR 32
103
104 /* The following is from pathmax.h.  */
105 /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
106    PATH_MAX but might cause redefinition warnings when sys/param.h is
107    later included (as on MORE/BSD 4.3).  */
108 #if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
109 # include <limits.h>
110 #endif
111
112 #ifndef _POSIX_PATH_MAX
113 # define _POSIX_PATH_MAX 255
114 #endif
115
116 #if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
117 # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
118 #endif
119
120 /* Don't include sys/param.h if it already has been.  */
121 #if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
122 # include <sys/param.h>
123 #endif
124
125 #if !defined(PATH_MAX) && defined(MAXPATHLEN)
126 # define PATH_MAX MAXPATHLEN
127 #endif
128
129 #ifndef PATH_MAX
130 # define PATH_MAX _POSIX_PATH_MAX
131 #endif
132
133 /* XPG3 defines the result of `setlocale (category, NULL)' as:
134    ``Directs `setlocale()' to query `category' and return the current
135      setting of `local'.''
136    However it does not specify the exact format.  And even worse: POSIX
137    defines this not at all.  So we can use this feature only on selected
138    system (e.g. those using GNU C Library).  */
139 #ifdef _LIBC
140 # define HAVE_LOCALE_NULL
141 #endif
142
143 /* Name of the default domain used for gettext(3) prior any call to
144    textdomain(3).  The default value for this is "messages".  */
145 const char _nl_default_default_domain[] = "messages";
146
147 /* Value used as the default domain for gettext(3).  */
148 const char *_nl_current_default_domain = _nl_default_default_domain;
149
150 /* Contains the default location of the message catalogs.  */
151 const char _nl_default_dirname[] = GNULOCALEDIR;
152
153 /* List with bindings of specific domains created by bindtextdomain()
154    calls.  */
155 struct binding *_nl_domain_bindings;
156
157 /* Prototypes for local functions.  */
158 static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
159                                const char *msgid));
160 static const char *category_to_name PARAMS ((int category));
161 static const char *guess_category_value PARAMS ((int category,
162                                                  const char *categoryname));
163
164
165 /* For those loosing systems which don't have `alloca' we have to add
166    some additional code emulating it.  */
167 #ifdef HAVE_ALLOCA
168 /* Nothing has to be done.  */
169 # define ADD_BLOCK(list, address) /* nothing */
170 # define FREE_BLOCKS(list) /* nothing */
171 #else
172 struct block_list
173 {
174   void *address;
175   struct block_list *next;
176 };
177 # define ADD_BLOCK(list, addr)                                                \
178   do {                                                                        \
179     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
180     /* If we cannot get a free block we cannot add the new element to         \
181        the list.  */                                                          \
182     if (newp != NULL) {                                                       \
183       newp->address = (addr);                                                 \
184       newp->next = (list);                                                    \
185       (list) = newp;                                                          \
186     }                                                                         \
187   } while (0)
188 # define FREE_BLOCKS(list)                                                    \
189   do {                                                                        \
190     while (list != NULL) {                                                    \
191       struct block_list *old = list;                                          \
192       list = list->next;                                                      \
193       free (old);                                                             \
194     }                                                                         \
195   } while (0)
196 # undef alloca
197 # define alloca(size) (malloc (size))
198 #endif  /* have alloca */
199
200
201 /* Names for the libintl functions are a problem.  They must not clash
202    with existing names and they should follow ANSI C.  But this source
203    code is also used in GNU C Library where the names have a __
204    prefix.  So we have to make a difference here.  */
205 #ifdef _LIBC
206 # define DCGETTEXT __dcgettext
207 #else
208 # define DCGETTEXT dcgettext__
209 #endif
210
211 /* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
212    locale.  */
213 char *
214 DCGETTEXT (domainname, msgid, category)
215      const char *domainname;
216      const char *msgid;
217      int category;
218 {
219 #ifndef HAVE_ALLOCA
220   struct block_list *alloca_list = NULL;
221 #endif
222   struct loaded_l10nfile *domain;
223   struct binding *binding;
224   const char *categoryname;
225   const char *categoryvalue;
226   char *dirname, *xdomainname;
227   char *single_locale;
228   char *retval;
229   int saved_errno = errno;
230
231   /* If no real MSGID is given return NULL.  */
232   if (msgid == NULL)
233     return NULL;
234
235   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
236      CATEGORY is not LC_MESSAGES this might not make much sense but the
237      defintion left this undefined.  */
238   if (domainname == NULL)
239     domainname = _nl_current_default_domain;
240
241   /* First find matching binding.  */
242   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
243     {
244       int compare = strcmp (domainname, binding->domainname);
245       if (compare == 0)
246         /* We found it!  */
247         break;
248       if (compare < 0)
249         {
250           /* It is not in the list.  */
251           binding = NULL;
252           break;
253         }
254     }
255
256   if (binding == NULL)
257     dirname = (char *) _nl_default_dirname;
258   else if (binding->dirname[0] == '/')
259     dirname = binding->dirname;
260   else
261     {
262       /* We have a relative path.  Make it absolute now.  */
263       size_t dirname_len = strlen (binding->dirname) + 1;
264       size_t path_max;
265       char *ret;
266
267       path_max = (unsigned) PATH_MAX;
268       path_max += 2;            /* The getcwd docs say to do this.  */
269
270       dirname = (char *) alloca (path_max + dirname_len);
271       ADD_BLOCK (block_list, dirname);
272
273       errno = 0;
274       while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
275         {
276           path_max += PATH_INCR;
277           dirname = (char *) alloca (path_max + dirname_len);
278           ADD_BLOCK (block_list, dirname);
279           errno = 0;
280         }
281
282       if (ret == NULL)
283         {
284           /* We cannot get the current working directory.  Don't signal an
285              error but simply return the default string.  */
286           FREE_BLOCKS (block_list);
287           errno = saved_errno;
288           return (char *) msgid;
289         }
290
291       /* We don't want libintl.a to depend on any other library.  So
292          we avoid the non-standard function stpcpy.  In GNU C Library
293          this function is available, though.  Also allow the symbol
294          HAVE_STPCPY to be defined.  */
295 #if defined _LIBC || defined HAVE_STPCPY
296       stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
297 #else
298       strcat (dirname, "/");
299       strcat (dirname, binding->dirname);
300 #endif
301     }
302
303   /* Now determine the symbolic name of CATEGORY and its value.  */
304   categoryname = category_to_name (category);
305   categoryvalue = guess_category_value (category, categoryname);
306
307   xdomainname = (char *) alloca (strlen (categoryname)
308                                  + strlen (domainname) + 5);
309   ADD_BLOCK (block_list, xdomainname);
310   /* We don't want libintl.a to depend on any other library.  So we
311      avoid the non-standard function stpcpy.  In GNU C Library this
312      function is available, though.  Also allow the symbol HAVE_STPCPY
313      to be defined.  */
314 #if defined _LIBC || defined HAVE_STPCPY
315   stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
316                   domainname),
317           ".mo");
318 #else
319   strcpy (xdomainname, categoryname);
320   strcat (xdomainname, "/");
321   strcat (xdomainname, domainname);
322   strcat (xdomainname, ".mo");
323 #endif
324
325   /* Creating working area.  */
326   single_locale = (char *) alloca (strlen (categoryvalue) + 1);
327   ADD_BLOCK (block_list, single_locale);
328
329
330   /* Search for the given string.  This is a loop because we perhaps
331      got an ordered list of languages to consider for th translation.  */
332   while (1)
333     {
334       /* Make CATEGORYVALUE point to the next element of the list.  */
335       while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
336         ++categoryvalue;
337       if (categoryvalue[0] == '\0')
338         {
339           /* The whole contents of CATEGORYVALUE has been searched but
340              no valid entry has been found.  We solve this situation
341              by implicitely appending a "C" entry, i.e. no translation
342              will take place.  */
343           single_locale[0] = 'C';
344           single_locale[1] = '\0';
345         }
346       else
347         {
348           char *cp = single_locale;
349           while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
350             *cp++ = *categoryvalue++;
351           *cp = '\0';
352         }
353
354       /* If the current locale value is C (or POSIX) we don't load a
355          domain.  Return the MSGID.  */
356       if (strcmp (single_locale, "C") == 0
357           || strcmp (single_locale, "POSIX") == 0)
358         {
359           FREE_BLOCKS (block_list);
360           errno = saved_errno;
361           return (char *) msgid;
362         }
363
364
365       /* Find structure describing the message catalog matching the
366          DOMAINNAME and CATEGORY.  */
367       domain = _nl_find_domain (dirname, single_locale, xdomainname);
368
369       if (domain != NULL)
370         {
371           retval = find_msg (domain, msgid);
372
373           if (retval == NULL)
374             {
375               int cnt;
376
377               for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
378                 {
379                   retval = find_msg (domain->successor[cnt], msgid);
380
381                   if (retval != NULL)
382                     break;
383                 }
384             }
385
386           if (retval != NULL)
387             {
388               FREE_BLOCKS (block_list);
389               errno = saved_errno;
390               return retval;
391             }
392         }
393     }
394   /* NOTREACHED */
395 }
396
397 #ifdef _LIBC
398 /* Alias for function name in GNU C Library.  */
399 weak_alias (__dcgettext, dcgettext);
400 #endif
401
402
403 static char *
404 find_msg (domain_file, msgid)
405      struct loaded_l10nfile *domain_file;
406      const char *msgid;
407 {
408   size_t top, act, bottom;
409   struct loaded_domain *domain;
410
411   if (domain_file->decided == 0)
412     _nl_load_domain (domain_file);
413
414   if (domain_file->data == NULL)
415     return NULL;
416
417   domain = (struct loaded_domain *) domain_file->data;
418
419   /* Locate the MSGID and its translation.  */
420   if (domain->hash_size > 2 && domain->hash_tab != NULL)
421     {
422       /* Use the hashing table.  */
423       nls_uint32 len = strlen (msgid);
424       nls_uint32 hash_val = hash_string (msgid);
425       nls_uint32 idx = hash_val % domain->hash_size;
426       nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
427       nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
428
429       if (nstr == 0)
430         /* Hash table entry is empty.  */
431         return NULL;
432
433       if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
434           && strcmp (msgid,
435                      domain->data + W (domain->must_swap,
436                                        domain->orig_tab[nstr - 1].offset)) == 0)
437         return (char *) domain->data + W (domain->must_swap,
438                                           domain->trans_tab[nstr - 1].offset);
439
440       while (1)
441         {
442           if (idx >= domain->hash_size - incr)
443             idx -= domain->hash_size - incr;
444           else
445             idx += incr;
446
447           nstr = W (domain->must_swap, domain->hash_tab[idx]);
448           if (nstr == 0)
449             /* Hash table entry is empty.  */
450             return NULL;
451
452           if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
453               && strcmp (msgid,
454                          domain->data + W (domain->must_swap,
455                                            domain->orig_tab[nstr - 1].offset))
456                  == 0)
457             return (char *) domain->data
458               + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
459         }
460       /* NOTREACHED */
461     }
462
463   /* Now we try the default method:  binary search in the sorted
464      array of messages.  */
465   bottom = 0;
466   top = domain->nstrings;
467   while (bottom < top)
468     {
469       int cmp_val;
470
471       act = (bottom + top) / 2;
472       cmp_val = strcmp (msgid, domain->data
473                                + W (domain->must_swap,
474                                     domain->orig_tab[act].offset));
475       if (cmp_val < 0)
476         top = act;
477       else if (cmp_val > 0)
478         bottom = act + 1;
479       else
480         break;
481     }
482
483   /* If an translation is found return this.  */
484   return bottom >= top ? NULL : (char *) domain->data
485                                 + W (domain->must_swap,
486                                      domain->trans_tab[act].offset);
487 }
488
489
490 /* Return string representation of locale CATEGORY.  */
491 static const char *
492 category_to_name (category)
493      int category;
494 {
495   const char *retval;
496
497   switch (category)
498   {
499 #ifdef LC_COLLATE
500   case LC_COLLATE:
501     retval = "LC_COLLATE";
502     break;
503 #endif
504 #ifdef LC_CTYPE
505   case LC_CTYPE:
506     retval = "LC_CTYPE";
507     break;
508 #endif
509 #ifdef LC_MONETARY
510   case LC_MONETARY:
511     retval = "LC_MONETARY";
512     break;
513 #endif
514 #ifdef LC_NUMERIC
515   case LC_NUMERIC:
516     retval = "LC_NUMERIC";
517     break;
518 #endif
519 #ifdef LC_TIME
520   case LC_TIME:
521     retval = "LC_TIME";
522     break;
523 #endif
524 #ifdef LC_MESSAGES
525   case LC_MESSAGES:
526     retval = "LC_MESSAGES";
527     break;
528 #endif
529 #ifdef LC_RESPONSE
530   case LC_RESPONSE:
531     retval = "LC_RESPONSE";
532     break;
533 #endif
534 #ifdef LC_ALL
535   case LC_ALL:
536     /* This might not make sense but is perhaps better than any other
537        value.  */
538     retval = "LC_ALL";
539     break;
540 #endif
541   default:
542     /* If you have a better idea for a default value let me know.  */
543     retval = "LC_XXX";
544   }
545
546   return retval;
547 }
548
549 /* Guess value of current locale from value of the environment variables.  */
550 static const char *guess_category_value (category, categoryname)
551      int category;
552      const char *categoryname;
553 {
554   const char *retval;
555
556   /* The highest priority value is the `LANGUAGE' environment
557      variable.  This is a GNU extension.  */
558   retval = getenv ("LANGUAGE");
559   if (retval != NULL && retval[0] != '\0')
560     return retval;
561
562   /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
563      methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
564      systems this can be done by the `setlocale' function itself.  */
565 #if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
566   return setlocale (category, NULL);
567 #else
568   /* Setting of LC_ALL overwrites all other.  */
569   retval = getenv ("LC_ALL");
570   if (retval != NULL && retval[0] != '\0')
571     return retval;
572
573   /* Next comes the name of the desired category.  */
574   retval = getenv (categoryname);
575   if (retval != NULL && retval[0] != '\0')
576     return retval;
577
578   /* Last possibility is the LANG environment variable.  */
579   retval = getenv ("LANG");
580   if (retval != NULL && retval[0] != '\0')
581     return retval;
582
583   /* We use C as the default domain.  POSIX says this is implementation
584      defined.  */
585   return "C";
586 #endif
587 }