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