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