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