Move rtld_db.h
[kopensolaris-gnu/glibc.git] / intl / bindtextdom.c
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.
4
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.
9
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.
14
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.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #ifdef _LIBC
29 # include <libintl.h>
30 #else
31 # include "libgnuintl.h"
32 #endif
33 #include "gettextP.h"
34
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
44
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
52
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
58 /* @@ end of prolog @@ */
59
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
65
66 /* List with bindings of specific domains.  */
67 extern struct binding *_nl_domain_bindings;
68
69 /* Lock variable to protect the global data in the gettext implementation.  */
70 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
71
72
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
87
88 /* Prototypes for local functions.  */
89 static void set_binding_values PARAMS ((const char *domainname,
90                                         const char **dirnamep,
91                                         const char **codesetp));
92
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;
104 {
105   struct binding *binding;
106   int modified;
107
108   /* Some sanity checks.  */
109   if (domainname == NULL || domainname[0] == '\0')
110     {
111       if (dirnamep)
112         *dirnamep = NULL;
113       if (codesetp)
114         *codesetp = NULL;
115       return;
116     }
117
118   __libc_rwlock_wrlock (_nl_state_lock);
119
120   modified = 0;
121
122   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
123     {
124       int compare = strcmp (domainname, binding->domainname);
125       if (compare == 0)
126         /* We found it!  */
127         break;
128       if (compare < 0)
129         {
130           /* It is not in the list.  */
131           binding = NULL;
132           break;
133         }
134     }
135
136   if (binding != NULL)
137     {
138       if (dirnamep)
139         {
140           const char *dirname = *dirnamep;
141
142           if (dirname == NULL)
143             /* The current binding has be to returned.  */
144             *dirnamep = binding->dirname;
145           else
146             {
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)
152                 {
153                   if (strcmp (dirname, _nl_default_dirname) == 0)
154                     result = (char *) _nl_default_dirname;
155                   else
156                     {
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
165                     }
166
167                   if (__builtin_expect (result != NULL, 1))
168                     {
169                       if (binding->dirname != _nl_default_dirname)
170                         free (binding->dirname);
171
172                       binding->dirname = result;
173                       modified = 1;
174                     }
175                 }
176               *dirnamep = result;
177             }
178         }
179
180       if (codesetp)
181         {
182           const char *codeset = *codesetp;
183
184           if (codeset == NULL)
185             /* The current binding has be to returned.  */
186             *codesetp = binding->codeset;
187           else
188             {
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)
194                 {
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
203
204                   if (__builtin_expect (result != NULL, 1))
205                     {
206                       if (binding->codeset != NULL)
207                         free (binding->codeset);
208
209                       binding->codeset = result;
210                       modified = 1;
211                     }
212                 }
213               *codesetp = result;
214             }
215         }
216     }
217   else if ((dirnamep == NULL || *dirnamep == NULL)
218            && (codesetp == NULL || *codesetp == NULL))
219     {
220       /* Simply return the default values.  */
221       if (dirnamep)
222         *dirnamep = _nl_default_dirname;
223       if (codesetp)
224         *codesetp = NULL;
225     }
226   else
227     {
228       /* We have to create a new binding.  */
229       size_t len = strlen (domainname) + 1;
230       struct binding *new_binding =
231         (struct binding *) malloc (offsetof (struct binding, domainname) + len);
232
233       if (__builtin_expect (new_binding == NULL, 0))
234         goto failed;
235
236       memcpy (new_binding->domainname, domainname, len);
237
238       if (dirnamep)
239         {
240           const char *dirname = *dirnamep;
241
242           if (dirname == NULL)
243             /* The default value.  */
244             dirname = _nl_default_dirname;
245           else
246             {
247               if (strcmp (dirname, _nl_default_dirname) == 0)
248                 dirname = _nl_default_dirname;
249               else
250                 {
251                   char *result;
252 #if defined _LIBC || defined HAVE_STRDUP
253                   result = strdup (dirname);
254                   if (__builtin_expect (result == NULL, 0))
255                     goto failed_dirname;
256 #else
257                   size_t len = strlen (dirname) + 1;
258                   result = (char *) malloc (len);
259                   if (__builtin_expect (result == NULL, 0))
260                     goto failed_dirname;
261                   memcpy (result, dirname, len);
262 #endif
263                   dirname = result;
264                 }
265             }
266           *dirnamep = dirname;
267           new_binding->dirname = (char *) dirname;
268         }
269       else
270         /* The default value.  */
271         new_binding->dirname = (char *) _nl_default_dirname;
272
273       if (codesetp)
274         {
275           const char *codeset = *codesetp;
276
277           if (codeset != NULL)
278             {
279               char *result;
280
281 #if defined _LIBC || defined HAVE_STRDUP
282               result = strdup (codeset);
283               if (__builtin_expect (result == NULL, 0))
284                 goto failed_codeset;
285 #else
286               size_t len = strlen (codeset) + 1;
287               result = (char *) malloc (len);
288               if (__builtin_expect (result == NULL, 0))
289                 goto failed_codeset;
290               memcpy (result, codeset, len);
291 #endif
292               codeset = result;
293             }
294           *codesetp = codeset;
295           new_binding->codeset = (char *) codeset;
296         }
297       else
298         new_binding->codeset = NULL;
299
300       /* Now enqueue it.  */
301       if (_nl_domain_bindings == NULL
302           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
303         {
304           new_binding->next = _nl_domain_bindings;
305           _nl_domain_bindings = new_binding;
306         }
307       else
308         {
309           binding = _nl_domain_bindings;
310           while (binding->next != NULL
311                  && strcmp (domainname, binding->next->domainname) > 0)
312             binding = binding->next;
313
314           new_binding->next = binding->next;
315           binding->next = new_binding;
316         }
317
318       modified = 1;
319
320       /* Here we deal with memory allocation failures.  */
321       if (0)
322         {
323         failed_codeset:
324           if (new_binding->dirname != _nl_default_dirname)
325             free (new_binding->dirname);
326         failed_dirname:
327           free (new_binding);
328         failed:
329           if (dirnamep)
330             *dirnamep = NULL;
331           if (codesetp)
332             *codesetp = NULL;
333         }
334     }
335
336   /* If we modified any binding, we flush the caches.  */
337   if (modified)
338     ++_nl_msg_cat_cntr;
339
340   __libc_rwlock_unlock (_nl_state_lock);
341 }
342
343 /* Specify that the DOMAINNAME message catalog will be found
344    in DIRNAME rather than in the system locale data base.  */
345 char *
346 BINDTEXTDOMAIN (domainname, dirname)
347      const char *domainname;
348      const char *dirname;
349 {
350   set_binding_values (domainname, &dirname, NULL);
351   return (char *) dirname;
352 }
353
354 /* Specify the character encoding in which the messages from the
355    DOMAINNAME message catalog will be returned.  */
356 char *
357 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
358      const char *domainname;
359      const char *codeset;
360 {
361   set_binding_values (domainname, NULL, &codeset);
362   return (char *) codeset;
363 }
364
365 #ifdef _LIBC
366 /* Aliases for function names in GNU C Library.  */
367 weak_alias (__bindtextdomain, bindtextdomain);
368 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
369 #endif