]> git.ipfire.org Git - thirdparty/glibc.git/blame - intl/bindtextdom.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / intl / bindtextdom.c
CommitLineData
8f2ece69 1/* Implementation of the bindtextdomain(3) function
04277e02 2 Copyright (C) 1995-2019 Free Software Foundation, Inc.
24906b43 3
6d248857
WN
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.
0393dfd6 8
6d248857 9 This program is distributed in the hope that it will be useful,
c84142e8 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
6d248857
WN
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
24906b43 13
6d248857 14 You should have received a copy of the GNU Lesser General Public License
5a82c748 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
24906b43
RM
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20
0555fcce
UD
21#include <stddef.h>
22#include <stdlib.h>
23#include <string.h>
24906b43 24
6d248857 25#include "gettextP.h"
24906b43
RM
26#ifdef _LIBC
27# include <libintl.h>
28#else
4a4d50f3 29# include "libgnuintl.h"
24906b43 30#endif
24906b43 31
6d248857 32/* Handle multi-threaded applications. */
0ed99ce4 33#ifdef _LIBC
ec999b8e 34# include <libc-lock.h>
6d248857
WN
35# define gl_rwlock_define __libc_rwlock_define
36# define gl_rwlock_wrlock __libc_rwlock_wrlock
37# define gl_rwlock_unlock __libc_rwlock_unlock
0ed99ce4 38#else
6d248857 39# include "lock.h"
52d895a4
UD
40#endif
41
4a4d50f3
UD
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
24906b43
RM
47/* @@ end of prolog @@ */
48
0ed99ce4 49/* Lock variable to protect the global data in the gettext implementation. */
6d248857 50gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
0ed99ce4 51
24906b43
RM
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
17c389fc 59# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
cb343854
UD
60# ifndef strdup
61# define strdup(str) __strdup (str)
62# endif
24906b43 63#else
0f131646
RM
64# define BINDTEXTDOMAIN libintl_bindtextdomain
65# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
24906b43
RM
66#endif
67
17c389fc
UD
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. */
74static void
6d248857
WN
75set_binding_values (const char *domainname,
76 const char **dirnamep, const char **codesetp)
24906b43
RM
77{
78 struct binding *binding;
17c389fc 79 int modified;
24906b43
RM
80
81 /* Some sanity checks. */
82 if (domainname == NULL || domainname[0] == '\0')
17c389fc
UD
83 {
84 if (dirnamep)
85 *dirnamep = NULL;
86 if (codesetp)
87 *codesetp = NULL;
88 return;
89 }
24906b43 90
6d248857 91 gl_rwlock_wrlock (_nl_state_lock);
0ed99ce4 92
17c389fc
UD
93 modified = 0;
94
24906b43
RM
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
17c389fc 109 if (binding != NULL)
24906b43 110 {
17c389fc 111 if (dirnamep)
24906b43 112 {
17c389fc
UD
113 const char *dirname = *dirnamep;
114
115 if (dirname == NULL)
116 /* The current binding has be to returned. */
117 *dirnamep = binding->dirname;
40a55d20
UD
118 else
119 {
17c389fc
UD
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 {
9cfe5381
RM
126 if (strcmp (dirname, _nl_default_dirname) == 0)
127 result = (char *) _nl_default_dirname;
17c389fc
UD
128 else
129 {
40a55d20 130#if defined _LIBC || defined HAVE_STRDUP
17c389fc 131 result = strdup (dirname);
40a55d20 132#else
17c389fc
UD
133 size_t len = strlen (dirname) + 1;
134 result = (char *) malloc (len);
6d248857 135 if (__builtin_expect (result != NULL, 1))
17c389fc 136 memcpy (result, dirname, len);
40a55d20 137#endif
17c389fc
UD
138 }
139
6d248857 140 if (__builtin_expect (result != NULL, 1))
17c389fc 141 {
9cfe5381 142 if (binding->dirname != _nl_default_dirname)
17c389fc
UD
143 free (binding->dirname);
144
145 binding->dirname = result;
146 modified = 1;
147 }
148 }
149 *dirnamep = result;
40a55d20 150 }
17c389fc
UD
151 }
152
153 if (codesetp)
154 {
155 const char *codeset = *codesetp;
24906b43 156
17c389fc
UD
157 if (codeset == NULL)
158 /* The current binding has be to returned. */
159 *codesetp = binding->codeset;
160 else
0ed99ce4 161 {
17c389fc
UD
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);
6d248857 173 if (__builtin_expect (result != NULL, 1))
17c389fc
UD
174 memcpy (result, codeset, len);
175#endif
24906b43 176
6d248857 177 if (__builtin_expect (result != NULL, 1))
17c389fc 178 {
72e6cdfa 179 free (binding->codeset);
17c389fc
UD
180
181 binding->codeset = result;
182 modified = 1;
183 }
184 }
185 *codesetp = result;
0ed99ce4 186 }
40a55d20 187 }
24906b43 188 }
17c389fc
UD
189 else if ((dirnamep == NULL || *dirnamep == NULL)
190 && (codesetp == NULL || *codesetp == NULL))
191 {
192 /* Simply return the default values. */
193 if (dirnamep)
9cfe5381 194 *dirnamep = _nl_default_dirname;
17c389fc
UD
195 if (codesetp)
196 *codesetp = NULL;
197 }
24906b43
RM
198 else
199 {
200 /* We have to create a new binding. */
0ed99ce4 201 size_t len = strlen (domainname) + 1;
24906b43 202 struct binding *new_binding =
4a4d50f3 203 (struct binding *) malloc (offsetof (struct binding, domainname) + len);
24906b43 204
6d248857 205 if (__builtin_expect (new_binding == NULL, 0))
17c389fc
UD
206 goto failed;
207
208 memcpy (new_binding->domainname, domainname, len);
209
210 if (dirnamep)
24906b43 211 {
17c389fc 212 const char *dirname = *dirnamep;
0ed99ce4 213
17c389fc
UD
214 if (dirname == NULL)
215 /* The default value. */
9cfe5381 216 dirname = _nl_default_dirname;
0ed99ce4
UD
217 else
218 {
9cfe5381
RM
219 if (strcmp (dirname, _nl_default_dirname) == 0)
220 dirname = _nl_default_dirname;
17c389fc
UD
221 else
222 {
223 char *result;
40a55d20 224#if defined _LIBC || defined HAVE_STRDUP
17c389fc 225 result = strdup (dirname);
6d248857 226 if (__builtin_expect (result == NULL, 0))
17c389fc 227 goto failed_dirname;
40a55d20 228#else
17c389fc
UD
229 size_t len = strlen (dirname) + 1;
230 result = (char *) malloc (len);
6d248857 231 if (__builtin_expect (result == NULL, 0))
17c389fc
UD
232 goto failed_dirname;
233 memcpy (result, dirname, len);
40a55d20 234#endif
17c389fc
UD
235 dirname = result;
236 }
0ed99ce4 237 }
17c389fc
UD
238 *dirnamep = dirname;
239 new_binding->dirname = (char *) dirname;
24906b43 240 }
17c389fc
UD
241 else
242 /* The default value. */
9cfe5381 243 new_binding->dirname = (char *) _nl_default_dirname;
a334319f 244
17c389fc 245 if (codesetp)
24906b43 246 {
17c389fc
UD
247 const char *codeset = *codesetp;
248
249 if (codeset != NULL)
0ed99ce4 250 {
17c389fc 251 char *result;
24906b43 252
17c389fc
UD
253#if defined _LIBC || defined HAVE_STRDUP
254 result = strdup (codeset);
6d248857 255 if (__builtin_expect (result == NULL, 0))
17c389fc
UD
256 goto failed_codeset;
257#else
258 size_t len = strlen (codeset) + 1;
259 result = (char *) malloc (len);
6d248857 260 if (__builtin_expect (result == NULL, 0))
17c389fc
UD
261 goto failed_codeset;
262 memcpy (result, codeset, len);
263#endif
264 codeset = result;
0ed99ce4 265 }
17c389fc
UD
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:
9cfe5381 296 if (new_binding->dirname != _nl_default_dirname)
17c389fc
UD
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;
24906b43 305 }
24906b43
RM
306 }
307
17c389fc
UD
308 /* If we modified any binding, we flush the caches. */
309 if (modified)
0ed99ce4
UD
310 ++_nl_msg_cat_cntr;
311
6d248857 312 gl_rwlock_unlock (_nl_state_lock);
17c389fc
UD
313}
314
315/* Specify that the DOMAINNAME message catalog will be found
316 in DIRNAME rather than in the system locale data base. */
317char *
6d248857 318BINDTEXTDOMAIN (const char *domainname, const char *dirname)
17c389fc
UD
319{
320 set_binding_values (domainname, &dirname, NULL);
321 return (char *) dirname;
322}
0ed99ce4 323
17c389fc
UD
324/* Specify the character encoding in which the messages from the
325 DOMAINNAME message catalog will be returned. */
326char *
6d248857 327BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
17c389fc
UD
328{
329 set_binding_values (domainname, NULL, &codeset);
330 return (char *) codeset;
24906b43
RM
331}
332
333#ifdef _LIBC
17c389fc 334/* Aliases for function names in GNU C Library. */
24906b43 335weak_alias (__bindtextdomain, bindtextdomain);
17c389fc 336weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
24906b43 337#endif