]> git.ipfire.org Git - thirdparty/glibc.git/blame - intl/bindtextdom.c
(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[thirdparty/glibc.git] / intl / bindtextdom.c
CommitLineData
8f2ece69 1/* Implementation of the bindtextdomain(3) function
a334319f 2 Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc.
41bdb6e2 3 This file is part of the GNU C Library.
24906b43 4
c84142e8 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
0393dfd6 9
c84142e8
UD
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
41bdb6e2 13 Lesser General Public License for more details.
24906b43 14
41bdb6e2
AJ
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. */
24906b43
RM
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
0555fcce
UD
24#include <stddef.h>
25#include <stdlib.h>
26#include <string.h>
24906b43
RM
27
28#ifdef _LIBC
29# include <libintl.h>
30#else
4a4d50f3 31# include "libgnuintl.h"
24906b43 32#endif
24906b43
RM
33#include "gettextP.h"
34
0ed99ce4
UD
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. */
0a55a284
UD
40# define __libc_rwlock_define(CLASS, NAME)
41# define __libc_rwlock_wrlock(NAME)
42# define __libc_rwlock_unlock(NAME)
0ed99ce4
UD
43#endif
44
52d895a4
UD
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
0f131646
RM
49# define _nl_default_dirname libintl_nl_default_dirname
50# define _nl_domain_bindings libintl_nl_domain_bindings
52d895a4
UD
51#endif
52
4a4d50f3
UD
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
57
24906b43
RM
58/* @@ end of prolog @@ */
59
60/* Contains the default location of the message catalogs. */
61extern const char _nl_default_dirname[];
230491f0 62#ifdef _LIBC
a334319f
UD
63extern const char _nl_default_dirname_internal[] attribute_hidden;
64#else
65# define INTUSE(name) name
230491f0 66#endif
24906b43
RM
67
68/* List with bindings of specific domains. */
69extern struct binding *_nl_domain_bindings;
70
0ed99ce4 71/* Lock variable to protect the global data in the gettext implementation. */
418f1701 72__libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
0ed99ce4 73
24906b43
RM
74
75/* Names for the libintl functions are a problem. They must not clash
76 with existing names and they should follow ANSI C. But this source
77 code is also used in GNU C Library where the names have a __
78 prefix. So we have to make a difference here. */
79#ifdef _LIBC
80# define BINDTEXTDOMAIN __bindtextdomain
17c389fc 81# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
cb343854
UD
82# ifndef strdup
83# define strdup(str) __strdup (str)
84# endif
24906b43 85#else
0f131646
RM
86# define BINDTEXTDOMAIN libintl_bindtextdomain
87# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
24906b43
RM
88#endif
89
fbd61fc1 90/* Prototypes for local functions. */
4a4d50f3
UD
91static void set_binding_values PARAMS ((const char *domainname,
92 const char **dirnamep,
93 const char **codesetp));
c44a663d 94
17c389fc
UD
95/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
96 to be used for the DOMAINNAME message catalog.
97 If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
98 modified, only the current value is returned.
99 If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
100 modified nor returned. */
101static void
102set_binding_values (domainname, dirnamep, codesetp)
24906b43 103 const char *domainname;
17c389fc
UD
104 const char **dirnamep;
105 const char **codesetp;
24906b43
RM
106{
107 struct binding *binding;
17c389fc 108 int modified;
24906b43
RM
109
110 /* Some sanity checks. */
111 if (domainname == NULL || domainname[0] == '\0')
17c389fc
UD
112 {
113 if (dirnamep)
114 *dirnamep = NULL;
115 if (codesetp)
116 *codesetp = NULL;
117 return;
118 }
24906b43 119
0ed99ce4
UD
120 __libc_rwlock_wrlock (_nl_state_lock);
121
17c389fc
UD
122 modified = 0;
123
24906b43
RM
124 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
125 {
126 int compare = strcmp (domainname, binding->domainname);
127 if (compare == 0)
128 /* We found it! */
129 break;
130 if (compare < 0)
131 {
132 /* It is not in the list. */
133 binding = NULL;
134 break;
135 }
136 }
137
17c389fc 138 if (binding != NULL)
24906b43 139 {
17c389fc 140 if (dirnamep)
24906b43 141 {
17c389fc
UD
142 const char *dirname = *dirnamep;
143
144 if (dirname == NULL)
145 /* The current binding has be to returned. */
146 *dirnamep = binding->dirname;
40a55d20
UD
147 else
148 {
17c389fc
UD
149 /* The domain is already bound. If the new value and the old
150 one are equal we simply do nothing. Otherwise replace the
151 old binding. */
152 char *result = binding->dirname;
153 if (strcmp (dirname, result) != 0)
154 {
a334319f
UD
155 if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
156 result = (char *) INTUSE(_nl_default_dirname);
17c389fc
UD
157 else
158 {
40a55d20 159#if defined _LIBC || defined HAVE_STRDUP
17c389fc 160 result = strdup (dirname);
40a55d20 161#else
17c389fc
UD
162 size_t len = strlen (dirname) + 1;
163 result = (char *) malloc (len);
164 if (__builtin_expect (result != NULL, 1))
165 memcpy (result, dirname, len);
40a55d20 166#endif
17c389fc
UD
167 }
168
169 if (__builtin_expect (result != NULL, 1))
170 {
a334319f 171 if (binding->dirname != INTUSE(_nl_default_dirname))
17c389fc
UD
172 free (binding->dirname);
173
174 binding->dirname = result;
175 modified = 1;
176 }
177 }
178 *dirnamep = result;
40a55d20 179 }
17c389fc
UD
180 }
181
182 if (codesetp)
183 {
184 const char *codeset = *codesetp;
24906b43 185
17c389fc
UD
186 if (codeset == NULL)
187 /* The current binding has be to returned. */
188 *codesetp = binding->codeset;
189 else
0ed99ce4 190 {
17c389fc
UD
191 /* The domain is already bound. If the new value and the old
192 one are equal we simply do nothing. Otherwise replace the
193 old binding. */
194 char *result = binding->codeset;
195 if (result == NULL || strcmp (codeset, result) != 0)
196 {
197#if defined _LIBC || defined HAVE_STRDUP
198 result = strdup (codeset);
199#else
200 size_t len = strlen (codeset) + 1;
201 result = (char *) malloc (len);
202 if (__builtin_expect (result != NULL, 1))
203 memcpy (result, codeset, len);
204#endif
24906b43 205
17c389fc
UD
206 if (__builtin_expect (result != NULL, 1))
207 {
208 if (binding->codeset != NULL)
209 free (binding->codeset);
210
211 binding->codeset = result;
a334319f 212 ++binding->codeset_cntr;
17c389fc
UD
213 modified = 1;
214 }
215 }
216 *codesetp = result;
0ed99ce4 217 }
40a55d20 218 }
24906b43 219 }
17c389fc
UD
220 else if ((dirnamep == NULL || *dirnamep == NULL)
221 && (codesetp == NULL || *codesetp == NULL))
222 {
223 /* Simply return the default values. */
224 if (dirnamep)
a334319f 225 *dirnamep = INTUSE(_nl_default_dirname);
17c389fc
UD
226 if (codesetp)
227 *codesetp = NULL;
228 }
24906b43
RM
229 else
230 {
231 /* We have to create a new binding. */
0ed99ce4 232 size_t len = strlen (domainname) + 1;
24906b43 233 struct binding *new_binding =
4a4d50f3 234 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
24906b43 235
17c389fc
UD
236 if (__builtin_expect (new_binding == NULL, 0))
237 goto failed;
238
239 memcpy (new_binding->domainname, domainname, len);
240
241 if (dirnamep)
24906b43 242 {
17c389fc 243 const char *dirname = *dirnamep;
0ed99ce4 244
17c389fc
UD
245 if (dirname == NULL)
246 /* The default value. */
a334319f 247 dirname = INTUSE(_nl_default_dirname);
0ed99ce4
UD
248 else
249 {
a334319f
UD
250 if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
251 dirname = INTUSE(_nl_default_dirname);
17c389fc
UD
252 else
253 {
254 char *result;
40a55d20 255#if defined _LIBC || defined HAVE_STRDUP
17c389fc
UD
256 result = strdup (dirname);
257 if (__builtin_expect (result == NULL, 0))
258 goto failed_dirname;
40a55d20 259#else
17c389fc
UD
260 size_t len = strlen (dirname) + 1;
261 result = (char *) malloc (len);
262 if (__builtin_expect (result == NULL, 0))
263 goto failed_dirname;
264 memcpy (result, dirname, len);
40a55d20 265#endif
17c389fc
UD
266 dirname = result;
267 }
0ed99ce4 268 }
17c389fc
UD
269 *dirnamep = dirname;
270 new_binding->dirname = (char *) dirname;
24906b43 271 }
17c389fc
UD
272 else
273 /* The default value. */
a334319f
UD
274 new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
275
276 new_binding->codeset_cntr = 0;
c44a663d 277
17c389fc 278 if (codesetp)
24906b43 279 {
17c389fc
UD
280 const char *codeset = *codesetp;
281
282 if (codeset != NULL)
0ed99ce4 283 {
17c389fc 284 char *result;
24906b43 285
17c389fc
UD
286#if defined _LIBC || defined HAVE_STRDUP
287 result = strdup (codeset);
288 if (__builtin_expect (result == NULL, 0))
289 goto failed_codeset;
290#else
291 size_t len = strlen (codeset) + 1;
292 result = (char *) malloc (len);
293 if (__builtin_expect (result == NULL, 0))
294 goto failed_codeset;
295 memcpy (result, codeset, len);
296#endif
297 codeset = result;
a334319f 298 ++new_binding->codeset_cntr;
0ed99ce4 299 }
17c389fc
UD
300 *codesetp = codeset;
301 new_binding->codeset = (char *) codeset;
302 }
303 else
304 new_binding->codeset = NULL;
305
306 /* Now enqueue it. */
307 if (_nl_domain_bindings == NULL
308 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
309 {
310 new_binding->next = _nl_domain_bindings;
311 _nl_domain_bindings = new_binding;
312 }
313 else
314 {
315 binding = _nl_domain_bindings;
316 while (binding->next != NULL
317 && strcmp (domainname, binding->next->domainname) > 0)
318 binding = binding->next;
319
320 new_binding->next = binding->next;
321 binding->next = new_binding;
322 }
323
324 modified = 1;
325
326 /* Here we deal with memory allocation failures. */
327 if (0)
328 {
329 failed_codeset:
a334319f 330 if (new_binding->dirname != INTUSE(_nl_default_dirname))
17c389fc
UD
331 free (new_binding->dirname);
332 failed_dirname:
333 free (new_binding);
334 failed:
335 if (dirnamep)
336 *dirnamep = NULL;
337 if (codesetp)
338 *codesetp = NULL;
24906b43 339 }
24906b43
RM
340 }
341
17c389fc
UD
342 /* If we modified any binding, we flush the caches. */
343 if (modified)
0ed99ce4
UD
344 ++_nl_msg_cat_cntr;
345
346 __libc_rwlock_unlock (_nl_state_lock);
17c389fc
UD
347}
348
349/* Specify that the DOMAINNAME message catalog will be found
350 in DIRNAME rather than in the system locale data base. */
351char *
352BINDTEXTDOMAIN (domainname, dirname)
353 const char *domainname;
354 const char *dirname;
355{
356 set_binding_values (domainname, &dirname, NULL);
357 return (char *) dirname;
358}
0ed99ce4 359
17c389fc
UD
360/* Specify the character encoding in which the messages from the
361 DOMAINNAME message catalog will be returned. */
362char *
363BIND_TEXTDOMAIN_CODESET (domainname, codeset)
364 const char *domainname;
365 const char *codeset;
366{
367 set_binding_values (domainname, NULL, &codeset);
368 return (char *) codeset;
24906b43
RM
369}
370
371#ifdef _LIBC
17c389fc 372/* Aliases for function names in GNU C Library. */
24906b43 373weak_alias (__bindtextdomain, bindtextdomain);
17c389fc 374weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
24906b43 375#endif