Main Page | Class List | Directories | File List | Class Members | File Members

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., 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 /* 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

© sourcejam.com 2005-2008