Blame iconv/loop.c

Packit 6c4009
/* Conversion loop frame work.
Packit 6c4009
   Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
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
/* This file provides a frame for the reader loop in all conversion modules.
Packit 6c4009
   The actual code must (of course) be provided in the actual module source
Packit 6c4009
   code but certain actions can be written down generically, with some
Packit 6c4009
   customization options which are these:
Packit 6c4009
Packit 6c4009
     MIN_NEEDED_INPUT	minimal number of input bytes needed for the next
Packit 6c4009
			conversion.
Packit 6c4009
     MIN_NEEDED_OUTPUT	minimal number of bytes produced by the next round
Packit 6c4009
			of conversion.
Packit 6c4009
Packit 6c4009
     MAX_NEEDED_INPUT	you guess it, this is the maximal number of input
Packit 6c4009
			bytes needed.  It defaults to MIN_NEEDED_INPUT
Packit 6c4009
     MAX_NEEDED_OUTPUT	likewise for output bytes.
Packit 6c4009
Packit 6c4009
     LOOPFCT		name of the function created.  If not specified
Packit 6c4009
			the name is `loop' but this prevents the use
Packit 6c4009
			of multiple functions in the same file.
Packit 6c4009
Packit 6c4009
     BODY		this is supposed to expand to the body of the loop.
Packit 6c4009
			The user must provide this.
Packit 6c4009
Packit 6c4009
     EXTRA_LOOP_DECLS	extra arguments passed from conversion loop call.
Packit 6c4009
Packit 6c4009
     INIT_PARAMS	code to define and initialize variables from params.
Packit 6c4009
     UPDATE_PARAMS	code to store result in params.
Packit 6c4009
Packit 6c4009
     ONEBYTE_BODY	body of the specialized conversion function for a
Packit 6c4009
			single byte from the current character set to INTERNAL.
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <endian.h>
Packit 6c4009
#include <gconv.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <sys/param.h>		/* For MIN.  */
Packit 6c4009
#define __need_size_t
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
/* We have to provide support for machines which are not able to handled
Packit 6c4009
   unaligned memory accesses.  Some of the character encodings have
Packit 6c4009
   representations with a fixed width of 2 or 4 bytes.  But if we cannot
Packit 6c4009
   access unaligned memory we still have to read byte-wise.  */
Packit 6c4009
#undef FCTNAME2
Packit 6c4009
#if _STRING_ARCH_unaligned || !defined DEFINE_UNALIGNED
Packit 6c4009
/* We can handle unaligned memory access.  */
Packit 6c4009
# define get16(addr) *((const uint16_t *) (addr))
Packit 6c4009
# define get32(addr) *((const uint32_t *) (addr))
Packit 6c4009
Packit 6c4009
/* We need no special support for writing values either.  */
Packit 6c4009
# define put16(addr, val) *((uint16_t *) (addr)) = (val)
Packit 6c4009
# define put32(addr, val) *((uint32_t *) (addr)) = (val)
Packit 6c4009
Packit 6c4009
# define FCTNAME2(name) name
Packit 6c4009
#else
Packit 6c4009
/* Distinguish between big endian and little endian.  */
Packit 6c4009
# if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
#  define get16(addr) \
Packit 6c4009
     (((const unsigned char *) (addr))[1] << 8				      \
Packit 6c4009
      | ((const unsigned char *) (addr))[0])
Packit 6c4009
#  define get32(addr) \
Packit 6c4009
     (((((const unsigned char *) (addr))[3] << 8			      \
Packit 6c4009
	| ((const unsigned char *) (addr))[2]) << 8			      \
Packit 6c4009
       | ((const unsigned char *) (addr))[1]) << 8			      \
Packit 6c4009
      | ((const unsigned char *) (addr))[0])
Packit 6c4009
Packit 6c4009
#  define put16(addr, val) \
Packit 6c4009
     ({ uint16_t __val = (val);						      \
Packit 6c4009
	((unsigned char *) (addr))[0] = __val;				      \
Packit 6c4009
	((unsigned char *) (addr))[1] = __val >> 8;			      \
Packit 6c4009
	(void) 0; })
Packit 6c4009
#  define put32(addr, val) \
Packit 6c4009
     ({ uint32_t __val = (val);						      \
Packit 6c4009
	((unsigned char *) (addr))[0] = __val;				      \
Packit 6c4009
	__val >>= 8;							      \
Packit 6c4009
	((unsigned char *) (addr))[1] = __val;				      \
Packit 6c4009
	__val >>= 8;							      \
Packit 6c4009
	((unsigned char *) (addr))[2] = __val;				      \
Packit 6c4009
	__val >>= 8;							      \
Packit 6c4009
	((unsigned char *) (addr))[3] = __val;				      \
Packit 6c4009
	(void) 0; })
Packit 6c4009
# else
Packit 6c4009
#  define get16(addr) \
Packit 6c4009
     (((const unsigned char *) (addr))[0] << 8				      \
Packit 6c4009
      | ((const unsigned char *) (addr))[1])
Packit 6c4009
#  define get32(addr) \
Packit 6c4009
     (((((const unsigned char *) (addr))[0] << 8			      \
Packit 6c4009
	| ((const unsigned char *) (addr))[1]) << 8			      \
Packit 6c4009
       | ((const unsigned char *) (addr))[2]) << 8			      \
Packit 6c4009
      | ((const unsigned char *) (addr))[3])
Packit 6c4009
Packit 6c4009
#  define put16(addr, val) \
Packit 6c4009
     ({ uint16_t __val = (val);						      \
Packit 6c4009
	((unsigned char *) (addr))[1] = __val;				      \
Packit 6c4009
	((unsigned char *) (addr))[0] = __val >> 8;			      \
Packit 6c4009
	(void) 0; })
Packit 6c4009
#  define put32(addr, val) \
Packit 6c4009
     ({ uint32_t __val = (val);						      \
Packit 6c4009
	((unsigned char *) (addr))[3] = __val;				      \
Packit 6c4009
	__val >>= 8;							      \
Packit 6c4009
	((unsigned char *) (addr))[2] = __val;				      \
Packit 6c4009
	__val >>= 8;							      \
Packit 6c4009
	((unsigned char *) (addr))[1] = __val;				      \
Packit 6c4009
	__val >>= 8;							      \
Packit 6c4009
	((unsigned char *) (addr))[0] = __val;				      \
Packit 6c4009
	(void) 0; })
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
# define FCTNAME2(name) name##_unaligned
Packit 6c4009
#endif
Packit 6c4009
#define FCTNAME(name) FCTNAME2(name)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We need at least one byte for the next round.  */
Packit 6c4009
#ifndef MIN_NEEDED_INPUT
Packit 6c4009
# error "MIN_NEEDED_INPUT definition missing"
Packit 6c4009
#elif MIN_NEEDED_INPUT < 1
Packit 6c4009
# error "MIN_NEEDED_INPUT must be >= 1"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Let's see how many bytes we produce.  */
Packit 6c4009
#ifndef MAX_NEEDED_INPUT
Packit 6c4009
# define MAX_NEEDED_INPUT	MIN_NEEDED_INPUT
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* We produce at least one byte in the next round.  */
Packit 6c4009
#ifndef MIN_NEEDED_OUTPUT
Packit 6c4009
# error "MIN_NEEDED_OUTPUT definition missing"
Packit 6c4009
#elif MIN_NEEDED_OUTPUT < 1
Packit 6c4009
# error "MIN_NEEDED_OUTPUT must be >= 1"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Let's see how many bytes we produce.  */
Packit 6c4009
#ifndef MAX_NEEDED_OUTPUT
Packit 6c4009
# define MAX_NEEDED_OUTPUT	MIN_NEEDED_OUTPUT
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Default name for the function.  */
Packit 6c4009
#ifndef LOOPFCT
Packit 6c4009
# define LOOPFCT		loop
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Make sure we have a loop body.  */
Packit 6c4009
#ifndef BODY
Packit 6c4009
# error "Definition of BODY missing for function" LOOPFCT
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* If no arguments have to passed to the loop function define the macro
Packit 6c4009
   as empty.  */
Packit 6c4009
#ifndef EXTRA_LOOP_DECLS
Packit 6c4009
# define EXTRA_LOOP_DECLS
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Allow using UPDATE_PARAMS in macros where #ifdef UPDATE_PARAMS test
Packit 6c4009
   isn't possible.  */
Packit 6c4009
#ifndef UPDATE_PARAMS
Packit 6c4009
# define UPDATE_PARAMS do { } while (0)
Packit 6c4009
#endif
Packit 6c4009
#ifndef REINIT_PARAMS
Packit 6c4009
# define REINIT_PARAMS do { } while (0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* To make it easier for the writers of the modules, we define a macro
Packit 6c4009
   to test whether we have to ignore errors.  */
Packit 6c4009
#define ignore_errors_p() \
Packit 6c4009
  (irreversible != NULL && (flags & __GCONV_IGNORE_ERRORS))
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Error handling for the FROM_LOOP direction, with ignoring of errors.
Packit 6c4009
   Note that we cannot use the do while (0) trick since `break' and
Packit 6c4009
   `continue' must reach certain points.  */
Packit 6c4009
#define STANDARD_FROM_LOOP_ERR_HANDLER(Incr) \
Packit 6c4009
  {									      \
Packit 6c4009
    result = __GCONV_ILLEGAL_INPUT;					      \
Packit 6c4009
									      \
Packit 6c4009
    if (! ignore_errors_p ())						      \
Packit 6c4009
      break;								      \
Packit 6c4009
									      \
Packit 6c4009
    /* We ignore the invalid input byte sequence.  */			      \
Packit 6c4009
    inptr += (Incr);							      \
Packit 6c4009
    ++*irreversible;							      \
Packit 6c4009
    /* But we keep result == __GCONV_ILLEGAL_INPUT, because of the constraint \
Packit 6c4009
       that "iconv -c" must give the same exitcode as "iconv".  */	      \
Packit 6c4009
    continue;								      \
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
/* Error handling for the TO_LOOP direction, with use of transliteration/
Packit 6c4009
   transcription functions and ignoring of errors.  Note that we cannot use
Packit 6c4009
   the do while (0) trick since `break' and `continue' must reach certain
Packit 6c4009
   points.  */
Packit 6c4009
#define STANDARD_TO_LOOP_ERR_HANDLER(Incr) \
Packit 6c4009
  {									      \
Packit 6c4009
    result = __GCONV_ILLEGAL_INPUT;					      \
Packit 6c4009
									      \
Packit 6c4009
    if (irreversible == NULL)						      \
Packit 6c4009
      /* This means we are in call from __gconv_transliterate.  In this	      \
Packit 6c4009
	 case we are not doing any error recovery outself.  */		      \
Packit 6c4009
      break;								      \
Packit 6c4009
									      \
Packit 6c4009
    /* If needed, flush any conversion state, so that __gconv_transliterate   \
Packit 6c4009
       starts with current shift state.  */				      \
Packit 6c4009
    UPDATE_PARAMS;							      \
Packit 6c4009
									      \
Packit 6c4009
    /* First try the transliteration methods.  */			      \
Packit 6c4009
    if ((step_data->__flags & __GCONV_TRANSLIT) != 0)			      \
Packit 6c4009
      result = __gconv_transliterate					      \
Packit 6c4009
	(step, step_data, *inptrp,					      \
Packit 6c4009
	 &inptr, inend, &outptr, irreversible);			      \
Packit 6c4009
									      \
Packit 6c4009
    REINIT_PARAMS;							      \
Packit 6c4009
									      \
Packit 6c4009
    /* If any of them recognized the input continue with the loop.  */	      \
Packit 6c4009
    if (result != __GCONV_ILLEGAL_INPUT)				      \
Packit 6c4009
      {									      \
Packit 6c4009
	if (__glibc_unlikely (result == __GCONV_FULL_OUTPUT))		      \
Packit 6c4009
	  break;							      \
Packit 6c4009
									      \
Packit 6c4009
	continue;							      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    /* Next see whether we have to ignore the error.  If not, stop.  */	      \
Packit 6c4009
    if (! ignore_errors_p ())						      \
Packit 6c4009
      break;								      \
Packit 6c4009
									      \
Packit 6c4009
    /* When we come here it means we ignore the character.  */		      \
Packit 6c4009
    ++*irreversible;							      \
Packit 6c4009
    inptr += Incr;							      \
Packit 6c4009
    /* But we keep result == __GCONV_ILLEGAL_INPUT, because of the constraint \
Packit 6c4009
       that "iconv -c" must give the same exitcode as "iconv".  */	      \
Packit 6c4009
    continue;								      \
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* With GCC 7 when compiling with -Os for 32-bit s390 the compiler
Packit 6c4009
   warns that the variable 'ch', in the definition of BODY in
Packit 6c4009
   sysdeps/s390/multiarch/8bit-generic.c, may be used uninitialized in
Packit 6c4009
   the call to UNICODE_TAG_HANDLER in that macro.  This variable is
Packit 6c4009
   actually always initialized before use, in the prior loop if INDEX
Packit 6c4009
   is nonzero and in the following 'if' if INDEX is zero.  That code
Packit 6c4009
   has a comment referencing this diagnostic disabling; updates in one
Packit 6c4009
   place may require updates in the other.  */
Packit 6c4009
DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
DIAG_IGNORE_Os_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
Packit 6c4009
/* Handling of Unicode 3.1 TAG characters.  Unicode recommends
Packit 6c4009
   "If language codes are not relevant to the particular processing
Packit 6c4009
    operation, then they should be ignored."  This macro is usually
Packit 6c4009
   called right before  STANDARD_TO_LOOP_ERR_HANDLER (Incr).  */
Packit 6c4009
#define UNICODE_TAG_HANDLER(Character, Incr) \
Packit 6c4009
  {									      \
Packit 6c4009
    /* TAG characters are those in the range U+E0000..U+E007F.  */	      \
Packit 6c4009
    if (((Character) >> 7) == (0xe0000 >> 7))				      \
Packit 6c4009
      {									      \
Packit 6c4009
	inptr += Incr;							      \
Packit 6c4009
	continue;							      \
Packit 6c4009
      }									      \
Packit 6c4009
  }
Packit 6c4009
DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The function returns the status, as defined in gconv.h.  */
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
FCTNAME (LOOPFCT) (struct __gconv_step *step,
Packit 6c4009
		   struct __gconv_step_data *step_data,
Packit 6c4009
		   const unsigned char **inptrp, const unsigned char *inend,
Packit 6c4009
		   unsigned char **outptrp, const unsigned char *outend,
Packit 6c4009
		   size_t *irreversible EXTRA_LOOP_DECLS)
Packit 6c4009
{
Packit 6c4009
#ifdef LOOP_NEED_STATE
Packit 6c4009
  mbstate_t *state = step_data->__statep;
Packit 6c4009
#endif
Packit 6c4009
#ifdef LOOP_NEED_FLAGS
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
#endif
Packit 6c4009
#ifdef LOOP_NEED_DATA
Packit 6c4009
  void *data = step->__data;
Packit 6c4009
#endif
Packit 6c4009
  int result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
Packit 6c4009
#ifdef INIT_PARAMS
Packit 6c4009
  INIT_PARAMS;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  while (inptr != inend)
Packit 6c4009
    {
Packit 6c4009
      /* `if' cases for MIN_NEEDED_OUTPUT ==/!= 1 is made to help the
Packit 6c4009
	 compiler generating better code.  They will be optimized away
Packit 6c4009
	 since MIN_NEEDED_OUTPUT is always a constant.  */
Packit 6c4009
      if (MIN_NEEDED_INPUT > 1
Packit 6c4009
	  && __builtin_expect (inptr + MIN_NEEDED_INPUT > inend, 0))
Packit 6c4009
	{
Packit 6c4009
	  /* We don't have enough input for another complete input
Packit 6c4009
	     character.  */
Packit 6c4009
	  result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      if ((MIN_NEEDED_OUTPUT != 1
Packit 6c4009
	   && __builtin_expect (outptr + MIN_NEEDED_OUTPUT > outend, 0))
Packit 6c4009
	  || (MIN_NEEDED_OUTPUT == 1
Packit 6c4009
	      && __builtin_expect (outptr >= outend, 0)))
Packit 6c4009
	{
Packit 6c4009
	  /* Overflow in the output buffer.  */
Packit 6c4009
	  result = __GCONV_FULL_OUTPUT;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Here comes the body the user provides.  It can stop with
Packit 6c4009
	 RESULT set to GCONV_INCOMPLETE_INPUT (if the size of the
Packit 6c4009
	 input characters vary in size), GCONV_ILLEGAL_INPUT, or
Packit 6c4009
	 GCONV_FULL_OUTPUT (if the output characters vary in size).  */
Packit 6c4009
      BODY
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Update the pointers pointed to by the parameters.  */
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
  UPDATE_PARAMS;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Include the file a second time to define the function to handle
Packit 6c4009
   unaligned access.  */
Packit 6c4009
#if !defined DEFINE_UNALIGNED && !_STRING_ARCH_unaligned \
Packit 6c4009
    && MIN_NEEDED_INPUT != 1 && MAX_NEEDED_INPUT % MIN_NEEDED_INPUT == 0 \
Packit 6c4009
    && MIN_NEEDED_OUTPUT != 1 && MAX_NEEDED_OUTPUT % MIN_NEEDED_OUTPUT == 0
Packit 6c4009
# undef get16
Packit 6c4009
# undef get32
Packit 6c4009
# undef put16
Packit 6c4009
# undef put32
Packit 6c4009
# undef unaligned
Packit 6c4009
Packit 6c4009
# define DEFINE_UNALIGNED
Packit 6c4009
# include "loop.c"
Packit 6c4009
# undef DEFINE_UNALIGNED
Packit 6c4009
#else
Packit 6c4009
# if MAX_NEEDED_INPUT > 1
Packit 6c4009
#  define SINGLE(fct) SINGLE2 (fct)
Packit 6c4009
#  define SINGLE2(fct) fct##_single
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
SINGLE(LOOPFCT) (struct __gconv_step *step,
Packit 6c4009
		 struct __gconv_step_data *step_data,
Packit 6c4009
		 const unsigned char **inptrp, const unsigned char *inend,
Packit 6c4009
		 unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
		 size_t *irreversible EXTRA_LOOP_DECLS)
Packit 6c4009
{
Packit 6c4009
  mbstate_t *state = step_data->__statep;
Packit 6c4009
#  ifdef LOOP_NEED_FLAGS
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
#  endif
Packit 6c4009
#  ifdef LOOP_NEED_DATA
Packit 6c4009
  void *data = step->__data;
Packit 6c4009
#  endif
Packit 6c4009
  int result = __GCONV_OK;
Packit 6c4009
  unsigned char bytebuf[MAX_NEEDED_INPUT];
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t inlen;
Packit 6c4009
Packit 6c4009
#  ifdef INIT_PARAMS
Packit 6c4009
  INIT_PARAMS;
Packit 6c4009
#  endif
Packit 6c4009
Packit 6c4009
#  ifdef UNPACK_BYTES
Packit 6c4009
  UNPACK_BYTES
Packit 6c4009
#  else
Packit 6c4009
  /* Add the bytes from the state to the input buffer.  */
Packit 6c4009
  assert ((state->__count & 7) <= sizeof (state->__value));
Packit 6c4009
  for (inlen = 0; inlen < (size_t) (state->__count & 7); ++inlen)
Packit 6c4009
    bytebuf[inlen] = state->__value.__wchb[inlen];
Packit 6c4009
#  endif
Packit 6c4009
Packit 6c4009
  /* Are there enough bytes in the input buffer?  */
Packit 6c4009
  if (MIN_NEEDED_INPUT > 1
Packit 6c4009
      && __builtin_expect (inptr + (MIN_NEEDED_INPUT - inlen) > inend, 0))
Packit 6c4009
    {
Packit 6c4009
      *inptrp = inend;
Packit 6c4009
#  ifdef STORE_REST
Packit 6c4009
Packit 6c4009
      /* Building with -O3 GCC emits a `array subscript is above array
Packit 6c4009
	 bounds' warning.  GCC BZ #64739 has been opened for this.  */
Packit 6c4009
      DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
      DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Warray-bounds");
Packit 6c4009
      while (inptr < inend)
Packit 6c4009
	bytebuf[inlen++] = *inptr++;
Packit 6c4009
      DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
Packit 6c4009
      inptr = bytebuf;
Packit 6c4009
      inptrp = &inptr;
Packit 6c4009
      inend = &bytebuf[inlen];
Packit 6c4009
Packit 6c4009
      STORE_REST
Packit 6c4009
#  else
Packit 6c4009
      /* We don't have enough input for another complete input
Packit 6c4009
	 character.  */
Packit 6c4009
      while (inptr < inend)
Packit 6c4009
	state->__value.__wchb[inlen++] = *inptr++;
Packit 6c4009
#  endif
Packit 6c4009
Packit 6c4009
      return __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Enough space in output buffer.  */
Packit 6c4009
  if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
Packit 6c4009
      || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
Packit 6c4009
    /* Overflow in the output buffer.  */
Packit 6c4009
    return __GCONV_FULL_OUTPUT;
Packit 6c4009
Packit 6c4009
  /*  Now add characters from the normal input buffer.  */
Packit 6c4009
  do
Packit 6c4009
    bytebuf[inlen++] = *inptr++;
Packit 6c4009
  while (inlen < MAX_NEEDED_INPUT && inptr < inend);
Packit 6c4009
Packit 6c4009
  inptr = bytebuf;
Packit 6c4009
  inend = &bytebuf[inlen];
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      BODY
Packit 6c4009
    }
Packit 6c4009
  while (0);
Packit 6c4009
Packit 6c4009
  /* Now we either have produced an output character and consumed all the
Packit 6c4009
     bytes from the state and at least one more, or the character is still
Packit 6c4009
     incomplete, or we have some other error (like illegal input character,
Packit 6c4009
     no space in output buffer).  */
Packit 6c4009
  if (__glibc_likely (inptr != bytebuf))
Packit 6c4009
    {
Packit 6c4009
      /* We found a new character.  */
Packit 6c4009
      assert (inptr - bytebuf > (state->__count & 7));
Packit 6c4009
Packit 6c4009
      *inptrp += inptr - bytebuf - (state->__count & 7);
Packit 6c4009
      *outptrp = outptr;
Packit 6c4009
Packit 6c4009
      result = __GCONV_OK;
Packit 6c4009
Packit 6c4009
      /* Clear the state buffer.  */
Packit 6c4009
#  ifdef CLEAR_STATE
Packit 6c4009
      CLEAR_STATE;
Packit 6c4009
#  else
Packit 6c4009
      state->__count &= ~7;
Packit 6c4009
#  endif
Packit 6c4009
    }
Packit 6c4009
  else if (result == __GCONV_INCOMPLETE_INPUT)
Packit 6c4009
    {
Packit 6c4009
      /* This can only happen if we have less than MAX_NEEDED_INPUT bytes
Packit 6c4009
	 available.  */
Packit 6c4009
      assert (inend != &bytebuf[MAX_NEEDED_INPUT]);
Packit 6c4009
Packit 6c4009
      *inptrp += inend - bytebuf - (state->__count & 7);
Packit 6c4009
#  ifdef STORE_REST
Packit 6c4009
      inptrp = &inptr;
Packit 6c4009
Packit 6c4009
      STORE_REST
Packit 6c4009
#  else
Packit 6c4009
      /* We don't have enough input for another complete input
Packit 6c4009
	 character.  */
Packit 6c4009
      assert (inend - inptr > (state->__count & ~7));
Packit 6c4009
      assert (inend - inptr <= sizeof (state->__value));
Packit 6c4009
      state->__count = (state->__count & ~7) | (inend - inptr);
Packit 6c4009
      inlen = 0;
Packit 6c4009
      while (inptr < inend)
Packit 6c4009
	state->__value.__wchb[inlen++] = *inptr++;
Packit 6c4009
#  endif
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
#  undef SINGLE
Packit 6c4009
#  undef SINGLE2
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
# ifdef ONEBYTE_BODY
Packit 6c4009
/* Define the shortcut function for btowc.  */
Packit 6c4009
static wint_t
Packit 6c4009
gconv_btowc (struct __gconv_step *step, unsigned char c)
Packit 6c4009
  ONEBYTE_BODY
Packit 6c4009
#  define FROM_ONEBYTE gconv_btowc
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* We remove the macro definitions so that we can include this file again
Packit 6c4009
   for the definition of another function.  */
Packit 6c4009
#undef MIN_NEEDED_INPUT
Packit 6c4009
#undef MAX_NEEDED_INPUT
Packit 6c4009
#undef MIN_NEEDED_OUTPUT
Packit 6c4009
#undef MAX_NEEDED_OUTPUT
Packit 6c4009
#undef LOOPFCT
Packit 6c4009
#undef BODY
Packit 6c4009
#undef LOOPFCT
Packit 6c4009
#undef EXTRA_LOOP_DECLS
Packit 6c4009
#undef INIT_PARAMS
Packit 6c4009
#undef UPDATE_PARAMS
Packit 6c4009
#undef REINIT_PARAMS
Packit 6c4009
#undef ONEBYTE_BODY
Packit 6c4009
#undef UNPACK_BYTES
Packit 6c4009
#undef CLEAR_STATE
Packit 6c4009
#undef LOOP_NEED_STATE
Packit 6c4009
#undef LOOP_NEED_FLAGS
Packit 6c4009
#undef LOOP_NEED_DATA
Packit 6c4009
#undef get16
Packit 6c4009
#undef get32
Packit 6c4009
#undef put16
Packit 6c4009
#undef put32
Packit 6c4009
#undef unaligned