[BZ #284, BZ #721]
[platform/upstream/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                       ++binding->codeset_cntr;
211                       modified = 1;
212                     }
213                 }
214               *codesetp = result;
215             }
216         }
217     }
218   else if ((dirnamep == NULL || *dirnamep == NULL)
219            && (codesetp == NULL || *codesetp == NULL))
220     {
221       /* Simply return the default values.  */
222       if (dirnamep)
223         *dirnamep = _nl_default_dirname;
224       if (codesetp)
225         *codesetp = NULL;
226     }
227   else
228     {
229       /* We have to create a new binding.  */
230       size_t len = strlen (domainname) + 1;
231       struct binding *new_binding =
232         (struct binding *) malloc (offsetof (struct binding, domainname) + len);
233
234       if (__builtin_expect (new_binding == NULL, 0))
235         goto failed;
236
237       memcpy (new_binding->domainname, domainname, len);
238
239       if (dirnamep)
240         {
241           const char *dirname = *dirnamep;
242
243           if (dirname == NULL)
244             /* The default value.  */
245             dirname = _nl_default_dirname;
246           else
247             {
248               if (strcmp (dirname, _nl_default_dirname) == 0)
249                 dirname = _nl_default_dirname;
250               else
251                 {
252                   char *result;
253 #if defined _LIBC || defined HAVE_STRDUP
254                   result = strdup (dirname);
255                   if (__builtin_expect (result == NULL, 0))
256                     goto failed_dirname;
257 #else
258                   size_t len = strlen (dirname) + 1;
259                   result = (char *) malloc (len);
260                   if (__builtin_expect (result == NULL, 0))
261                     goto failed_dirname;
262                   memcpy (result, dirname, len);
263 #endif
264                   dirname = result;
265                 }
266             }
267           *dirnamep = dirname;
268           new_binding->dirname = (char *) dirname;
269         }
270       else
271         /* The default value.  */
272         new_binding->dirname = (char *) _nl_default_dirname;
273
274       new_binding->codeset_cntr = 0;
275
276       if (codesetp)
277         {
278           const char *codeset = *codesetp;
279
280           if (codeset != NULL)
281             {
282               char *result;
283
284 #if defined _LIBC || defined HAVE_STRDUP
285               result = strdup (codeset);
286               if (__builtin_expect (result == NULL, 0))
287                 goto failed_codeset;
288 #else
289               size_t len = strlen (codeset) + 1;
290               result = (char *) malloc (len);
291               if (__builtin_expect (result == NULL, 0))
292                 goto failed_codeset;
293               memcpy (result, codeset, len);
294 #endif
295               codeset = result;
296               ++new_binding->codeset_cntr;
297             }
298           *codesetp = codeset;
299           new_binding->codeset = (char *) codeset;
300         }
301       else
302         new_binding->codeset = NULL;
303
304       /* Now enqueue it.  */
305       if (_nl_domain_bindings == NULL
306           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
307         {
308           new_binding->next = _nl_domain_bindings;
309           _nl_domain_bindings = new_binding;
310         }
311       else
312         {
313           binding = _nl_domain_bindings;
314           while (binding->next != NULL
315                  && strcmp (domainname, binding->next->domainname) > 0)
316             binding = binding->next;
317
318           new_binding->next = binding->next;
319           binding->next = new_binding;
320         }
321
322       modified = 1;
323
324       /* Here we deal with memory allocation failures.  */
325       if (0)
326         {
327         failed_codeset:
328           if (new_binding->dirname != _nl_default_dirname)
329             free (new_binding->dirname);
330         failed_dirname:
331           free (new_binding);
332         failed:
333           if (dirnamep)
334             *dirnamep = NULL;
335           if (codesetp)
336             *codesetp = NULL;
337         }
338     }
339
340   /* If we modified any binding, we flush the caches.  */
341   if (modified)
342     ++_nl_msg_cat_cntr;
343
344   __libc_rwlock_unlock (_nl_state_lock);
345 }
346
347 /* Specify that the DOMAINNAME message catalog will be found
348    in DIRNAME rather than in the system locale data base.  */
349 char *
350 BINDTEXTDOMAIN (domainname, dirname)
351      const char *domainname;
352      const char *dirname;
353 {
354   set_binding_values (domainname, &dirname, NULL);
355   return (char *) dirname;
356 }
357
358 /* Specify the character encoding in which the messages from the
359    DOMAINNAME message catalog will be returned.  */
360 char *
361 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
362      const char *domainname;
363      const char *codeset;
364 {
365   set_binding_values (domainname, NULL, &codeset);
366   return (char *) codeset;
367 }
368
369 #ifdef _LIBC
370 /* Aliases for function names in GNU C Library.  */
371 weak_alias (__bindtextdomain, bindtextdomain);
372 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
373 #endif