Imported from ../bash-4.0-rc1.tar.gz.
[platform/upstream/bash.git] / lib / intl / bindtextdom.c
1 /* bindtextdom.c - Implementation of the bindtextdomain(3) function */
2
3 /* Copyright (C) 1995-1998, 2000, 2001, 2002, 2005-2009 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash.
6
7    Bash is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Bash is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #ifdef _LIBC
30 # include <libintl.h>
31 #else
32 # include "libgnuintl.h"
33 #endif
34 #include "gettextP.h"
35
36 #ifdef _LIBC
37 /* We have to handle multi-threaded applications.  */
38 # include <bits/libc-lock.h>
39 #else
40 /* Provide dummy implementation if this is outside glibc.  */
41 # define __libc_rwlock_define(CLASS, NAME)
42 # define __libc_rwlock_wrlock(NAME)
43 # define __libc_rwlock_unlock(NAME)
44 #endif
45
46 /* The internal variables in the standalone libintl.a must have different
47    names than the internal variables in GNU libc, otherwise programs
48    using libintl.a cannot be linked statically.  */
49 #if !defined _LIBC
50 # define _nl_default_dirname libintl_nl_default_dirname
51 # define _nl_domain_bindings libintl_nl_domain_bindings
52 #endif
53
54 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
55 #ifndef offsetof
56 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
57 #endif
58
59 /* @@ end of prolog @@ */
60
61 /* Contains the default location of the message catalogs.  */
62 extern const char _nl_default_dirname[];
63 #ifdef _LIBC
64 extern const char _nl_default_dirname_internal[] attribute_hidden;
65 #else
66 # define INTUSE(name) name
67 #endif
68
69 /* List with bindings of specific domains.  */
70 extern struct binding *_nl_domain_bindings;
71
72 /* Lock variable to protect the global data in the gettext implementation.  */
73 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
74
75
76 /* Names for the libintl functions are a problem.  They must not clash
77    with existing names and they should follow ANSI C.  But this source
78    code is also used in GNU C Library where the names have a __
79    prefix.  So we have to make a difference here.  */
80 #ifdef _LIBC
81 # define BINDTEXTDOMAIN __bindtextdomain
82 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
83 # ifndef strdup
84 #  define strdup(str) __strdup (str)
85 # endif
86 #else
87 # define BINDTEXTDOMAIN libintl_bindtextdomain
88 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
89 #endif
90
91 /* Prototypes for local functions.  */
92 static void set_binding_values PARAMS ((const char *domainname,
93                                         const char **dirnamep,
94                                         const char **codesetp));
95
96 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
97    to be used for the DOMAINNAME message catalog.
98    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
99    modified, only the current value is returned.
100    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
101    modified nor returned.  */
102 static void
103 set_binding_values (domainname, dirnamep, codesetp)
104      const char *domainname;
105      const char **dirnamep;
106      const char **codesetp;
107 {
108   struct binding *binding;
109   int modified;
110
111   /* Some sanity checks.  */
112   if (domainname == NULL || domainname[0] == '\0')
113     {
114       if (dirnamep)
115         *dirnamep = NULL;
116       if (codesetp)
117         *codesetp = NULL;
118       return;
119     }
120
121   __libc_rwlock_wrlock (_nl_state_lock);
122
123   modified = 0;
124
125   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
126     {
127       int compare = strcmp (domainname, binding->domainname);
128       if (compare == 0)
129         /* We found it!  */
130         break;
131       if (compare < 0)
132         {
133           /* It is not in the list.  */
134           binding = NULL;
135           break;
136         }
137     }
138
139   if (binding != NULL)
140     {
141       if (dirnamep)
142         {
143           const char *dirname = *dirnamep;
144
145           if (dirname == NULL)
146             /* The current binding has be to returned.  */
147             *dirnamep = binding->dirname;
148           else
149             {
150               /* The domain is already bound.  If the new value and the old
151                  one are equal we simply do nothing.  Otherwise replace the
152                  old binding.  */
153               char *result = binding->dirname;
154               if (strcmp (dirname, result) != 0)
155                 {
156                   if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
157                     result = (char *) INTUSE(_nl_default_dirname);
158                   else
159                     {
160 #if defined _LIBC || defined HAVE_STRDUP
161                       result = strdup (dirname);
162 #else
163                       size_t len = strlen (dirname) + 1;
164                       result = (char *) malloc (len);
165                       if (__builtin_expect (result != NULL, 1))
166                         memcpy (result, dirname, len);
167 #endif
168                     }
169
170                   if (__builtin_expect (result != NULL, 1))
171                     {
172                       if (binding->dirname != INTUSE(_nl_default_dirname))
173                         free (binding->dirname);
174
175                       binding->dirname = result;
176                       modified = 1;
177                     }
178                 }
179               *dirnamep = result;
180             }
181         }
182
183       if (codesetp)
184         {
185           const char *codeset = *codesetp;
186
187           if (codeset == NULL)
188             /* The current binding has be to returned.  */
189             *codesetp = binding->codeset;
190           else
191             {
192               /* The domain is already bound.  If the new value and the old
193                  one are equal we simply do nothing.  Otherwise replace the
194                  old binding.  */
195               char *result = binding->codeset;
196               if (result == NULL || strcmp (codeset, result) != 0)
197                 {
198 #if defined _LIBC || defined HAVE_STRDUP
199                   result = strdup (codeset);
200 #else
201                   size_t len = strlen (codeset) + 1;
202                   result = (char *) malloc (len);
203                   if (__builtin_expect (result != NULL, 1))
204                     memcpy (result, codeset, len);
205 #endif
206
207                   if (__builtin_expect (result != NULL, 1))
208                     {
209                       if (binding->codeset != NULL)
210                         free (binding->codeset);
211
212                       binding->codeset = result;
213                       binding->codeset_cntr++;
214                       modified = 1;
215                     }
216                 }
217               *codesetp = result;
218             }
219         }
220     }
221   else if ((dirnamep == NULL || *dirnamep == NULL)
222            && (codesetp == NULL || *codesetp == NULL))
223     {
224       /* Simply return the default values.  */
225       if (dirnamep)
226         *dirnamep = INTUSE(_nl_default_dirname);
227       if (codesetp)
228         *codesetp = NULL;
229     }
230   else
231     {
232       /* We have to create a new binding.  */
233       size_t len = strlen (domainname) + 1;
234       struct binding *new_binding =
235         (struct binding *) malloc (offsetof (struct binding, domainname) + len);
236
237       if (__builtin_expect (new_binding == NULL, 0))
238         goto failed;
239
240       memcpy (new_binding->domainname, domainname, len);
241
242       if (dirnamep)
243         {
244           const char *dirname = *dirnamep;
245
246           if (dirname == NULL)
247             /* The default value.  */
248             dirname = INTUSE(_nl_default_dirname);
249           else
250             {
251               if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
252                 dirname = INTUSE(_nl_default_dirname);
253               else
254                 {
255                   char *result;
256 #if defined _LIBC || defined HAVE_STRDUP
257                   result = strdup (dirname);
258                   if (__builtin_expect (result == NULL, 0))
259                     goto failed_dirname;
260 #else
261                   size_t len = strlen (dirname) + 1;
262                   result = (char *) malloc (len);
263                   if (__builtin_expect (result == NULL, 0))
264                     goto failed_dirname;
265                   memcpy (result, dirname, len);
266 #endif
267                   dirname = result;
268                 }
269             }
270           *dirnamep = dirname;
271           new_binding->dirname = (char *) dirname;
272         }
273       else
274         /* The default value.  */
275         new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
276
277       new_binding->codeset_cntr = 0;
278
279       if (codesetp)
280         {
281           const char *codeset = *codesetp;
282
283           if (codeset != NULL)
284             {
285               char *result;
286
287 #if defined _LIBC || defined HAVE_STRDUP
288               result = strdup (codeset);
289               if (__builtin_expect (result == NULL, 0))
290                 goto failed_codeset;
291 #else
292               size_t len = strlen (codeset) + 1;
293               result = (char *) malloc (len);
294               if (__builtin_expect (result == NULL, 0))
295                 goto failed_codeset;
296               memcpy (result, codeset, len);
297 #endif
298               codeset = result;
299               new_binding->codeset_cntr++;
300             }
301           *codesetp = codeset;
302           new_binding->codeset = (char *) codeset;
303         }
304       else
305         new_binding->codeset = NULL;
306
307       /* Now enqueue it.  */
308       if (_nl_domain_bindings == NULL
309           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
310         {
311           new_binding->next = _nl_domain_bindings;
312           _nl_domain_bindings = new_binding;
313         }
314       else
315         {
316           binding = _nl_domain_bindings;
317           while (binding->next != NULL
318                  && strcmp (domainname, binding->next->domainname) > 0)
319             binding = binding->next;
320
321           new_binding->next = binding->next;
322           binding->next = new_binding;
323         }
324
325       modified = 1;
326
327       /* Here we deal with memory allocation failures.  */
328       if (0)
329         {
330         failed_codeset:
331           if (new_binding->dirname != INTUSE(_nl_default_dirname))
332             free (new_binding->dirname);
333         failed_dirname:
334           free (new_binding);
335         failed:
336           if (dirnamep)
337             *dirnamep = NULL;
338           if (codesetp)
339             *codesetp = NULL;
340         }
341     }
342
343   /* If we modified any binding, we flush the caches.  */
344   if (modified)
345     ++_nl_msg_cat_cntr;
346
347   __libc_rwlock_unlock (_nl_state_lock);
348 }
349
350 /* Specify that the DOMAINNAME message catalog will be found
351    in DIRNAME rather than in the system locale data base.  */
352 char *
353 BINDTEXTDOMAIN (domainname, dirname)
354      const char *domainname;
355      const char *dirname;
356 {
357   set_binding_values (domainname, &dirname, NULL);
358   return (char *) dirname;
359 }
360
361 /* Specify the character encoding in which the messages from the
362    DOMAINNAME message catalog will be returned.  */
363 char *
364 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
365      const char *domainname;
366      const char *codeset;
367 {
368   set_binding_values (domainname, NULL, &codeset);
369   return (char *) codeset;
370 }
371
372 #ifdef _LIBC
373 /* Aliases for function names in GNU C Library.  */
374 weak_alias (__bindtextdomain, bindtextdomain);
375 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
376 #endif