Don't include gettext.h.
[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                       modified = 1;
222                     }
223                 }
224               *codesetp = result;
225             }
226         }
227     }
228   else if ((dirnamep == NULL || *dirnamep == NULL)
229            && (codesetp == NULL || *codesetp == NULL))
230     {
231       /* Simply return the default values.  */
232       if (dirnamep)
233         *dirnamep = _nl_default_dirname;
234       if (codesetp)
235         *codesetp = NULL;
236     }
237   else
238     {
239       /* We have to create a new binding.  */
240       size_t len = strlen (domainname) + 1;
241       struct binding *new_binding =
242         (struct binding *) malloc (offsetof (struct binding, domainname) + len);
243
244       if (__builtin_expect (new_binding == NULL, 0))
245         goto failed;
246
247       memcpy (new_binding->domainname, domainname, len);
248
249       if (dirnamep)
250         {
251           const char *dirname = *dirnamep;
252
253           if (dirname == NULL)
254             /* The default value.  */
255             dirname = _nl_default_dirname;
256           else
257             {
258               if (strcmp (dirname, _nl_default_dirname) == 0)
259                 dirname = _nl_default_dirname;
260               else
261                 {
262                   char *result;
263 #if defined _LIBC || defined HAVE_STRDUP
264                   result = strdup (dirname);
265                   if (__builtin_expect (result == NULL, 0))
266                     goto failed_dirname;
267 #else
268                   size_t len = strlen (dirname) + 1;
269                   result = (char *) malloc (len);
270                   if (__builtin_expect (result == NULL, 0))
271                     goto failed_dirname;
272                   memcpy (result, dirname, len);
273 #endif
274                   dirname = result;
275                 }
276             }
277           *dirnamep = dirname;
278           new_binding->dirname = (char *) dirname;
279         }
280       else
281         /* The default value.  */
282         new_binding->dirname = (char *) _nl_default_dirname;
283
284       if (codesetp)
285         {
286           const char *codeset = *codesetp;
287
288           if (codeset != NULL)
289             {
290               char *result;
291
292 #if defined _LIBC || defined HAVE_STRDUP
293               result = strdup (codeset);
294               if (__builtin_expect (result == NULL, 0))
295                 goto failed_codeset;
296 #else
297               size_t len = strlen (codeset) + 1;
298               result = (char *) malloc (len);
299               if (__builtin_expect (result == NULL, 0))
300                 goto failed_codeset;
301               memcpy (result, codeset, len);
302 #endif
303               codeset = result;
304             }
305           *codesetp = codeset;
306           new_binding->codeset = (char *) codeset;
307         }
308       else
309         new_binding->codeset = NULL;
310
311       /* Now enqueue it.  */
312       if (_nl_domain_bindings == NULL
313           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
314         {
315           new_binding->next = _nl_domain_bindings;
316           _nl_domain_bindings = new_binding;
317         }
318       else
319         {
320           binding = _nl_domain_bindings;
321           while (binding->next != NULL
322                  && strcmp (domainname, binding->next->domainname) > 0)
323             binding = binding->next;
324
325           new_binding->next = binding->next;
326           binding->next = new_binding;
327         }
328
329       modified = 1;
330
331       /* Here we deal with memory allocation failures.  */
332       if (0)
333         {
334         failed_codeset:
335           if (new_binding->dirname != _nl_default_dirname)
336             free (new_binding->dirname);
337         failed_dirname:
338           free (new_binding);
339         failed:
340           if (dirnamep)
341             *dirnamep = NULL;
342           if (codesetp)
343             *codesetp = NULL;
344         }
345     }
346
347   /* If we modified any binding, we flush the caches.  */
348   if (modified)
349     ++_nl_msg_cat_cntr;
350
351   __libc_rwlock_unlock (_nl_state_lock);
352 }
353
354 /* Specify that the DOMAINNAME message catalog will be found
355    in DIRNAME rather than in the system locale data base.  */
356 char *
357 BINDTEXTDOMAIN (domainname, dirname)
358      const char *domainname;
359      const char *dirname;
360 {
361   set_binding_values (domainname, &dirname, NULL);
362   return (char *) dirname;
363 }
364
365 /* Specify the character encoding in which the messages from the
366    DOMAINNAME message catalog will be returned.  */
367 char *
368 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
369      const char *domainname;
370      const char *codeset;
371 {
372   set_binding_values (domainname, NULL, &codeset);
373   return (char *) codeset;
374 }
375
376 #ifdef _LIBC
377 /* Aliases for function names in GNU C Library.  */
378 weak_alias (__bindtextdomain, bindtextdomain);
379 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
380 #endif