Tue Jun 4 00:16:03 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[glibc.git] / intl / dcgettext.c
blob743c85bf2272c82ca81cc205e09968ce9a80d945
1 /* dcgettext.c -- implementation of the dcgettext(3) function
2 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
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.
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.
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.
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. */
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #include <sys/types.h>
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
44 #include <errno.h>
45 #ifndef errno
46 extern int errno;
47 #endif
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
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
71 #if defined HAVE_UNISTD_H || defined _LIBC
72 # include <unistd.h>
73 #endif
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"
84 /* @@ end of prolog @@ */
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
101 /* Amount to increase buffer size by in each try. */
102 #define PATH_INCR 32
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
112 #ifndef _POSIX_PATH_MAX
113 # define _POSIX_PATH_MAX 255
114 #endif
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
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
125 #if !defined(PATH_MAX) && defined(MAXPATHLEN)
126 # define PATH_MAX MAXPATHLEN
127 #endif
129 #ifndef PATH_MAX
130 # define PATH_MAX _POSIX_PATH_MAX
131 #endif
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
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";
147 /* Value used as the default domain for gettext(3). */
148 const char *_nl_current_default_domain = _nl_default_default_domain;
150 /* Contains the default location of the message catalogs. */
151 const char _nl_default_dirname[] = GNULOCALEDIR;
153 /* List with bindings of specific domains created by bindtextdomain()
154 calls. */
155 struct binding *_nl_domain_bindings;
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));
165 #ifdef _LIBC
166 #define HAVE_ALLOCA 1
167 #endif
169 /* For those loosing systems which don't have `alloca' we have to add
170 some additional code emulating it. */
171 #ifdef HAVE_ALLOCA
172 /* Nothing has to be done. */
173 # define ADD_BLOCK(list, address) /* nothing */
174 # define FREE_BLOCKS(list) /* nothing */
175 #else
176 struct block_list
178 void *address;
179 struct block_list *next;
181 # define ADD_BLOCK(list, addr) \
182 do { \
183 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
184 /* If we cannot get a free block we cannot add the new element to \
185 the list. */ \
186 if (newp != NULL) { \
187 newp->address = (addr); \
188 newp->next = (list); \
189 (list) = newp; \
191 } while (0)
192 # define FREE_BLOCKS(list) \
193 do { \
194 while (list != NULL) { \
195 struct block_list *old = list; \
196 list = list->next; \
197 free (old); \
199 } while (0)
200 # undef alloca
201 # define alloca(size) (malloc (size))
202 #endif /* have alloca */
205 /* Names for the libintl functions are a problem. They must not clash
206 with existing names and they should follow ANSI C. But this source
207 code is also used in GNU C Library where the names have a __
208 prefix. So we have to make a difference here. */
209 #ifdef _LIBC
210 # define DCGETTEXT __dcgettext
211 #else
212 # define DCGETTEXT dcgettext__
213 #endif
215 /* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
216 locale. */
217 char *
218 DCGETTEXT (domainname, msgid, category)
219 const char *domainname;
220 const char *msgid;
221 int category;
223 #ifndef HAVE_ALLOCA
224 struct block_list *alloca_list = NULL;
225 #endif
226 struct loaded_l10nfile *domain;
227 struct binding *binding;
228 const char *categoryname;
229 const char *categoryvalue;
230 char *dirname, *xdomainname;
231 char *single_locale;
232 char *retval;
233 int saved_errno = errno;
235 /* If no real MSGID is given return NULL. */
236 if (msgid == NULL)
237 return NULL;
239 /* If DOMAINNAME is NULL, we are interested in the default domain. If
240 CATEGORY is not LC_MESSAGES this might not make much sense but the
241 defintion left this undefined. */
242 if (domainname == NULL)
243 domainname = _nl_current_default_domain;
245 /* First find matching binding. */
246 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
248 int compare = strcmp (domainname, binding->domainname);
249 if (compare == 0)
250 /* We found it! */
251 break;
252 if (compare < 0)
254 /* It is not in the list. */
255 binding = NULL;
256 break;
260 if (binding == NULL)
261 dirname = (char *) _nl_default_dirname;
262 else if (binding->dirname[0] == '/')
263 dirname = binding->dirname;
264 else
266 /* We have a relative path. Make it absolute now. */
267 size_t dirname_len = strlen (binding->dirname) + 1;
268 size_t path_max;
269 char *ret;
271 path_max = (unsigned) PATH_MAX;
272 path_max += 2; /* The getcwd docs say to do this. */
274 dirname = (char *) alloca (path_max + dirname_len);
275 ADD_BLOCK (block_list, dirname);
277 errno = 0;
278 while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
280 path_max += PATH_INCR;
281 dirname = (char *) alloca (path_max + dirname_len);
282 ADD_BLOCK (block_list, dirname);
283 errno = 0;
286 if (ret == NULL)
288 /* We cannot get the current working directory. Don't signal an
289 error but simply return the default string. */
290 FREE_BLOCKS (block_list);
291 errno = saved_errno;
292 return (char *) msgid;
295 /* We don't want libintl.a to depend on any other library. So
296 we avoid the non-standard function stpcpy. In GNU C Library
297 this function is available, though. Also allow the symbol
298 HAVE_STPCPY to be defined. */
299 #if defined _LIBC || defined HAVE_STPCPY
300 stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
301 #else
302 strcat (dirname, "/");
303 strcat (dirname, binding->dirname);
304 #endif
307 /* Now determine the symbolic name of CATEGORY and its value. */
308 categoryname = category_to_name (category);
309 categoryvalue = guess_category_value (category, categoryname);
311 xdomainname = (char *) alloca (strlen (categoryname)
312 + strlen (domainname) + 5);
313 ADD_BLOCK (block_list, xdomainname);
314 /* We don't want libintl.a to depend on any other library. So we
315 avoid the non-standard function stpcpy. In GNU C Library this
316 function is available, though. Also allow the symbol HAVE_STPCPY
317 to be defined. */
318 #if defined _LIBC || defined HAVE_STPCPY
319 stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
320 domainname),
321 ".mo");
322 #else
323 strcpy (xdomainname, categoryname);
324 strcat (xdomainname, "/");
325 strcat (xdomainname, domainname);
326 strcat (xdomainname, ".mo");
327 #endif
329 /* Creating working area. */
330 single_locale = (char *) alloca (strlen (categoryvalue) + 1);
331 ADD_BLOCK (block_list, single_locale);
334 /* Search for the given string. This is a loop because we perhaps
335 got an ordered list of languages to consider for th translation. */
336 while (1)
338 /* Make CATEGORYVALUE point to the next element of the list. */
339 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
340 ++categoryvalue;
341 if (categoryvalue[0] == '\0')
343 /* The whole contents of CATEGORYVALUE has been searched but
344 no valid entry has been found. We solve this situation
345 by implicitely appending a "C" entry, i.e. no translation
346 will take place. */
347 single_locale[0] = 'C';
348 single_locale[1] = '\0';
350 else
352 char *cp = single_locale;
353 while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
354 *cp++ = *categoryvalue++;
355 *cp = '\0';
358 /* If the current locale value is C (or POSIX) we don't load a
359 domain. Return the MSGID. */
360 if (strcmp (single_locale, "C") == 0
361 || strcmp (single_locale, "POSIX") == 0)
363 FREE_BLOCKS (block_list);
364 errno = saved_errno;
365 return (char *) msgid;
369 /* Find structure describing the message catalog matching the
370 DOMAINNAME and CATEGORY. */
371 domain = _nl_find_domain (dirname, single_locale, xdomainname);
373 if (domain != NULL)
375 retval = find_msg (domain, msgid);
377 if (retval == NULL)
379 int cnt;
381 for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
383 retval = find_msg (domain->successor[cnt], msgid);
385 if (retval != NULL)
386 break;
390 if (retval != NULL)
392 FREE_BLOCKS (block_list);
393 errno = saved_errno;
394 return retval;
398 /* NOTREACHED */
401 #ifdef _LIBC
402 /* Alias for function name in GNU C Library. */
403 weak_alias (__dcgettext, dcgettext);
404 #endif
407 static char *
408 find_msg (domain_file, msgid)
409 struct loaded_l10nfile *domain_file;
410 const char *msgid;
412 size_t top, act, bottom;
413 struct loaded_domain *domain;
415 if (domain_file->decided == 0)
416 _nl_load_domain (domain_file);
418 if (domain_file->data == NULL)
419 return NULL;
421 domain = (struct loaded_domain *) domain_file->data;
423 /* Locate the MSGID and its translation. */
424 if (domain->hash_size > 2 && domain->hash_tab != NULL)
426 /* Use the hashing table. */
427 nls_uint32 len = strlen (msgid);
428 nls_uint32 hash_val = hash_string (msgid);
429 nls_uint32 idx = hash_val % domain->hash_size;
430 nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
431 nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
433 if (nstr == 0)
434 /* Hash table entry is empty. */
435 return NULL;
437 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
438 && strcmp (msgid,
439 domain->data + W (domain->must_swap,
440 domain->orig_tab[nstr - 1].offset)) == 0)
441 return (char *) domain->data + W (domain->must_swap,
442 domain->trans_tab[nstr - 1].offset);
444 while (1)
446 if (idx >= domain->hash_size - incr)
447 idx -= domain->hash_size - incr;
448 else
449 idx += incr;
451 nstr = W (domain->must_swap, domain->hash_tab[idx]);
452 if (nstr == 0)
453 /* Hash table entry is empty. */
454 return NULL;
456 if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
457 && strcmp (msgid,
458 domain->data + W (domain->must_swap,
459 domain->orig_tab[nstr - 1].offset))
460 == 0)
461 return (char *) domain->data
462 + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
464 /* NOTREACHED */
467 /* Now we try the default method: binary search in the sorted
468 array of messages. */
469 bottom = 0;
470 top = domain->nstrings;
471 while (bottom < top)
473 int cmp_val;
475 act = (bottom + top) / 2;
476 cmp_val = strcmp (msgid, domain->data
477 + W (domain->must_swap,
478 domain->orig_tab[act].offset));
479 if (cmp_val < 0)
480 top = act;
481 else if (cmp_val > 0)
482 bottom = act + 1;
483 else
484 break;
487 /* If an translation is found return this. */
488 return bottom >= top ? NULL : (char *) domain->data
489 + W (domain->must_swap,
490 domain->trans_tab[act].offset);
494 /* Return string representation of locale CATEGORY. */
495 static const char *
496 category_to_name (category)
497 int category;
499 const char *retval;
501 switch (category)
503 #ifdef LC_COLLATE
504 case LC_COLLATE:
505 retval = "LC_COLLATE";
506 break;
507 #endif
508 #ifdef LC_CTYPE
509 case LC_CTYPE:
510 retval = "LC_CTYPE";
511 break;
512 #endif
513 #ifdef LC_MONETARY
514 case LC_MONETARY:
515 retval = "LC_MONETARY";
516 break;
517 #endif
518 #ifdef LC_NUMERIC
519 case LC_NUMERIC:
520 retval = "LC_NUMERIC";
521 break;
522 #endif
523 #ifdef LC_TIME
524 case LC_TIME:
525 retval = "LC_TIME";
526 break;
527 #endif
528 #ifdef LC_MESSAGES
529 case LC_MESSAGES:
530 retval = "LC_MESSAGES";
531 break;
532 #endif
533 #ifdef LC_RESPONSE
534 case LC_RESPONSE:
535 retval = "LC_RESPONSE";
536 break;
537 #endif
538 #ifdef LC_ALL
539 case LC_ALL:
540 /* This might not make sense but is perhaps better than any other
541 value. */
542 retval = "LC_ALL";
543 break;
544 #endif
545 default:
546 /* If you have a better idea for a default value let me know. */
547 retval = "LC_XXX";
550 return retval;
553 /* Guess value of current locale from value of the environment variables. */
554 static const char *guess_category_value (category, categoryname)
555 int category;
556 const char *categoryname;
558 const char *retval;
560 /* The highest priority value is the `LANGUAGE' environment
561 variable. This is a GNU extension. */
562 retval = getenv ("LANGUAGE");
563 if (retval != NULL && retval[0] != '\0')
564 return retval;
566 /* `LANGUAGE' is not set. So we have to proceed with the POSIX
567 methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
568 systems this can be done by the `setlocale' function itself. */
569 #if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
570 return setlocale (category, NULL);
571 #else
572 /* Setting of LC_ALL overwrites all other. */
573 retval = getenv ("LC_ALL");
574 if (retval != NULL && retval[0] != '\0')
575 return retval;
577 /* Next comes the name of the desired category. */
578 retval = getenv (categoryname);
579 if (retval != NULL && retval[0] != '\0')
580 return retval;
582 /* Last possibility is the LANG environment variable. */
583 retval = getenv ("LANG");
584 if (retval != NULL && retval[0] != '\0')
585 return retval;
587 /* We use C as the default domain. POSIX says this is implementation
588 defined. */
589 return "C";
590 #endif