Sync up loadmsgcat.c with gettext
[glibc.git] / intl / bindtextdom.c
blobc3624961a8fcd0f23caf806722c07fe9a324d656
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-2014 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, see
17 <http://www.gnu.org/licenses/>. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #ifdef _LIBC
28 # include <libintl.h>
29 #else
30 # include "libgnuintl.h"
31 #endif
32 #include "gettextP.h"
34 #ifdef _LIBC
35 /* We have to handle multi-threaded applications. */
36 # include <bits/libc-lock.h>
37 #else
38 /* Provide dummy implementation if this is outside glibc. */
39 # define __libc_rwlock_define(CLASS, NAME)
40 # define __libc_rwlock_wrlock(NAME)
41 # define __libc_rwlock_unlock(NAME)
42 #endif
44 /* The internal variables in the standalone libintl.a must have different
45 names than the internal variables in GNU libc, otherwise programs
46 using libintl.a cannot be linked statically. */
47 #if !defined _LIBC
48 # define _nl_default_dirname libintl_nl_default_dirname
49 # define _nl_domain_bindings libintl_nl_domain_bindings
50 #endif
52 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
53 #ifndef offsetof
54 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
55 #endif
57 /* @@ end of prolog @@ */
59 /* Contains the default location of the message catalogs. */
60 extern const char _nl_default_dirname[];
61 #ifdef _LIBC
62 libc_hidden_proto (_nl_default_dirname)
63 #endif
65 /* List with bindings of specific domains. */
66 extern struct binding *_nl_domain_bindings;
68 /* Lock variable to protect the global data in the gettext implementation. */
69 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
72 /* Names for the libintl functions are a problem. They must not clash
73 with existing names and they should follow ANSI C. But this source
74 code is also used in GNU C Library where the names have a __
75 prefix. So we have to make a difference here. */
76 #ifdef _LIBC
77 # define BINDTEXTDOMAIN __bindtextdomain
78 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
79 # ifndef strdup
80 # define strdup(str) __strdup (str)
81 # endif
82 #else
83 # define BINDTEXTDOMAIN libintl_bindtextdomain
84 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
85 #endif
87 /* Prototypes for local functions. */
88 static void set_binding_values PARAMS ((const char *domainname,
89 const char **dirnamep,
90 const char **codesetp));
92 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
93 to be used for the DOMAINNAME message catalog.
94 If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
95 modified, only the current value is returned.
96 If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
97 modified nor returned. */
98 static void
99 set_binding_values (domainname, dirnamep, codesetp)
100 const char *domainname;
101 const char **dirnamep;
102 const char **codesetp;
104 struct binding *binding;
105 int modified;
107 /* Some sanity checks. */
108 if (domainname == NULL || domainname[0] == '\0')
110 if (dirnamep)
111 *dirnamep = NULL;
112 if (codesetp)
113 *codesetp = NULL;
114 return;
117 __libc_rwlock_wrlock (_nl_state_lock);
119 modified = 0;
121 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
123 int compare = strcmp (domainname, binding->domainname);
124 if (compare == 0)
125 /* We found it! */
126 break;
127 if (compare < 0)
129 /* It is not in the list. */
130 binding = NULL;
131 break;
135 if (binding != NULL)
137 if (dirnamep)
139 const char *dirname = *dirnamep;
141 if (dirname == NULL)
142 /* The current binding has be to returned. */
143 *dirnamep = binding->dirname;
144 else
146 /* The domain is already bound. If the new value and the old
147 one are equal we simply do nothing. Otherwise replace the
148 old binding. */
149 char *result = binding->dirname;
150 if (strcmp (dirname, result) != 0)
152 if (strcmp (dirname, _nl_default_dirname) == 0)
153 result = (char *) _nl_default_dirname;
154 else
156 #if defined _LIBC || defined HAVE_STRDUP
157 result = strdup (dirname);
158 #else
159 size_t len = strlen (dirname) + 1;
160 result = (char *) malloc (len);
161 if (__glibc_likely (result != NULL))
162 memcpy (result, dirname, len);
163 #endif
166 if (__glibc_likely (result != NULL))
168 if (binding->dirname != _nl_default_dirname)
169 free (binding->dirname);
171 binding->dirname = result;
172 modified = 1;
175 *dirnamep = result;
179 if (codesetp)
181 const char *codeset = *codesetp;
183 if (codeset == NULL)
184 /* The current binding has be to returned. */
185 *codesetp = binding->codeset;
186 else
188 /* The domain is already bound. If the new value and the old
189 one are equal we simply do nothing. Otherwise replace the
190 old binding. */
191 char *result = binding->codeset;
192 if (result == NULL || strcmp (codeset, result) != 0)
194 #if defined _LIBC || defined HAVE_STRDUP
195 result = strdup (codeset);
196 #else
197 size_t len = strlen (codeset) + 1;
198 result = (char *) malloc (len);
199 if (__glibc_likely (result != NULL))
200 memcpy (result, codeset, len);
201 #endif
203 if (__glibc_likely (result != NULL))
205 free (binding->codeset);
207 binding->codeset = result;
208 modified = 1;
211 *codesetp = result;
215 else if ((dirnamep == NULL || *dirnamep == NULL)
216 && (codesetp == NULL || *codesetp == NULL))
218 /* Simply return the default values. */
219 if (dirnamep)
220 *dirnamep = _nl_default_dirname;
221 if (codesetp)
222 *codesetp = NULL;
224 else
226 /* We have to create a new binding. */
227 size_t len = strlen (domainname) + 1;
228 struct binding *new_binding =
229 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
231 if (__glibc_unlikely (new_binding == NULL))
232 goto failed;
234 memcpy (new_binding->domainname, domainname, len);
236 if (dirnamep)
238 const char *dirname = *dirnamep;
240 if (dirname == NULL)
241 /* The default value. */
242 dirname = _nl_default_dirname;
243 else
245 if (strcmp (dirname, _nl_default_dirname) == 0)
246 dirname = _nl_default_dirname;
247 else
249 char *result;
250 #if defined _LIBC || defined HAVE_STRDUP
251 result = strdup (dirname);
252 if (__glibc_unlikely (result == NULL))
253 goto failed_dirname;
254 #else
255 size_t len = strlen (dirname) + 1;
256 result = (char *) malloc (len);
257 if (__glibc_unlikely (result == NULL))
258 goto failed_dirname;
259 memcpy (result, dirname, len);
260 #endif
261 dirname = result;
264 *dirnamep = dirname;
265 new_binding->dirname = (char *) dirname;
267 else
268 /* The default value. */
269 new_binding->dirname = (char *) _nl_default_dirname;
271 if (codesetp)
273 const char *codeset = *codesetp;
275 if (codeset != NULL)
277 char *result;
279 #if defined _LIBC || defined HAVE_STRDUP
280 result = strdup (codeset);
281 if (__glibc_unlikely (result == NULL))
282 goto failed_codeset;
283 #else
284 size_t len = strlen (codeset) + 1;
285 result = (char *) malloc (len);
286 if (__glibc_unlikely (result == NULL))
287 goto failed_codeset;
288 memcpy (result, codeset, len);
289 #endif
290 codeset = result;
292 *codesetp = codeset;
293 new_binding->codeset = (char *) codeset;
295 else
296 new_binding->codeset = NULL;
298 /* Now enqueue it. */
299 if (_nl_domain_bindings == NULL
300 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
302 new_binding->next = _nl_domain_bindings;
303 _nl_domain_bindings = new_binding;
305 else
307 binding = _nl_domain_bindings;
308 while (binding->next != NULL
309 && strcmp (domainname, binding->next->domainname) > 0)
310 binding = binding->next;
312 new_binding->next = binding->next;
313 binding->next = new_binding;
316 modified = 1;
318 /* Here we deal with memory allocation failures. */
319 if (0)
321 failed_codeset:
322 if (new_binding->dirname != _nl_default_dirname)
323 free (new_binding->dirname);
324 failed_dirname:
325 free (new_binding);
326 failed:
327 if (dirnamep)
328 *dirnamep = NULL;
329 if (codesetp)
330 *codesetp = NULL;
334 /* If we modified any binding, we flush the caches. */
335 if (modified)
336 ++_nl_msg_cat_cntr;
338 __libc_rwlock_unlock (_nl_state_lock);
341 /* Specify that the DOMAINNAME message catalog will be found
342 in DIRNAME rather than in the system locale data base. */
343 char *
344 BINDTEXTDOMAIN (domainname, dirname)
345 const char *domainname;
346 const char *dirname;
348 set_binding_values (domainname, &dirname, NULL);
349 return (char *) dirname;
352 /* Specify the character encoding in which the messages from the
353 DOMAINNAME message catalog will be returned. */
354 char *
355 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
356 const char *domainname;
357 const char *codeset;
359 set_binding_values (domainname, NULL, &codeset);
360 return (char *) codeset;
363 #ifdef _LIBC
364 /* Aliases for function names in GNU C Library. */
365 weak_alias (__bindtextdomain, bindtextdomain);
366 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
367 #endif