Update.
[platform/upstream/glibc.git] / intl / bindtextdom.c
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.
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 extern const char _nl_default_dirname_internal[] attribute_hidden;
64 #else
65 # define INTUSE(name) name
66 #endif
67
68 /* List with bindings of specific domains.  */
69 extern struct binding *_nl_domain_bindings;
70
71 /* Lock variable to protect the global data in the gettext implementation.  */
72 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
73
74
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.  */
79 #ifdef _LIBC
80 # define BINDTEXTDOMAIN __bindtextdomain
81 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
82 # ifndef strdup
83 #  define strdup(str) __strdup (str)
84 # endif
85 #else
86 # define BINDTEXTDOMAIN libintl_bindtextdomain
87 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
88 #endif
89
90 /* Prototypes for local functions.  */
91 static void set_binding_values PARAMS ((const char *domainname,
92                                         const char **dirnamep,
93                                         const char **codesetp));
94
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.  */
101 static void
102 set_binding_values (domainname, dirnamep, codesetp)
103      const char *domainname;
104      const char **dirnamep;
105      const char **codesetp;
106 {
107   struct binding *binding;
108   int modified;
109
110   /* Some sanity checks.  */
111   if (domainname == NULL || domainname[0] == '\0')
112     {
113       if (dirnamep)
114         *dirnamep = NULL;
115       if (codesetp)
116         *codesetp = NULL;
117       return;
118     }
119
120   __libc_rwlock_wrlock (_nl_state_lock);
121
122   modified = 0;
123
124   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
125     {
126       int compare = strcmp (domainname, binding->domainname);
127       if (compare == 0)
128         /* We found it!  */
129         break;
130       if (compare < 0)
131         {
132           /* It is not in the list.  */
133           binding = NULL;
134           break;
135         }
136     }
137
138   if (binding != NULL)
139     {
140       if (dirnamep)
141         {
142           const char *dirname = *dirnamep;
143
144           if (dirname == NULL)
145             /* The current binding has be to returned.  */
146             *dirnamep = binding->dirname;
147           else
148             {
149               /* The domain is already bound.  If the new value and the old
150                  one are equal we simply do nothing.  Otherwise replace the
151                  old binding.  */
152               char *result = binding->dirname;
153               if (strcmp (dirname, result) != 0)
154                 {
155                   if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
156                     result = (char *) INTUSE(_nl_default_dirname);
157                   else
158                     {
159 #if defined _LIBC || defined HAVE_STRDUP
160                       result = strdup (dirname);
161 #else
162                       size_t len = strlen (dirname) + 1;
163                       result = (char *) malloc (len);
164                       if (__builtin_expect (result != NULL, 1))
165                         memcpy (result, dirname, len);
166 #endif
167                     }
168
169                   if (__builtin_expect (result != NULL, 1))
170                     {
171                       if (binding->dirname != INTUSE(_nl_default_dirname))
172                         free (binding->dirname);
173
174                       binding->dirname = result;
175                       modified = 1;
176                     }
177                 }
178               *dirnamep = result;
179             }
180         }
181
182       if (codesetp)
183         {
184           const char *codeset = *codesetp;
185
186           if (codeset == NULL)
187             /* The current binding has be to returned.  */
188             *codesetp = binding->codeset;
189           else
190             {
191               /* The domain is already bound.  If the new value and the old
192                  one are equal we simply do nothing.  Otherwise replace the
193                  old binding.  */
194               char *result = binding->codeset;
195               if (result == NULL || strcmp (codeset, result) != 0)
196                 {
197 #if defined _LIBC || defined HAVE_STRDUP
198                   result = strdup (codeset);
199 #else
200                   size_t len = strlen (codeset) + 1;
201                   result = (char *) malloc (len);
202                   if (__builtin_expect (result != NULL, 1))
203                     memcpy (result, codeset, len);
204 #endif
205
206                   if (__builtin_expect (result != NULL, 1))
207                     {
208                       if (binding->codeset != NULL)
209                         free (binding->codeset);
210
211                       binding->codeset = result;
212                       ++binding->codeset_cntr;
213                       modified = 1;
214                     }
215                 }
216               *codesetp = result;
217             }
218         }
219     }
220   else if ((dirnamep == NULL || *dirnamep == NULL)
221            && (codesetp == NULL || *codesetp == NULL))
222     {
223       /* Simply return the default values.  */
224       if (dirnamep)
225         *dirnamep = INTUSE(_nl_default_dirname);
226       if (codesetp)
227         *codesetp = NULL;
228     }
229   else
230     {
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);
235
236       if (__builtin_expect (new_binding == NULL, 0))
237         goto failed;
238
239       memcpy (new_binding->domainname, domainname, len);
240
241       if (dirnamep)
242         {
243           const char *dirname = *dirnamep;
244
245           if (dirname == NULL)
246             /* The default value.  */
247             dirname = INTUSE(_nl_default_dirname);
248           else
249             {
250               if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
251                 dirname = INTUSE(_nl_default_dirname);
252               else
253                 {
254                   char *result;
255 #if defined _LIBC || defined HAVE_STRDUP
256                   result = strdup (dirname);
257                   if (__builtin_expect (result == NULL, 0))
258                     goto failed_dirname;
259 #else
260                   size_t len = strlen (dirname) + 1;
261                   result = (char *) malloc (len);
262                   if (__builtin_expect (result == NULL, 0))
263                     goto failed_dirname;
264                   memcpy (result, dirname, len);
265 #endif
266                   dirname = result;
267                 }
268             }
269           *dirnamep = dirname;
270           new_binding->dirname = (char *) dirname;
271         }
272       else
273         /* The default value.  */
274         new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
275
276       new_binding->codeset_cntr = 0;
277
278       if (codesetp)
279         {
280           const char *codeset = *codesetp;
281
282           if (codeset != NULL)
283             {
284               char *result;
285
286 #if defined _LIBC || defined HAVE_STRDUP
287               result = strdup (codeset);
288               if (__builtin_expect (result == NULL, 0))
289                 goto failed_codeset;
290 #else
291               size_t len = strlen (codeset) + 1;
292               result = (char *) malloc (len);
293               if (__builtin_expect (result == NULL, 0))
294                 goto failed_codeset;
295               memcpy (result, codeset, len);
296 #endif
297               codeset = result;
298               ++new_binding->codeset_cntr;
299             }
300           *codesetp = codeset;
301           new_binding->codeset = (char *) codeset;
302         }
303       else
304         new_binding->codeset = NULL;
305
306       /* Now enqueue it.  */
307       if (_nl_domain_bindings == NULL
308           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
309         {
310           new_binding->next = _nl_domain_bindings;
311           _nl_domain_bindings = new_binding;
312         }
313       else
314         {
315           binding = _nl_domain_bindings;
316           while (binding->next != NULL
317                  && strcmp (domainname, binding->next->domainname) > 0)
318             binding = binding->next;
319
320           new_binding->next = binding->next;
321           binding->next = new_binding;
322         }
323
324       modified = 1;
325
326       /* Here we deal with memory allocation failures.  */
327       if (0)
328         {
329         failed_codeset:
330           if (new_binding->dirname != INTUSE(_nl_default_dirname))
331             free (new_binding->dirname);
332         failed_dirname:
333           free (new_binding);
334         failed:
335           if (dirnamep)
336             *dirnamep = NULL;
337           if (codesetp)
338             *codesetp = NULL;
339         }
340     }
341
342   /* If we modified any binding, we flush the caches.  */
343   if (modified)
344     ++_nl_msg_cat_cntr;
345
346   __libc_rwlock_unlock (_nl_state_lock);
347 }
348
349 /* Specify that the DOMAINNAME message catalog will be found
350    in DIRNAME rather than in the system locale data base.  */
351 char *
352 BINDTEXTDOMAIN (domainname, dirname)
353      const char *domainname;
354      const char *dirname;
355 {
356   set_binding_values (domainname, &dirname, NULL);
357   return (char *) dirname;
358 }
359
360 /* Specify the character encoding in which the messages from the
361    DOMAINNAME message catalog will be returned.  */
362 char *
363 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
364      const char *domainname;
365      const char *codeset;
366 {
367   set_binding_values (domainname, NULL, &codeset);
368   return (char *) codeset;
369 }
370
371 #ifdef _LIBC
372 /* Aliases for function names in GNU C Library.  */
373 weak_alias (__bindtextdomain, bindtextdomain);
374 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
375 #endif