Blame iconvdata/iso-2022-cn-ext.c

Packit Service 82fcde
/* Conversion module for ISO-2022-CN-EXT.
Packit Service 82fcde
   Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <dlfcn.h>
Packit Service 82fcde
#include <gconv.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include "gb2312.h"
Packit Service 82fcde
#include "iso-ir-165.h"
Packit Service 82fcde
#include "cns11643.h"
Packit Service 82fcde
#include "cns11643l1.h"
Packit Service 82fcde
#include "cns11643l2.h"
Packit Service 82fcde
#include <libc-diag.h>
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
Packit Service 82fcde
/* This makes obvious what everybody knows: 0x1b is the Esc character.  */
Packit Service 82fcde
#define ESC	0x1b
Packit Service 82fcde
Packit Service 82fcde
/* We have single-byte shift-in and shift-out sequences, and the single
Packit Service 82fcde
   shift sequences SS2 and SS3 which replaces the SS2/SS3 designation for
Packit Service 82fcde
   the next two bytes.  */
Packit Service 82fcde
#define SI	0x0f
Packit Service 82fcde
#define SO	0x0e
Packit Service 82fcde
#define SS2_0	ESC
Packit Service 82fcde
#define SS2_1	0x4e
Packit Service 82fcde
#define SS3_0	ESC
Packit Service 82fcde
#define SS3_1	0x4f
Packit Service 82fcde
Packit Service 82fcde
/* Definitions used in the body of the `gconv' function.  */
Packit Service 82fcde
#define CHARSET_NAME		"ISO-2022-CN-EXT//"
Packit Service 82fcde
#define DEFINE_INIT		1
Packit Service 82fcde
#define DEFINE_FINI		1
Packit Service 82fcde
#define ONE_DIRECTION		0
Packit Service 82fcde
#define FROM_LOOP		from_iso2022cn_ext_loop
Packit Service 82fcde
#define TO_LOOP			to_iso2022cn_ext_loop
Packit Service 82fcde
#define FROM_LOOP_MIN_NEEDED_FROM	1
Packit Service 82fcde
#define FROM_LOOP_MAX_NEEDED_FROM	4
Packit Service 82fcde
#define FROM_LOOP_MIN_NEEDED_TO		4
Packit Service 82fcde
#define FROM_LOOP_MAX_NEEDED_TO		4
Packit Service 82fcde
#define TO_LOOP_MIN_NEEDED_FROM		4
Packit Service 82fcde
#define TO_LOOP_MAX_NEEDED_FROM		4
Packit Service 82fcde
#define TO_LOOP_MIN_NEEDED_TO		1
Packit Service 82fcde
#define TO_LOOP_MAX_NEEDED_TO		6
Packit Service 82fcde
#define PREPARE_LOOP \
Packit Service 82fcde
  int save_set;								      \
Packit Service 82fcde
  int *setp = &data->__statep->__count;
Packit Service 82fcde
#define EXTRA_LOOP_ARGS		, setp
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* The charsets GB/T 12345-90, GB 7589-87, GB/T 13131-9X, GB 7590-87,
Packit Service 82fcde
   and GB/T 13132-9X are not registered to the best of my knowledge and
Packit Service 82fcde
   therefore have no escape sequence assigned.  We cannot handle them
Packit Service 82fcde
   for this reason.  Tell the implementation about this.  */
Packit Service 82fcde
#define X12345	'\0'
Packit Service 82fcde
#define X7589	'\0'
Packit Service 82fcde
#define X13131	'\0'
Packit Service 82fcde
#define X7590	'\0'
Packit Service 82fcde
#define X13132	'\0'
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* The COUNT element of the state keeps track of the currently selected
Packit Service 82fcde
   character set.  The possible values are:  */
Packit Service 82fcde
enum
Packit Service 82fcde
{
Packit Service 82fcde
  ASCII_set = 0,
Packit Service 82fcde
  GB2312_set,
Packit Service 82fcde
  GB12345_set,
Packit Service 82fcde
  CNS11643_1_set,
Packit Service 82fcde
  ISO_IR_165_set,
Packit Service 82fcde
  SO_mask = 7,
Packit Service 82fcde
Packit Service 82fcde
  GB7589_set = 1 << 3,
Packit Service 82fcde
  GB13131_set = 2 << 3,
Packit Service 82fcde
  CNS11643_2_set = 3 << 3,
Packit Service 82fcde
  SS2_mask = 3 << 3,
Packit Service 82fcde
Packit Service 82fcde
  GB7590_set = 1 << 5,
Packit Service 82fcde
  GB13132_set = 2 << 5,
Packit Service 82fcde
  CNS11643_3_set = 3 << 5,
Packit Service 82fcde
  CNS11643_4_set = 4 << 5,
Packit Service 82fcde
  CNS11643_5_set = 5 << 5,
Packit Service 82fcde
  CNS11643_6_set = 6 << 5,
Packit Service 82fcde
  CNS11643_7_set = 7 << 5,
Packit Service 82fcde
  SS3_mask = 7 << 5,
Packit Service 82fcde
Packit Service 82fcde
#define CURRENT_MASK (SO_mask | SS2_mask | SS3_mask)
Packit Service 82fcde
Packit Service 82fcde
  GB2312_ann = 1 << 8,
Packit Service 82fcde
  GB12345_ann = 2 << 8,
Packit Service 82fcde
  CNS11643_1_ann = 3 << 8,
Packit Service 82fcde
  ISO_IR_165_ann = 4 << 8,
Packit Service 82fcde
  SO_ann = 7 << 8,
Packit Service 82fcde
Packit Service 82fcde
  GB7589_ann = 1 << 11,
Packit Service 82fcde
  GB13131_ann = 2 << 11,
Packit Service 82fcde
  CNS11643_2_ann = 3 << 11,
Packit Service 82fcde
  SS2_ann = 3 << 11,
Packit Service 82fcde
Packit Service 82fcde
  GB7590_ann = 1 << 13,
Packit Service 82fcde
  GB13132_ann = 2 << 13,
Packit Service 82fcde
  CNS11643_3_ann = 3 << 13,
Packit Service 82fcde
  CNS11643_4_ann = 4 << 13,
Packit Service 82fcde
  CNS11643_5_ann = 5 << 13,
Packit Service 82fcde
  CNS11643_6_ann = 6 << 13,
Packit Service 82fcde
  CNS11643_7_ann = 7 << 13,
Packit Service 82fcde
  SS3_ann = 7 << 13
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Since this is a stateful encoding we have to provide code which resets
Packit Service 82fcde
   the output state to the initial state.  This has to be done during the
Packit Service 82fcde
   flushing.  */
Packit Service 82fcde
#define EMIT_SHIFT_TO_INIT \
Packit Service 82fcde
  if (data->__statep->__count >> 3 != ASCII_set)			      \
Packit Service 82fcde
    {									      \
Packit Service 82fcde
      if (FROM_DIRECTION)						      \
Packit Service 82fcde
	/* It's easy, we don't have to emit anything, we just reset the	      \
Packit Service 82fcde
	   state for the input.  */					      \
Packit Service 82fcde
	data->__statep->__count = ASCII_set << 3;			      \
Packit Service 82fcde
      else								      \
Packit Service 82fcde
	{								      \
Packit Service 82fcde
	  /* We are not in the initial state.  To switch back we have	      \
Packit Service 82fcde
	     to emit `SI'.  */						      \
Packit Service 82fcde
	  if (__glibc_unlikely (outbuf == outend))			      \
Packit Service 82fcde
	    /* We don't have enough room in the output buffer.  */	      \
Packit Service 82fcde
	    status = __GCONV_FULL_OUTPUT;				      \
Packit Service 82fcde
	  else								      \
Packit Service 82fcde
	    {								      \
Packit Service 82fcde
	      /* Write out the shift sequence.  */			      \
Packit Service 82fcde
	      *outbuf++ = SI;						      \
Packit Service 82fcde
	      if (data->__flags & __GCONV_IS_LAST)			      \
Packit Service 82fcde
		*irreversible += 1;					      \
Packit Service 82fcde
	      data->__statep->__count = ASCII_set << 3;			      \
Packit Service 82fcde
	    }								      \
Packit Service 82fcde
	}								      \
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Since we might have to reset input pointer we must be able to save
Packit Service 82fcde
   and retore the state.  */
Packit Service 82fcde
#define SAVE_RESET_STATE(Save) \
Packit Service 82fcde
  if (Save)								      \
Packit Service 82fcde
    save_set = *setp;							      \
Packit Service 82fcde
  else									      \
Packit Service 82fcde
    *setp = save_set
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* First define the conversion function from ISO-2022-CN to UCS4.  */
Packit Service 82fcde
#define MIN_NEEDED_INPUT	FROM_LOOP_MIN_NEEDED_FROM
Packit Service 82fcde
#define MAX_NEEDED_INPUT	FROM_LOOP_MAX_NEEDED_FROM
Packit Service 82fcde
#define MIN_NEEDED_OUTPUT	FROM_LOOP_MIN_NEEDED_TO
Packit Service 82fcde
#define MAX_NEEDED_OUTPUT	FROM_LOOP_MAX_NEEDED_TO
Packit Service 82fcde
#define LOOPFCT			FROM_LOOP
Packit Service 82fcde
#define BODY \
Packit Service 82fcde
  {									      \
Packit Service 82fcde
    uint32_t ch = *inptr;						      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    /* This is a 7bit character set, disallow all 8bit characters.  */	      \
Packit Service 82fcde
    if (ch > 0x7f)							      \
Packit Service 82fcde
      STANDARD_FROM_LOOP_ERR_HANDLER (1);				      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    /* Recognize escape sequences.  */					      \
Packit Service 82fcde
    if (ch == ESC)							      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* There are three kinds of escape sequences we have to handle:	      \
Packit Service 82fcde
	   - those announcing the use of GB and CNS characters on the	      \
Packit Service 82fcde
	     line; we can simply ignore them				      \
Packit Service 82fcde
	   - the initial byte of the SS2 sequence.			      \
Packit Service 82fcde
	   - the initial byte of the SS3 sequence.			      \
Packit Service 82fcde
	*/								      \
Packit Service 82fcde
	if (inptr + 2 > inend						      \
Packit Service 82fcde
	    || (inptr[1] == '$'						      \
Packit Service 82fcde
		&& (inptr + 3 > inend					      \
Packit Service 82fcde
		    || (inptr[2] == ')' && inptr + 4 > inend)		      \
Packit Service 82fcde
		    || (inptr[2] == '*' && inptr + 4 > inend)		      \
Packit Service 82fcde
		    || (inptr[2] == '+' && inptr + 4 > inend)))		      \
Packit Service 82fcde
	    || (inptr[1] == SS2_1 && inptr + 4 > inend)			      \
Packit Service 82fcde
	    || (inptr[1] == SS3_1 && inptr + 4 > inend))		      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    result = __GCONV_INCOMPLETE_INPUT;				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	if (inptr[1] == '$'						      \
Packit Service 82fcde
	    && ((inptr[2] == ')'					      \
Packit Service 82fcde
		 && (inptr[3] == 'A'					      \
Packit Service 82fcde
		     || (X12345 != '\0' && inptr[3] == X12345)		      \
Packit Service 82fcde
		     || inptr[3] == 'E' || inptr[3] == 'G'))		      \
Packit Service 82fcde
		|| (inptr[2] == '*'					      \
Packit Service 82fcde
		    && ((X7589 != '\0' && inptr[3] == X7589)		      \
Packit Service 82fcde
			|| (X13131 != '\0' && inptr[3] == X13131)	      \
Packit Service 82fcde
			|| inptr[3] == 'H'))				      \
Packit Service 82fcde
		|| (inptr[2] == '+'					      \
Packit Service 82fcde
		    && ((X7590 != '\0' && inptr[3] == X7590)		      \
Packit Service 82fcde
			|| (X13132 != '\0' && inptr[3] == X13132)	      \
Packit Service 82fcde
			|| inptr[3] == 'I' || inptr[3] == 'J'		      \
Packit Service 82fcde
			|| inptr[3] == 'K' || inptr[3] == 'L'		      \
Packit Service 82fcde
			|| inptr[3] == 'M'))))				      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    /* OK, we accept those character sets.  */			      \
Packit Service 82fcde
	    if (inptr[3] == 'A')					      \
Packit Service 82fcde
	      ann = (ann & ~SO_ann) | GB2312_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'G')					      \
Packit Service 82fcde
	      ann = (ann & ~SO_ann) | CNS11643_1_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'E')					      \
Packit Service 82fcde
	      ann = (ann & ~SO_ann) | ISO_IR_165_ann;			      \
Packit Service 82fcde
	    else if (X12345 != '\0' && inptr[3] == X12345)		      \
Packit Service 82fcde
	      ann = (ann & ~SO_ann) | GB12345_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'H')					      \
Packit Service 82fcde
	      ann = (ann & ~SS2_ann) | CNS11643_2_ann;			      \
Packit Service 82fcde
	    else if (X7589 != '\0' && inptr[3] == X7589)		      \
Packit Service 82fcde
	      ann = (ann & ~SS2_ann) | GB7589_ann;			      \
Packit Service 82fcde
	    else if (X13131 != '\0' && inptr[3] == X13131)		      \
Packit Service 82fcde
	      ann = (ann & ~SS2_ann) | GB13131_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'I')					      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | CNS11643_3_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'J')					      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | CNS11643_4_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'K')					      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | CNS11643_5_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'L')					      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | CNS11643_6_ann;			      \
Packit Service 82fcde
	    else if (inptr[3] == 'M')					      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | CNS11643_7_ann;			      \
Packit Service 82fcde
	    else if (X7590 != '\0' && inptr[3] == X7590)		      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | GB7590_ann;			      \
Packit Service 82fcde
	    else if (X13132 != '\0' && inptr[3] == X13132)		      \
Packit Service 82fcde
	      ann = (ann & ~SS3_ann) | GB13132_ann;			      \
Packit Service 82fcde
	    inptr += 4;							      \
Packit Service 82fcde
	    continue;							      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    else if (ch == SO)							      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* Switch to use GB2312, GB12345, CNS 11643 plane 1, or ISO-IR-165,   \
Packit Service 82fcde
	   depending on which S0 designation came last.  The only problem     \
Packit Service 82fcde
	   is what to do with faulty input files where no designator came.    \
Packit Service 82fcde
	   XXX For now I'll default to use GB2312.  If this is not the	      \
Packit Service 82fcde
	   best behavior (e.g., we should flag an error) let me know.  */     \
Packit Service 82fcde
	++inptr;							      \
Packit Service 82fcde
	if ((ann & SO_ann) != 0)					      \
Packit Service 82fcde
	  switch (ann & SO_ann)						      \
Packit Service 82fcde
	    {								      \
Packit Service 82fcde
	    case GB2312_ann:						      \
Packit Service 82fcde
	      set = GB2312_set;						      \
Packit Service 82fcde
	      break;							      \
Packit Service 82fcde
	    case GB12345_ann:						      \
Packit Service 82fcde
	      set = GB12345_set;					      \
Packit Service 82fcde
	      break;							      \
Packit Service 82fcde
	    case CNS11643_1_ann:					      \
Packit Service 82fcde
	      set = CNS11643_1_set;					      \
Packit Service 82fcde
	      break;							      \
Packit Service 82fcde
	    case ISO_IR_165_ann:					      \
Packit Service 82fcde
	      set = ISO_IR_165_set;					      \
Packit Service 82fcde
	      break;							      \
Packit Service 82fcde
	    default:							      \
Packit Service 82fcde
	      abort ();							      \
Packit Service 82fcde
	    }								      \
Packit Service 82fcde
	else								      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    STANDARD_FROM_LOOP_ERR_HANDLER (1);				      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	continue;							      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    else if (ch == SI)							      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* Switch to use ASCII.  */					      \
Packit Service 82fcde
	++inptr;							      \
Packit Service 82fcde
	set = ASCII_set;						      \
Packit Service 82fcde
	continue;							      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    if (ch == ESC && inptr[1] == SS2_1)					      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* This is a character from CNS 11643 plane 2.			      \
Packit Service 82fcde
	   XXX We could test here whether the use of this character	      \
Packit Service 82fcde
	   set was announced.						      \
Packit Service 82fcde
	   XXX Currently GB7589 and GB13131 are not supported.  */	      \
Packit Service 82fcde
	inptr += 2;							      \
Packit Service 82fcde
	ch = cns11643l2_to_ucs4 (&inptr, 2, 0);				      \
Packit Service 82fcde
	if (ch == __UNKNOWN_10646_CHAR)					      \
Packit Service 82fcde
	  STANDARD_FROM_LOOP_ERR_HANDLER (2);				      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    /* Note that we can assume here that at least 4 bytes are available if    \
Packit Service 82fcde
       the first byte is ESC since otherwise the first if would have been     \
Packit Service 82fcde
       true.  */							      \
Packit Service 82fcde
    else if (ch == ESC && inptr[1] == SS3_1)				      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* This is a character from CNS 11643 plane 3 or higher.	      \
Packit Service 82fcde
	   XXX Currently GB7590 and GB13132 are not supported.  */	      \
Packit Service 82fcde
	unsigned char buf[3];						      \
Packit Service 82fcde
	const unsigned char *tmp = buf;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	buf[1] = inptr[2];						      \
Packit Service 82fcde
	buf[2] = inptr[3];						      \
Packit Service 82fcde
	switch (ann & SS3_ann)						      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	  case CNS11643_3_ann:						      \
Packit Service 82fcde
	    buf[0] = 0x23;						      \
Packit Service 82fcde
	    ch = cns11643_to_ucs4 (&tmp, 3, 0);				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  case CNS11643_4_ann:						      \
Packit Service 82fcde
	    buf[0] = 0x24;						      \
Packit Service 82fcde
	    ch = cns11643_to_ucs4 (&tmp, 3, 0);				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  case CNS11643_5_ann:						      \
Packit Service 82fcde
	    buf[0] = 0x25;						      \
Packit Service 82fcde
	    ch = cns11643_to_ucs4 (&tmp, 3, 0);				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  case CNS11643_6_ann:						      \
Packit Service 82fcde
	    buf[0] = 0x26;						      \
Packit Service 82fcde
	    ch = cns11643_to_ucs4 (&tmp, 3, 0);				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  case CNS11643_7_ann:						      \
Packit Service 82fcde
	    buf[0] = 0x27;						      \
Packit Service 82fcde
	    ch = cns11643_to_ucs4 (&tmp, 3, 0);				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  default:							      \
Packit Service 82fcde
	    /* XXX Currently GB7590 and GB13132 are not supported.  */	      \
Packit Service 82fcde
	    ch = __UNKNOWN_10646_CHAR;					      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	if (ch == __UNKNOWN_10646_CHAR)					      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    STANDARD_FROM_LOOP_ERR_HANDLER (4);				      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	assert (tmp == buf + 3);					      \
Packit Service 82fcde
	inptr += 4;							      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    else if (set == ASCII_set)						      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* Almost done, just advance the input pointer.  */		      \
Packit Service 82fcde
	++inptr;							      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    else								      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	/* That's pretty easy, we have a dedicated functions for this.  */    \
Packit Service 82fcde
	if (inend - inptr < 2)						      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    result = __GCONV_INCOMPLETE_INPUT;				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	if (set == GB2312_set)						      \
Packit Service 82fcde
	  ch = gb2312_to_ucs4 (&inptr, inend - inptr, 0);		      \
Packit Service 82fcde
	else if (set == ISO_IR_165_set)					      \
Packit Service 82fcde
	  ch = isoir165_to_ucs4 (&inptr, inend - inptr);		      \
Packit Service 82fcde
	else								      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    assert (set == CNS11643_1_set);				      \
Packit Service 82fcde
	    ch = cns11643l1_to_ucs4 (&inptr, inend - inptr, 0);		      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	if (ch == 0)							      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    result = __GCONV_INCOMPLETE_INPUT;				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	else if (ch == __UNKNOWN_10646_CHAR)				      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    STANDARD_FROM_LOOP_ERR_HANDLER (2);				      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    *((uint32_t *) outptr) = ch;					      \
Packit Service 82fcde
    outptr += sizeof (uint32_t);					      \
Packit Service 82fcde
  }
Packit Service 82fcde
#define EXTRA_LOOP_DECLS	, int *setp
Packit Service 82fcde
#define INIT_PARAMS		int set = (*setp >> 3) & CURRENT_MASK; \
Packit Service 82fcde
				int ann = (*setp >> 3) & ~CURRENT_MASK
Packit Service 82fcde
#define UPDATE_PARAMS		*setp = (set | ann) << 3
Packit Service 82fcde
#define LOOP_NEED_FLAGS
Packit Service 82fcde
#include <iconv/loop.c>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Next, define the other direction.  */
Packit Service 82fcde
#define MIN_NEEDED_INPUT	TO_LOOP_MIN_NEEDED_FROM
Packit Service 82fcde
#define MAX_NEEDED_INPUT	TO_LOOP_MAX_NEEDED_FROM
Packit Service 82fcde
#define MIN_NEEDED_OUTPUT	TO_LOOP_MIN_NEEDED_TO
Packit Service 82fcde
#define MAX_NEEDED_OUTPUT	TO_LOOP_MAX_NEEDED_TO
Packit Service 82fcde
#define LOOPFCT			TO_LOOP
Packit Service 82fcde
/* With GCC 5.3 when compiling with -Os the compiler emits a warning
Packit Service 82fcde
   that buf[0] and buf[1] may be used uninitialized.  This can only
Packit Service 82fcde
   happen in the case where tmpbuf[3] is used, and in that case the
Packit Service 82fcde
   write to the tmpbuf[1] and tmpbuf[2] was assured because
Packit Service 82fcde
   ucs4_to_cns11643 would have filled in those entries.  The difficulty
Packit Service 82fcde
   is in getting the compiler to see this logic because tmpbuf[0] is
Packit Service 82fcde
   involved in determining the code page and is the indicator that
Packit Service 82fcde
   tmpbuf[2] is initialized.  */
Packit Service 82fcde
DIAG_PUSH_NEEDS_COMMENT;
Packit Service 82fcde
DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
Packit Service 82fcde
#define BODY \
Packit Service 82fcde
  {									      \
Packit Service 82fcde
    uint32_t ch;							      \
Packit Service 82fcde
    size_t written = 0;							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    ch = *((const uint32_t *) inptr);					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    /* First see whether we can write the character using the currently	      \
Packit Service 82fcde
       selected character set.  */					      \
Packit Service 82fcde
    if (ch < 0x80)							      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	if (set != ASCII_set)						      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    *outptr++ = SI;						      \
Packit Service 82fcde
	    set = ASCII_set;						      \
Packit Service 82fcde
	    if (outptr == outend)					      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		result = __GCONV_FULL_OUTPUT;				      \
Packit Service 82fcde
		break;							      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	*outptr++ = ch;							      \
Packit Service 82fcde
	written = 1;							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	/* At the end of the line we have to clear the `ann' flags since      \
Packit Service 82fcde
	   every line must contain this information again.  */		      \
Packit Service 82fcde
	if (ch == L'\n')						      \
Packit Service 82fcde
	  ann = 0;							      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
    else								      \
Packit Service 82fcde
      {									      \
Packit Service 82fcde
	unsigned char buf[2] = { 0, 0 };				      \
Packit Service 82fcde
	int used;							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	if (set == GB2312_set || ((ann & SO_ann) != CNS11643_1_ann	      \
Packit Service 82fcde
				  && (ann & SO_ann) != ISO_IR_165_ann))	      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    written = ucs4_to_gb2312 (ch, buf, 2);			      \
Packit Service 82fcde
	    used = GB2312_set;						      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	else if (set == ISO_IR_165_set || (ann & SO_ann) == ISO_IR_165_set)   \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    written = ucs4_to_isoir165 (ch, buf, 2);			      \
Packit Service 82fcde
	    used = ISO_IR_165_set;					      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	else								      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    written = ucs4_to_cns11643l1 (ch, buf, 2);			      \
Packit Service 82fcde
	    used = CNS11643_1_set;					      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	if (written == __UNKNOWN_10646_CHAR)				      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    /* Cannot convert it using the currently selected SO set.	      \
Packit Service 82fcde
	       Next try the SS2 set.  */				      \
Packit Service 82fcde
	    written = ucs4_to_cns11643l2 (ch, buf, 2);			      \
Packit Service 82fcde
	    if (written != __UNKNOWN_10646_CHAR)			      \
Packit Service 82fcde
	      /* Yep, that worked.  */					      \
Packit Service 82fcde
	      used = CNS11643_2_set;					      \
Packit Service 82fcde
	    else							      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		unsigned char tmpbuf[3];				      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		switch (0)						      \
Packit Service 82fcde
		  {							      \
Packit Service 82fcde
		  default:						      \
Packit Service 82fcde
		    /* Well, see whether we have to change the SO set.  */    \
Packit Service 82fcde
									      \
Packit Service 82fcde
		    if (used != GB2312_set)				      \
Packit Service 82fcde
		      {							      \
Packit Service 82fcde
			written = ucs4_to_gb2312 (ch, buf, 2);		      \
Packit Service 82fcde
			if (written != __UNKNOWN_10646_CHAR)		      \
Packit Service 82fcde
			  {						      \
Packit Service 82fcde
			    used = GB2312_set;				      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  }						      \
Packit Service 82fcde
		      }							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		    if (used != ISO_IR_165_set)				      \
Packit Service 82fcde
		      {							      \
Packit Service 82fcde
			written = ucs4_to_isoir165 (ch, buf, 2);	      \
Packit Service 82fcde
			if (written != __UNKNOWN_10646_CHAR)		      \
Packit Service 82fcde
			  {						      \
Packit Service 82fcde
			    used = ISO_IR_165_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  }						      \
Packit Service 82fcde
		      }							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		    if (used != CNS11643_1_set)				      \
Packit Service 82fcde
		      {							      \
Packit Service 82fcde
			written = ucs4_to_cns11643l1 (ch, buf, 2);	      \
Packit Service 82fcde
			if (written != __UNKNOWN_10646_CHAR)		      \
Packit Service 82fcde
			  {						      \
Packit Service 82fcde
			    used = CNS11643_1_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  }						      \
Packit Service 82fcde
		      }							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		    written = ucs4_to_cns11643 (ch, tmpbuf, 3);		      \
Packit Service 82fcde
		    if (written == 3 && tmpbuf[0] >= 3 && tmpbuf[0] <= 7)     \
Packit Service 82fcde
		      {							      \
Packit Service 82fcde
			buf[0] = tmpbuf[1];				      \
Packit Service 82fcde
			buf[1] = tmpbuf[2];				      \
Packit Service 82fcde
			switch (tmpbuf[0])				      \
Packit Service 82fcde
			  {						      \
Packit Service 82fcde
			  case 3:					      \
Packit Service 82fcde
			    used = CNS11643_3_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  case 4:					      \
Packit Service 82fcde
			    used = CNS11643_4_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  case 5:					      \
Packit Service 82fcde
			    used = CNS11643_5_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  case 6:					      \
Packit Service 82fcde
			    used = CNS11643_6_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  case 7:					      \
Packit Service 82fcde
			    used = CNS11643_7_set;			      \
Packit Service 82fcde
			    break;					      \
Packit Service 82fcde
			  default:					      \
Packit Service 82fcde
			    abort ();					      \
Packit Service 82fcde
			  }						      \
Packit Service 82fcde
			written = 2;					      \
Packit Service 82fcde
			break;						      \
Packit Service 82fcde
		      }							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		    /* XXX Currently GB7590 and GB13132 are not supported.  */\
Packit Service 82fcde
									      \
Packit Service 82fcde
		    /* Even this does not work.  Error.  */		      \
Packit Service 82fcde
		    used = ASCII_set;					      \
Packit Service 82fcde
		  }							      \
Packit Service 82fcde
		if (used == ASCII_set)					      \
Packit Service 82fcde
		  {							      \
Packit Service 82fcde
		    UNICODE_TAG_HANDLER (ch, 4);			      \
Packit Service 82fcde
		    STANDARD_TO_LOOP_ERR_HANDLER (4);			      \
Packit Service 82fcde
		  }							      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	assert (written == 2);						      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	/* See whether we have to emit an escape sequence.  */		      \
Packit Service 82fcde
	if (set != used)						      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    /* First see whether we announced that we use this		      \
Packit Service 82fcde
	       character set.  */					      \
Packit Service 82fcde
	    if ((used & SO_mask) != 0 && (ann & SO_ann) != (used << 8))	      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		const char *escseq;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		if (outptr + 4 > outend)				      \
Packit Service 82fcde
		  {							      \
Packit Service 82fcde
		    result = __GCONV_FULL_OUTPUT;			      \
Packit Service 82fcde
		    break;						      \
Packit Service 82fcde
		  }							      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		assert (used >= 1 && used <= 4);			      \
Packit Service 82fcde
		escseq = ")A\0\0)G)E" + (used - 1) * 2;			      \
Packit Service 82fcde
		*outptr++ = ESC;					      \
Packit Service 82fcde
		*outptr++ = '$';					      \
Packit Service 82fcde
		*outptr++ = *escseq++;					      \
Packit Service 82fcde
		*outptr++ = *escseq++;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		ann = (ann & ~SO_ann) | (used << 8);			      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	    else if ((used & SS2_mask) != 0 && (ann & SS2_ann) != (used << 8))\
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		const char *escseq;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		assert (used == CNS11643_2_set); /* XXX */		      \
Packit Service 82fcde
		escseq = "*H";						      \
Packit Service 82fcde
		*outptr++ = ESC;					      \
Packit Service 82fcde
		*outptr++ = '$';					      \
Packit Service 82fcde
		*outptr++ = *escseq++;					      \
Packit Service 82fcde
		*outptr++ = *escseq++;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		ann = (ann & ~SS2_ann) | (used << 8);			      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	    else if ((used & SS3_mask) != 0 && (ann & SS3_ann) != (used << 8))\
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		const char *escseq;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		assert ((used >> 5) >= 3 && (used >> 5) <= 7);		      \
Packit Service 82fcde
		escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2;		      \
Packit Service 82fcde
		*outptr++ = ESC;					      \
Packit Service 82fcde
		*outptr++ = '$';					      \
Packit Service 82fcde
		*outptr++ = *escseq++;					      \
Packit Service 82fcde
		*outptr++ = *escseq++;					      \
Packit Service 82fcde
									      \
Packit Service 82fcde
		ann = (ann & ~SS3_ann) | (used << 8);			      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	    if (used == CNS11643_2_set)					      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		if (outptr + 2 > outend)				      \
Packit Service 82fcde
		  {							      \
Packit Service 82fcde
		    result = __GCONV_FULL_OUTPUT;			      \
Packit Service 82fcde
		    break;						      \
Packit Service 82fcde
		  }							      \
Packit Service 82fcde
		*outptr++ = SS2_0;					      \
Packit Service 82fcde
		*outptr++ = SS2_1;					      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	    else if (used >= CNS11643_3_set && used <= CNS11643_7_set)	      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		if (outptr + 2 > outend)				      \
Packit Service 82fcde
		  {							      \
Packit Service 82fcde
		    result = __GCONV_FULL_OUTPUT;			      \
Packit Service 82fcde
		    break;						      \
Packit Service 82fcde
		  }							      \
Packit Service 82fcde
		*outptr++ = SS3_0;					      \
Packit Service 82fcde
		*outptr++ = SS3_1;					      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	    else							      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		/* We only have to emit something if currently ASCII is	      \
Packit Service 82fcde
		   selected.  Otherwise we are switching within the	      \
Packit Service 82fcde
		   SO charset.  */					      \
Packit Service 82fcde
		if (set == ASCII_set)					      \
Packit Service 82fcde
		  {							      \
Packit Service 82fcde
		    if (outptr + 1 > outend)				      \
Packit Service 82fcde
		      {							      \
Packit Service 82fcde
			result = __GCONV_FULL_OUTPUT;			      \
Packit Service 82fcde
			break;						      \
Packit Service 82fcde
		      }							      \
Packit Service 82fcde
		    *outptr++ = SO;					      \
Packit Service 82fcde
		  }							      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	    /* Always test the length here since we have used up all the      \
Packit Service 82fcde
	       guaranteed output buffer slots.  */			      \
Packit Service 82fcde
	    if (outptr + 2 > outend)					      \
Packit Service 82fcde
	      {								      \
Packit Service 82fcde
		result = __GCONV_FULL_OUTPUT;				      \
Packit Service 82fcde
		break;							      \
Packit Service 82fcde
	      }								      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
	else if (outptr + 2 > outend)					      \
Packit Service 82fcde
	  {								      \
Packit Service 82fcde
	    result = __GCONV_FULL_OUTPUT;				      \
Packit Service 82fcde
	    break;							      \
Packit Service 82fcde
	  }								      \
Packit Service 82fcde
									      \
Packit Service 82fcde
	*outptr++ = buf[0];						      \
Packit Service 82fcde
	*outptr++ = buf[1];						      \
Packit Service 82fcde
	set = used;							      \
Packit Service 82fcde
      }									      \
Packit Service 82fcde
									      \
Packit Service 82fcde
    /* Now that we wrote the output increment the input pointer.  */	      \
Packit Service 82fcde
    inptr += 4;								      \
Packit Service 82fcde
  }
Packit Service 82fcde
DIAG_POP_NEEDS_COMMENT;
Packit Service 82fcde
#define EXTRA_LOOP_DECLS	, int *setp
Packit Service 82fcde
#define INIT_PARAMS		int set = (*setp >> 3) & CURRENT_MASK; \
Packit Service 82fcde
				int ann = (*setp >> 3) & ~CURRENT_MASK
Packit Service 82fcde
#define REINIT_PARAMS		do					      \
Packit Service 82fcde
				  {					      \
Packit Service 82fcde
				    set = (*setp >> 3) & CURRENT_MASK;	      \
Packit Service 82fcde
				    ann = (*setp >> 3) & ~CURRENT_MASK;	      \
Packit Service 82fcde
				  }					      \
Packit Service 82fcde
				while (0)
Packit Service 82fcde
#define UPDATE_PARAMS		*setp = (set | ann) << 3
Packit Service 82fcde
#define LOOP_NEED_FLAGS
Packit Service 82fcde
#include <iconv/loop.c>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Now define the toplevel functions.  */
Packit Service 82fcde
#include <iconv/skeleton.c>