Back to index

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