Home | History | Annotate | Download | only in intl
      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 		      if (binding->codeset != NULL)
    201 			free (binding->codeset);
    202 
    203 		      binding->codeset = result;
    204 		      binding->codeset_cntr++;
    205 		      modified = 1;
    206 		    }
    207 		}
    208 	      *codesetp = result;
    209 	    }
    210 	}
    211     }
    212   else if ((dirnamep == NULL || *dirnamep == NULL)
    213 	   && (codesetp == NULL || *codesetp == NULL))
    214     {
    215       /* Simply return the default values.  */
    216       if (dirnamep)
    217 	*dirnamep = INTUSE(_nl_default_dirname);
    218       if (codesetp)
    219 	*codesetp = NULL;
    220     }
    221   else
    222     {
    223       /* We have to create a new binding.  */
    224       size_t len = strlen (domainname) + 1;
    225       struct binding *new_binding =
    226 	(struct binding *) malloc (offsetof (struct binding, domainname) + len);
    227 
    228       if (__builtin_expect (new_binding == NULL, 0))
    229 	goto failed;
    230 
    231       memcpy (new_binding->domainname, domainname, len);
    232 
    233       if (dirnamep)
    234 	{
    235 	  const char *dirname = *dirnamep;
    236 
    237 	  if (dirname == NULL)
    238 	    /* The default value.  */
    239 	    dirname = INTUSE(_nl_default_dirname);
    240 	  else
    241 	    {
    242 	      if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
    243 		dirname = INTUSE(_nl_default_dirname);
    244 	      else
    245 		{
    246 		  char *result;
    247 #if defined _LIBC || defined HAVE_STRDUP
    248 		  result = strdup (dirname);
    249 		  if (__builtin_expect (result == NULL, 0))
    250 		    goto failed_dirname;
    251 #else
    252 		  size_t len = strlen (dirname) + 1;
    253 		  result = (char *) malloc (len);
    254 		  if (__builtin_expect (result == NULL, 0))
    255 		    goto failed_dirname;
    256 		  memcpy (result, dirname, len);
    257 #endif
    258 		  dirname = result;
    259 		}
    260 	    }
    261 	  *dirnamep = dirname;
    262 	  new_binding->dirname = (char *) dirname;
    263 	}
    264       else
    265 	/* The default value.  */
    266 	new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
    267 
    268       new_binding->codeset_cntr = 0;
    269 
    270       if (codesetp)
    271 	{
    272 	  const char *codeset = *codesetp;
    273 
    274 	  if (codeset != NULL)
    275 	    {
    276 	      char *result;
    277 
    278 #if defined _LIBC || defined HAVE_STRDUP
    279 	      result = strdup (codeset);
    280 	      if (__builtin_expect (result == NULL, 0))
    281 		goto failed_codeset;
    282 #else
    283 	      size_t len = strlen (codeset) + 1;
    284 	      result = (char *) malloc (len);
    285 	      if (__builtin_expect (result == NULL, 0))
    286 		goto failed_codeset;
    287 	      memcpy (result, codeset, len);
    288 #endif
    289 	      codeset = result;
    290 	      new_binding->codeset_cntr++;
    291 	    }
    292 	  *codesetp = codeset;
    293 	  new_binding->codeset = (char *) codeset;
    294 	}
    295       else
    296 	new_binding->codeset = NULL;
    297 
    298       /* Now enqueue it.  */
    299       if (_nl_domain_bindings == NULL
    300 	  || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
    301 	{
    302 	  new_binding->next = _nl_domain_bindings;
    303 	  _nl_domain_bindings = new_binding;
    304 	}
    305       else
    306 	{
    307 	  binding = _nl_domain_bindings;
    308 	  while (binding->next != NULL
    309 		 && strcmp (domainname, binding->next->domainname) > 0)
    310 	    binding = binding->next;
    311 
    312 	  new_binding->next = binding->next;
    313 	  binding->next = new_binding;
    314 	}
    315 
    316       modified = 1;
    317 
    318       /* Here we deal with memory allocation failures.  */
    319       if (0)
    320 	{
    321 	failed_codeset:
    322 	  if (new_binding->dirname != INTUSE(_nl_default_dirname))
    323 	    free (new_binding->dirname);
    324 	failed_dirname:
    325 	  free (new_binding);
    326 	failed:
    327 	  if (dirnamep)
    328 	    *dirnamep = NULL;
    329 	  if (codesetp)
    330 	    *codesetp = NULL;
    331 	}
    332     }
    333 
    334   /* If we modified any binding, we flush the caches.  */
    335   if (modified)
    336     ++_nl_msg_cat_cntr;
    337 
    338   __libc_rwlock_unlock (_nl_state_lock);
    339 }
    340 
    341 /* Specify that the DOMAINNAME message catalog will be found
    342    in DIRNAME rather than in the system locale data base.  */
    343 char *
    344 BINDTEXTDOMAIN (const char *domainname, const char *dirname)
    345 {
    346   set_binding_values (domainname, &dirname, NULL);
    347   return (char *) dirname;
    348 }
    349 
    350 /* Specify the character encoding in which the messages from the
    351    DOMAINNAME message catalog will be returned.  */
    352 char *
    353 BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
    354 {
    355   set_binding_values (domainname, NULL, &codeset);
    356   return (char *) codeset;
    357 }
    358 
    359 #ifdef _LIBC
    360 /* Aliases for function names in GNU C Library.  */
    361 weak_alias (__bindtextdomain, bindtextdomain);
    362 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
    363 #endif
    364