Back to index

cell-binutils  2.17cvs20070401
bindtextdom.c
Go to the documentation of this file.
00001 /* Implementation of the bindtextdomain(3) function
00002    Copyright (C) 1995-1998, 2000, 2001, 2002 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
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 /* Prototypes for local functions.  */
00090 static void set_binding_values PARAMS ((const char *domainname,
00091                                    const char **dirnamep,
00092                                    const char **codesetp));
00093 
00094 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
00095    to be used for the DOMAINNAME message catalog.
00096    If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
00097    modified, only the current value is returned.
00098    If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
00099    modified nor returned.  */
00100 static void
00101 set_binding_values (domainname, dirnamep, codesetp)
00102      const char *domainname;
00103      const char **dirnamep;
00104      const char **codesetp;
00105 {
00106   struct binding *binding;
00107   int modified;
00108 
00109   /* Some sanity checks.  */
00110   if (domainname == NULL || domainname[0] == '\0')
00111     {
00112       if (dirnamep)
00113        *dirnamep = NULL;
00114       if (codesetp)
00115        *codesetp = NULL;
00116       return;
00117     }
00118 
00119   __libc_rwlock_wrlock (_nl_state_lock);
00120 
00121   modified = 0;
00122 
00123   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
00124     {
00125       int compare = strcmp (domainname, binding->domainname);
00126       if (compare == 0)
00127        /* We found it!  */
00128        break;
00129       if (compare < 0)
00130        {
00131          /* It is not in the list.  */
00132          binding = NULL;
00133          break;
00134        }
00135     }
00136 
00137   if (binding != NULL)
00138     {
00139       if (dirnamep)
00140        {
00141          const char *dirname = *dirnamep;
00142 
00143          if (dirname == NULL)
00144            /* The current binding has be to returned.  */
00145            *dirnamep = binding->dirname;
00146          else
00147            {
00148              /* The domain is already bound.  If the new value and the old
00149                one are equal we simply do nothing.  Otherwise replace the
00150                old binding.  */
00151              char *result = binding->dirname;
00152              if (strcmp (dirname, result) != 0)
00153               {
00154                 if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
00155                   result = (char *) INTUSE(_nl_default_dirname);
00156                 else
00157                   {
00158 #if defined _LIBC || defined HAVE_STRDUP
00159                     result = strdup (dirname);
00160 #else
00161                     size_t len = strlen (dirname) + 1;
00162                     result = (char *) malloc (len);
00163                     if (__builtin_expect (result != NULL, 1))
00164                      memcpy (result, dirname, len);
00165 #endif
00166                   }
00167 
00168                 if (__builtin_expect (result != NULL, 1))
00169                   {
00170                     if (binding->dirname != INTUSE(_nl_default_dirname))
00171                      free (binding->dirname);
00172 
00173                     binding->dirname = result;
00174                     modified = 1;
00175                   }
00176               }
00177              *dirnamep = result;
00178            }
00179        }
00180 
00181       if (codesetp)
00182        {
00183          const char *codeset = *codesetp;
00184 
00185          if (codeset == NULL)
00186            /* The current binding has be to returned.  */
00187            *codesetp = binding->codeset;
00188          else
00189            {
00190              /* The domain is already bound.  If the new value and the old
00191                one are equal we simply do nothing.  Otherwise replace the
00192                old binding.  */
00193              char *result = binding->codeset;
00194              if (result == NULL || strcmp (codeset, result) != 0)
00195               {
00196 #if defined _LIBC || defined HAVE_STRDUP
00197                 result = strdup (codeset);
00198 #else
00199                 size_t len = strlen (codeset) + 1;
00200                 result = (char *) malloc (len);
00201                 if (__builtin_expect (result != NULL, 1))
00202                   memcpy (result, codeset, len);
00203 #endif
00204 
00205                 if (__builtin_expect (result != NULL, 1))
00206                   {
00207                     if (binding->codeset != NULL)
00208                      free (binding->codeset);
00209 
00210                     binding->codeset = result;
00211                     binding->codeset_cntr++;
00212                     modified = 1;
00213                   }
00214               }
00215              *codesetp = result;
00216            }
00217        }
00218     }
00219   else if ((dirnamep == NULL || *dirnamep == NULL)
00220           && (codesetp == NULL || *codesetp == NULL))
00221     {
00222       /* Simply return the default values.  */
00223       if (dirnamep)
00224        *dirnamep = INTUSE(_nl_default_dirname);
00225       if (codesetp)
00226        *codesetp = NULL;
00227     }
00228   else
00229     {
00230       /* We have to create a new binding.  */
00231       size_t len = strlen (domainname) + 1;
00232       struct binding *new_binding =
00233        (struct binding *) malloc (offsetof (struct binding, domainname) + len);
00234 
00235       if (__builtin_expect (new_binding == NULL, 0))
00236        goto failed;
00237 
00238       memcpy (new_binding->domainname, domainname, len);
00239 
00240       if (dirnamep)
00241        {
00242          const char *dirname = *dirnamep;
00243 
00244          if (dirname == NULL)
00245            /* The default value.  */
00246            dirname = INTUSE(_nl_default_dirname);
00247          else
00248            {
00249              if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
00250               dirname = INTUSE(_nl_default_dirname);
00251              else
00252               {
00253                 char *result;
00254 #if defined _LIBC || defined HAVE_STRDUP
00255                 result = strdup (dirname);
00256                 if (__builtin_expect (result == NULL, 0))
00257                   goto failed_dirname;
00258 #else
00259                 size_t len = strlen (dirname) + 1;
00260                 result = (char *) malloc (len);
00261                 if (__builtin_expect (result == NULL, 0))
00262                   goto failed_dirname;
00263                 memcpy (result, dirname, len);
00264 #endif
00265                 dirname = result;
00266               }
00267            }
00268          *dirnamep = dirname;
00269          new_binding->dirname = (char *) dirname;
00270        }
00271       else
00272        /* The default value.  */
00273        new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
00274 
00275       new_binding->codeset_cntr = 0;
00276 
00277       if (codesetp)
00278        {
00279          const char *codeset = *codesetp;
00280 
00281          if (codeset != NULL)
00282            {
00283              char *result;
00284 
00285 #if defined _LIBC || defined HAVE_STRDUP
00286              result = strdup (codeset);
00287              if (__builtin_expect (result == NULL, 0))
00288               goto failed_codeset;
00289 #else
00290              size_t len = strlen (codeset) + 1;
00291              result = (char *) malloc (len);
00292              if (__builtin_expect (result == NULL, 0))
00293               goto failed_codeset;
00294              memcpy (result, codeset, len);
00295 #endif
00296              codeset = result;
00297              new_binding->codeset_cntr++;
00298            }
00299          *codesetp = codeset;
00300          new_binding->codeset = (char *) codeset;
00301        }
00302       else
00303        new_binding->codeset = NULL;
00304 
00305       /* Now enqueue it.  */
00306       if (_nl_domain_bindings == NULL
00307          || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
00308        {
00309          new_binding->next = _nl_domain_bindings;
00310          _nl_domain_bindings = new_binding;
00311        }
00312       else
00313        {
00314          binding = _nl_domain_bindings;
00315          while (binding->next != NULL
00316                && strcmp (domainname, binding->next->domainname) > 0)
00317            binding = binding->next;
00318 
00319          new_binding->next = binding->next;
00320          binding->next = new_binding;
00321        }
00322 
00323       modified = 1;
00324 
00325       /* Here we deal with memory allocation failures.  */
00326       if (0)
00327        {
00328        failed_codeset:
00329          if (new_binding->dirname != INTUSE(_nl_default_dirname))
00330            free (new_binding->dirname);
00331        failed_dirname:
00332          free (new_binding);
00333        failed:
00334          if (dirnamep)
00335            *dirnamep = NULL;
00336          if (codesetp)
00337            *codesetp = NULL;
00338        }
00339     }
00340 
00341   /* If we modified any binding, we flush the caches.  */
00342   if (modified)
00343     ++_nl_msg_cat_cntr;
00344 
00345   __libc_rwlock_unlock (_nl_state_lock);
00346 }
00347 
00348 /* Specify that the DOMAINNAME message catalog will be found
00349    in DIRNAME rather than in the system locale data base.  */
00350 char *
00351 BINDTEXTDOMAIN (domainname, dirname)
00352      const char *domainname;
00353      const char *dirname;
00354 {
00355   set_binding_values (domainname, &dirname, NULL);
00356   return (char *) dirname;
00357 }
00358 
00359 /* Specify the character encoding in which the messages from the
00360    DOMAINNAME message catalog will be returned.  */
00361 char *
00362 BIND_TEXTDOMAIN_CODESET (domainname, codeset)
00363      const char *domainname;
00364      const char *codeset;
00365 {
00366   set_binding_values (domainname, NULL, &codeset);
00367   return (char *) codeset;
00368 }
00369 
00370 #ifdef _LIBC
00371 /* Aliases for function names in GNU C Library.  */
00372 weak_alias (__bindtextdomain, bindtextdomain);
00373 weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
00374 #endif