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