Merged changes made for version 4.1.20 onto the trunk
[findutils.git] / intl / bindtextdom.c
blob3c5ff30579d2c6a4cc21bbeeda0bc6ffadaa5bb3
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
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.
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.
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. */
18 #ifdef HAVE_CONFIG_H
19 # include <gnulib/config.h>
20 # undef VERSION
21 # undef PACKAGE_VERSION
22 # undef PACKAGE_TARNAME
23 # undef PACKAGE_STRING
24 # include <config.h>
25 #endif
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #ifdef _LIBC
32 # include <libintl.h>
33 #else
34 # include "libgnuintl.h"
35 #endif
36 #include "gettextP.h"
38 #ifdef _LIBC
39 /* We have to handle multi-threaded applications. */
40 # include <bits/libc-lock.h>
41 #else
42 /* Provide dummy implementation if this is outside glibc. */
43 # define __libc_rwlock_define(CLASS, NAME)
44 # define __libc_rwlock_wrlock(NAME)
45 # define __libc_rwlock_unlock(NAME)
46 #endif
48 /* The internal variables in the standalone libintl.a must have different
49 names than the internal variables in GNU libc, otherwise programs
50 using libintl.a cannot be linked statically. */
51 #if !defined _LIBC
52 # define _nl_default_dirname _nl_default_dirname__
53 # define _nl_domain_bindings _nl_domain_bindings__
54 #endif
56 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
57 #ifndef offsetof
58 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
59 #endif
61 /* @@ end of prolog @@ */
63 /* Contains the default location of the message catalogs. */
64 extern const char _nl_default_dirname[];
66 /* List with bindings of specific domains. */
67 extern struct binding *_nl_domain_bindings;
69 /* Lock variable to protect the global data in the gettext implementation. */
70 __libc_rwlock_define (extern, _nl_state_lock)
73 /* Names for the libintl functions are a problem. They must not clash
74 with existing names and they should follow ANSI C. But this source
75 code is also used in GNU C Library where the names have a __
76 prefix. So we have to make a difference here. */
77 #ifdef _LIBC
78 # define BINDTEXTDOMAIN __bindtextdomain
79 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
80 # ifndef strdup
81 # define strdup(str) __strdup (str)
82 # endif
83 #else
84 # define BINDTEXTDOMAIN bindtextdomain__
85 # define BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset__
86 #endif
88 /* Prototypes for local functions. */
89 static void set_binding_values PARAMS ((const char *domainname,
90 const char **dirnamep,
91 const char **codesetp));
93 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
94 to be used for the DOMAINNAME message catalog.
95 If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
96 modified, only the current value is returned.
97 If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
98 modified nor returned. */
99 static void
100 set_binding_values (domainname, dirnamep, codesetp)
101 const char *domainname;
102 const char **dirnamep;
103 const char **codesetp;
105 struct binding *binding;
106 int modified;
108 /* Some sanity checks. */
109 if (domainname == NULL || domainname[0] == '\0')
111 if (dirnamep)
112 *dirnamep = NULL;
113 if (codesetp)
114 *codesetp = NULL;
115 return;
118 __libc_rwlock_wrlock (_nl_state_lock);
120 modified = 0;
122 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
124 int compare = strcmp (domainname, binding->domainname);
125 if (compare == 0)
126 /* We found it! */
127 break;
128 if (compare < 0)
130 /* It is not in the list. */
131 binding = NULL;
132 break;
136 if (binding != NULL)
138 if (dirnamep)
140 const char *dirname = *dirnamep;
142 if (dirname == NULL)
143 /* The current binding has be to returned. */
144 *dirnamep = binding->dirname;
145 else
147 /* The domain is already bound. If the new value and the old
148 one are equal we simply do nothing. Otherwise replace the
149 old binding. */
150 char *result = binding->dirname;
151 if (strcmp (dirname, result) != 0)
153 if (strcmp (dirname, _nl_default_dirname) == 0)
154 result = (char *) _nl_default_dirname;
155 else
157 #if defined _LIBC || defined HAVE_STRDUP
158 result = strdup (dirname);
159 #else
160 size_t len = strlen (dirname) + 1;
161 result = (char *) malloc (len);
162 if (__builtin_expect (result != NULL, 1))
163 memcpy (result, dirname, len);
164 #endif
167 if (__builtin_expect (result != NULL, 1))
169 if (binding->dirname != _nl_default_dirname)
170 free (binding->dirname);
172 binding->dirname = result;
173 modified = 1;
176 *dirnamep = result;
180 if (codesetp)
182 const char *codeset = *codesetp;
184 if (codeset == NULL)
185 /* The current binding has be to returned. */
186 *codesetp = binding->codeset;
187 else
189 /* The domain is already bound. If the new value and the old
190 one are equal we simply do nothing. Otherwise replace the
191 old binding. */
192 char *result = binding->codeset;
193 if (result == NULL || strcmp (codeset, result) != 0)
195 #if defined _LIBC || defined HAVE_STRDUP
196 result = strdup (codeset);
197 #else
198 size_t len = strlen (codeset) + 1;
199 result = (char *) malloc (len);
200 if (__builtin_expect (result != NULL, 1))
201 memcpy (result, codeset, len);
202 #endif
204 if (__builtin_expect (result != NULL, 1))
206 if (binding->codeset != NULL)
207 free (binding->codeset);
209 binding->codeset = result;
210 binding->codeset_cntr++;
211 modified = 1;
214 *codesetp = result;
218 else if ((dirnamep == NULL || *dirnamep == NULL)
219 && (codesetp == NULL || *codesetp == NULL))
221 /* Simply return the default values. */
222 if (dirnamep)
223 *dirnamep = _nl_default_dirname;
224 if (codesetp)
225 *codesetp = NULL;
227 else
229 /* We have to create a new binding. */
230 size_t len = strlen (domainname) + 1;
231 struct binding *new_binding =
232 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
234 if (__builtin_expect (new_binding == NULL, 0))
235 goto failed;
237 memcpy (new_binding->domainname, domainname, len);
239 if (dirnamep)
241 const char *dirname = *dirnamep;
243 if (dirname == NULL)
244 /* The default value. */
245 dirname = _nl_default_dirname;
246 else
248 if (strcmp (dirname, _nl_default_dirname) == 0)
249 dirname = _nl_default_dirname;
250 else
252 char *result;
253 #if defined _LIBC || defined HAVE_STRDUP
254 result = strdup (dirname);
255 if (__builtin_expect (result == NULL, 0))
256 goto failed_dirname;
257 #else
258 size_t len = strlen (dirname) + 1;
259 result = (char *) malloc (len);
260 if (__builtin_expect (result == NULL, 0))
261 goto failed_dirname;
262 memcpy (result, dirname, len);
263 #endif
264 dirname = result;
267 *dirnamep = dirname;
268 new_binding->dirname = (char *) dirname;
270 else
271 /* The default value. */
272 new_binding->dirname = (char *) _nl_default_dirname;
274 new_binding->codeset_cntr = 0;
276 if (codesetp)
278 const char *codeset = *codesetp;
280 if (codeset != NULL)
282 char *result;
284 #if defined _LIBC || defined HAVE_STRDUP
285 result = strdup (codeset);
286 if (__builtin_expect (result == NULL, 0))
287 goto failed_codeset;
288 #else
289 size_t len = strlen (codeset) + 1;
290 result = (char *) malloc (len);
291 if (__builtin_expect (result == NULL, 0))
292 goto failed_codeset;
293 memcpy (result, codeset, len);
294 #endif
295 codeset = result;
296 new_binding->codeset_cntr++;
298 *codesetp = codeset;
299 new_binding->codeset = (char *) codeset;
301 else
302 new_binding->codeset = NULL;
304 /* Now enqueue it. */
305 if (_nl_domain_bindings == NULL
306 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
308 new_binding->next = _nl_domain_bindings;
309 _nl_domain_bindings = new_binding;
311 else
313 binding = _nl_domain_bindings;
314 while (binding->next != NULL
315 && strcmp (domainname, binding->next->domainname) > 0)
316 binding = binding->next;
318 new_binding->next = binding->next;
319 binding->next = new_binding;
322 modified = 1;
324 /* Here we deal with memory allocation failures. */
325 if (0)
327 failed_codeset:
328 if (new_binding->dirname != _nl_default_dirname)
329 free (new_binding->dirname);
330 failed_dirname:
331 free (new_binding);
332 failed:
333 if (dirnamep)
334 *dirnamep = NULL;
335 if (codesetp)
336 *codesetp = NULL;
340 /* If we modified any binding, we flush the caches. */
341 if (modified)
342 ++_nl_msg_cat_cntr;
344 __libc_rwlock_unlock (_nl_state_lock);
347 /* Specify that the DOMAINNAME message catalog will be found
348 in DIRNAME rather than in the system locale data base. */
349 char *
350 BINDTEXTDOMAIN (domainname, dirname)
351 const char *domainname;
352 const char *dirname;
354 set_binding_values (domainname, &dirname, NULL);
355 return (char *) dirname;
358 /* Specify the character encoding in which the messages from the
359 DOMAINNAME message catalog will be returned. */
360 char *
361 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
362 const char *domainname;
363 const char *codeset;
365 set_binding_values (domainname, NULL, &codeset);
366 return (char *) codeset;
369 #ifdef _LIBC
370 /* Aliases for function names in GNU C Library. */
371 weak_alias (__bindtextdomain, bindtextdomain);
372 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
373 #endif