(root)/
glibc-2.38/
iconv/
gconv_open.c
       1  /* Find matching transformation algorithms and initialize steps.
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <locale.h>
      21  #include "../locale/localeinfo.h"
      22  #include <stdlib.h>
      23  #include <string.h>
      24  
      25  #include <gconv_int.h>
      26  
      27  
      28  /* How many character should be converted in one call?  */
      29  #define GCONV_NCHAR_GOAL	8160
      30  
      31  
      32  int
      33  __gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle,
      34  	      int flags)
      35  {
      36    struct __gconv_step *steps;
      37    size_t nsteps;
      38    __gconv_t result = NULL;
      39    size_t cnt = 0;
      40    int res;
      41    int conv_flags = 0;
      42    bool translit = false;
      43    char *tocode, *fromcode;
      44  
      45    /* Find out whether any error handling method is specified.  */
      46    translit = conv_spec->translit;
      47  
      48    if (conv_spec->ignore)
      49      conv_flags |= __GCONV_IGNORE_ERRORS;
      50  
      51    tocode = conv_spec->tocode;
      52    fromcode = conv_spec->fromcode;
      53  
      54    /* If the string is empty define this to mean the charset of the
      55       currently selected locale.  */
      56    if (strcmp (tocode, "//") == 0)
      57      {
      58        const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
      59        size_t len = strlen (codeset);
      60        char *dest;
      61        tocode = dest = (char *) alloca (len + 3);
      62        memcpy (__mempcpy (dest, codeset, len), "//", 3);
      63      }
      64    if (strcmp (fromcode, "//") == 0)
      65      {
      66        const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
      67        size_t len = strlen (codeset);
      68        char *dest;
      69        fromcode = dest = (char *) alloca (len + 3);
      70        memcpy (__mempcpy (dest, codeset, len), "//", 3);
      71      }
      72  
      73    res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags);
      74    if (res == __GCONV_OK)
      75      {
      76        /* Allocate room for handle.  */
      77        result = (__gconv_t) malloc (sizeof (struct __gconv_info)
      78  				   + (nsteps
      79  				      * sizeof (struct __gconv_step_data)));
      80        if (result == NULL)
      81  	res = __GCONV_NOMEM;
      82        else
      83  	{
      84  	  /* Remember the list of steps.  */
      85  	  result->__steps = steps;
      86  	  result->__nsteps = nsteps;
      87  
      88  	  /* Clear the array for the step data.  */
      89  	  memset (result->__data, '\0',
      90  		  nsteps * sizeof (struct __gconv_step_data));
      91  
      92  	  /* Call all initialization functions for the transformation
      93  	     step implementations.  */
      94  	  for (cnt = 0; cnt < nsteps; ++cnt)
      95  	    {
      96  	      size_t size;
      97  
      98  	      /* Would have to be done if we would not clear the whole
      99                   array above.  */
     100  #if 0
     101  	      /* Reset the counter.  */
     102  	      result->__data[cnt].__invocation_counter = 0;
     103  
     104  	      /* It's a regular use.  */
     105  	      result->__data[cnt].__internal_use = 0;
     106  #endif
     107  
     108  	      /* We use the `mbstate_t' member in DATA.  */
     109  	      result->__data[cnt].__statep = &result->__data[cnt].__state;
     110  
     111  	      /* The builtin transliteration handling only
     112  		 supports the internal encoding.  */
     113  	      if (translit
     114  		  && __strcasecmp_l (steps[cnt].__from_name,
     115  				     "INTERNAL", _nl_C_locobj_ptr) == 0)
     116  		conv_flags |= __GCONV_TRANSLIT;
     117  
     118  	      /* If this is the last step we must not allocate an
     119  		 output buffer.  */
     120  	      if (cnt < nsteps - 1)
     121  		{
     122  		  result->__data[cnt].__flags = conv_flags;
     123  
     124  		  /* Allocate the buffer.  */
     125  		  size = (GCONV_NCHAR_GOAL * steps[cnt].__max_needed_to);
     126  
     127  		  result->__data[cnt].__outbuf = malloc (size);
     128  		  if (result->__data[cnt].__outbuf == NULL)
     129  		    {
     130  		      res = __GCONV_NOMEM;
     131  		      goto bail;
     132  		    }
     133  
     134  		  result->__data[cnt].__outbufend =
     135  		    result->__data[cnt].__outbuf + size;
     136  		}
     137  	      else
     138  		{
     139  		  /* Handle the last entry.  */
     140  		  result->__data[cnt].__flags = conv_flags | __GCONV_IS_LAST;
     141  
     142  		  break;
     143  		}
     144  	    }
     145  	}
     146  
     147        if (res != __GCONV_OK)
     148  	{
     149  	  /* Something went wrong.  Free all the resources.  */
     150  	  int serrno;
     151  	bail:
     152  	  serrno = errno;
     153  
     154  	  if (result != NULL)
     155  	    {
     156  	      while (cnt-- > 0)
     157  		free (result->__data[cnt].__outbuf);
     158  
     159  	      free (result);
     160  	      result = NULL;
     161  	    }
     162  
     163  	  __gconv_close_transform (steps, nsteps);
     164  
     165  	  __set_errno (serrno);
     166  	}
     167      }
     168  
     169    *handle = result;
     170    return res;
     171  }
     172  libc_hidden_def (__gconv_open)