Fix assertion in ld.so, introduced by delayed adding to global list.
[glibc.git] / intl / bindtextdom.c
blob7a956d4471c592e27b583fc7c636bec010ca441c
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-1998, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #ifdef _LIBC
29 # include <libintl.h>
30 #else
31 # include "libgnuintl.h"
32 #endif
33 #include "gettextP.h"
35 #ifdef _LIBC
36 /* We have to handle multi-threaded applications. */
37 # include <bits/libc-lock.h>
38 #else
39 /* Provide dummy implementation if this is outside glibc. */
40 # define __libc_rwlock_define(CLASS, NAME)
41 # define __libc_rwlock_wrlock(NAME)
42 # define __libc_rwlock_unlock(NAME)
43 #endif
45 /* The internal variables in the standalone libintl.a must have different
46 names than the internal variables in GNU libc, otherwise programs
47 using libintl.a cannot be linked statically. */
48 #if !defined _LIBC
49 # define _nl_default_dirname libintl_nl_default_dirname
50 # define _nl_domain_bindings libintl_nl_domain_bindings
51 #endif
53 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
54 #ifndef offsetof
55 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
56 #endif
58 /* @@ end of prolog @@ */
60 /* Contains the default location of the message catalogs. */
61 extern const char _nl_default_dirname[];
62 #ifdef _LIBC
63 libc_hidden_proto (_nl_default_dirname)
64 #endif
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 attribute_hidden)
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 libintl_bindtextdomain
85 # define BIND_TEXTDOMAIN_CODESET libintl_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 free (binding->codeset);
208 binding->codeset = result;
209 modified = 1;
212 *codesetp = result;
216 else if ((dirnamep == NULL || *dirnamep == NULL)
217 && (codesetp == NULL || *codesetp == NULL))
219 /* Simply return the default values. */
220 if (dirnamep)
221 *dirnamep = _nl_default_dirname;
222 if (codesetp)
223 *codesetp = NULL;
225 else
227 /* We have to create a new binding. */
228 size_t len = strlen (domainname) + 1;
229 struct binding *new_binding =
230 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
232 if (__builtin_expect (new_binding == NULL, 0))
233 goto failed;
235 memcpy (new_binding->domainname, domainname, len);
237 if (dirnamep)
239 const char *dirname = *dirnamep;
241 if (dirname == NULL)
242 /* The default value. */
243 dirname = _nl_default_dirname;
244 else
246 if (strcmp (dirname, _nl_default_dirname) == 0)
247 dirname = _nl_default_dirname;
248 else
250 char *result;
251 #if defined _LIBC || defined HAVE_STRDUP
252 result = strdup (dirname);
253 if (__builtin_expect (result == NULL, 0))
254 goto failed_dirname;
255 #else
256 size_t len = strlen (dirname) + 1;
257 result = (char *) malloc (len);
258 if (__builtin_expect (result == NULL, 0))
259 goto failed_dirname;
260 memcpy (result, dirname, len);
261 #endif
262 dirname = result;
265 *dirnamep = dirname;
266 new_binding->dirname = (char *) dirname;
268 else
269 /* The default value. */
270 new_binding->dirname = (char *) _nl_default_dirname;
272 if (codesetp)
274 const char *codeset = *codesetp;
276 if (codeset != NULL)
278 char *result;
280 #if defined _LIBC || defined HAVE_STRDUP
281 result = strdup (codeset);
282 if (__builtin_expect (result == NULL, 0))
283 goto failed_codeset;
284 #else
285 size_t len = strlen (codeset) + 1;
286 result = (char *) malloc (len);
287 if (__builtin_expect (result == NULL, 0))
288 goto failed_codeset;
289 memcpy (result, codeset, len);
290 #endif
291 codeset = result;
293 *codesetp = codeset;
294 new_binding->codeset = (char *) codeset;
296 else
297 new_binding->codeset = NULL;
299 /* Now enqueue it. */
300 if (_nl_domain_bindings == NULL
301 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
303 new_binding->next = _nl_domain_bindings;
304 _nl_domain_bindings = new_binding;
306 else
308 binding = _nl_domain_bindings;
309 while (binding->next != NULL
310 && strcmp (domainname, binding->next->domainname) > 0)
311 binding = binding->next;
313 new_binding->next = binding->next;
314 binding->next = new_binding;
317 modified = 1;
319 /* Here we deal with memory allocation failures. */
320 if (0)
322 failed_codeset:
323 if (new_binding->dirname != _nl_default_dirname)
324 free (new_binding->dirname);
325 failed_dirname:
326 free (new_binding);
327 failed:
328 if (dirnamep)
329 *dirnamep = NULL;
330 if (codesetp)
331 *codesetp = NULL;
335 /* If we modified any binding, we flush the caches. */
336 if (modified)
337 ++_nl_msg_cat_cntr;
339 __libc_rwlock_unlock (_nl_state_lock);
342 /* Specify that the DOMAINNAME message catalog will be found
343 in DIRNAME rather than in the system locale data base. */
344 char *
345 BINDTEXTDOMAIN (domainname, dirname)
346 const char *domainname;
347 const char *dirname;
349 set_binding_values (domainname, &dirname, NULL);
350 return (char *) dirname;
353 /* Specify the character encoding in which the messages from the
354 DOMAINNAME message catalog will be returned. */
355 char *
356 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
357 const char *domainname;
358 const char *codeset;
360 set_binding_values (domainname, NULL, &codeset);
361 return (char *) codeset;
364 #ifdef _LIBC
365 /* Aliases for function names in GNU C Library. */
366 weak_alias (__bindtextdomain, bindtextdomain);
367 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
368 #endif