Home | History | Annotate | Download | only in intl
      1 /* Implementation of the bindtextdomain(3) function
      2    Copyright (C) 1995-1998, 2000, 2001, 2002 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
     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 /* Prototypes for local functions.  */
     90 static void set_binding_values PARAMS ((const char *domainname,
     91 					const char **dirnamep,
     92 					const char **codesetp));
     93 
     94 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
     95    to be used for the DOMAINNAME message catalog.
     96    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
     97    modified, only the current value is returned.
     98    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
     99    modified nor returned.  */
    100 static void
    101 set_binding_values (domainname, dirnamep, codesetp)
    102      const char *domainname;
    103      const char **dirnamep;
    104      const char **codesetp;
    105 {
    106   struct binding *binding;
    107   int modified;
    108 
    109   /* Some sanity checks.  */
    110   if (domainname == NULL || domainname[0] == '\0')
    111     {
    112       if (dirnamep)
    113 	*dirnamep = NULL;
    114       if (codesetp)
    115 	*codesetp = NULL;
    116       return;
    117     }
    118 
    119   __libc_rwlock_wrlock (_nl_state_lock);
    120 
    121   modified = 0;
    122 
    123   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
    124     {
    125       int compare = strcmp (domainname, binding->domainname);
    126       if (compare == 0)
    127 	/* We found it!  */
    128 	break;
    129       if (compare < 0)
    130 	{
    131 	  /* It is not in the list.  */
    132 	  binding = NULL;
    133 	  break;
    134 	}
    135     }
    136 
    137   if (binding != NULL)
    138     {
    139       if (dirnamep)
    140 	{
    141 	  const char *dirname = *dirnamep;
    142 
    143 	  if (dirname == NULL)
    144 	    /* The current binding has be to returned.  */
    145 	    *dirnamep = binding->dirname;
    146 	  else
    147 	    {
    148 	      /* The domain is already bound.  If the new value and the old
    149 		 one are equal we simply do nothing.  Otherwise replace the
    150 		 old binding.  */
    151 	      char *result = binding->dirname;
    152 	      if (strcmp (dirname, result) != 0)
    153 		{
    154 		  if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
    155 		    result = (char *) INTUSE(_nl_default_dirname);
    156 		  else
    157 		    {
    158 #if defined _LIBC || defined HAVE_STRDUP
    159 		      result = strdup (dirname);
    160 #else
    161 		      size_t len = strlen (dirname) + 1;
    162 		      result = (char *) malloc (len);
    163 		      if (__builtin_expect (result != NULL, 1))
    164 			memcpy (result, dirname, len);
    165 #endif
    166 		    }
    167 
    168 		  if (__builtin_expect (result != NULL, 1))
    169 		    {
    170 		      if (binding->dirname != INTUSE(_nl_default_dirname))
    171 			free (binding->dirname);
    172 
    173 		      binding->dirname = result;
    174 		      modified = 1;
    175 		    }
    176 		}
    177 	      *dirnamep = result;
    178 	    }
    179 	}
    180 
    181       if (codesetp)
    182 	{
    183 	  const char *codeset = *codesetp;
    184 
    185 	  if (codeset == NULL)
    186 	    /* The current binding has be to returned.  */
    187 	    *codesetp = binding->codeset;
    188 	  else
    189 	    {
    190 	      /* The domain is already bound.  If the new value and the old
    191 		 one are equal we simply do nothing.  Otherwise replace the
    192 		 old binding.  */
    193 	      char *result = binding->codeset;
    194 	      if (result == NULL || strcmp (codeset, result) != 0)
    195 		{
    196 #if defined _LIBC || defined HAVE_STRDUP
    197 		  result = strdup (codeset);
    198 #else
    199 		  size_t len = strlen (codeset) + 1;
    200 		  result = (char *) malloc (len);
    201 		  if (__builtin_expect (result != NULL, 1))
    202 		    memcpy (result, codeset, len);
    203 #endif
    204 
    205 		  if (__builtin_expect (result != NULL, 1))
    206 		    {
    207 		      if (binding->codeset != NULL)
    208 			free (binding->codeset);
    209 
    210 		      binding->codeset = result;
    211 		      binding->codeset_cntr++;
    212 		      modified = 1;
    213 		    }
    214 		}
    215 	      *codesetp = result;
    216 	    }
    217 	}
    218     }
    219   else if ((dirnamep == NULL || *dirnamep == NULL)
    220 	   && (codesetp == NULL || *codesetp == NULL))
    221     {
    222       /* Simply return the default values.  */
    223       if (dirnamep)
    224 	*dirnamep = INTUSE(_nl_default_dirname);
    225       if (codesetp)
    226 	*codesetp = NULL;
    227     }
    228   else
    229     {
    230       /* We have to create a new binding.  */
    231       size_t len = strlen (domainname) + 1;
    232       struct binding *new_binding =
    233 	(struct binding *) malloc (offsetof (struct binding, domainname) + len);
    234 
    235       if (__builtin_expect (new_binding == NULL, 0))
    236 	goto failed;
    237 
    238       memcpy (new_binding->domainname, domainname, len);
    239 
    240       if (dirnamep)
    241 	{
    242 	  const char *dirname = *dirnamep;
    243 
    244 	  if (dirname == NULL)
    245 	    /* The default value.  */
    246 	    dirname = INTUSE(_nl_default_dirname);
    247 	  else
    248 	    {
    249 	      if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
    250 		dirname = INTUSE(_nl_default_dirname);
    251 	      else
    252 		{
    253 		  char *result;
    254 #if defined _LIBC || defined HAVE_STRDUP
    255 		  result = strdup (dirname);
    256 		  if (__builtin_expect (result == NULL, 0))
    257 		    goto failed_dirname;
    258 #else
    259 		  size_t len = strlen (dirname) + 1;
    260 		  result = (char *) malloc (len);
    261 		  if (__builtin_expect (result == NULL, 0))
    262 		    goto failed_dirname;
    263 		  memcpy (result, dirname, len);
    264 #endif
    265 		  dirname = result;
    266 		}
    267 	    }
    268 	  *dirnamep = dirname;
    269 	  new_binding->dirname = (char *) dirname;
    270 	}
    271       else
    272 	/* The default value.  */
    273 	new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
    274 
    275       new_binding->codeset_cntr = 0;
    276 
    277       if (codesetp)
    278 	{
    279 	  const char *codeset = *codesetp;
    280 
    281 	  if (codeset != NULL)
    282 	    {
    283 	      char *result;
    284 
    285 #if defined _LIBC || defined HAVE_STRDUP
    286 	      result = strdup (codeset);
    287 	      if (__builtin_expect (result == NULL, 0))
    288 		goto failed_codeset;
    289 #else
    290 	      size_t len = strlen (codeset) + 1;
    291 	      result = (char *) malloc (len);
    292 	      if (__builtin_expect (result == NULL, 0))
    293 		goto failed_codeset;
    294 	      memcpy (result, codeset, len);
    295 #endif
    296 	      codeset = result;
    297 	      new_binding->codeset_cntr++;
    298 	    }
    299 	  *codesetp = codeset;
    300 	  new_binding->codeset = (char *) codeset;
    301 	}
    302       else
    303 	new_binding->codeset = NULL;
    304 
    305       /* Now enqueue it.  */
    306       if (_nl_domain_bindings == NULL
    307 	  || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
    308 	{
    309 	  new_binding->next = _nl_domain_bindings;
    310 	  _nl_domain_bindings = new_binding;
    311 	}
    312       else
    313 	{
    314 	  binding = _nl_domain_bindings;
    315 	  while (binding->next != NULL
    316 		 && strcmp (domainname, binding->next->domainname) > 0)
    317 	    binding = binding->next;
    318 
    319 	  new_binding->next = binding->next;
    320 	  binding->next = new_binding;
    321 	}
    322 
    323       modified = 1;
    324 
    325       /* Here we deal with memory allocation failures.  */
    326       if (0)
    327 	{
    328 	failed_codeset:
    329 	  if (new_binding->dirname != INTUSE(_nl_default_dirname))
    330 	    free (new_binding->dirname);
    331 	failed_dirname:
    332 	  free (new_binding);
    333 	failed:
    334 	  if (dirnamep)
    335 	    *dirnamep = NULL;
    336 	  if (codesetp)
    337 	    *codesetp = NULL;
    338 	}
    339     }
    340 
    341   /* If we modified any binding, we flush the caches.  */
    342   if (modified)
    343     ++_nl_msg_cat_cntr;
    344 
    345   __libc_rwlock_unlock (_nl_state_lock);
    346 }
    347 
    348 /* Specify that the DOMAINNAME message catalog will be found
    349    in DIRNAME rather than in the system locale data base.  */
    350 char *
    351 BINDTEXTDOMAIN (domainname, dirname)
    352      const char *domainname;
    353      const char *dirname;
    354 {
    355   set_binding_values (domainname, &dirname, NULL);
    356   return (char *) dirname;
    357 }
    358 
    359 /* Specify the character encoding in which the messages from the
    360    DOMAINNAME message catalog will be returned.  */
    361 char *
    362 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
    363      const char *domainname;
    364      const char *codeset;
    365 {
    366   set_binding_values (domainname, NULL, &codeset);
    367   return (char *) codeset;
    368 }
    369 
    370 #ifdef _LIBC
    371 /* Aliases for function names in GNU C Library.  */
    372 weak_alias (__bindtextdomain, bindtextdomain);
    373 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
    374 #endif
    375