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