(set_binding_values): New function.
[kopensolaris-gnu/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 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
88    to be used for the DOMAINNAME message catalog.
89    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
90    modified, only the current value is returned.
91    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
92    modified nor returned.  */
93 static void
94 set_binding_values (domainname, dirnamep, codesetp)
95      const char *domainname;
96      const char **dirnamep;
97      const char **codesetp;
98 {
99   struct binding *binding;
100   int modified;
101
102   /* Some sanity checks.  */
103   if (domainname == NULL || domainname[0] == '\0')
104     {
105       if (dirnamep)
106         *dirnamep = NULL;
107       if (codesetp)
108         *codesetp = NULL;
109       return;
110     }
111
112   __libc_rwlock_wrlock (_nl_state_lock);
113
114   modified = 0;
115
116   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
117     {
118       int compare = strcmp (domainname, binding->domainname);
119       if (compare == 0)
120         /* We found it!  */
121         break;
122       if (compare < 0)
123         {
124           /* It is not in the list.  */
125           binding = NULL;
126           break;
127         }
128     }
129
130   if (binding != NULL)
131     {
132       if (dirnamep)
133         {
134           const char *dirname = *dirnamep;
135
136           if (dirname == NULL)
137             /* The current binding has be to returned.  */
138             *dirnamep = binding->dirname;
139           else
140             {
141               /* The domain is already bound.  If the new value and the old
142                  one are equal we simply do nothing.  Otherwise replace the
143                  old binding.  */
144               char *result = binding->dirname;
145               if (strcmp (dirname, result) != 0)
146                 {
147                   if (strcmp (dirname, _nl_default_dirname) == 0)
148                     result = (char *) _nl_default_dirname;
149                   else
150                     {
151 #if defined _LIBC || defined HAVE_STRDUP
152                       result = strdup (dirname);
153 #else
154                       size_t len = strlen (dirname) + 1;
155                       result = (char *) malloc (len);
156                       if (__builtin_expect (result != NULL, 1))
157                         memcpy (result, dirname, len);
158 #endif
159                     }
160
161                   if (__builtin_expect (result != NULL, 1))
162                     {
163                       if (binding->dirname != _nl_default_dirname)
164                         free (binding->dirname);
165
166                       binding->dirname = result;
167                       modified = 1;
168                     }
169                 }
170               *dirnamep = result;
171             }
172         }
173
174       if (codesetp)
175         {
176           const char *codeset = *codesetp;
177
178           if (codeset == NULL)
179             /* The current binding has be to returned.  */
180             *codesetp = binding->codeset;
181           else
182             {
183               /* The domain is already bound.  If the new value and the old
184                  one are equal we simply do nothing.  Otherwise replace the
185                  old binding.  */
186               char *result = binding->codeset;
187               if (result == NULL || strcmp (codeset, result) != 0)
188                 {
189 #if defined _LIBC || defined HAVE_STRDUP
190                   result = strdup (codeset);
191 #else
192                   size_t len = strlen (codeset) + 1;
193                   result = (char *) malloc (len);
194                   if (__builtin_expect (result != NULL, 1))
195                     memcpy (result, codeset, len);
196 #endif
197
198                   if (__builtin_expect (result != NULL, 1))
199                     {
200                       if (binding->codeset != NULL)
201                         free (binding->codeset);
202
203                       binding->codeset = result;
204                       modified = 1;
205                     }
206                 }
207               *codesetp = result;
208             }
209         }
210     }
211   else if ((dirnamep == NULL || *dirnamep == NULL)
212            && (codesetp == NULL || *codesetp == NULL))
213     {
214       /* Simply return the default values.  */
215       if (dirnamep)
216         *dirnamep = _nl_default_dirname;
217       if (codesetp)
218         *codesetp = NULL;
219     }
220   else
221     {
222       /* We have to create a new binding.  */
223       size_t len = strlen (domainname) + 1;
224       struct binding *new_binding =
225         (struct binding *) malloc (sizeof (*new_binding) + len);
226
227       if (__builtin_expect (new_binding == NULL, 0))
228         goto failed;
229
230       memcpy (new_binding->domainname, domainname, len);
231
232       if (dirnamep)
233         {
234           const char *dirname = *dirnamep;
235
236           if (dirname == NULL)
237             /* The default value.  */
238             dirname = _nl_default_dirname;
239           else
240             {
241               if (strcmp (dirname, _nl_default_dirname) == 0)
242                 dirname = _nl_default_dirname;
243               else
244                 {
245                   char *result;
246 #if defined _LIBC || defined HAVE_STRDUP
247                   result = strdup (dirname);
248                   if (__builtin_expect (result == NULL, 0))
249                     goto failed_dirname;
250 #else
251                   size_t len = strlen (dirname) + 1;
252                   result = (char *) malloc (len);
253                   if (__builtin_expect (result == NULL, 0))
254                     goto failed_dirname;
255                   memcpy (result, dirname, len);
256 #endif
257                   dirname = result;
258                 }
259             }
260           *dirnamep = dirname;
261           new_binding->dirname = (char *) dirname;
262         }
263       else
264         /* The default value.  */
265         new_binding->dirname = (char *) _nl_default_dirname;
266
267       if (codesetp)
268         {
269           const char *codeset = *codesetp;
270
271           if (codeset != NULL)
272             {
273               char *result;
274
275 #if defined _LIBC || defined HAVE_STRDUP
276               result = strdup (codeset);
277               if (__builtin_expect (result == NULL, 0))
278                 goto failed_codeset;
279 #else
280               size_t len = strlen (codeset) + 1;
281               result = (char *) malloc (len);
282               if (__builtin_expect (result == NULL, 0))
283                 goto failed_codeset;
284               memcpy (result, codeset, len);
285 #endif
286               codeset = result;
287             }
288           *codesetp = codeset;
289           new_binding->codeset = (char *) codeset;
290         }
291       else
292         new_binding->codeset = NULL;
293
294       /* Now enqueue it.  */
295       if (_nl_domain_bindings == NULL
296           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
297         {
298           new_binding->next = _nl_domain_bindings;
299           _nl_domain_bindings = new_binding;
300         }
301       else
302         {
303           binding = _nl_domain_bindings;
304           while (binding->next != NULL
305                  && strcmp (domainname, binding->next->domainname) > 0)
306             binding = binding->next;
307
308           new_binding->next = binding->next;
309           binding->next = new_binding;
310         }
311
312       modified = 1;
313
314       /* Here we deal with memory allocation failures.  */
315       if (0)
316         {
317         failed_codeset:
318           if (new_binding->dirname != _nl_default_dirname)
319             free (new_binding->dirname);
320         failed_dirname:
321           free (new_binding);
322         failed:
323           if (dirnamep)
324             *dirnamep = NULL;
325           if (codesetp)
326             *codesetp = NULL;
327         }
328     }
329
330   /* If we modified any binding, we flush the caches.  */
331   if (modified)
332     ++_nl_msg_cat_cntr;
333
334   __libc_rwlock_unlock (_nl_state_lock);
335 }
336
337 /* Specify that the DOMAINNAME message catalog will be found
338    in DIRNAME rather than in the system locale data base.  */
339 char *
340 BINDTEXTDOMAIN (domainname, dirname)
341      const char *domainname;
342      const char *dirname;
343 {
344   set_binding_values (domainname, &dirname, NULL);
345   return (char *) dirname;
346 }
347
348 /* Specify the character encoding in which the messages from the
349    DOMAINNAME message catalog will be returned.  */
350 char *
351 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
352      const char *domainname;
353      const char *codeset;
354 {
355   set_binding_values (domainname, NULL, &codeset);
356   return (char *) codeset;
357 }
358
359 #ifdef _LIBC
360 /* Aliases for function names in GNU C Library.  */
361 weak_alias (__bindtextdomain, bindtextdomain);
362 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
363 #endif