]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - iconvdata/iso-2022-jp.c
Update copyright notices with scripts/update-copyrights.
[thirdparty/glibc.git] / iconvdata / iso-2022-jp.c
index 9b22ddd6b398bc5e40acf7fe1dab73aacd5db509..ce66121380559e1a513e3b2cb11b78a8e9c34255 100644 (file)
@@ -1,23 +1,24 @@
-/* Conversion module for ISO-2022-JP.
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Conversion module for ISO-2022-JP and ISO-2022-JP-2.
+   Copyright (C) 1998-2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
+   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
-   Library General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
+#include <assert.h>
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -47,10 +48,14 @@ struct gap
 /* Definitions used in the body of the `gconv' function.  */
 #define FROM_LOOP              from_iso2022jp_loop
 #define TO_LOOP                        to_iso2022jp_loop
-#define MIN_NEEDED_FROM                1
-#define MAX_NEEDED_FROM                4
-#define MIN_NEEDED_TO          4
-#define MAX_NEEDED_TO          4
+#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                4
+#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 FROM_DIRECTION         (dir == from_iso2022jp)
 #define PREPARE_LOOP \
   enum direction dir = ((struct iso2022jp_data *) step->__data)->dir;        \
@@ -89,14 +94,14 @@ struct iso2022jp_data
 enum
 {
   ASCII_set = 0,
-  JISX0208_1978_set = 8,
-  JISX0208_1983_set = 16,
-  JISX0201_Roman_set = 24,
-  JISX0201_Kana_set = 32,
-  GB2312_set = 40,
-  KSC5601_set = 48,
-  JISX0212_set = 56,
-  CURRENT_SEL_MASK = 56
+  JISX0208_1978_set = 1 << 3,
+  JISX0208_1983_set = 2 << 3,
+  JISX0201_Roman_set = 3 << 3,
+  JISX0201_Kana_set = 4 << 3,
+  GB2312_set = 5 << 3,
+  KSC5601_set = 6 << 3,
+  JISX0212_set = 7 << 3,
+  CURRENT_SEL_MASK = 7 << 3
 };
 
 /* The second value stored is the designation of the G2 set.  The following
@@ -104,12 +109,29 @@ enum
 enum
 {
   UNSPECIFIED_set = 0,
-  ISO88591_set = 64,
-  ISO88597_set = 128,
-  CURRENT_ASSIGN_MASK = 192
+  ISO88591_set = 1 << 6,
+  ISO88597_set = 2 << 6,
+  CURRENT_ASSIGN_MASK = 3 << 6
 };
 
+/* The third value, only used during conversion from Unicode to ISO-2022-JP-2,
+   describes the language tag parsing status.  The possible values are as
+   follows.  Values >= TAG_language are temporary tag parsing states.  */
+enum
+{
+  TAG_none = 0,
+  TAG_language = 4 << 8,
+  TAG_language_j = 5 << 8,
+  TAG_language_ja = 1 << 8,
+  TAG_language_k = 6 << 8,
+  TAG_language_ko = 2 << 8,
+  TAG_language_z = 7 << 8,
+  TAG_language_zh = 3 << 8,
+  CURRENT_TAG_MASK = 7 << 8
+};
 
+
+extern int gconv_init (struct __gconv_step *step);
 int
 gconv_init (struct __gconv_step *step)
 {
@@ -155,17 +177,17 @@ gconv_init (struct __gconv_step *step)
 
          if (dir == from_iso2022jp)
            {
-             step->__min_needed_from = MIN_NEEDED_FROM;
-             step->__max_needed_from = MAX_NEEDED_FROM;
-             step->__min_needed_to = MIN_NEEDED_TO;
-             step->__max_needed_to = MAX_NEEDED_TO;
+             step->__min_needed_from = FROM_LOOP_MIN_NEEDED_FROM;
+             step->__max_needed_from = FROM_LOOP_MAX_NEEDED_FROM;
+             step->__min_needed_to = FROM_LOOP_MIN_NEEDED_TO;
+             step->__max_needed_to = FROM_LOOP_MAX_NEEDED_TO;
            }
          else
            {
-             step->__min_needed_from = MIN_NEEDED_TO;
-             step->__max_needed_from = MAX_NEEDED_TO;
-             step->__min_needed_to = MIN_NEEDED_FROM;
-             step->__max_needed_to = MAX_NEEDED_FROM + 2;
+             step->__min_needed_from = TO_LOOP_MIN_NEEDED_FROM;
+             step->__max_needed_from = TO_LOOP_MAX_NEEDED_FROM;
+             step->__min_needed_to = TO_LOOP_MIN_NEEDED_TO;
+             step->__max_needed_to = TO_LOOP_MAX_NEEDED_TO;
            }
 
          /* Yes, this is a stateful encoding.  */
@@ -179,6 +201,7 @@ gconv_init (struct __gconv_step *step)
 }
 
 
+extern void gconv_end (struct __gconv_step *data);
 void
 gconv_end (struct __gconv_step *data)
 {
@@ -190,11 +213,13 @@ gconv_end (struct __gconv_step *data)
    the output state to the initial state.  This has to be done during the
    flushing.  */
 #define EMIT_SHIFT_TO_INIT \
+  /* Avoid warning about unused variable 'var'.  */                          \
+  (void) var;                                                                \
+                                                                             \
   if ((data->__statep->__count & ~7) != ASCII_set)                           \
     {                                                                        \
-      enum direction dir = ((struct iso2022jp_data *) step->__data)->dir;     \
-                                                                             \
-      if (dir == from_iso2022jp)                                             \
+      if (dir == from_iso2022jp                                                      \
+         || (data->__statep->__count & CURRENT_SEL_MASK) == ASCII_set)       \
        {                                                                     \
          /* It's easy, we don't have to emit anything, we just reset the     \
             state for the input.  Note that this also clears the G2          \
@@ -204,11 +229,9 @@ gconv_end (struct __gconv_step *data)
        }                                                                     \
       else                                                                   \
        {                                                                     \
-         unsigned char *outbuf = data->__outbuf;                             \
-                                                                             \
          /* We are not in the initial state.  To switch back we have         \
             to emit the sequence `Esc ( B'.  */                              \
-         if (__builtin_expect (outbuf + 3 > data->__outbufend, 0))           \
+         if (__builtin_expect (outbuf + 3 > outend, 0))                      \
            /* We don't have enough room in the output buffer.  */            \
            status = __GCONV_FULL_OUTPUT;                                     \
          else                                                                \
@@ -217,9 +240,8 @@ gconv_end (struct __gconv_step *data)
              *outbuf++ = ESC;                                                \
              *outbuf++ = '(';                                                \
              *outbuf++ = 'B';                                                \
-             data->__outbuf = outbuf;                                        \
              /* Note that this also clears the G2 designation.  */           \
-             data->__statep->__count &= ~7;                                  \
+             data->__statep->__count &= 7;                                   \
              data->__statep->__count |= ASCII_set;                           \
            }                                                                 \
        }                                                                     \
@@ -236,9 +258,10 @@ gconv_end (struct __gconv_step *data)
 
 
 /* First define the conversion function from ISO-2022-JP to UCS4.  */
-#define MIN_NEEDED_INPUT       MIN_NEEDED_FROM
-#define MAX_NEEDED_INPUT       MAX_NEEDED_FROM
-#define MIN_NEEDED_OUTPUT      MIN_NEEDED_TO
+#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 \
   {                                                                          \
@@ -257,7 +280,7 @@ gconv_end (struct __gconv_step *data)
                && __builtin_expect (inptr + 3 >= inend, 0)))                 \
          {                                                                   \
            /* Not enough input available.  */                                \
-           result = __GCONV_EMPTY_INPUT;                                     \
+           result = __GCONV_INCOMPLETE_INPUT;                                \
            break;                                                            \
          }                                                                   \
                                                                              \
@@ -358,46 +381,22 @@ gconv_end (struct __gconv_step *data)
        else if (__builtin_expect (set2, ISO88597_set) == ISO88597_set)       \
          {                                                                   \
            /* We use the table from the ISO 8859-7 module.  */               \
-           if (inptr[2] < 0x20 || inptr[2] > 0x80)                           \
-             {                                                               \
-               if (! ignore_errors_p ())                                     \
-                 {                                                           \
-                   result = __GCONV_ILLEGAL_INPUT;                           \
-                   break;                                                    \
-                 }                                                           \
-                                                                             \
-               ++inptr;                                                      \
-               ++*irreversible;                                              \
-               continue;                                                     \
-             }                                                               \
+           if (inptr[2] < 0x20 || inptr[2] >= 0x80)                          \
+             STANDARD_FROM_LOOP_ERR_HANDLER (1);                             \
            ch = iso88597_to_ucs4[inptr[2] - 0x20];                           \
            if (ch == 0)                                                      \
-             {                                                               \
-               if (! ignore_errors_p ())                                     \
-                 {                                                           \
-                   result = __GCONV_ILLEGAL_INPUT;                           \
-                   break;                                                    \
-                 }                                                           \
-                                                                             \
-               inptr += 3;                                                   \
-               ++*irreversible;                                              \
-               continue;                                                     \
-             }                                                               \
+             STANDARD_FROM_LOOP_ERR_HANDLER (3);                             \
            inptr += 3;                                                       \
          }                                                                   \
        else                                                                  \
          {                                                                   \
-           if (! ignore_errors_p ())                                         \
-             {                                                               \
-               result = __GCONV_ILLEGAL_INPUT;                               \
-               break;                                                        \
-             }                                                               \
-                                                                             \
-           ++inptr;                                                          \
-           ++*irreversible;                                                  \
-           continue;                                                         \
+           STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
          }                                                                   \
       }                                                                              \
+    else if (ch >= 0x80)                                                     \
+      {                                                                              \
+       STANDARD_FROM_LOOP_ERR_HANDLER (1);                                   \
+      }                                                                              \
     else if (set == ASCII_set || (ch < 0x21 || ch == 0x7f))                  \
       /* Almost done, just advance the input pointer.  */                    \
       ++inptr;                                                               \
@@ -405,36 +404,16 @@ gconv_end (struct __gconv_step *data)
       {                                                                              \
        /* Use the JIS X 0201 table.  */                                      \
        ch = jisx0201_to_ucs4 (ch);                                           \
-       if (__builtin_expect (ch, 0) == __UNKNOWN_10646_CHAR)                 \
-         {                                                                   \
-           if (! ignore_errors_p ())                                         \
-             {                                                               \
-               result = __GCONV_ILLEGAL_INPUT;                               \
-               break;                                                        \
-             }                                                               \
-                                                                             \
-           ++inptr;                                                          \
-           ++*irreversible;                                                  \
-           continue;                                                         \
-         }                                                                   \
+       if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))                 \
+         STANDARD_FROM_LOOP_ERR_HANDLER (1);                                 \
        ++inptr;                                                              \
       }                                                                              \
     else if (set == JISX0201_Kana_set)                                       \
       {                                                                              \
        /* Use the JIS X 0201 table.  */                                      \
        ch = jisx0201_to_ucs4 (ch + 0x80);                                    \
-       if (__builtin_expect (ch, 0) == __UNKNOWN_10646_CHAR)                 \
-         {                                                                   \
-           if (! ignore_errors_p ())                                         \
-             {                                                               \
-               result = __GCONV_ILLEGAL_INPUT;                               \
-               break;                                                        \
-             }                                                               \
-                                                                             \
-           ++inptr;                                                          \
-           ++*irreversible;                                                  \
-           continue;                                                         \
-         }                                                                   \
+       if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))                 \
+         STANDARD_FROM_LOOP_ERR_HANDLER (1);                                 \
        ++inptr;                                                              \
       }                                                                              \
     else                                                                     \
@@ -444,47 +423,36 @@ gconv_end (struct __gconv_step *data)
             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,                                      \
-                                NEED_LENGTH_TEST ? inend - inptr : 2, 0);    \
+         ch = jisx0208_to_ucs4 (&inptr, inend - inptr, 0);                   \
        else if (set == JISX0212_set)                                         \
          /* Use the JIS X 0212 table.  */                                    \
-         ch = jisx0212_to_ucs4 (&inptr,                                      \
-                                NEED_LENGTH_TEST ? inend - inptr : 2, 0);    \
+         ch = jisx0212_to_ucs4 (&inptr, inend - inptr, 0);                   \
        else if (set == GB2312_set)                                           \
          /* Use the GB 2312 table.  */                                       \
-         ch = gb2312_to_ucs4 (&inptr,                                        \
-                              NEED_LENGTH_TEST ? inend - inptr : 2, 0);      \
+         ch = gb2312_to_ucs4 (&inptr, inend - inptr, 0);                     \
        else                                                                  \
          {                                                                   \
            assert (set == KSC5601_set);                                      \
                                                                              \
            /* Use the KSC 5601 table.  */                                    \
-           ch = ksc5601_to_ucs4 (&inptr,                                     \
-                                 NEED_LENGTH_TEST ? inend - inptr : 2, 0);   \
+           ch = ksc5601_to_ucs4 (&inptr, inend - inptr, 0);                  \
          }                                                                   \
                                                                              \
-       if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)                \
+       if (__builtin_expect (ch == 0, 0))                                    \
          {                                                                   \
-           result = __GCONV_EMPTY_INPUT;                                     \
+           result = __GCONV_INCOMPLETE_INPUT;                                \
            break;                                                            \
          }                                                                   \
-       else if (__builtin_expect (ch, 0) == __UNKNOWN_10646_CHAR)            \
+       else if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))            \
          {                                                                   \
-           if (! ignore_errors_p ())                                         \
-             {                                                               \
-               result = __GCONV_ILLEGAL_INPUT;                               \
-               break;                                                        \
-             }                                                               \
-                                                                             \
-           ++inptr;                                                          \
-           ++*irreversible;                                                  \
-           continue;                                                         \
+           STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
          }                                                                   \
       }                                                                              \
                                                                              \
     put32 (outptr, ch);                                                              \
     outptr += 4;                                                             \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS       , enum variant var, int *setp
 #define INIT_PARAMS            int set = *setp & CURRENT_SEL_MASK;           \
                                int set2 = *setp & CURRENT_ASSIGN_MASK
@@ -493,19 +461,81 @@ gconv_end (struct __gconv_step *data)
 
 
 /* Next, define the other direction.  */
-#define MIN_NEEDED_INPUT       MIN_NEEDED_TO
-#define MIN_NEEDED_OUTPUT      MIN_NEEDED_FROM
-#define MAX_NEEDED_OUTPUT      (MAX_NEEDED_FROM + 2)
+
+enum conversion { none = 0, european, japanese, chinese, korean, other };
+
+/* A datatype for conversion lists.  */
+typedef unsigned int cvlist_t;
+#define CVLIST(cv1, cv2, cv3, cv4, cv5) \
+  ((cv1) + ((cv2) << 3) + ((cv3) << 6) + ((cv4) << 9) + ((cv5) << 12))
+#define CVLIST_FIRST(cvl) ((cvl) & ((1 << 3) - 1))
+#define CVLIST_REST(cvl) ((cvl) >> 3)
+static const cvlist_t conversion_lists[4] =
+  {
+    /* TAG_none */        CVLIST (japanese, european, chinese, korean, other),
+    /* TAG_language_ja */ CVLIST (japanese, european, chinese, korean, other),
+    /* TAG_language_ko */ CVLIST (korean, european, japanese, chinese, other),
+    /* TAG_language_zh */ CVLIST (chinese, european, japanese, korean, other)
+  };
+
+#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;                                                             \
-    size_t written = 0;                                                              \
+    size_t written;                                                          \
                                                                              \
     ch = get32 (inptr);                                                              \
                                                                              \
+    if (var == iso2022jp2)                                                   \
+      {                                                                              \
+       /* Handle Unicode tag characters (range U+E0000..U+E007F).  */        \
+       if (__builtin_expect ((ch >> 7) == (0xe0000 >> 7), 0))                \
+         {                                                                   \
+           ch &= 0x7f;                                                       \
+           if (ch >= 'A' && ch <= 'Z')                                       \
+             ch += 'a' - 'A';                                                \
+           if (ch == 0x01)                                                   \
+             tag = TAG_language;                                             \
+           else if (ch == 'j' && tag == TAG_language)                        \
+             tag = TAG_language_j;                                           \
+           else if (ch == 'a' && tag == TAG_language_j)                      \
+             tag = TAG_language_ja;                                          \
+           else if (ch == 'k' && tag == TAG_language)                        \
+             tag = TAG_language_k;                                           \
+           else if (ch == 'o' && tag == TAG_language_k)                      \
+             tag = TAG_language_ko;                                          \
+           else if (ch == 'z' && tag == TAG_language)                        \
+             tag = TAG_language_z;                                           \
+           else if (ch == 'h' && tag == TAG_language_z)                      \
+             tag = TAG_language_zh;                                          \
+           else if (ch == 0x7f)                                              \
+             tag = TAG_none;                                                 \
+           else                                                              \
+             {                                                               \
+               /* Other tag characters reset the tag parsing state (if the   \
+                  current state is a temporary state) or are ignored (if     \
+                  the current state is a stable one).  */                    \
+               if (tag >= TAG_language)                                      \
+                 tag = TAG_none;                                             \
+             }                                                               \
+                                                                             \
+           inptr += 4;                                                       \
+           continue;                                                         \
+         }                                                                   \
+                                                                             \
+       /* Non-tag characters reset the tag parsing state, if the current     \
+          state is a temporary state.  */                                    \
+       if (__builtin_expect (tag >= TAG_language, 0))                        \
+         tag = TAG_none;                                                     \
+      }                                                                              \
+                                                                             \
     /* First see whether we can write the character using the currently              \
-       selected character set.  */                                           \
+       selected character set.  But ignore the selected character set if      \
+       the current language tag shows different preferences.  */             \
     if (set == ASCII_set)                                                    \
       {                                                                              \
        /* Please note that the NUL byte is *not* matched if we are not       \
@@ -515,65 +545,75 @@ gconv_end (struct __gconv_step *data)
          {                                                                   \
            *outptr++ = ch;                                                   \
            written = 1;                                                      \
+                                                                             \
+           /* At the beginning of a line, G2 designation is cleared.  */     \
+           if (var == iso2022jp2 && ch == 0x0a)                              \
+             set2 = UNSPECIFIED_set;                                         \
          }                                                                   \
-       /* At the beginning of a line, G2 designation is cleared.  */         \
-       if (var == iso2022jp2 && ch == 0x0a)                                  \
-         set2 = UNSPECIFIED_set;                                             \
+       else                                                                  \
+         written = __UNKNOWN_10646_CHAR;                                     \
       }                                                                              \
     /* 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)                                              \
+    else if (set == JISX0201_Roman_set                                       \
+            && (__builtin_expect (tag == TAG_none, 1)                        \
+                || tag == TAG_language_ja))                                  \
       {                                                                              \
-       unsigned char buf[2];                                                 \
+       unsigned char buf[1];                                                 \
        written = ucs4_to_jisx0201 (ch, buf);                                 \
-       if (written != __UNKNOWN_10646_CHAR && buf[0] > 0x20                  \
-           && buf[0] < 0x80)                                                 \
+       if (written != __UNKNOWN_10646_CHAR)                                  \
          {                                                                   \
-           *outptr++ = buf[0];                                               \
-           written = 1;                                                      \
+           if (buf[0] > 0x20 && buf[0] < 0x80)                               \
+             {                                                               \
+               *outptr++ = buf[0];                                           \
+               written = 1;                                                  \
+             }                                                               \
+           else                                                              \
+             written = __UNKNOWN_10646_CHAR;                                 \
          }                                                                   \
-       else                                                                  \
-         written = __UNKNOWN_10646_CHAR;                                     \
       }                                                                              \
-    else if (set == JISX0201_Kana_set)                                       \
+    else if (set == JISX0201_Kana_set                                        \
+            && (__builtin_expect (tag == TAG_none, 1)                        \
+                || tag == TAG_language_ja))                                  \
       {                                                                              \
-       unsigned char buf[2];                                                 \
+       unsigned char buf[1];                                                 \
        written = ucs4_to_jisx0201 (ch, buf);                                 \
-       if (written != __UNKNOWN_10646_CHAR && buf[0] > 0xa0                  \
-           && buf[0] < 0xe0)                                                 \
+       if (written != __UNKNOWN_10646_CHAR)                                  \
          {                                                                   \
-           *outptr++ = buf[0] - 0x80;                                        \
-           written = 1;                                                      \
+           if (buf[0] > 0xa0 && buf[0] < 0xe0)                               \
+             {                                                               \
+               *outptr++ = buf[0] - 0x80;                                    \
+               written = 1;                                                  \
+             }                                                               \
+           else                                                              \
+             written = __UNKNOWN_10646_CHAR;                                 \
          }                                                                   \
-       else                                                                  \
-         written = __UNKNOWN_10646_CHAR;                                     \
       }                                                                              \
     else                                                                     \
       {                                                                              \
-       if (set == JISX0208_1978_set || set == JISX0208_1983_set)             \
-         written = ucs4_to_jisx0208 (ch, outptr,                             \
-                                     (NEED_LENGTH_TEST                       \
-                                      ? outend - outptr : 2));               \
-       else if (set == JISX0212_set)                                         \
-         written = ucs4_to_jisx0212 (ch, outptr,                             \
-                                     (NEED_LENGTH_TEST                       \
-                                      ? outend - outptr : 2));               \
-       else if (set == GB2312_set)                                           \
-         written = ucs4_to_gb2312 (ch, outptr, (NEED_LENGTH_TEST             \
-                                                ? outend - outptr : 2));     \
+       if ((set == JISX0208_1978_set || set == JISX0208_1983_set)            \
+           && (__builtin_expect (tag == TAG_none, 1)                         \
+               || tag == TAG_language_ja))                                   \
+         written = ucs4_to_jisx0208 (ch, outptr, outend - outptr);           \
+       else if (set == JISX0212_set                                          \
+                && (__builtin_expect (tag == TAG_none, 1)                    \
+                    || tag == TAG_language_ja))                              \
+         written = ucs4_to_jisx0212 (ch, outptr, outend - outptr);           \
+       else if (set == GB2312_set                                            \
+                && (__builtin_expect (tag == TAG_none, 1)                    \
+                    || tag == TAG_language_zh))                              \
+         written = ucs4_to_gb2312 (ch, outptr, outend - outptr);             \
+       else if (set == KSC5601_set                                           \
+                && (__builtin_expect (tag == TAG_none, 1)                    \
+                    || tag == TAG_language_ko))                              \
+         written = ucs4_to_ksc5601 (ch, outptr, outend - outptr);            \
        else                                                                  \
-         {                                                                   \
-           assert (set == KSC5601_set);                                      \
-                                                                             \
-           written = ucs4_to_ksc5601 (ch, outptr,                            \
-                                      (NEED_LENGTH_TEST                      \
-                                       ? outend - outptr : 2));              \
-         }                                                                   \
+         written = __UNKNOWN_10646_CHAR;                                     \
                                                                              \
-       if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)           \
+       if (__builtin_expect (written == 0, 0))                               \
          {                                                                   \
            result = __GCONV_FULL_OUTPUT;                                     \
            break;                                                            \
@@ -582,12 +622,19 @@ gconv_end (struct __gconv_step *data)
          outptr += written;                                                  \
       }                                                                              \
                                                                              \
-    if (written == __UNKNOWN_10646_CHAR || written == 0)                     \
+    if (written == __UNKNOWN_10646_CHAR                                              \
+       && __builtin_expect (tag == TAG_none, 1))                             \
       {                                                                              \
        if (set2 == ISO88591_set)                                             \
          {                                                                   \
-           if (ch >= 0x80 && ch <= 0xff)                                     \
+           if (ch >= 0x80 && ch <= 0xff)                                     \
              {                                                               \
+               if (__builtin_expect (outptr + 3 > outend, 0))                \
+                 {                                                           \
+                   result = __GCONV_FULL_OUTPUT;                             \
+                   break;                                                    \
+                 }                                                           \
+                                                                             \
                *outptr++ = ESC;                                              \
                *outptr++ = 'N';                                              \
                *outptr++ = ch & 0x7f;                                        \
@@ -596,42 +643,49 @@ gconv_end (struct __gconv_step *data)
          }                                                                   \
        else if (set2 == ISO88597_set)                                        \
          {                                                                   \
-           const struct gap *rp = from_idx;                                  \
-                                                                             \
-           while (ch > rp->end)                                              \
-             ++rp;                                                           \
-           if (ch >= rp->start)                                              \
+           if (__builtin_expect (ch < 0xffff, 1))                            \
              {                                                               \
-               unsigned char res = iso88597_from_ucs4[ch - 0xa0 + rp->idx];  \
-               if (res != '\0')                                              \
+               const struct gap *rp = from_idx;                              \
+                                                                             \
+               while (ch > rp->end)                                          \
+                 ++rp;                                                       \
+               if (ch >= rp->start)                                          \
                  {                                                           \
-                   *outptr++ = ESC;                                          \
-                   *outptr++ = 'N';                                          \
-                   *outptr++ = res;                                          \
-                   written = 3;                                              \
+                   unsigned char res =                                       \
+                     iso88597_from_ucs4[ch - 0xa0 + rp->idx];                \
+                   if (res != '\0')                                          \
+                     {                                                       \
+                       if (__builtin_expect (outptr + 3 > outend, 0))        \
+                         {                                                   \
+                           result = __GCONV_FULL_OUTPUT;                     \
+                           break;                                            \
+                         }                                                   \
+                                                                             \
+                       *outptr++ = ESC;                                      \
+                       *outptr++ = 'N';                                      \
+                       *outptr++ = res & 0x7f;                               \
+                       written = 3;                                          \
+                     }                                                       \
                  }                                                           \
              }                                                               \
          }                                                                   \
       }                                                                              \
                                                                              \
-    if (written == __UNKNOWN_10646_CHAR || written == 0)                     \
+    if (written == __UNKNOWN_10646_CHAR)                                     \
       {                                                                              \
-       /* Either this is an unknown character or we have to switch           \
-          the currently selected character set.  The character sets          \
-          do not code entirely separate parts of ISO 10646 and               \
-          therefore there is no single correct result.  If we choose         \
-          the character set to use wrong we might be end up with             \
-          using yet another character set for the next character             \
-          though the current and the next could be encoded with one          \
-          character set.  We leave this kind of optimization for             \
-          later and now simply use a fixed order in which we test for        \
-          availability  */                                                   \
+       /* The attempts to use the currently selected character set           \
+          failed, either because the language tag changed, or because        \
+          the character requires a different character set, or because       \
+          the character is unknown.                                          \
+          The CJK character sets partially overlap when seen as subsets      \
+          of ISO 10646; therefore there is no single correct result.         \
+          We use a preferrence order which depends on the language tag.  */  \
                                                                              \
        if (ch <= 0x7f)                                                       \
          {                                                                   \
            /* We must encode using ASCII.  First write out the               \
               escape sequence.  */                                           \
-           if (NEED_LENGTH_TEST && __builtin_expect (outptr + 3 > outend, 0))\
+           if (__builtin_expect (outptr + 3 > outend, 0))                    \
              {                                                               \
                result = __GCONV_FULL_OUTPUT;                                 \
                break;                                                        \
@@ -642,7 +696,7 @@ gconv_end (struct __gconv_step *data)
            *outptr++ = 'B';                                                  \
            set = ASCII_set;                                                  \
                                                                              \
-           if (NEED_LENGTH_TEST && __builtin_expect (outptr + 1 > outend, 0))\
+           if (__builtin_expect (outptr + 1 > outend, 0))                    \
              {                                                               \
                result = __GCONV_FULL_OUTPUT;                                 \
                break;                                                        \
@@ -651,270 +705,307 @@ gconv_end (struct __gconv_step *data)
                                                                              \
            /* At the beginning of a line, G2 designation is cleared.  */     \
            if (var == iso2022jp2 && ch == 0x0a)                              \
-             set2 = UNSPECIFIED_set;                                         \
+             set2 = UNSPECIFIED_set;                                         \
          }                                                                   \
        else                                                                  \
          {                                                                   \
            /* Now it becomes difficult.  We must search the other            \
-              character sets one by one and we cannot use simple             \
-              arithmetic to determine whether the character can be           \
-              encoded using this set.  */                                    \
-           size_t written;                                                   \
+              character sets one by one.  Use an ordered conversion          \
+              list that depends on the current language tag.  */             \
+           cvlist_t conversion_list;                                         \
            unsigned char buf[2];                                             \
+           int res = __GCONV_ILLEGAL_INPUT;                                  \
                                                                              \
-           written = ucs4_to_jisx0201 (ch, buf);                             \
-           if (written != __UNKNOWN_10646_CHAR && buf[0] < 0x80)             \
-             {                                                               \
-               /* We use JIS X 0201.  */                                     \
-               if (NEED_LENGTH_TEST                                          \
-                   && __builtin_expect (outptr + 3 > outend, 0))             \
-                 {                                                           \
-                   result = __GCONV_FULL_OUTPUT;                             \
-                   break;                                                    \
-                 }                                                           \
+           if (var == iso2022jp2)                                            \
+             conversion_list = conversion_lists[tag >> 8];                   \
+           else                                                              \
+             conversion_list = CVLIST (japanese, 0, 0, 0, 0);                \
                                                                              \
-               *outptr++ = ESC;                                              \
-               *outptr++ = '(';                                              \
-               *outptr++ = 'J';                                              \
-               set = JISX0201_Roman_set;                                     \
+           do                                                                \
+             switch (CVLIST_FIRST (conversion_list))                         \
+               {                                                             \
+               case european:                                                \
                                                                              \
-               if (NEED_LENGTH_TEST                                          \
-                   && __builtin_expect (outptr + 1 > outend, 0))             \
-                 {                                                           \
-                   result = __GCONV_FULL_OUTPUT;                             \
+                 /* Try ISO 8859-1 upper half.   */                          \
+                 if (ch >= 0x80 && ch <= 0xff)                               \
+                   {                                                         \
+                     if (set2 != ISO88591_set)                               \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 3 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '.';                                    \
+                         *outptr++ = 'A';                                    \
+                         set2 = ISO88591_set;                                \
+                       }                                                     \
+                                                                             \
+                     if (__builtin_expect (outptr + 3 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = ESC;                                        \
+                     *outptr++ = 'N';                                        \
+                     *outptr++ = ch - 0x80;                                  \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
+                                                                             \
+                 /* Try ISO 8859-7 upper half.  */                           \
+                 if (__builtin_expect (ch < 0xffff, 1))                      \
+                   {                                                         \
+                     const struct gap *rp = from_idx;                        \
+                                                                             \
+                     while (ch > rp->end)                                    \
+                       ++rp;                                                 \
+                     if (ch >= rp->start)                                    \
+                       {                                                     \
+                         unsigned char ch2 =                                 \
+                           iso88597_from_ucs4[ch - 0xa0 + rp->idx];          \
+                         if (ch2 != '\0')                                    \
+                           {                                                 \
+                             if (set2 != ISO88597_set)                       \
+                               {                                             \
+                                 if (__builtin_expect (outptr + 3 > outend,  \
+                                                       0))                   \
+                                   {                                         \
+                                     res = __GCONV_FULL_OUTPUT;              \
+                                     break;                                  \
+                                   }                                         \
+                                 *outptr++ = ESC;                            \
+                                 *outptr++ = '.';                            \
+                                 *outptr++ = 'F';                            \
+                                 set2 = ISO88597_set;                        \
+                               }                                             \
+                                                                             \
+                             if (__builtin_expect (outptr + 3 > outend, 0))  \
+                               {                                             \
+                                 res = __GCONV_FULL_OUTPUT;                  \
+                                 break;                                      \
+                               }                                             \
+                             *outptr++ = ESC;                                \
+                             *outptr++ = 'N';                                \
+                             *outptr++ = ch2 - 0x80;                         \
+                             res = __GCONV_OK;                               \
+                             break;                                          \
+                           }                                                 \
+                       }                                                     \
+                   }                                                         \
+                                                                             \
+                 break;                                                      \
+                                                                             \
+               case japanese:                                                \
+                                                                             \
+                 /* Try JIS X 0201 Roman.  */                                \
+                 written = ucs4_to_jisx0201 (ch, buf);                       \
+                 if (written != __UNKNOWN_10646_CHAR                         \
+                     && buf[0] > 0x20 && buf[0] < 0x80)                      \
+                   {                                                         \
+                     if (set != JISX0201_Roman_set)                          \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 3 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '(';                                    \
+                         *outptr++ = 'J';                                    \
+                         set = JISX0201_Roman_set;                           \
+                       }                                                     \
+                                                                             \
+                     if (__builtin_expect (outptr + 1 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = buf[0];                                     \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
+                                                                             \
+                 /* Try JIS X 0208.  */                                      \
+                 written = ucs4_to_jisx0208 (ch, buf, 2);                    \
+                 if (written != __UNKNOWN_10646_CHAR)                        \
+                   {                                                         \
+                     if (set != JISX0208_1983_set)                           \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 3 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '$';                                    \
+                         *outptr++ = 'B';                                    \
+                         set = JISX0208_1983_set;                            \
+                       }                                                     \
+                                                                             \
+                     if (__builtin_expect (outptr + 2 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = buf[0];                                     \
+                     *outptr++ = buf[1];                                     \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
+                                                                             \
+                 if (__builtin_expect (var == iso2022jp, 0))                 \
+                   /* Don't use the other Japanese character sets.  */       \
                    break;                                                    \
-                 }                                                           \
-               *outptr++ = buf[0];                                           \
-             }                                                               \
-           else                                                              \
-             {                                                               \
-               written = ucs4_to_jisx0208 (ch, buf, 2);                      \
-               if (written != __UNKNOWN_10646_CHAR)                          \
-                 {                                                           \
-                   /* We use JIS X 0208.  */                                 \
-                   if (NEED_LENGTH_TEST                                      \
-                       && __builtin_expect (outptr + 3 > outend, 0))         \
-                     {                                                       \
-                       result = __GCONV_FULL_OUTPUT;                         \
-                       break;                                                \
-                     }                                                       \
                                                                              \
-                   *outptr++ = ESC;                                          \
-                   *outptr++ = '$';                                          \
-                   *outptr++ = 'B';                                          \
-                   set = JISX0208_1983_set;                                  \
+                 /* Try JIS X 0212.  */                                      \
+                 written = ucs4_to_jisx0212 (ch, buf, 2);                    \
+                 if (written != __UNKNOWN_10646_CHAR)                        \
+                   {                                                         \
+                     if (set != JISX0212_set)                                \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 4 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '$';                                    \
+                         *outptr++ = '(';                                    \
+                         *outptr++ = 'D';                                    \
+                         set = JISX0212_set;                                 \
+                       }                                                     \
                                                                              \
-                   if (NEED_LENGTH_TEST                                      \
-                       && __builtin_expect (outptr + 2 > outend, 0))         \
-                     {                                                       \
-                       result = __GCONV_FULL_OUTPUT;                         \
-                       break;                                                \
-                     }                                                       \
-                   *outptr++ = buf[0];                                       \
-                   *outptr++ = buf[1];                                       \
-                 }                                                           \
-               else if (__builtin_expect (var, iso2022jp2) == iso2022jp)     \
-                 {                                                           \
-                   /* We have no other choice.  */                           \
-                   if (! ignore_errors_p ())                                 \
-                     {                                                       \
-                       result = __GCONV_ILLEGAL_INPUT;                       \
-                       break;                                                \
-                     }                                                       \
+                     if (__builtin_expect (outptr + 2 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = buf[0];                                     \
+                     *outptr++ = buf[1];                                     \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
                                                                              \
-                   ++*irreversible;                                          \
-                 }                                                           \
-               else                                                          \
-                 {                                                           \
-                   written = ucs4_to_jisx0212 (ch, buf, 2);                  \
-                   if (written != __UNKNOWN_10646_CHAR)                      \
-                     {                                                       \
-                       /* We use JIS X 0212.  */                             \
-                       if (NEED_LENGTH_TEST                                  \
-                           && __builtin_expect (outptr + 4 > outend, 0))     \
-                         {                                                   \
-                           result = __GCONV_FULL_OUTPUT;                     \
-                           break;                                            \
-                         }                                                   \
-                       *outptr++ = ESC;                                      \
-                       *outptr++ = '$';                                      \
-                       *outptr++ = '(';                                      \
-                       *outptr++ = 'D';                                      \
-                       set = JISX0212_set;                                   \
+                 break;                                                      \
                                                                              \
-                       if (NEED_LENGTH_TEST                                  \
-                           && __builtin_expect (outptr + 2 > outend, 0))     \
-                         {                                                   \
-                           result = __GCONV_FULL_OUTPUT;                     \
-                           break;                                            \
-                         }                                                   \
-                       *outptr++ = buf[0];                                   \
-                       *outptr++ = buf[1];                                   \
-                     }                                                       \
-                   else                                                      \
-                     {                                                       \
-                       written = ucs4_to_jisx0201 (ch, buf);                 \
-                       if (written != __UNKNOWN_10646_CHAR                   \
-                           && buf[0] >= 0x80)                                \
-                         {                                                   \
-                           /* We use JIS X 0201.  */                         \
-                           if (NEED_LENGTH_TEST                              \
-                               && __builtin_expect (outptr + 3 > outend, 0)) \
-                             {                                               \
-                               result = __GCONV_FULL_OUTPUT;                 \
-                               break;                                        \
-                             }                                               \
-                                                                             \
-                           *outptr++ = ESC;                                  \
-                           *outptr++ = '(';                                  \
-                           *outptr++ = 'I';                                  \
-                           set = JISX0201_Kana_set;                          \
-                                                                             \
-                           if (NEED_LENGTH_TEST                              \
-                               && __builtin_expect (outptr + 1 > outend, 0)) \
-                             {                                               \
-                               result = __GCONV_FULL_OUTPUT;                 \
-                               break;                                        \
-                             }                                               \
-                           *outptr++ = buf[0] - 0x80;                        \
-                         }                                                   \
-                       else if (ch != 0xa5 && ch >= 0x80 && ch <= 0xff)      \
-                         {                                                   \
-                           /* ISO 8859-1 upper half.   */                    \
-                           if (NEED_LENGTH_TEST                              \
-                               && __builtin_expect (outptr + 3 > outend, 0)) \
-                             {                                               \
-                               result = __GCONV_FULL_OUTPUT;                 \
-                               break;                                        \
-                             }                                               \
-                                                                             \
-                           *outptr++ = ESC;                                  \
-                           *outptr++ = '.';                                  \
-                           *outptr++ = 'A';                                  \
-                           set2 = ISO88591_set;                              \
-                                                                             \
-                           if (NEED_LENGTH_TEST                              \
-                               && __builtin_expect (outptr + 3 > outend, 0)) \
-                             {                                               \
-                               result = __GCONV_FULL_OUTPUT;                 \
-                               break;                                        \
-                             }                                               \
-                           *outptr++ = ESC;                                  \
-                           *outptr++ = 'N';                                  \
-                           *outptr++ = ch;                                   \
-                         }                                                   \
-                       else                                                  \
-                         {                                                   \
-                           written = ucs4_to_gb2312 (ch, buf, 2);            \
-                           if (written != __UNKNOWN_10646_CHAR)              \
-                             {                                               \
-                               /* We use GB 2312.  */                        \
-                               if (NEED_LENGTH_TEST                          \
-                                   && __builtin_expect (outptr + 3 > outend, \
-                                                        0))                  \
-                                 {                                           \
-                                   result = __GCONV_FULL_OUTPUT;             \
-                                   break;                                    \
-                                 }                                           \
+               case chinese:                                                 \
+                 assert (var == iso2022jp2);                                 \
                                                                              \
-                               *outptr++ = ESC;                              \
-                               *outptr++ = '$';                              \
-                               *outptr++ = 'A';                              \
-                               set = GB2312_set;                             \
+                 /* Try GB 2312.  */                                         \
+                 written = ucs4_to_gb2312 (ch, buf, 2);                      \
+                 if (written != __UNKNOWN_10646_CHAR)                        \
+                   {                                                         \
+                     if (set != GB2312_set)                                  \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 3 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '$';                                    \
+                         *outptr++ = 'A';                                    \
+                         set = GB2312_set;                                   \
+                       }                                                     \
                                                                              \
-                               if (NEED_LENGTH_TEST                          \
-                                   && __builtin_expect (outptr + 2 > outend, \
-                                                        0))                  \
-                                 {                                           \
-                                   result = __GCONV_FULL_OUTPUT;             \
-                                   break;                                    \
-                                 }                                           \
-                               *outptr++ = buf[0];                           \
-                               *outptr++ = buf[1];                           \
-                             }                                               \
-                           else                                              \
-                             {                                               \
-                               written = ucs4_to_ksc5601 (ch, buf, 2);       \
-                               if (written != __UNKNOWN_10646_CHAR)          \
-                                 {                                           \
-                                   /* We use KSC 5601.  */                   \
-                                   if (NEED_LENGTH_TEST                      \
-                                       && __builtin_expect (outptr + 4       \
-                                                            > outend, 0))    \
-                                     {                                       \
-                                       result = __GCONV_FULL_OUTPUT;         \
-                                       break;                                \
-                                     }                                       \
-                                   *outptr++ = ESC;                          \
-                                   *outptr++ = '$';                          \
-                                   *outptr++ = '(';                          \
-                                   *outptr++ = 'C';                          \
-                                   set = KSC5601_set;                        \
-                                                                             \
-                                   if (NEED_LENGTH_TEST                      \
-                                       && __builtin_expect (outptr + 2       \
-                                                            > outend, 0))    \
-                                     {                                       \
-                                       result = __GCONV_FULL_OUTPUT;         \
-                                       break;                                \
-                                     }                                       \
-                                   *outptr++ = buf[0];                       \
-                                   *outptr++ = buf[1];                       \
-                                 }                                           \
-                               else                                          \
-                                 {                                           \
-                                   const struct gap *rp = from_idx;          \
-                                   unsigned char gch = 0;                    \
-                                                                             \
-                                   while (ch > rp->end)                      \
-                                     ++rp;                                   \
-                                   if (ch >= rp->start)                      \
-                                     {                                       \
-                                       ch = ch - 0xa0 + rp->idx;             \
-                                       gch = iso88597_from_ucs4[ch];         \
-                                     }                                       \
-                                                                             \
-                                   if (__builtin_expect (gch, 1) != 0)       \
-                                     {                                       \
-                                       /* We use ISO 8859-7 greek.  */       \
-                                       if (NEED_LENGTH_TEST                  \
-                                           && __builtin_expect (outptr + 3   \
-                                                                > outend, 0))\
-                                         {                                   \
-                                           result = __GCONV_FULL_OUTPUT;     \
-                                           break;                            \
-                                         }                                   \
-                                       *outptr++ = ESC;                      \
-                                       *outptr++ = '.';                      \
-                                       *outptr++ = 'F';                      \
-                                       set2 = ISO88597_set;                  \
-                                                                             \
-                                       if (NEED_LENGTH_TEST                  \
-                                           && __builtin_expect (outptr + 3   \
-                                                                > outend, 0))\
-                                         {                                   \
-                                           result = __GCONV_FULL_OUTPUT;     \
-                                           break;                            \
-                                         }                                   \
-                                       *outptr++ = ESC;                      \
-                                       *outptr++ = 'N';                      \
-                                       *outptr++ = gch;                      \
-                                     }                                       \
-                                   else                                      \
-                                     {                                       \
-                                       if (! ignore_errors_p ())             \
-                                         {                                   \
-                                            result = __GCONV_ILLEGAL_INPUT;  \
-                                            break;                           \
-                                         }                                   \
-                                                                             \
-                                       ++*irreversible;                      \
-                                     }                                       \
-                                 }                                           \
-                             }                                               \
-                         }                                                   \
-                     }                                                       \
-                 }                                                           \
+                     if (__builtin_expect (outptr + 2 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = buf[0];                                     \
+                     *outptr++ = buf[1];                                     \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
+                                                                             \
+                 break;                                                      \
+                                                                             \
+               case korean:                                                  \
+                 assert (var == iso2022jp2);                                 \
+                                                                             \
+                 /* Try KSC 5601.  */                                        \
+                 written = ucs4_to_ksc5601 (ch, buf, 2);                     \
+                 if (written != __UNKNOWN_10646_CHAR)                        \
+                   {                                                         \
+                     if (set != KSC5601_set)                                 \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 4 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '$';                                    \
+                         *outptr++ = '(';                                    \
+                         *outptr++ = 'C';                                    \
+                         set = KSC5601_set;                                  \
+                       }                                                     \
+                                                                             \
+                     if (__builtin_expect (outptr + 2 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = buf[0];                                     \
+                     *outptr++ = buf[1];                                     \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
+                                                                             \
+                 break;                                                      \
+                                                                             \
+               case other:                                                   \
+                 assert (var == iso2022jp2);                                 \
+                                                                             \
+                 /* Try JIS X 0201 Kana.  This is not officially part        \
+                    of ISO-2022-JP-2, according to RFC 1554.  Therefore      \
+                    we try this only after all other attempts.  */           \
+                 written = ucs4_to_jisx0201 (ch, buf);                       \
+                 if (written != __UNKNOWN_10646_CHAR && buf[0] >= 0x80)      \
+                   {                                                         \
+                     if (set != JISX0201_Kana_set)                           \
+                       {                                                     \
+                         if (__builtin_expect (outptr + 3 > outend, 0))      \
+                           {                                                 \
+                             res = __GCONV_FULL_OUTPUT;                      \
+                             break;                                          \
+                           }                                                 \
+                         *outptr++ = ESC;                                    \
+                         *outptr++ = '(';                                    \
+                         *outptr++ = 'I';                                    \
+                         set = JISX0201_Kana_set;                            \
+                       }                                                     \
+                                                                             \
+                     if (__builtin_expect (outptr + 1 > outend, 0))          \
+                       {                                                     \
+                         res = __GCONV_FULL_OUTPUT;                          \
+                         break;                                              \
+                       }                                                     \
+                     *outptr++ = buf[0] - 0x80;                              \
+                     res = __GCONV_OK;                                       \
+                     break;                                                  \
+                   }                                                         \
+                                                                             \
+                 break;                                                      \
+                                                                             \
+               default:                                                      \
+                 abort ();                                                   \
+               }                                                             \
+           while (res == __GCONV_ILLEGAL_INPUT                               \
+                  && (conversion_list = CVLIST_REST (conversion_list)) != 0);\
+                                                                             \
+           if (res == __GCONV_FULL_OUTPUT)                                   \
+             {                                                               \
+               result = res;                                                 \
+               break;                                                        \
+             }                                                               \
+                                                                             \
+           if (res == __GCONV_ILLEGAL_INPUT)                                 \
+             {                                                               \
+               STANDARD_TO_LOOP_ERR_HANDLER (4);                             \
              }                                                               \
          }                                                                   \
       }                                                                              \
@@ -922,10 +1013,19 @@ gconv_end (struct __gconv_step *data)
     /* Now that we wrote the output increment the input pointer.  */         \
     inptr += 4;                                                                      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS       , enum variant var, int *setp
 #define INIT_PARAMS            int set = *setp & CURRENT_SEL_MASK;           \
-                               int set2 = *setp & CURRENT_ASSIGN_MASK
-#define UPDATE_PARAMS          *setp = set | set2
+                               int set2 = *setp & CURRENT_ASSIGN_MASK;       \
+                               int tag = *setp & CURRENT_TAG_MASK;
+#define REINIT_PARAMS          do                                            \
+                                 {                                           \
+                                   set = *setp & CURRENT_SEL_MASK;           \
+                                   set2 = *setp & CURRENT_ASSIGN_MASK;       \
+                                   tag = *setp & CURRENT_TAG_MASK;           \
+                                 }                                           \
+                               while (0)
+#define UPDATE_PARAMS          *setp = set | set2 | tag
 #include <iconv/loop.c>