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