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