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