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