(root)/
gcc-13.2.0/
intl/
bindtextdom.c
       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