powerpc: Optimize memchr for power8
[glibc.git] / intl / bindtextdom.c
blob86ae7f2501f6e26a669e2345d3789b3e01a95a6a
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-2017 Free Software Foundation, Inc.
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.
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.
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/>. */
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "gettextP.h"
26 #ifdef _LIBC
27 # include <libintl.h>
28 #else
29 # include "libgnuintl.h"
30 #endif
32 /* Handle multi-threaded applications. */
33 #ifdef _LIBC
34 # include <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
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
47 /* @@ end of prolog @@ */
49 /* Lock variable to protect the global data in the gettext implementation. */
50 gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
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
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)
78 struct binding *binding;
79 int modified;
81 /* Some sanity checks. */
82 if (domainname == NULL || domainname[0] == '\0')
84 if (dirnamep)
85 *dirnamep = NULL;
86 if (codesetp)
87 *codesetp = NULL;
88 return;
91 gl_rwlock_wrlock (_nl_state_lock);
93 modified = 0;
95 for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
97 int compare = strcmp (domainname, binding->domainname);
98 if (compare == 0)
99 /* We found it! */
100 break;
101 if (compare < 0)
103 /* It is not in the list. */
104 binding = NULL;
105 break;
109 if (binding != NULL)
111 if (dirnamep)
113 const char *dirname = *dirnamep;
115 if (dirname == NULL)
116 /* The current binding has be to returned. */
117 *dirnamep = binding->dirname;
118 else
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)
126 if (strcmp (dirname, _nl_default_dirname) == 0)
127 result = (char *) _nl_default_dirname;
128 else
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
140 if (__builtin_expect (result != NULL, 1))
142 if (binding->dirname != _nl_default_dirname)
143 free (binding->dirname);
145 binding->dirname = result;
146 modified = 1;
149 *dirnamep = result;
153 if (codesetp)
155 const char *codeset = *codesetp;
157 if (codeset == NULL)
158 /* The current binding has be to returned. */
159 *codesetp = binding->codeset;
160 else
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)
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
177 if (__builtin_expect (result != NULL, 1))
179 free (binding->codeset);
181 binding->codeset = result;
182 modified = 1;
185 *codesetp = result;
189 else if ((dirnamep == NULL || *dirnamep == NULL)
190 && (codesetp == NULL || *codesetp == NULL))
192 /* Simply return the default values. */
193 if (dirnamep)
194 *dirnamep = _nl_default_dirname;
195 if (codesetp)
196 *codesetp = NULL;
198 else
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);
205 if (__builtin_expect (new_binding == NULL, 0))
206 goto failed;
208 memcpy (new_binding->domainname, domainname, len);
210 if (dirnamep)
212 const char *dirname = *dirnamep;
214 if (dirname == NULL)
215 /* The default value. */
216 dirname = _nl_default_dirname;
217 else
219 if (strcmp (dirname, _nl_default_dirname) == 0)
220 dirname = _nl_default_dirname;
221 else
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;
238 *dirnamep = dirname;
239 new_binding->dirname = (char *) dirname;
241 else
242 /* The default value. */
243 new_binding->dirname = (char *) _nl_default_dirname;
245 if (codesetp)
247 const char *codeset = *codesetp;
249 if (codeset != NULL)
251 char *result;
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;
266 *codesetp = codeset;
267 new_binding->codeset = (char *) codeset;
269 else
270 new_binding->codeset = NULL;
272 /* Now enqueue it. */
273 if (_nl_domain_bindings == NULL
274 || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
276 new_binding->next = _nl_domain_bindings;
277 _nl_domain_bindings = new_binding;
279 else
281 binding = _nl_domain_bindings;
282 while (binding->next != NULL
283 && strcmp (domainname, binding->next->domainname) > 0)
284 binding = binding->next;
286 new_binding->next = binding->next;
287 binding->next = new_binding;
290 modified = 1;
292 /* Here we deal with memory allocation failures. */
293 if (0)
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;
308 /* If we modified any binding, we flush the caches. */
309 if (modified)
310 ++_nl_msg_cat_cntr;
312 gl_rwlock_unlock (_nl_state_lock);
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)
320 set_binding_values (domainname, &dirname, NULL);
321 return (char *) dirname;
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)
329 set_binding_values (domainname, NULL, &codeset);
330 return (char *) codeset;
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