Back to index

courier  0.68.2
bindtextdom.c
Go to the documentation of this file.
00001 /* Implementation of the bindtextdomain(3) function
00002    Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008 Free Software
00003    Foundation, Inc.
00004 
00005    This program is free software; you can redistribute it and/or modify it
00006    under the terms of the GNU Library General Public License as published
00007    by the Free Software Foundation; either version 2, or (at your option)
00008    any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this program; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00018    USA.  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023 
00024 #include <stddef.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 
00028 #include "gettextP.h"
00029 #ifdef _LIBC
00030 # include <libintl.h>
00031 #else
00032 # include "libgnuintl.h"
00033 #endif
00034 
00035 /* Handle multi-threaded applications.  */
00036 #ifdef _LIBC
00037 # include <bits/libc-lock.h>
00038 # define gl_rwlock_define __libc_rwlock_define
00039 # define gl_rwlock_wrlock __libc_rwlock_wrlock
00040 # define gl_rwlock_unlock __libc_rwlock_unlock
00041 #else
00042 # include "lock.h"
00043 #endif
00044 
00045 /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
00046 #ifndef offsetof
00047 # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
00048 #endif
00049 
00050 /* @@ end of prolog @@ */
00051 
00052 /* Lock variable to protect the global data in the gettext implementation.  */
00053 gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
00054 
00055 
00056 /* Names for the libintl functions are a problem.  They must not clash
00057    with existing names and they should follow ANSI C.  But this source
00058    code is also used in GNU C Library where the names have a __
00059    prefix.  So we have to make a difference here.  */
00060 #ifdef _LIBC
00061 # define BINDTEXTDOMAIN __bindtextdomain
00062 # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
00063 # ifndef strdup
00064 #  define strdup(str) __strdup (str)
00065 # endif
00066 #else
00067 # define BINDTEXTDOMAIN libintl_bindtextdomain
00068 # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
00069 #endif
00070 
00071 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
00072    to be used for the DOMAINNAME message catalog.
00073    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
00074    modified, only the current value is returned.
00075    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
00076    modified nor returned.  */
00077 static void
00078 set_binding_values (const char *domainname,
00079                   const char **dirnamep, const char **codesetp)
00080 {
00081   struct binding *binding;
00082   int modified;
00083 
00084   /* Some sanity checks.  */
00085   if (domainname == NULL || domainname[0] == '\0')
00086     {
00087       if (dirnamep)
00088        *dirnamep = NULL;
00089       if (codesetp)
00090        *codesetp = NULL;
00091       return;
00092     }
00093 
00094   gl_rwlock_wrlock (_nl_state_lock);
00095 
00096   modified = 0;
00097 
00098   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
00099     {
00100       int compare = strcmp (domainname, binding->domainname);
00101       if (compare == 0)
00102        /* We found it!  */
00103        break;
00104       if (compare < 0)
00105        {
00106          /* It is not in the list.  */
00107          binding = NULL;
00108          break;
00109        }
00110     }
00111 
00112   if (binding != NULL)
00113     {
00114       if (dirnamep)
00115        {
00116          const char *dirname = *dirnamep;
00117 
00118          if (dirname == NULL)
00119            /* The current binding has be to returned.  */
00120            *dirnamep = binding->dirname;
00121          else
00122            {
00123              /* The domain is already bound.  If the new value and the old
00124                one are equal we simply do nothing.  Otherwise replace the
00125                old binding.  */
00126              char *result = binding->dirname;
00127              if (strcmp (dirname, result) != 0)
00128               {
00129                 if (strcmp (dirname, _nl_default_dirname) == 0)
00130                   result = (char *) _nl_default_dirname;
00131                 else
00132                   {
00133 #if defined _LIBC || defined HAVE_STRDUP
00134                     result = strdup (dirname);
00135 #else
00136                     size_t len = strlen (dirname) + 1;
00137                     result = (char *) malloc (len);
00138                     if (__builtin_expect (result != NULL, 1))
00139                      memcpy (result, dirname, len);
00140 #endif
00141                   }
00142 
00143                 if (__builtin_expect (result != NULL, 1))
00144                   {
00145                     if (binding->dirname != _nl_default_dirname)
00146                      free (binding->dirname);
00147 
00148                     binding->dirname = result;
00149                     modified = 1;
00150                   }
00151               }
00152              *dirnamep = result;
00153            }
00154        }
00155 
00156       if (codesetp)
00157        {
00158          const char *codeset = *codesetp;
00159 
00160          if (codeset == NULL)
00161            /* The current binding has be to returned.  */
00162            *codesetp = binding->codeset;
00163          else
00164            {
00165              /* The domain is already bound.  If the new value and the old
00166                one are equal we simply do nothing.  Otherwise replace the
00167                old binding.  */
00168              char *result = binding->codeset;
00169              if (result == NULL || strcmp (codeset, result) != 0)
00170               {
00171 #if defined _LIBC || defined HAVE_STRDUP
00172                 result = strdup (codeset);
00173 #else
00174                 size_t len = strlen (codeset) + 1;
00175                 result = (char *) malloc (len);
00176                 if (__builtin_expect (result != NULL, 1))
00177                   memcpy (result, codeset, len);
00178 #endif
00179 
00180                 if (__builtin_expect (result != NULL, 1))
00181                   {
00182                     free (binding->codeset);
00183 
00184                     binding->codeset = result;
00185                     modified = 1;
00186                   }
00187               }
00188              *codesetp = result;
00189            }
00190        }
00191     }
00192   else if ((dirnamep == NULL || *dirnamep == NULL)
00193           && (codesetp == NULL || *codesetp == NULL))
00194     {
00195       /* Simply return the default values.  */
00196       if (dirnamep)
00197        *dirnamep = _nl_default_dirname;
00198       if (codesetp)
00199        *codesetp = NULL;
00200     }
00201   else
00202     {
00203       /* We have to create a new binding.  */
00204       size_t len = strlen (domainname) + 1;
00205       struct binding *new_binding =
00206        (struct binding *) malloc (offsetof (struct binding, domainname) + len);
00207 
00208       if (__builtin_expect (new_binding == NULL, 0))
00209        goto failed;
00210 
00211       memcpy (new_binding->domainname, domainname, len);
00212 
00213       if (dirnamep)
00214        {
00215          const char *dirname = *dirnamep;
00216 
00217          if (dirname == NULL)
00218            /* The default value.  */
00219            dirname = _nl_default_dirname;
00220          else
00221            {
00222              if (strcmp (dirname, _nl_default_dirname) == 0)
00223               dirname = _nl_default_dirname;
00224              else
00225               {
00226                 char *result;
00227 #if defined _LIBC || defined HAVE_STRDUP
00228                 result = strdup (dirname);
00229                 if (__builtin_expect (result == NULL, 0))
00230                   goto failed_dirname;
00231 #else
00232                 size_t len = strlen (dirname) + 1;
00233                 result = (char *) malloc (len);
00234                 if (__builtin_expect (result == NULL, 0))
00235                   goto failed_dirname;
00236                 memcpy (result, dirname, len);
00237 #endif
00238                 dirname = result;
00239               }
00240            }
00241          *dirnamep = dirname;
00242          new_binding->dirname = (char *) dirname;
00243        }
00244       else
00245        /* The default value.  */
00246        new_binding->dirname = (char *) _nl_default_dirname;
00247 
00248       if (codesetp)
00249        {
00250          const char *codeset = *codesetp;
00251 
00252          if (codeset != NULL)
00253            {
00254              char *result;
00255 
00256 #if defined _LIBC || defined HAVE_STRDUP
00257              result = strdup (codeset);
00258              if (__builtin_expect (result == NULL, 0))
00259               goto failed_codeset;
00260 #else
00261              size_t len = strlen (codeset) + 1;
00262              result = (char *) malloc (len);
00263              if (__builtin_expect (result == NULL, 0))
00264               goto failed_codeset;
00265              memcpy (result, codeset, len);
00266 #endif
00267              codeset = result;
00268            }
00269          *codesetp = codeset;
00270          new_binding->codeset = (char *) codeset;
00271        }
00272       else
00273        new_binding->codeset = NULL;
00274 
00275       /* Now enqueue it.  */
00276       if (_nl_domain_bindings == NULL
00277          || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
00278        {
00279          new_binding->next = _nl_domain_bindings;
00280          _nl_domain_bindings = new_binding;
00281        }
00282       else
00283        {
00284          binding = _nl_domain_bindings;
00285          while (binding->next != NULL
00286                && strcmp (domainname, binding->next->domainname) > 0)
00287            binding = binding->next;
00288 
00289          new_binding->next = binding->next;
00290          binding->next = new_binding;
00291        }
00292 
00293       modified = 1;
00294 
00295       /* Here we deal with memory allocation failures.  */
00296       if (0)
00297        {
00298        failed_codeset:
00299          if (new_binding->dirname != _nl_default_dirname)
00300            free (new_binding->dirname);
00301        failed_dirname:
00302          free (new_binding);
00303        failed:
00304          if (dirnamep)
00305            *dirnamep = NULL;
00306          if (codesetp)
00307            *codesetp = NULL;
00308        }
00309     }
00310 
00311   /* If we modified any binding, we flush the caches.  */
00312   if (modified)
00313     ++_nl_msg_cat_cntr;
00314 
00315   gl_rwlock_unlock (_nl_state_lock);
00316 }
00317 
00318 /* Specify that the DOMAINNAME message catalog will be found
00319    in DIRNAME rather than in the system locale data base.  */
00320 char *
00321 BINDTEXTDOMAIN (const char *domainname, const char *dirname)
00322 {
00323   set_binding_values (domainname, &dirname, NULL);
00324   return (char *) dirname;
00325 }
00326 
00327 /* Specify the character encoding in which the messages from the
00328    DOMAINNAME message catalog will be returned.  */
00329 char *
00330 BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
00331 {
00332   set_binding_values (domainname, NULL, &codeset);
00333   return (char *) codeset;
00334 }
00335 
00336 #ifdef _LIBC
00337 /* Aliases for function names in GNU C Library.  */
00338 weak_alias (__bindtextdomain, bindtextdomain);
00339 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
00340 #endif