1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-1998, 2000, 2001, 2002 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
31 # include "libgnuintl.h"
36 /* We have to handle multi-threaded applications. */
37 # include <bits/libc-lock.h>
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)
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. */
49 # define _nl_default_dirname libintl_nl_default_dirname
50 # define _nl_domain_bindings libintl_nl_domain_bindings
53 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
55 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
58 /* @@ end of prolog @@ */
60 /* Contains the default location of the message catalogs. */
61 extern const char _nl_default_dirname[];
63 extern const char _nl_default_dirname_internal[] attribute_hidden;
65 # define INTUSE(name) name
68 /* List with bindings of specific domains. */
69 extern struct binding *_nl_domain_bindings;
71 /* Lock variable to protect the global data in the gettext implementation. */
72 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
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. */
80 # define BINDTEXTDOMAIN __bindtextdomain
81 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
83 # define strdup(str) __strdup (str)
86 # define BINDTEXTDOMAIN libintl_bindtextdomain
87 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
90 /* Prototypes for local functions. */
91 static void set_binding_values PARAMS ((const char *domainname,
92 const char **dirnamep,
93 const char **codesetp));
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. */
102 set_binding_values (domainname, dirnamep, codesetp)
103 const char *domainname;
104 const char **dirnamep;
105 const char **codesetp;
107 struct binding *binding;
110 /* Some sanity checks. */
111 if (domainname == NULL || domainname[0] == '\0')
120 __libc_rwlock_wrlock (_nl_state_lock);
124 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
126 int compare = strcmp (domainname, binding->domainname);
132 /* It is not in the list. */
142 const char *dirname = *dirnamep;
145 /* The current binding has be to returned. */
146 *dirnamep = binding->dirname;
149 /* The domain is already bound. If the new value and the old
150 one are equal we simply do nothing. Otherwise replace the
152 char *result = binding->dirname;
153 if (strcmp (dirname, result) != 0)
155 if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
156 result = (char *) INTUSE(_nl_default_dirname);
159 #if defined _LIBC || defined HAVE_STRDUP
160 result = strdup (dirname);
162 size_t len = strlen (dirname) + 1;
163 result = (char *) malloc (len);
164 if (__builtin_expect (result != NULL, 1))
165 memcpy (result, dirname, len);
169 if (__builtin_expect (result != NULL, 1))
171 if (binding->dirname != INTUSE(_nl_default_dirname))
172 free (binding->dirname);
174 binding->dirname = result;
184 const char *codeset = *codesetp;
187 /* The current binding has be to returned. */
188 *codesetp = binding->codeset;
191 /* The domain is already bound. If the new value and the old
192 one are equal we simply do nothing. Otherwise replace the
194 char *result = binding->codeset;
195 if (result == NULL || strcmp (codeset, result) != 0)
197 #if defined _LIBC || defined HAVE_STRDUP
198 result = strdup (codeset);
200 size_t len = strlen (codeset) + 1;
201 result = (char *) malloc (len);
202 if (__builtin_expect (result != NULL, 1))
203 memcpy (result, codeset, len);
206 if (__builtin_expect (result != NULL, 1))
208 if (binding->codeset != NULL)
209 free (binding->codeset);
211 binding->codeset = result;
212 ++binding->codeset_cntr;
220 else if ((dirnamep == NULL || *dirnamep == NULL)
221 && (codesetp == NULL || *codesetp == NULL))
223 /* Simply return the default values. */
225 *dirnamep = INTUSE(_nl_default_dirname);
231 /* We have to create a new binding. */
232 size_t len = strlen (domainname) + 1;
233 struct binding *new_binding =
234 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
236 if (__builtin_expect (new_binding == NULL, 0))
239 memcpy (new_binding->domainname, domainname, len);
243 const char *dirname = *dirnamep;
246 /* The default value. */
247 dirname = INTUSE(_nl_default_dirname);
250 if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
251 dirname = INTUSE(_nl_default_dirname);
255 #if defined _LIBC || defined HAVE_STRDUP
256 result = strdup (dirname);
257 if (__builtin_expect (result == NULL, 0))
260 size_t len = strlen (dirname) + 1;
261 result = (char *) malloc (len);
262 if (__builtin_expect (result == NULL, 0))
264 memcpy (result, dirname, len);
270 new_binding->dirname = (char *) dirname;
273 /* The default value. */
274 new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
276 new_binding->codeset_cntr = 0;
280 const char *codeset = *codesetp;
286 #if defined _LIBC || defined HAVE_STRDUP
287 result = strdup (codeset);
288 if (__builtin_expect (result == NULL, 0))
291 size_t len = strlen (codeset) + 1;
292 result = (char *) malloc (len);
293 if (__builtin_expect (result == NULL, 0))
295 memcpy (result, codeset, len);
298 ++new_binding->codeset_cntr;
301 new_binding->codeset = (char *) codeset;
304 new_binding->codeset = NULL;
306 /* Now enqueue it. */
307 if (_nl_domain_bindings == NULL
308 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
310 new_binding->next = _nl_domain_bindings;
311 _nl_domain_bindings = new_binding;
315 binding = _nl_domain_bindings;
316 while (binding->next != NULL
317 && strcmp (domainname, binding->next->domainname) > 0)
318 binding = binding->next;
320 new_binding->next = binding->next;
321 binding->next = new_binding;
326 /* Here we deal with memory allocation failures. */
330 if (new_binding->dirname != INTUSE(_nl_default_dirname))
331 free (new_binding->dirname);
342 /* If we modified any binding, we flush the caches. */
346 __libc_rwlock_unlock (_nl_state_lock);
349 /* Specify that the DOMAINNAME message catalog will be found
350 in DIRNAME rather than in the system locale data base. */
352 BINDTEXTDOMAIN (domainname, dirname)
353 const char *domainname;
356 set_binding_values (domainname, &dirname, NULL);
357 return (char *) dirname;
360 /* Specify the character encoding in which the messages from the
361 DOMAINNAME message catalog will be returned. */
363 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
364 const char *domainname;
367 set_binding_values (domainname, NULL, &codeset);
368 return (char *) codeset;
372 /* Aliases for function names in GNU C Library. */
373 weak_alias (__bindtextdomain, bindtextdomain);
374 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);