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