Merge glibc-ports into ports/ directory.
[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, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #ifdef _LIBC
28 # include <libintl.h>
29 #else
30 # include "libgnuintl.h"
31 #endif
32 #include "gettextP.h"
33
34 #ifdef _LIBC
35 /* We have to handle multi-threaded applications.  */
36 # include <bits/libc-lock.h>
37 #else
38 /* Provide dummy implementation if this is outside glibc.  */
39 # define __libc_rwlock_define(CLASS, NAME)
40 # define __libc_rwlock_wrlock(NAME)
41 # define __libc_rwlock_unlock(NAME)
42 #endif
43
44 /* The internal variables in the standalone libintl.a must have different
45    names than the internal variables in GNU libc, otherwise programs
46    using libintl.a cannot be linked statically.  */
47 #if !defined _LIBC
48 # define _nl_default_dirname libintl_nl_default_dirname
49 # define _nl_domain_bindings libintl_nl_domain_bindings
50 #endif
51
52 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
53 #ifndef offsetof
54 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
55 #endif
56
57 /* @@ end of prolog @@ */
58
59 /* Contains the default location of the message catalogs.  */
60 extern const char _nl_default_dirname[];
61 #ifdef _LIBC
62 libc_hidden_proto (_nl_default_dirname)
63 #endif
64
65 /* List with bindings of specific domains.  */
66 extern struct binding *_nl_domain_bindings;
67
68 /* Lock variable to protect the global data in the gettext implementation.  */
69 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
70
71
72 /* Names for the libintl functions are a problem.  They must not clash
73    with existing names and they should follow ANSI C.  But this source
74    code is also used in GNU C Library where the names have a __
75    prefix.  So we have to make a difference here.  */
76 #ifdef _LIBC
77 # define BINDTEXTDOMAIN __bindtextdomain
78 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
79 # ifndef strdup
80 #  define strdup(str) __strdup (str)
81 # endif
82 #else
83 # define BINDTEXTDOMAIN libintl_bindtextdomain
84 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
85 #endif
86
87 /* Prototypes for local functions.  */
88 static void set_binding_values PARAMS ((const char *domainname,
89                                         const char **dirnamep,
90                                         const char **codesetp));
91
92 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
93    to be used for the DOMAINNAME message catalog.
94    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
95    modified, only the current value is returned.
96    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
97    modified nor returned.  */
98 static void
99 set_binding_values (domainname, dirnamep, codesetp)
100      const char *domainname;
101      const char **dirnamep;
102      const char **codesetp;
103 {
104   struct binding *binding;
105   int modified;
106
107   /* Some sanity checks.  */
108   if (domainname == NULL || domainname[0] == '\0')
109     {
110       if (dirnamep)
111         *dirnamep = NULL;
112       if (codesetp)
113         *codesetp = NULL;
114       return;
115     }
116
117   __libc_rwlock_wrlock (_nl_state_lock);
118
119   modified = 0;
120
121   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
122     {
123       int compare = strcmp (domainname, binding->domainname);
124       if (compare == 0)
125         /* We found it!  */
126         break;
127       if (compare < 0)
128         {
129           /* It is not in the list.  */
130           binding = NULL;
131           break;
132         }
133     }
134
135   if (binding != NULL)
136     {
137       if (dirnamep)
138         {
139           const char *dirname = *dirnamep;
140
141           if (dirname == NULL)
142             /* The current binding has be to returned.  */
143             *dirnamep = binding->dirname;
144           else
145             {
146               /* The domain is already bound.  If the new value and the old
147                  one are equal we simply do nothing.  Otherwise replace the
148                  old binding.  */
149               char *result = binding->dirname;
150               if (strcmp (dirname, result) != 0)
151                 {
152                   if (strcmp (dirname, _nl_default_dirname) == 0)
153                     result = (char *) _nl_default_dirname;
154                   else
155                     {
156 #if defined _LIBC || defined HAVE_STRDUP
157                       result = strdup (dirname);
158 #else
159                       size_t len = strlen (dirname) + 1;
160                       result = (char *) malloc (len);
161                       if (__builtin_expect (result != NULL, 1))
162                         memcpy (result, dirname, len);
163 #endif
164                     }
165
166                   if (__builtin_expect (result != NULL, 1))
167                     {
168                       if (binding->dirname != _nl_default_dirname)
169                         free (binding->dirname);
170
171                       binding->dirname = result;
172                       modified = 1;
173                     }
174                 }
175               *dirnamep = result;
176             }
177         }
178
179       if (codesetp)
180         {
181           const char *codeset = *codesetp;
182
183           if (codeset == NULL)
184             /* The current binding has be to returned.  */
185             *codesetp = binding->codeset;
186           else
187             {
188               /* The domain is already bound.  If the new value and the old
189                  one are equal we simply do nothing.  Otherwise replace the
190                  old binding.  */
191               char *result = binding->codeset;
192               if (result == NULL || strcmp (codeset, result) != 0)
193                 {
194 #if defined _LIBC || defined HAVE_STRDUP
195                   result = strdup (codeset);
196 #else
197                   size_t len = strlen (codeset) + 1;
198                   result = (char *) malloc (len);
199                   if (__builtin_expect (result != NULL, 1))
200                     memcpy (result, codeset, len);
201 #endif
202
203                   if (__builtin_expect (result != NULL, 1))
204                     {
205                       free (binding->codeset);
206
207                       binding->codeset = result;
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       if (codesetp)
272         {
273           const char *codeset = *codesetp;
274
275           if (codeset != NULL)
276             {
277               char *result;
278
279 #if defined _LIBC || defined HAVE_STRDUP
280               result = strdup (codeset);
281               if (__builtin_expect (result == NULL, 0))
282                 goto failed_codeset;
283 #else
284               size_t len = strlen (codeset) + 1;
285               result = (char *) malloc (len);
286               if (__builtin_expect (result == NULL, 0))
287                 goto failed_codeset;
288               memcpy (result, codeset, len);
289 #endif
290               codeset = result;
291             }
292           *codesetp = codeset;
293           new_binding->codeset = (char *) codeset;
294         }
295       else
296         new_binding->codeset = NULL;
297
298       /* Now enqueue it.  */
299       if (_nl_domain_bindings == NULL
300           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
301         {
302           new_binding->next = _nl_domain_bindings;
303           _nl_domain_bindings = new_binding;
304         }
305       else
306         {
307           binding = _nl_domain_bindings;
308           while (binding->next != NULL
309                  && strcmp (domainname, binding->next->domainname) > 0)
310             binding = binding->next;
311
312           new_binding->next = binding->next;
313           binding->next = new_binding;
314         }
315
316       modified = 1;
317
318       /* Here we deal with memory allocation failures.  */
319       if (0)
320         {
321         failed_codeset:
322           if (new_binding->dirname != _nl_default_dirname)
323             free (new_binding->dirname);
324         failed_dirname:
325           free (new_binding);
326         failed:
327           if (dirnamep)
328             *dirnamep = NULL;
329           if (codesetp)
330             *codesetp = NULL;
331         }
332     }
333
334   /* If we modified any binding, we flush the caches.  */
335   if (modified)
336     ++_nl_msg_cat_cntr;
337
338   __libc_rwlock_unlock (_nl_state_lock);
339 }
340
341 /* Specify that the DOMAINNAME message catalog will be found
342    in DIRNAME rather than in the system locale data base.  */
343 char *
344 BINDTEXTDOMAIN (domainname, dirname)
345      const char *domainname;
346      const char *dirname;
347 {
348   set_binding_values (domainname, &dirname, NULL);
349   return (char *) dirname;
350 }
351
352 /* Specify the character encoding in which the messages from the
353    DOMAINNAME message catalog will be returned.  */
354 char *
355 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
356      const char *domainname;
357      const char *codeset;
358 {
359   set_binding_values (domainname, NULL, &codeset);
360   return (char *) codeset;
361 }
362
363 #ifdef _LIBC
364 /* Aliases for function names in GNU C Library.  */
365 weak_alias (__bindtextdomain, bindtextdomain);
366 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
367 #endif