(root)/
glibc-2.38/
wcsmbs/
wcsmbsload.c
       1  /* Copyright (C) 1998-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library 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     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <ctype.h>
      19  #include <langinfo.h>
      20  #include <limits.h>
      21  #include <stdlib.h>
      22  #include <stdio.h>
      23  #include <string.h>
      24  
      25  #include <locale/localeinfo.h>
      26  #include <wcsmbsload.h>
      27  #include <libc-lock.h>
      28  
      29  
      30  /* These are the descriptions for the default conversion functions.  */
      31  static const struct __gconv_step to_wc =
      32  {
      33    .__shlib_handle = NULL,
      34    .__modname = NULL,
      35    .__counter = INT_MAX,
      36    .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
      37    .__to_name = (char *) "INTERNAL",
      38    .__fct = __gconv_transform_ascii_internal,
      39    .__btowc_fct = __gconv_btwoc_ascii,
      40    .__init_fct = NULL,
      41    .__end_fct = NULL,
      42    .__min_needed_from = 1,
      43    .__max_needed_from = 1,
      44    .__min_needed_to = 4,
      45    .__max_needed_to = 4,
      46    .__stateful = 0,
      47    .__data = NULL
      48  };
      49  
      50  static const struct __gconv_step to_mb =
      51  {
      52    .__shlib_handle = NULL,
      53    .__modname = NULL,
      54    .__counter = INT_MAX,
      55    .__from_name = (char *) "INTERNAL",
      56    .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
      57    .__fct = __gconv_transform_internal_ascii,
      58    .__btowc_fct = NULL,
      59    .__init_fct = NULL,
      60    .__end_fct = NULL,
      61    .__min_needed_from = 4,
      62    .__max_needed_from = 4,
      63    .__min_needed_to = 1,
      64    .__max_needed_to = 1,
      65    .__stateful = 0,
      66    .__data = NULL
      67  };
      68  
      69  
      70  /* For the default locale we only have to handle ANSI_X3.4-1968.  */
      71  const struct gconv_fcts __wcsmbs_gconv_fcts_c =
      72  {
      73    .towc = (struct __gconv_step *) &to_wc,
      74    .towc_nsteps = 1,
      75    .tomb = (struct __gconv_step *) &to_mb,
      76    .tomb_nsteps = 1,
      77  };
      78  
      79  
      80  attribute_hidden
      81  struct __gconv_step *
      82  __wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp)
      83  {
      84    size_t nsteps;
      85    struct __gconv_step *result;
      86  #if 0
      87    size_t nstateful;
      88    size_t cnt;
      89  #endif
      90  
      91    if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK)
      92      /* Loading the conversion step is not possible.  */
      93      return NULL;
      94  
      95    /* Maybe it is someday necessary to allow more than one step.
      96       Currently this is not the case since the conversions handled here
      97       are from and to INTERNAL and there always is a converted for
      98       that.  It the directly following code is enabled the libio
      99       functions will have to allocate appropriate __gconv_step_data
     100       elements instead of only one.  */
     101  #if 0
     102    /* Count the number of stateful conversions.  Since we will only
     103       have one 'mbstate_t' object available we can only deal with one
     104       stateful conversion.  */
     105    nstateful = 0;
     106    for (cnt = 0; cnt < nsteps; ++cnt)
     107      if (result[cnt].__stateful)
     108        ++nstateful;
     109    if (nstateful > 1)
     110  #else
     111    if (nsteps > 1)
     112  #endif
     113      {
     114        /* We cannot handle this case.  */
     115        __gconv_close_transform (result, nsteps);
     116        result = NULL;
     117      }
     118    else
     119      *nstepsp = nsteps;
     120  
     121    return result;
     122  }
     123  
     124  
     125  /* Extract from the given locale name the character set portion.  Since
     126     only the XPG form of the name includes this information we don't have
     127     to take care for the CEN form.  */
     128  #define extract_charset_name(str) \
     129    ({									      \
     130      const char *cp = str;						      \
     131      char *result = NULL;						      \
     132  									      \
     133      cp += strcspn (cp, "@.+,");						      \
     134      if (*cp == '.')							      \
     135        {									      \
     136  	const char *endp = ++cp;					      \
     137  	while (*endp != '\0' && *endp != '@')				      \
     138  	  ++endp;							      \
     139  	if (endp != cp)							      \
     140  	  result = strndupa (cp, endp - cp);				      \
     141        }									      \
     142      result;								      \
     143    })
     144  
     145  
     146  /* Some of the functions here must not be used while setlocale is called.  */
     147  __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
     148  
     149  /* Load conversion functions for the currently selected locale.  */
     150  void
     151  __wcsmbs_load_conv (struct __locale_data *new_category)
     152  {
     153    struct lc_ctype_data *data = new_category->private;
     154  
     155    /* Acquire the lock.  */
     156    __libc_rwlock_wrlock (__libc_setlocale_lock);
     157  
     158    /* We should repeat the test since while we waited some other thread
     159       might have run this function.  */
     160    if (__glibc_likely (data->fcts == NULL))
     161      {
     162        /* We must find the real functions.  */
     163        const char *charset_name;
     164        const char *complete_name;
     165        struct gconv_fcts *new_fcts;
     166        int use_translit;
     167  
     168        /* Allocate the gconv_fcts structure.  */
     169        new_fcts = calloc (1, sizeof *new_fcts);
     170        if (new_fcts == NULL)
     171  	goto failed;
     172  
     173        /* Get name of charset of the locale.  */
     174        charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
     175  
     176        /* Does the user want transliteration?  */
     177        use_translit = new_category->use_translit;
     178  
     179        /* Normalize the name and add the slashes necessary for a
     180  	 complete lookup.  */
     181        complete_name = norm_add_slashes (charset_name,
     182  					use_translit ? "TRANSLIT" : "");
     183  
     184        /* It is not necessary to use transliteration in this direction
     185  	 since the internal character set is supposed to be able to
     186  	 represent all others.  */
     187        new_fcts->towc = __wcsmbs_getfct ("INTERNAL", complete_name,
     188  					&new_fcts->towc_nsteps);
     189        if (new_fcts->towc != NULL)
     190  	new_fcts->tomb = __wcsmbs_getfct (complete_name, "INTERNAL",
     191  					  &new_fcts->tomb_nsteps);
     192  
     193        /* If any of the conversion functions is not available we don't
     194  	 use any since this would mean we cannot convert back and
     195  	 forth.  NB: NEW_FCTS was allocated with calloc.  */
     196        if (new_fcts->tomb == NULL)
     197  	{
     198  	  if (new_fcts->towc != NULL)
     199  	    __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps);
     200  
     201  	  free (new_fcts);
     202  
     203  	failed:
     204  	  data->fcts = (void *) &__wcsmbs_gconv_fcts_c;
     205  	}
     206        else
     207  	data->fcts = new_fcts;
     208      }
     209  
     210    __libc_rwlock_unlock (__libc_setlocale_lock);
     211  }
     212  
     213  
     214  /* Clone the current conversion function set.  */
     215  void
     216  __wcsmbs_clone_conv (struct gconv_fcts *copy)
     217  {
     218    const struct gconv_fcts *orig;
     219  
     220    orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
     221  
     222    /* Copy the data.  */
     223    *copy = *orig;
     224  
     225    /* Now increment the usage counters.  Note: This assumes
     226       copy->*_nsteps == 1.  The current locale holds a reference, so it
     227       is still there after acquiring the lock.  */
     228  
     229    __libc_lock_lock (__gconv_lock);
     230  
     231    bool overflow = false;
     232    if (copy->towc->__shlib_handle != NULL)
     233      overflow |= __builtin_add_overflow (copy->towc->__counter, 1,
     234  					&copy->towc->__counter);
     235    if (copy->tomb->__shlib_handle != NULL)
     236      overflow |= __builtin_add_overflow (copy->tomb->__counter, 1,
     237  					&copy->tomb->__counter);
     238  
     239    __libc_lock_unlock (__gconv_lock);
     240  
     241    if (overflow)
     242      __libc_fatal ("\
     243  Fatal glibc error: gconv module reference counter overflow\n");
     244  }
     245  
     246  
     247  /* Get converters for named charset.  */
     248  int
     249  __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
     250  {
     251    copy->towc = __wcsmbs_getfct ("INTERNAL", name, &copy->towc_nsteps);
     252    if (copy->towc == NULL)
     253      return 1;
     254  
     255    copy->tomb = __wcsmbs_getfct (name, "INTERNAL", &copy->tomb_nsteps);
     256    if (copy->tomb == NULL)
     257      {
     258        __gconv_close_transform (copy->towc, copy->towc_nsteps);
     259        return 1;
     260      }
     261  
     262    return 0;
     263  }
     264  
     265  void
     266  _nl_cleanup_ctype (struct __locale_data *locale)
     267  {
     268    struct lc_ctype_data *data = locale->private;
     269    if (data->fcts != NULL && data->fcts != &__wcsmbs_gconv_fcts_c)
     270      {
     271        /* Free the old conversions.  */
     272        __gconv_close_transform (data->fcts->tomb, data->fcts->tomb_nsteps);
     273        __gconv_close_transform (data->fcts->towc, data->fcts->towc_nsteps);
     274  
     275        free ((void *) data->fcts);
     276        data->fcts = NULL;
     277        /* data itself is allocated within locale.  */
     278      }
     279  }