about summary refs log tree commit diff
path: root/iconvdata/iso-2022-jp-3.c
diff options
context:
space:
mode:
Diffstat (limited to 'iconvdata/iso-2022-jp-3.c')
-rw-r--r--iconvdata/iso-2022-jp-3.c793
1 files changed, 793 insertions, 0 deletions
diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
new file mode 100644
index 0000000000..29e7be93fc
--- /dev/null
+++ b/iconvdata/iso-2022-jp-3.c
@@ -0,0 +1,793 @@
+/* Conversion module for ISO-2022-JP-3.
+   Copyright (C) 1998-1999, 2000-2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
+   and Bruno Haible <bruno@clisp.org>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <gconv.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "jis0201.h"
+#include "jis0208.h"
+#include "jisx0213.h"
+
+/* This makes obvious what everybody knows: 0x1b is the Esc character.  */
+#define ESC 0x1b
+
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"ISO-2022-JP-3//"
+#define FROM_LOOP		from_iso2022jp3_loop
+#define TO_LOOP			to_iso2022jp3_loop
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define FROM_LOOP_MIN_NEEDED_FROM	1
+#define FROM_LOOP_MAX_NEEDED_FROM	4
+#define FROM_LOOP_MIN_NEEDED_TO		4
+#define FROM_LOOP_MAX_NEEDED_TO		8
+#define TO_LOOP_MIN_NEEDED_FROM		4
+#define TO_LOOP_MAX_NEEDED_FROM		4
+#define TO_LOOP_MIN_NEEDED_TO		1
+#define TO_LOOP_MAX_NEEDED_TO		6
+#define PREPARE_LOOP \
+  int saved_state;							      \
+  int *statep = &data->__statep->__count;
+#define EXTRA_LOOP_ARGS		, statep
+
+
+/* The COUNT element of the state keeps track of the currently selected
+   character set.  The possible values are:  */
+enum
+{
+  ASCII_set = 0,		/* Esc ( B */
+  JISX0208_1978_set = 1 << 3,	/* Esc $ @ */
+  JISX0208_1983_set = 2 << 3,	/* Esc $ B */
+  JISX0201_Roman_set = 3 << 3,	/* Esc ( J */
+  JISX0201_Kana_set = 4 << 3,	/* Esc ( I */
+  JISX0213_1_set = 5 << 3,	/* Esc $ ( O */
+  JISX0213_2_set = 6 << 3,	/* Esc $ ( P */
+  CURRENT_SEL_MASK = 7 << 3
+};
+
+/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
+   also contains the last two bytes to be output, shifted by 6 bits, and a
+   one-bit indicator whether they must be preceded by the shift sequence,
+   in bit 22.  */
+
+/* Since this is a stateful encoding we have to provide code which resets
+   the output state to the initial state.  This has to be done during the
+   flushing.  */
+#define EMIT_SHIFT_TO_INIT \
+  if ((data->__statep->__count & ~7) != ASCII_set)			      \
+    {									      \
+      if (FROM_DIRECTION)						      \
+	{								      \
+	  /* It's easy, we don't have to emit anything, we just reset the     \
+	     state for the input.  */					      \
+	  data->__statep->__count &= 7;					      \
+	  data->__statep->__count |= ASCII_set;				      \
+	}								      \
+      else								      \
+	{								      \
+	  /* We are not in the initial state.  To switch back we have	      \
+	     to write out the buffered character and/or emit the sequence     \
+	     `Esc ( B'.  */						      \
+	  size_t need =							      \
+	    (data->__statep->__count >> 6				      \
+	     ? (data->__statep->__count >> 22 ? 3 : 0) + 2		      \
+	     : 0)							      \
+	    + ((data->__statep->__count & CURRENT_SEL_MASK) != ASCII_set      \
+	       ? 3 : 0);						      \
+									      \
+	  if (__builtin_expect (outbuf + need > outend, 0))		      \
+	    /* We don't have enough room in the output buffer.  */	      \
+	    status = __GCONV_FULL_OUTPUT;				      \
+	  else								      \
+	    {								      \
+	      if (data->__statep->__count >> 6)				      \
+		{							      \
+		  uint32_t lasttwo = data->__statep->__count >> 6;	      \
+									      \
+		  if (lasttwo >> 16)					      \
+		    {							      \
+		      /* Write out the shift sequence before the last	      \
+			 character.  */					      \
+		      int set = data->__statep->__count & CURRENT_SEL_MASK;   \
+									      \
+		      assert (set == JISX0208_1983_set);		      \
+		      *outbuf++ = ESC;					      \
+		      *outbuf++ = '$';					      \
+		      *outbuf++ = 'B';					      \
+		    }							      \
+		  /* Write out the last character.  */			      \
+		  *outbuf++ = (lasttwo >> 8) & 0xff;			      \
+		  *outbuf++ = lasttwo & 0xff;				      \
+		}							      \
+	      if ((data->__statep->__count & CURRENT_SEL_MASK) != ASCII_set)  \
+		{							      \
+		  /* Write out the shift sequence.  */			      \
+		  *outbuf++ = ESC;					      \
+		  *outbuf++ = '(';					      \
+		  *outbuf++ = 'B';					      \
+		}							      \
+	      data->__statep->__count &= 7;				      \
+	      data->__statep->__count |= ASCII_set;			      \
+	    }								      \
+	}								      \
+    }
+
+
+/* Since we might have to reset input pointer we must be able to save
+   and retore the state.  */
+#define SAVE_RESET_STATE(Save) \
+  if (Save)								      \
+    saved_state = *statep;						      \
+  else									      \
+    *statep = saved_state
+
+
+/* First define the conversion function from ISO-2022-JP-3 to UCS-4.  */
+#define MIN_NEEDED_INPUT	FROM_LOOP_MIN_NEEDED_FROM
+#define MAX_NEEDED_INPUT	FROM_LOOP_MAX_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	FROM_LOOP_MIN_NEEDED_TO
+#define MAX_NEEDED_OUTPUT	FROM_LOOP_MAX_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    /* Recognize escape sequences.  */					      \
+    if (__builtin_expect (ch == ESC, 0))				      \
+      {									      \
+	/* We now must be prepared to read two to three more bytes.	      \
+	   If we have a match in the first byte but then the input buffer     \
+	   ends we terminate with an error since we must not risk missing     \
+	   an escape sequence just because it is not entirely in the	      \
+	   current input buffer.  */					      \
+	if (__builtin_expect (inptr + 2 >= inend, 0)			      \
+	    || (inptr[1] == '$' && inptr[2] == '('			      \
+		&& __builtin_expect (inptr + 3 >= inend, 0)))		      \
+	  {								      \
+	    /* Not enough input available.  */				      \
+	    result = __GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	if (inptr[1] == '(')						      \
+	  {								      \
+	    if (inptr[2] == 'B')					      \
+	      {								      \
+		/* ASCII selected.  */					      \
+		set = ASCII_set;					      \
+		inptr += 3;						      \
+		continue;						      \
+	      }								      \
+	    else if (inptr[2] == 'J')					      \
+	      {								      \
+		/* JIS X 0201 selected.  */				      \
+		set = JISX0201_Roman_set;				      \
+		inptr += 3;						      \
+		continue;						      \
+	      }								      \
+	    else if (inptr[2] == 'I')					      \
+	      {								      \
+		/* JIS X 0201 selected.  */				      \
+		set = JISX0201_Kana_set;				      \
+		inptr += 3;						      \
+		continue;						      \
+	      }								      \
+	  }								      \
+	else if (inptr[1] == '$')					      \
+	  {								      \
+	    if (inptr[2] == '@')					      \
+	      {								      \
+		/* JIS X 0208-1978 selected.  */			      \
+		set = JISX0208_1978_set;				      \
+		inptr += 3;						      \
+		continue;						      \
+	      }								      \
+	    else if (inptr[2] == 'B')					      \
+	      {								      \
+		/* JIS X 0208-1983 selected.  */			      \
+		set = JISX0208_1983_set;				      \
+		inptr += 3;						      \
+		continue;						      \
+	      }								      \
+	    else if (inptr[2] == '(')					      \
+	      {								      \
+		if (inptr[3] == 'O')					      \
+		  {							      \
+		    /* JIS X 0213 plane 1 selected.  */			      \
+		    set = JISX0213_1_set;				      \
+		    inptr += 4;						      \
+		    continue;						      \
+		  }							      \
+		else if (inptr[3] == 'P')				      \
+		  {							      \
+		    /* JIS X 0213 plane 2 selected.  */			      \
+		    set = JISX0213_2_set;				      \
+		    inptr += 4;						      \
+		    continue;						      \
+		  }							      \
+	      }								      \
+	  }								      \
+      }									      \
+									      \
+    if (ch >= 0x80)							      \
+      {									      \
+	if (! ignore_errors_p ())					      \
+	  {								      \
+	    result = __GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	++inptr;							      \
+	++*irreversible;						      \
+	continue;							      \
+      }									      \
+    else if (set == ASCII_set || (ch < 0x21 || ch == 0x7f))		      \
+      /* Almost done, just advance the input pointer.  */		      \
+      ++inptr;								      \
+    else if (set == JISX0201_Roman_set)					      \
+      {									      \
+	/* Use the JIS X 0201 table.  */				      \
+	ch = jisx0201_to_ucs4 (ch);					      \
+	if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))		      \
+	  {								      \
+	    if (! ignore_errors_p ())					      \
+	      {								      \
+		result = __GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    ++inptr;							      \
+	    ++*irreversible;						      \
+	    continue;							      \
+	  }								      \
+	++inptr;							      \
+      }									      \
+    else if (set == JISX0201_Kana_set)					      \
+      {									      \
+	/* Use the JIS X 0201 table.  */				      \
+	ch = jisx0201_to_ucs4 (ch + 0x80);				      \
+	if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))		      \
+	  {								      \
+	    if (! ignore_errors_p ())					      \
+	      {								      \
+		result = __GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    ++inptr;							      \
+	    ++*irreversible;						      \
+	    continue;							      \
+	  }								      \
+	++inptr;							      \
+      }									      \
+    else if (set == JISX0208_1978_set || set == JISX0208_1983_set)	      \
+      {									      \
+	/* XXX I don't have the tables for these two old variants of	      \
+	   JIS X 0208.  Therefore I'm using the tables for JIS X	      \
+	   0208-1990.  If somebody has problems with this please	      \
+	   provide the appropriate tables.  */				      \
+	ch = jisx0208_to_ucs4 (&inptr, inend - inptr, 0);		      \
+									      \
+	if (__builtin_expect (ch == 0, 0))				      \
+	  {								      \
+	    result = __GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+	else if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))	      \
+	  {								      \
+	    if (! ignore_errors_p ())					      \
+	      {								      \
+		result = __GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    ++inptr;							      \
+	    ++*irreversible;						      \
+	    continue;							      \
+	  }								      \
+      }									      \
+    else /* (set == JISX0213_1_set || set == JISX0213_2_set) */		      \
+      {									      \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
+	  {								      \
+	    result = __GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch = jisx0213_to_ucs4 (((set - JISX0213_1_set + (1 << 3)) << 5) + ch, \
+			       inptr[1]);				      \
+	if (ch == 0)							      \
+	  {								      \
+	    if (! ignore_errors_p ())					      \
+	      {								      \
+		result = __GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    ++inptr;							      \
+	    ++*irreversible;						      \
+	    continue;							      \
+	  }								      \
+									      \
+	if (ch < 0x80)							      \
+	  {								      \
+	    /* It's a combining character.  */				      \
+	    uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0];	      \
+	    uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1];	      \
+									      \
+	    /* See whether we have room for two characters.  */		      \
+	    if (outptr + 8 <= outend)					      \
+	      {								      \
+		inptr += 2;						      \
+		put32 (outptr, u1);					      \
+		outptr += 4;						      \
+		put32 (outptr, u2);					      \
+		outptr += 4;						      \
+		continue;						      \
+	      }								      \
+	    else							      \
+	      {								      \
+		result = __GCONV_FULL_OUTPUT;				      \
+		break;							      \
+	      }								      \
+	  }								      \
+									      \
+	inptr += 2;							      \
+      }									      \
+									      \
+    put32 (outptr, ch);							      \
+    outptr += 4;							      \
+  }
+#define LOOP_NEED_FLAGS
+#define EXTRA_LOOP_DECLS	, int *statep
+#define INIT_PARAMS		int set = *statep
+#define UPDATE_PARAMS		*statep = set
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction, from UCS-4 to ISO-2022-JP-3.  */
+
+/* Composition tables for each of the relevant combining characters.  */
+static const struct
+{
+  uint16_t base;
+  uint16_t composed;
+} comp_table_data[] =
+{
+#define COMP_TABLE_IDX_02E5 0
+#define COMP_TABLE_LEN_02E5 1
+  { 0x2b64, 0x2b65 }, /* 0x12B65 = 0x12B64 U+02E5 */
+#define COMP_TABLE_IDX_02E9 (COMP_TABLE_IDX_02E5 + COMP_TABLE_LEN_02E5)
+#define COMP_TABLE_LEN_02E9 1
+  { 0x2b60, 0x2b66 }, /* 0x12B66 = 0x12B60 U+02E9 */
+#define COMP_TABLE_IDX_0300 (COMP_TABLE_IDX_02E9 + COMP_TABLE_LEN_02E9)
+#define COMP_TABLE_LEN_0300 5
+  { 0x295c, 0x2b44 }, /* 0x12B44 = 0x1295C U+0300 */
+  { 0x2b38, 0x2b48 }, /* 0x12B48 = 0x12B38 U+0300 */
+  { 0x2b37, 0x2b4a }, /* 0x12B4A = 0x12B37 U+0300 */
+  { 0x2b30, 0x2b4c }, /* 0x12B4C = 0x12B30 U+0300 */
+  { 0x2b43, 0x2b4e }, /* 0x12B4E = 0x12B43 U+0300 */
+#define COMP_TABLE_IDX_0301 (COMP_TABLE_IDX_0300 + COMP_TABLE_LEN_0300)
+#define COMP_TABLE_LEN_0301 4
+  { 0x2b38, 0x2b49 }, /* 0x12B49 = 0x12B38 U+0301 */
+  { 0x2b37, 0x2b4b }, /* 0x12B4B = 0x12B37 U+0301 */
+  { 0x2b30, 0x2b4d }, /* 0x12B4D = 0x12B30 U+0301 */
+  { 0x2b43, 0x2b4f }, /* 0x12B4F = 0x12B43 U+0301 */
+#define COMP_TABLE_IDX_309A (COMP_TABLE_IDX_0301 + COMP_TABLE_LEN_0301)
+#define COMP_TABLE_LEN_309A 14
+  { 0x242b, 0x2477 }, /* 0x12477 = 0x1242B U+309A */
+  { 0x242d, 0x2478 }, /* 0x12478 = 0x1242D U+309A */
+  { 0x242f, 0x2479 }, /* 0x12479 = 0x1242F U+309A */
+  { 0x2431, 0x247a }, /* 0x1247A = 0x12431 U+309A */
+  { 0x2433, 0x247b }, /* 0x1247B = 0x12433 U+309A */
+  { 0x252b, 0x2577 }, /* 0x12577 = 0x1252B U+309A */
+  { 0x252d, 0x2578 }, /* 0x12578 = 0x1252D U+309A */
+  { 0x252f, 0x2579 }, /* 0x12579 = 0x1252F U+309A */
+  { 0x2531, 0x257a }, /* 0x1257A = 0x12531 U+309A */
+  { 0x2533, 0x257b }, /* 0x1257B = 0x12533 U+309A */
+  { 0x253b, 0x257c }, /* 0x1257C = 0x1253B U+309A */
+  { 0x2544, 0x257d }, /* 0x1257D = 0x12544 U+309A */
+  { 0x2548, 0x257e }, /* 0x1257E = 0x12548 U+309A */
+  { 0x2675, 0x2678 }, /* 0x12678 = 0x12675 U+309A */
+};
+
+#define MIN_NEEDED_INPUT	TO_LOOP_MIN_NEEDED_FROM
+#define MAX_NEEDED_INPUT	TO_LOOP_MAX_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	TO_LOOP_MIN_NEEDED_TO
+#define MAX_NEEDED_OUTPUT	TO_LOOP_MAX_NEEDED_TO
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = get32 (inptr);					      \
+									      \
+    if (lasttwo != 0)							      \
+      {									      \
+	/* Attempt to combine the last character with this one.  */	      \
+	unsigned int idx;						      \
+	unsigned int len;						      \
+									      \
+	if (ch == 0x02e5)						      \
+	  idx = COMP_TABLE_IDX_02E5, len = COMP_TABLE_LEN_02E5;		      \
+	else if (ch == 0x02e9)						      \
+	  idx = COMP_TABLE_IDX_02E9, len = COMP_TABLE_LEN_02E9;		      \
+	else if (ch == 0x0300)						      \
+	  idx = COMP_TABLE_IDX_0300, len = COMP_TABLE_LEN_0300;		      \
+	else if (ch == 0x0301)						      \
+	  idx = COMP_TABLE_IDX_0301, len = COMP_TABLE_LEN_0301;		      \
+	else if (ch == 0x309a)						      \
+	  idx = COMP_TABLE_IDX_309A, len = COMP_TABLE_LEN_309A;		      \
+	else								      \
+	  goto not_combining;						      \
+									      \
+	do								      \
+	  if (comp_table_data[idx].base == (uint16_t) lasttwo)		      \
+	    break;							      \
+	while (++idx, --len > 0);					      \
+									      \
+	if (len > 0)							      \
+	  {								      \
+	    /* Output the combined character.  */			      \
+	    /* We know the combined character is in JISX0213 plane 1,	      \
+	       but the buffered character may have been in JISX0208 or in     \
+	       JISX0213 plane 1.  */					      \
+	    size_t need = (lasttwo >> 16 || set != JISX0213_1_set ? 4 : 0);   \
+									      \
+	    if (__builtin_expect (outptr + need + 2 > outend, 0))	      \
+	      {								      \
+		result = __GCONV_FULL_OUTPUT;				      \
+		break;							      \
+	      }								      \
+	    if (need)							      \
+	      {								      \
+		/* But first, output the escape sequence.  */		      \
+		*outptr++ = ESC;					      \
+		*outptr++ = '$';					      \
+		*outptr++ = '(';					      \
+		*outptr++ = 'O';					      \
+		set = JISX0213_1_set;					      \
+	      }								      \
+	    lasttwo = comp_table_data[idx].composed;			      \
+	    *outptr++ = (lasttwo >> 8) & 0xff;				      \
+	    *outptr++ = lasttwo & 0xff;					      \
+	    lasttwo = 0;						      \
+	    inptr += 4;							      \
+	    continue;							      \
+	  }								      \
+									      \
+      not_combining:							      \
+	/* Output the buffered character.  */				      \
+	/* We know it is in JISX0208 or in JISX0213 plane 1.  */	      \
+	{								      \
+	  size_t need = (lasttwo >> 16 ? 3 : 0);			      \
+									      \
+	  if (__builtin_expect (outptr + need + 2 > outend, 0))		      \
+	    {								      \
+	      result = __GCONV_FULL_OUTPUT;				      \
+	      break;							      \
+	    }								      \
+	  if (need)							      \
+	    {								      \
+	      /* But first, output the escape sequence.  */		      \
+	      assert (set == JISX0208_1983_set);			      \
+	      *outptr++ = ESC;						      \
+	      *outptr++ = '$';						      \
+	      *outptr++ = 'B';						      \
+	    }								      \
+	  *outptr++ = (lasttwo >> 8) & 0xff;				      \
+	  *outptr++ = lasttwo & 0xff;					      \
+	  lasttwo = 0;							      \
+	  continue;							      \
+	}								      \
+      }									      \
+									      \
+    /* First see whether we can write the character using the currently	      \
+       selected character set.  */					      \
+    if (set == ASCII_set)						      \
+      {									      \
+	/* Please note that the NUL byte is *not* matched if we are not	      \
+	   currently using the ASCII charset.  This is because we must	      \
+	   switch to the initial state whenever a NUL byte is written.  */    \
+	if (ch <= 0x7f)							      \
+	  {								      \
+	    *outptr++ = ch;						      \
+	    inptr += 4;							      \
+	    continue;							      \
+	  }								      \
+      }									      \
+    /* ISO-2022-JP recommends to encode the newline character always in	      \
+       ASCII since this allows a context-free interpretation of the	      \
+       characters at the beginning of the next line.  Otherwise it would      \
+       have to be known whether the last line ended using ASCII or	      \
+       JIS X 0201.  */							      \
+    else if (set == JISX0201_Roman_set)					      \
+      {									      \
+	unsigned char buf[1];						      \
+	if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR		      \
+	    && buf[0] > 0x20 && buf[0] < 0x80)				      \
+	  {								      \
+	    *outptr++ = buf[0];						      \
+	    inptr += 4;							      \
+	    continue;							      \
+	  }								      \
+      }									      \
+    else if (set == JISX0201_Kana_set)					      \
+      {									      \
+	unsigned char buf[1];						      \
+	if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR		      \
+	    && buf[0] >= 0x80)						      \
+	  {								      \
+	    *outptr++ = buf[0] - 0x80;					      \
+	    inptr += 4;							      \
+	    continue;							      \
+	  }								      \
+      }									      \
+    else if (/*set == JISX0208_1978_set || */ set == JISX0208_1983_set)	      \
+      {									      \
+	size_t written = ucs4_to_jisx0208 (ch, outptr, outend - outptr);      \
+									      \
+	if (written != __UNKNOWN_10646_CHAR)				      \
+	  {								      \
+	    uint32_t jch = ucs4_to_jisx0213 (ch);			      \
+									      \
+	    if (jch & 0x0080)						      \
+	      {								      \
+		/* A possible match in comp_table_data.  Buffer it.  */	      \
+		lasttwo = jch & 0x7f7f;					      \
+		inptr += 4;						      \
+		continue;						      \
+	      }								      \
+	    if (__builtin_expect (written == 0, 0))			      \
+	      {								      \
+		result = __GCONV_FULL_OUTPUT;				      \
+		break;							      \
+	      }								      \
+	    else							      \
+	      {								      \
+	 	outptr += written;					      \
+		inptr += 4;						      \
+		continue;						      \
+	     }								      \
+	  }								      \
+      }									      \
+    else								      \
+      {									      \
+	/* (set == JISX0213_1_set || set == JISX0213_2_set) */		      \
+	uint32_t jch = ucs4_to_jisx0213 (ch);				      \
+									      \
+	if (jch != 0							      \
+	    && (set == (jch & 0x8000 ? JISX0213_2_set : JISX0213_1_set)))     \
+	  {								      \
+	    if (jch & 0x0080)						      \
+	      {								      \
+		/* A possible match in comp_table_data.  Buffer it.  */	      \
+									      \
+		/* We know it's a JISX 0213 plane 1 character.  */	      \
+		assert ((jch & 0x8000) == 0);				      \
+									      \
+		lasttwo = jch & 0x7f7f;					      \
+		inptr += 4;						      \
+		continue;						      \
+	      }								      \
+									      \
+	    if (__builtin_expect (outptr + 1 >= outend, 0))		      \
+	      {								      \
+		result = __GCONV_FULL_OUTPUT;				      \
+		break;							      \
+	      }								      \
+	    *outptr++ = (jch >> 8) & 0x7f;				      \
+	    *outptr++ = jch & 0x7f;					      \
+	    inptr += 4;							      \
+	    continue;							      \
+	  }								      \
+      }									      \
+									      \
+    /* The attempts to use the currently selected character set failed,	      \
+       either because the character requires a different character set,	      \
+       or because the character is unknown.  */				      \
+									      \
+    if (ch <= 0x7f)							      \
+      {									      \
+	/* We must encode using ASCII.  First write out the escape	      \
+	   sequence.  */						      \
+	if (__builtin_expect (outptr + 3 > outend, 0))			      \
+	  {								      \
+	    result = __GCONV_FULL_OUTPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	*outptr++ = ESC;						      \
+	*outptr++ = '(';						      \
+	*outptr++ = 'B';						      \
+	set = ASCII_set;						      \
+									      \
+	if (__builtin_expect (outptr >= outend, 0))			      \
+	  {								      \
+	    result = __GCONV_FULL_OUTPUT;				      \
+	    break;							      \
+	  }								      \
+	*outptr++ = ch;							      \
+      }									      \
+    else								      \
+      {									      \
+	unsigned char buf[2];						      \
+									      \
+	/* Try JIS X 0201 Roman.  */					      \
+	if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR		      \
+	    && buf[0] > 0x20 && buf[0] < 0x80)				      \
+	  {								      \
+	    if (set != JISX0201_Roman_set)				      \
+	      {								      \
+		if (__builtin_expect (outptr + 3 > outend, 0))		      \
+		  {							      \
+		    result = __GCONV_FULL_OUTPUT;			      \
+		    break;						      \
+		  }							      \
+		*outptr++ = ESC;					      \
+		*outptr++ = '(';					      \
+		*outptr++ = 'J';					      \
+		set = JISX0201_Roman_set;				      \
+	      }								      \
+									      \
+	    if (__builtin_expect (outptr >= outend, 0))			      \
+	      {								      \
+		result = __GCONV_FULL_OUTPUT;				      \
+		break;							      \
+	      }								      \
+	    *outptr++ = buf[0];						      \
+	  }								      \
+	else								      \
+	  {								      \
+	    uint32_t jch = ucs4_to_jisx0213 (ch);			      \
+									      \
+	    /* Try JIS X 0208.  */					      \
+	    size_t written = ucs4_to_jisx0208 (ch, buf, 2);		      \
+	    if (written != __UNKNOWN_10646_CHAR)			      \
+	      {								      \
+		if (jch & 0x0080)					      \
+		  {							      \
+		    /* A possible match in comp_table_data.  Buffer it.  */   \
+		    lasttwo = ((set != JISX0208_1983_set ? 1 : 0) << 16)      \
+			      | (jch & 0x7f7f);				      \
+		    set = JISX0208_1983_set;				      \
+		    inptr += 4;						      \
+		    continue;						      \
+		  }							      \
+									      \
+		if (set != JISX0208_1983_set)				      \
+		  {							      \
+		    if (__builtin_expect (outptr + 3 > outend, 0))	      \
+		      {							      \
+			result = __GCONV_FULL_OUTPUT;			      \
+			break;						      \
+		      }							      \
+		    *outptr++ = ESC;					      \
+		    *outptr++ = '$';					      \
+		    *outptr++ = 'B';					      \
+		    set = JISX0208_1983_set;				      \
+		  }							      \
+									      \
+		if (__builtin_expect (outptr + 2 > outend, 0))		      \
+		  {							      \
+		    result = __GCONV_FULL_OUTPUT;			      \
+		    break;						      \
+		  }							      \
+		*outptr++ = buf[0];					      \
+		*outptr++ = buf[1];					      \
+	      }								      \
+	    else							      \
+	      {								      \
+		/* Try JIS X 0213.  */					      \
+		if (jch != 0)						      \
+		  {							      \
+		    int new_set =					      \
+		      (jch & 0x8000 ? JISX0213_2_set : JISX0213_1_set);	      \
+									      \
+		    if (set != new_set)					      \
+		      {							      \
+			if (__builtin_expect (outptr + 4 > outend, 0))	      \
+			  {						      \
+			    result = __GCONV_FULL_OUTPUT;		      \
+			    break;					      \
+			  }						      \
+			*outptr++ = ESC;				      \
+			*outptr++ = '$';				      \
+			*outptr++ = '(';				      \
+			*outptr++ = ((new_set - JISX0213_1_set) >> 3) + 'O';  \
+			set = new_set;					      \
+		      }							      \
+									      \
+		    if (jch & 0x0080)					      \
+		      {							      \
+			/* A possible match in comp_table_data.		      \
+			   Buffer it.  */				      \
+									      \
+			/* We know it's a JIS X 0213 plane 1 character.  */   \
+			assert ((jch & 0x8000) == 0);			      \
+									      \
+			lasttwo = jch & 0x7f7f;				      \
+			inptr += 4;					      \
+			continue;					      \
+		      }							      \
+									      \
+		    if (__builtin_expect (outptr + 1 >= outend, 0))	      \
+		      {							      \
+			result = __GCONV_FULL_OUTPUT;			      \
+			break;						      \
+		      }							      \
+		    *outptr++ = (jch >> 8) & 0x7f;			      \
+		    *outptr++ = jch & 0x7f;				      \
+		  }							      \
+		else							      \
+		  {							      \
+		    /* Try JIS X 0201 Katakana.  This is officially not part  \
+		       of ISO-2022-JP-3.  Therefore we try it after all other \
+		       attempts.  */					      \
+		    if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR    \
+			&& buf[0] >= 0x80)				      \
+		      {							      \
+			if (set != JISX0201_Kana_set)			      \
+			  {						      \
+			    if (__builtin_expect (outptr + 3 > outend, 0))    \
+			      {						      \
+				result = __GCONV_FULL_OUTPUT;		      \
+				break;					      \
+			      }						      \
+			    *outptr++ = ESC;				      \
+			    *outptr++ = '(';				      \
+			    *outptr++ = 'I';				      \
+			    set = JISX0201_Kana_set;			      \
+			  }						      \
+									      \
+			if (__builtin_expect (outptr >= outend, 0))	      \
+			  {						      \
+			    result = __GCONV_FULL_OUTPUT;		      \
+			    break;					      \
+			  }						      \
+			*outptr++ = buf[0] - 0x80;			      \
+		      }							      \
+		    else						      \
+		      {							      \
+			UNICODE_TAG_HANDLER (ch, 4);			      \
+									      \
+			/* Illegal character.  */			      \
+			STANDARD_ERR_HANDLER (4);			      \
+		      }							      \
+		  }							      \
+	      }								      \
+	  }								      \
+      }									      \
+									      \
+    /* Now that we wrote the output increment the input pointer.  */	      \
+    inptr += 4;								      \
+  }
+#define LOOP_NEED_FLAGS
+#define EXTRA_LOOP_DECLS	, int *statep
+#define INIT_PARAMS		int set = *statep & CURRENT_SEL_MASK;	      \
+				uint32_t lasttwo = *statep >> 6
+#define UPDATE_PARAMS		*statep = set | (lasttwo << 6)
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>