source: branches/libc-0.6/src/binutils/intl/dcgettext.c@ 3951

Last change on this file since 3951 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 16.1 KB
Line 
1/* Implementation of the dcgettext(3) function.
2 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 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
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <sys/types.h>
23
24#ifdef __GNUC__
25# define alloca __builtin_alloca
26# define HAVE_ALLOCA 1
27#else
28# if defined HAVE_ALLOCA_H || defined _LIBC
29# include <alloca.h>
30# else
31# ifdef _AIX
32 #pragma alloca
33# else
34# ifndef alloca
35char *alloca ();
36# endif
37# endif
38# endif
39#endif
40
41#include <errno.h>
42#ifndef errno
43extern int errno;
44#endif
45#ifndef __set_errno
46# define __set_errno(val) errno = (val)
47#endif
48
49#if defined STDC_HEADERS || defined _LIBC
50# include <stdlib.h>
51#else
52char *getenv ();
53# ifdef HAVE_MALLOC_H
54# include <malloc.h>
55# else
56void free ();
57# endif
58#endif
59
60#if defined HAVE_STRING_H || defined _LIBC
61# ifndef _GNU_SOURCE
62# define _GNU_SOURCE 1
63# endif
64# include <string.h>
65#else
66# include <strings.h>
67#endif
68#if !HAVE_STRCHR && !defined _LIBC
69# ifndef strchr
70# define strchr index
71# endif
72#endif
73
74#if defined HAVE_UNISTD_H || defined _LIBC
75# include <unistd.h>
76#endif
77
78#include "gettext.h"
79#include "gettextP.h"
80#ifdef _LIBC
81# include <libintl.h>
82#else
83# include "libgettext.h"
84#endif
85#include "hash-string.h"
86
87/* @@ end of prolog @@ */
88
89#ifdef _LIBC
90/* Rename the non ANSI C functions. This is required by the standard
91 because some ANSI C functions will require linking with this object
92 file and the name space must not be polluted. */
93# define getcwd __getcwd
94# ifndef stpcpy
95# define stpcpy __stpcpy
96# endif
97#else
98# if !defined HAVE_GETCWD
99char *getwd ();
100# define getcwd(buf, max) getwd (buf)
101# else
102char *getcwd ();
103# endif
104# ifndef HAVE_STPCPY
105static char *stpcpy PARAMS ((char *dest, const char *src));
106# endif
107#endif
108
109/* Amount to increase buffer size by in each try. */
110#define PATH_INCR 32
111
112/* The following is from pathmax.h. */
113/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
114 PATH_MAX but might cause redefinition warnings when sys/param.h is
115 later included (as on MORE/BSD 4.3). */
116#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
117# include <limits.h>
118#endif
119
120#ifndef _POSIX_PATH_MAX
121# define _POSIX_PATH_MAX 255
122#endif
123
124#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
125# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
126#endif
127
128/* Don't include sys/param.h if it already has been. */
129#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
130# include <sys/param.h>
131#endif
132
133#if !defined(PATH_MAX) && defined(MAXPATHLEN)
134# define PATH_MAX MAXPATHLEN
135#endif
136
137#ifndef PATH_MAX
138# define PATH_MAX _POSIX_PATH_MAX
139#endif
140
141/* XPG3 defines the result of `setlocale (category, NULL)' as:
142 ``Directs `setlocale()' to query `category' and return the current
143 setting of `local'.''
144 However it does not specify the exact format. And even worse: POSIX
145 defines this not at all. So we can use this feature only on selected
146 system (e.g. those using GNU C Library). */
147#ifdef _LIBC
148# define HAVE_LOCALE_NULL
149#endif
150
151/* Name of the default domain used for gettext(3) prior any call to
152 textdomain(3). The default value for this is "messages". */
153const char _nl_default_default_domain[] = "messages";
154
155/* Value used as the default domain for gettext(3). */
156const char *_nl_current_default_domain = _nl_default_default_domain;
157
158/* Contains the default location of the message catalogs. */
159const char _nl_default_dirname[] = GNULOCALEDIR;
160
161/* List with bindings of specific domains created by bindtextdomain()
162 calls. */
163struct binding *_nl_domain_bindings;
164
165/* Prototypes for local functions. */
166static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
167 const char *msgid)) internal_function;
168static const char *category_to_name PARAMS ((int category)) internal_function;
169static const char *guess_category_value PARAMS ((int category,
170 const char *categoryname))
171 internal_function;
172
173
174/* For those loosing systems which don't have `alloca' we have to add
175 some additional code emulating it. */
176#ifdef HAVE_ALLOCA
177/* Nothing has to be done. */
178# define ADD_BLOCK(list, address) /* nothing */
179# define FREE_BLOCKS(list) /* nothing */
180#else
181struct block_list
182{
183 void *address;
184 struct block_list *next;
185};
186# define ADD_BLOCK(list, addr) \
187 do { \
188 struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
189 /* If we cannot get a free block we cannot add the new element to \
190 the list. */ \
191 if (newp != NULL) { \
192 newp->address = (addr); \
193 newp->next = (list); \
194 (list) = newp; \
195 } \
196 } while (0)
197# define FREE_BLOCKS(list) \
198 do { \
199 while (list != NULL) { \
200 struct block_list *old = list; \
201 list = list->next; \
202 free (old); \
203 } \
204 } while (0)
205# undef alloca
206# define alloca(size) (malloc (size))
207#endif /* have alloca */
208
209
210/* Names for the libintl functions are a problem. They must not clash
211 with existing names and they should follow ANSI C. But this source
212 code is also used in GNU C Library where the names have a __
213 prefix. So we have to make a difference here. */
214#ifdef _LIBC
215# define DCGETTEXT __dcgettext
216#else
217# define DCGETTEXT dcgettext__
218#endif
219
220/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
221 locale. */
222char *
223DCGETTEXT (domainname, msgid, category)
224 const char *domainname;
225 const char *msgid;
226 int category;
227{
228#ifndef HAVE_ALLOCA
229 struct block_list *block_list = NULL;
230#endif
231 struct loaded_l10nfile *domain;
232 struct binding *binding;
233 const char *categoryname;
234 const char *categoryvalue;
235 char *dirname, *xdomainname;
236 char *single_locale;
237 char *retval;
238 int saved_errno = errno;
239
240 /* If no real MSGID is given return NULL. */
241 if (msgid == NULL)
242 return NULL;
243
244 /* If DOMAINNAME is NULL, we are interested in the default domain. If
245 CATEGORY is not LC_MESSAGES this might not make much sense but the
246 defintion left this undefined. */
247 if (domainname == NULL)
248 domainname = _nl_current_default_domain;
249
250 /* First find matching binding. */
251 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
252 {
253 int compare = strcmp (domainname, binding->domainname);
254 if (compare == 0)
255 /* We found it! */
256 break;
257 if (compare < 0)
258 {
259 /* It is not in the list. */
260 binding = NULL;
261 break;
262 }
263 }
264
265 if (binding == NULL)
266 dirname = (char *) _nl_default_dirname;
267 else if (binding->dirname[0] == '/')
268 dirname = binding->dirname;
269 else
270 {
271 /* We have a relative path. Make it absolute now. */
272 size_t dirname_len = strlen (binding->dirname) + 1;
273 size_t path_max;
274 char *ret;
275
276 path_max = (unsigned) PATH_MAX;
277 path_max += 2; /* The getcwd docs say to do this. */
278
279 dirname = (char *) alloca (path_max + dirname_len);
280 ADD_BLOCK (block_list, dirname);
281
282 __set_errno (0);
283 while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
284 {
285 path_max += PATH_INCR;
286 dirname = (char *) alloca (path_max + dirname_len);
287 ADD_BLOCK (block_list, dirname);
288 __set_errno (0);
289 }
290
291 if (ret == NULL)
292 {
293 /* We cannot get the current working directory. Don't signal an
294 error but simply return the default string. */
295 FREE_BLOCKS (block_list);
296 __set_errno (saved_errno);
297 return (char *) msgid;
298 }
299
300 stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
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
311 stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
312 domainname),
313 ".mo");
314
315 /* Creating working area. */
316 single_locale = (char *) alloca (strlen (categoryvalue) + 1);
317 ADD_BLOCK (block_list, single_locale);
318
319
320 /* Search for the given string. This is a loop because we perhaps
321 got an ordered list of languages to consider for th translation. */
322 while (1)
323 {
324 /* Make CATEGORYVALUE point to the next element of the list. */
325 while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
326 ++categoryvalue;
327 if (categoryvalue[0] == '\0')
328 {
329 /* The whole contents of CATEGORYVALUE has been searched but
330 no valid entry has been found. We solve this situation
331 by implicitly appending a "C" entry, i.e. no translation
332 will take place. */
333 single_locale[0] = 'C';
334 single_locale[1] = '\0';
335 }
336 else
337 {
338 char *cp = single_locale;