Update.
[platform/upstream/glibc.git] / intl / bindtextdom.c
1 /* Implementation of the bindtextdomain(3) function
2    Copyright (C) 1995, 1996, 1997, 1998, 2000 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)
39 # endif
40 #endif
41
42 #ifdef _LIBC
43 # include <libintl.h>
44 #else
45 # include "libgettext.h"
46 #endif
47 #include "gettext.h"
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 /* @@ end of prolog @@ */
61
62 /* Contains the default location of the message catalogs.  */
63 extern const char _nl_default_dirname[];
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)
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 bindtextdomain__
84 # define BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset__
85 #endif
86
87 /* Prototypes for local functions.  */
88 static void set_binding_values (const char *domainname, const char **dirnamep,
89                                 const char **codesetp);
90      
91 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
92    to be used for the DOMAINNAME message catalog.
93    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
94    modified, only the current value is returned.
95    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
96    modified nor returned.  */
97 static void
98 set_binding_values (domainname, dirnamep, codesetp)
99      const char *domainname;
100      const char **dirnamep;
101      const char **codesetp;
102 {
103   struct binding *binding;
104   int modified;
105
106   /* Some sanity checks.  */
107   if (domainname == NULL || domainname[0] == '\0')
108     {
109       if (dirnamep)
110         *dirnamep = NULL;
111       if (codesetp)
112         *codesetp = NULL;
113       return;
114     }
115
116   __libc_rwlock_wrlock (_nl_state_lock);
117
118   modified = 0;
119
120   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
121     {
122       int compare = strcmp (domainname, binding->domainname);
123       if (compare == 0)
124         /* We found it!  */
125         break;
126       if (compare < 0)
127         {
128           /* It is not in the list.  */
129           binding = NULL;
130           break;
131         }
132     }
133
134   if (binding != NULL)
135     {
136       if (dirnamep)
137         {
138           const char *dirname = *dirnamep;
139
140           if (dirname == NULL)
141             /* The current binding has be to returned.  */
142             *dirnamep = binding->dirname;
143           else
144             {
145               /* The domain is already bound.  If the new value and the old
146                  one are equal we simply do nothing.  Otherwise replace the
147                  old binding.  */
148               char *result = binding->dirname;
149               if (strcmp (dirname, result) != 0)
150                 {
151                   if (strcmp (dirname, _nl_default_dirname) == 0)
152                     result = (char *) _nl_default_dirname;
153                   else
154                     {
155 #if defined _LIBC || defined HAVE_STRDUP
156                       result = strdup (dirname);
157 #else
158                       size_t len = strlen (dirname) + 1;
159                       result = (char *) malloc (len);
160                       if (__builtin_expect (result != NULL, 1))
161                         memcpy (result, dirname, len);
162 #endif
163                     }
164
165                   if (__builtin_expect (result != NULL, 1))
166                     {
167                       if (binding->dirname != _nl_default_dirname)
168                         free (binding->dirname);
169
170                       binding->dirname = result;
171                       modified = 1;
172                     }
173                 }
174               *dirnamep = result;
175             }
176         }
177
178       if (codesetp)
179         {
180           const char *codeset = *codesetp;
181
182           if (codeset == NULL)
183             /* The current binding has be to returned.  */
184             *codesetp = binding->codeset;
185           else
186             {
187               /* The domain is already bound.  If the new value and the old
188                  one are equal we simply do nothing.  Otherwise replace the
189                  old binding.  */
190               char *result = binding->codeset;
191               if (result == NULL || strcmp (codeset, result) != 0)
192                 {
193 #if defined _LIBC || defined HAVE_STRDUP
194                   result = strdup (codeset);
195 #else
196                   size_t len = strlen (codeset) + 1;
197                   result = (char *) malloc (len);
198                   if (__builtin_expect (result != NULL, 1))
199                     memcpy (result, codeset, len);
200 #endif
201
202                   if (__builtin_expect (result != NULL, 1))
203                     {
204                       if (binding->codeset != NULL)
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 (sizeof (*new_binding) + 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