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