Blame wcsmbs/mbsnrtowcs.c

Packit 6c4009
/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <gconv.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <wcsmbsload.h>
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
Packit 6c4009
#ifndef EILSEQ
Packit 6c4009
# define EILSEQ EINVAL
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is the private state used if PS is NULL.  */
Packit 6c4009
static mbstate_t state;
Packit 6c4009
Packit 6c4009
/* This is a non-standard function but it is very useful in the
Packit 6c4009
   implementation of stdio because we have to deal with unterminated
Packit 6c4009
   buffers.  At most NMC bytes will be converted.  */
Packit 6c4009
size_t
Packit 6c4009
__mbsnrtowcs (wchar_t *dst, const char **src, size_t nmc, size_t len,
Packit 6c4009
	      mbstate_t *ps)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *srcend;
Packit 6c4009
  struct __gconv_step_data data;
Packit 6c4009
  size_t result;
Packit 6c4009
  int status;
Packit 6c4009
  struct __gconv_step *towc;
Packit 6c4009
  size_t dummy;
Packit 6c4009
  const struct gconv_fcts *fcts;
Packit 6c4009
Packit 6c4009
  /* Tell where we want the result.  */
Packit 6c4009
  data.__invocation_counter = 0;
Packit 6c4009
  data.__internal_use = 1;
Packit 6c4009
  data.__flags = __GCONV_IS_LAST;
Packit 6c4009
  data.__statep = ps ?: &stat;;
Packit 6c4009
Packit 6c4009
  if (nmc == 0)
Packit 6c4009
    return 0;
Packit 6c4009
  srcend = (const unsigned char *) *src + __strnlen (*src, nmc - 1) + 1;
Packit 6c4009
Packit 6c4009
  /* Get the conversion functions.  */
Packit 6c4009
  fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
Packit 6c4009
Packit 6c4009
  /* Get the structure with the function pointers.  */
Packit 6c4009
  towc = fcts->towc;
Packit 6c4009
  __gconv_fct fct = towc->__fct;
Packit 6c4009
#ifdef PTR_DEMANGLE
Packit 6c4009
  if (towc->__shlib_handle != NULL)
Packit 6c4009
    PTR_DEMANGLE (fct);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* We have to handle DST == NULL special.  */
Packit 6c4009
  if (dst == NULL)
Packit 6c4009
    {
Packit 6c4009
      mbstate_t temp_state;
Packit 6c4009
      wchar_t buf[64];		/* Just an arbitrary size.  */
Packit 6c4009
      const unsigned char *inbuf = (const unsigned char *) *src;
Packit 6c4009
Packit 6c4009
      temp_state = *data.__statep;
Packit 6c4009
      data.__statep = &temp_state;
Packit 6c4009
Packit 6c4009
      result = 0;
Packit 6c4009
      data.__outbufend = (unsigned char *) buf + sizeof (buf);
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  data.__outbuf = (unsigned char *) buf;
Packit 6c4009
Packit 6c4009
	  status = DL_CALL_FCT (fct, (towc, &data, &inbuf, srcend, NULL,
Packit 6c4009
				      &dummy, 0, 1));
Packit 6c4009
Packit 6c4009
	  result += (wchar_t *) data.__outbuf - buf;
Packit 6c4009
	}
Packit 6c4009
      while (status == __GCONV_FULL_OUTPUT);
Packit 6c4009
Packit 6c4009
      if ((status == __GCONV_OK || status == __GCONV_EMPTY_INPUT)
Packit 6c4009
	  && ((wchar_t *) data.__outbuf)[-1] == L'\0')
Packit 6c4009
	/* Don't count the NUL character in.  */
Packit 6c4009
	--result;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* This code is based on the safe assumption that all internal
Packit 6c4009
	 multi-byte encodings use the NUL byte only to mark the end
Packit 6c4009
	 of the string.  */
Packit 6c4009
      data.__outbuf = (unsigned char *) dst;
Packit 6c4009
      data.__outbufend = data.__outbuf + len * sizeof (wchar_t);
Packit 6c4009
Packit 6c4009
      status = DL_CALL_FCT (fct,
Packit 6c4009
			    (towc, &data, (const unsigned char **) src, srcend,
Packit 6c4009
			     NULL, &dummy, 0, 1));
Packit 6c4009
Packit 6c4009
      result = (wchar_t *) data.__outbuf - dst;
Packit 6c4009
Packit 6c4009
      /* We have to determine whether the last character converted
Packit 6c4009
	 is the NUL character.  */
Packit 6c4009
      if ((status == __GCONV_OK || status == __GCONV_EMPTY_INPUT)
Packit 6c4009
	  && (assert (result > 0),
Packit 6c4009
	      ((wchar_t *) dst)[result - 1] == L'\0'))
Packit 6c4009
	{
Packit 6c4009
	  assert (__mbsinit (data.__statep));
Packit 6c4009
	  *src = NULL;
Packit 6c4009
	  --result;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* There must not be any problems with the conversion but illegal input
Packit 6c4009
     characters.  */
Packit 6c4009
  assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
Packit 6c4009
	  || status == __GCONV_ILLEGAL_INPUT
Packit 6c4009
	  || status == __GCONV_INCOMPLETE_INPUT
Packit 6c4009
	  || status == __GCONV_FULL_OUTPUT);
Packit 6c4009
Packit 6c4009
  if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT
Packit 6c4009
      && status != __GCONV_EMPTY_INPUT && status != __GCONV_INCOMPLETE_INPUT)
Packit 6c4009
    {
Packit 6c4009
      result = (size_t) -1;
Packit 6c4009
      __set_errno (EILSEQ);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
weak_alias (__mbsnrtowcs, mbsnrtowcs)