(root)/
glibc-2.38/
libio/
iofwide.c
       1  /* Copyright (C) 1999-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     As a special exception, if you link the code in this file with
      19     files compiled with a GNU compiler to produce an executable,
      20     that does not cause the resulting executable to be covered by
      21     the GNU Lesser General Public License.  This exception does not
      22     however invalidate any other reasons why the executable file
      23     might be covered by the GNU Lesser General Public License.
      24     This exception applies to code released by its copyright holders
      25     in files containing the exception.  */
      26  
      27  #include <libioP.h>
      28  #include <dlfcn.h>
      29  #include <wchar.h>
      30  #include <assert.h>
      31  #include <stdlib.h>
      32  #include <string.h>
      33  
      34  #include <langinfo.h>
      35  #include <locale/localeinfo.h>
      36  #include <wcsmbs/wcsmbsload.h>
      37  #include <iconv/gconv_int.h>
      38  #include <shlib-compat.h>
      39  #include <pointer_guard.h>
      40  
      41  
      42  /* Return orientation of stream.  If mode is nonzero try to change
      43     the orientation first.  */
      44  #undef _IO_fwide
      45  int
      46  _IO_fwide (FILE *fp, int mode)
      47  {
      48    /* Normalize the value.  */
      49    mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);
      50  
      51  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
      52    if (__glibc_unlikely (&_IO_stdin_used == NULL) && _IO_legacy_file (fp))
      53      /* This is for a stream in the glibc 2.0 format.  */
      54      return -1;
      55  #endif
      56  
      57    /* The orientation already has been determined.  */
      58    if (fp->_mode != 0
      59        /* Or the caller simply wants to know about the current orientation.  */
      60        || mode == 0)
      61      return fp->_mode;
      62  
      63    /* Set the orientation appropriately.  */
      64    if (mode > 0)
      65      {
      66        struct _IO_codecvt *cc = fp->_codecvt = &fp->_wide_data->_codecvt;
      67  
      68        fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
      69        fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
      70  
      71        /* Get the character conversion functions based on the currently
      72  	 selected locale for LC_CTYPE.  */
      73        {
      74  	/* Clear the state.  We start all over again.  */
      75  	memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
      76  	memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
      77  
      78  	struct gconv_fcts fcts;
      79  	__wcsmbs_clone_conv (&fcts);
      80  	assert (fcts.towc_nsteps == 1);
      81  	assert (fcts.tomb_nsteps == 1);
      82  
      83  	cc->__cd_in.step = fcts.towc;
      84  
      85  	cc->__cd_in.step_data.__invocation_counter = 0;
      86  	cc->__cd_in.step_data.__internal_use = 1;
      87  	cc->__cd_in.step_data.__flags = __GCONV_IS_LAST;
      88  	cc->__cd_in.step_data.__statep = &fp->_wide_data->_IO_state;
      89  
      90  	cc->__cd_out.step = fcts.tomb;
      91  
      92  	cc->__cd_out.step_data.__invocation_counter = 0;
      93  	cc->__cd_out.step_data.__internal_use = 1;
      94  	cc->__cd_out.step_data.__flags = __GCONV_IS_LAST | __GCONV_TRANSLIT;
      95  	cc->__cd_out.step_data.__statep = &fp->_wide_data->_IO_state;
      96        }
      97  
      98        /* From now on use the wide character callback functions.  */
      99        _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
     100      }
     101  
     102    /* Set the mode now.  */
     103    fp->_mode = mode;
     104  
     105    return mode;
     106  }
     107  
     108  
     109  enum __codecvt_result
     110  __libio_codecvt_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
     111  		     const wchar_t *from_start, const wchar_t *from_end,
     112  		     const wchar_t **from_stop, char *to_start, char *to_end,
     113  		     char **to_stop)
     114  {
     115    enum __codecvt_result result;
     116  
     117    struct __gconv_step *gs = codecvt->__cd_out.step;
     118    int status;
     119    size_t dummy;
     120    const unsigned char *from_start_copy = (unsigned char *) from_start;
     121  
     122    codecvt->__cd_out.step_data.__outbuf = (unsigned char *) to_start;
     123    codecvt->__cd_out.step_data.__outbufend = (unsigned char *) to_end;
     124    codecvt->__cd_out.step_data.__statep = statep;
     125  
     126    __gconv_fct fct = gs->__fct;
     127    if (gs->__shlib_handle != NULL)
     128      PTR_DEMANGLE (fct);
     129  
     130    status = DL_CALL_FCT (fct,
     131  			(gs, &codecvt->__cd_out.step_data, &from_start_copy,
     132  			 (const unsigned char *) from_end, NULL,
     133  			 &dummy, 0, 0));
     134  
     135    *from_stop = (wchar_t *) from_start_copy;
     136    *to_stop = (char *) codecvt->__cd_out.step_data.__outbuf;
     137  
     138    switch (status)
     139      {
     140      case __GCONV_OK:
     141      case __GCONV_EMPTY_INPUT:
     142        result = __codecvt_ok;
     143        break;
     144  
     145      case __GCONV_FULL_OUTPUT:
     146      case __GCONV_INCOMPLETE_INPUT:
     147        result = __codecvt_partial;
     148        break;
     149  
     150      default:
     151        result = __codecvt_error;
     152        break;
     153      }
     154  
     155    return result;
     156  }
     157  
     158  
     159  enum __codecvt_result
     160  __libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
     161  		    const char *from_start, const char *from_end,
     162  		    const char **from_stop,
     163  		    wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
     164  {
     165    enum __codecvt_result result;
     166  
     167    struct __gconv_step *gs = codecvt->__cd_in.step;
     168    int status;
     169    size_t dummy;
     170    const unsigned char *from_start_copy = (unsigned char *) from_start;
     171  
     172    codecvt->__cd_in.step_data.__outbuf = (unsigned char *) to_start;
     173    codecvt->__cd_in.step_data.__outbufend = (unsigned char *) to_end;
     174    codecvt->__cd_in.step_data.__statep = statep;
     175  
     176    __gconv_fct fct = gs->__fct;
     177    if (gs->__shlib_handle != NULL)
     178      PTR_DEMANGLE (fct);
     179  
     180    status = DL_CALL_FCT (fct,
     181  			(gs, &codecvt->__cd_in.step_data, &from_start_copy,
     182  			 (const unsigned char *) from_end, NULL,
     183  			 &dummy, 0, 0));
     184  
     185    *from_stop = (const char *) from_start_copy;
     186    *to_stop = (wchar_t *) codecvt->__cd_in.step_data.__outbuf;
     187  
     188    switch (status)
     189      {
     190      case __GCONV_OK:
     191      case __GCONV_EMPTY_INPUT:
     192        result = __codecvt_ok;
     193        break;
     194  
     195      case __GCONV_FULL_OUTPUT:
     196      case __GCONV_INCOMPLETE_INPUT:
     197        result = __codecvt_partial;
     198        break;
     199  
     200      default:
     201        result = __codecvt_error;
     202        break;
     203      }
     204  
     205    return result;
     206  }
     207  
     208  
     209  int
     210  __libio_codecvt_encoding (struct _IO_codecvt *codecvt)
     211  {
     212    /* See whether the encoding is stateful.  */
     213    if (codecvt->__cd_in.step->__stateful)
     214      return -1;
     215    /* Fortunately not.  Now determine the input bytes for the conversion
     216       necessary for each wide character.  */
     217    if (codecvt->__cd_in.step->__min_needed_from
     218        != codecvt->__cd_in.step->__max_needed_from)
     219      /* Not a constant value.  */
     220      return 0;
     221  
     222    return codecvt->__cd_in.step->__min_needed_from;
     223  }
     224  
     225  
     226  int
     227  __libio_codecvt_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
     228  			const char *from_start, const char *from_end,
     229  			size_t max)
     230  {
     231    int result;
     232    const unsigned char *cp = (const unsigned char *) from_start;
     233    wchar_t to_buf[max];
     234    struct __gconv_step *gs = codecvt->__cd_in.step;
     235    size_t dummy;
     236  
     237    codecvt->__cd_in.step_data.__outbuf = (unsigned char *) to_buf;
     238    codecvt->__cd_in.step_data.__outbufend = (unsigned char *) &to_buf[max];
     239    codecvt->__cd_in.step_data.__statep = statep;
     240  
     241    __gconv_fct fct = gs->__fct;
     242    if (gs->__shlib_handle != NULL)
     243      PTR_DEMANGLE (fct);
     244  
     245    DL_CALL_FCT (fct,
     246  	       (gs, &codecvt->__cd_in.step_data, &cp,
     247  		(const unsigned char *) from_end, NULL,
     248  		&dummy, 0, 0));
     249  
     250    result = cp - (const unsigned char *) from_start;
     251  
     252    return result;
     253  }