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 363