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