Home | History | Annotate | Line # | Download | only in intl
      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