OSDN Git Service

merge in master-release history after reset to 2079d768f79f636223d89b988a30209adf8dddbe
[android-x86/external-e2fsprogs.git] / intl / bindtextdom.c
1 /* Implementation of the bindtextdomain(3) function
2    Copyright (C) 1995-1998, 2000-2003 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU Library General Public License as published
6    by the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program 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 this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17    USA.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #ifdef _LIBC
28 # include <libintl.h>
29 #else
30 # include "libgnuintl.h"
31 #endif
32 #include "gettextP.h"
33
34 #ifdef _LIBC
35 /* We have to handle multi-threaded applications.  */
36 # include <bits/libc-lock.h>
37 #else
38 /* Provide dummy implementation if this is outside glibc.  */
39 # define __libc_rwlock_define(CLASS, NAME)
40 # define __libc_rwlock_wrlock(NAME)
41 # define __libc_rwlock_unlock(NAME)
42 #endif
43
44 /* The internal variables in the standalone libintl.a must have different
45    names than the internal variables in GNU libc, otherwise programs
46    using libintl.a cannot be linked statically.  */
47 #if !defined _LIBC
48 # define _nl_default_dirname libintl_nl_default_dirname
49 # define _nl_domain_bindings libintl_nl_domain_bindings
50 #endif
51
52 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
53 #ifndef offsetof
54 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
55 #endif
56
57 /* @@ end of prolog @@ */
58
59 /* Contains the default location of the message catalogs.  */
60 extern const char _nl_default_dirname[];
61 #ifdef _LIBC
62 extern const char _nl_default_dirname_internal[] attribute_hidden;
63 #else
64 # define INTUSE(name) name
65 #endif
66
67 /* List with bindings of specific domains.  */
68 extern struct binding *_nl_domain_bindings;
69
70 /* Lock variable to protect the global data in the gettext implementation.  */
71 __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
72
73
74 /* Names for the libintl functions are a problem.  They must not clash
75    with existing names and they should follow ANSI C.  But this source
76    code is also used in GNU C Library where the names have a __
77    prefix.  So we have to make a difference here.  */
78 #ifdef _LIBC
79 # define BINDTEXTDOMAIN __bindtextdomain
80 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
81 # ifndef strdup
82 #  define strdup(str) __strdup (str)
83 # endif
84 #else
85 # define BINDTEXTDOMAIN libintl_bindtextdomain
86 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
87 #endif
88
89 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
90    to be used for the DOMAINNAME message catalog.
91    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
92    modified, only the current value is returned.
93    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
94    modified nor returned.  */
95 static void
96 set_binding_values (const char *domainname,
97                     const char **dirnamep, 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, INTUSE(_nl_default_dirname)) == 0)
148                     result = (char *) INTUSE(_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 != INTUSE(_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                       free (binding->codeset);
201
202                       binding->codeset = result;
203                       binding->codeset_cntr++;
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 = INTUSE(_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 (offsetof (struct binding, domainname) + 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 = INTUSE(_nl_default_dirname);
239           else
240             {
241               if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
242                 dirname = INTUSE(_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 *) INTUSE(_nl_default_dirname);
266
267       new_binding->codeset_cntr = 0;
268
269       if (codesetp)
270         {
271           const char *codeset = *codesetp;
272
273           if (codeset != NULL)
274             {
275               char *result;
276
277 #if defined _LIBC || defined HAVE_STRDUP
278               result = strdup (codeset);
279               if (__builtin_expect (result == NULL, 0))
280                 goto failed_codeset;
281 #else
282               size_t len = strlen (codeset) + 1;
283               result = (char *) malloc (len);
284               if (__builtin_expect (result == NULL, 0))
285                 goto failed_codeset;
286               memcpy (result, codeset, len);
287 #endif
288               codeset = result;
289               new_binding->codeset_cntr++;
290             }
291           *codesetp = codeset;
292           new_binding->codeset = (char *) codeset;
293         }
294       else
295         new_binding->codeset = NULL;
296
297       /* Now enqueue it.  */
298       if (_nl_domain_bindings == NULL
299           || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
300         {
301           new_binding->next = _nl_domain_bindings;
302           _nl_domain_bindings = new_binding;
303         }
304       else
305         {
306           binding = _nl_domain_bindings;
307           while (binding->next != NULL
308                  && strcmp (domainname, binding->next->domainname) > 0)
309             binding = binding->next;
310
311           new_binding->next = binding->next;
312           binding->next = new_binding;
313         }
314
315       modified = 1;
316
317       /* Here we deal with memory allocation failures.  */
318       if (0)
319         {
320         failed_codeset:
321           if (new_binding->dirname != INTUSE(_nl_default_dirname))
322             free (new_binding->dirname);
323         failed_dirname:
324           free (new_binding);
325         failed:
326           if (dirnamep)
327             *dirnamep = NULL;
328           if (codesetp)
329             *codesetp = NULL;
330         }
331     }
332
333   /* If we modified any binding, we flush the caches.  */
334   if (modified)
335     ++_nl_msg_cat_cntr;
336
337   __libc_rwlock_unlock (_nl_state_lock);
338 }
339
340 /* Specify that the DOMAINNAME message catalog will be found
341    in DIRNAME rather than in the system locale data base.  */
342 char *
343 BINDTEXTDOMAIN (const char *domainname, const char *dirname)
344 {
345   set_binding_values (domainname, &dirname, NULL);
346   return (char *) dirname;
347 }
348
349 /* Specify the character encoding in which the messages from the
350    DOMAINNAME message catalog will be returned.  */
351 char *
352 BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
353 {
354   set_binding_values (domainname, NULL, &codeset);
355   return (char *) codeset;
356 }
357
358 #ifdef _LIBC
359 /* Aliases for function names in GNU C Library.  */
360 weak_alias (__bindtextdomain, bindtextdomain);
361 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
362 #endif