Update BIG5-HKSCS charmap to HKSCS-2008
[platform/upstream/glibc.git] / iconvdata / iso-2022-jp-3.c
1 /* Conversion module for ISO-2022-JP-3.
2    Copyright (C) 1998-2013 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
5    and Bruno Haible <bruno@clisp.org>, 2002.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <assert.h>
22 #include <dlfcn.h>
23 #include <gconv.h>
24 #include <stdint.h>
25 #include <string.h>
26
27 #include "jis0201.h"
28 #include "jis0208.h"
29 #include "jisx0213.h"
30
31 /* This makes obvious what everybody knows: 0x1b is the Esc character.  */
32 #define ESC 0x1b
33
34 /* Definitions used in the body of the `gconv' function.  */
35 #define CHARSET_NAME            "ISO-2022-JP-3//"
36 #define FROM_LOOP               from_iso2022jp3_loop
37 #define TO_LOOP                 to_iso2022jp3_loop
38 #define DEFINE_INIT             1
39 #define DEFINE_FINI             1
40 #define FROM_LOOP_MIN_NEEDED_FROM       1
41 #define FROM_LOOP_MAX_NEEDED_FROM       4
42 #define FROM_LOOP_MIN_NEEDED_TO         4
43 #define FROM_LOOP_MAX_NEEDED_TO         8
44 #define TO_LOOP_MIN_NEEDED_FROM         4
45 #define TO_LOOP_MAX_NEEDED_FROM         4
46 #define TO_LOOP_MIN_NEEDED_TO           1
47 #define TO_LOOP_MAX_NEEDED_TO           6
48 #define PREPARE_LOOP \
49   int saved_state;                                                            \
50   int *statep = &data->__statep->__count;
51 #define EXTRA_LOOP_ARGS         , statep
52
53
54 /* The COUNT element of the state keeps track of the currently selected
55    character set.  The possible values are:  */
56 enum
57 {
58   ASCII_set = 0,                /* Esc ( B */
59   JISX0208_1978_set = 1 << 3,   /* Esc $ @ */
60   JISX0208_1983_set = 2 << 3,   /* Esc $ B */
61   JISX0201_Roman_set = 3 << 3,  /* Esc ( J */
62   JISX0201_Kana_set = 4 << 3,   /* Esc ( I */
63   JISX0213_1_2000_set = 5 << 3, /* Esc $ ( O */
64   JISX0213_2_set = 6 << 3,      /* Esc $ ( P */
65   JISX0213_1_2004_set = 7 << 3, /* Esc $ ( Q */
66   CURRENT_SEL_MASK = 7 << 3
67 };
68
69 /* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
70    also contains the last two bytes to be output, shifted by 6 bits, and a
71    one-bit indicator whether they must be preceded by the shift sequence,
72    in bit 22.  */
73
74 /* Since this is a stateful encoding we have to provide code which resets
75    the output state to the initial state.  This has to be done during the
76    flushing.  */
77 #define EMIT_SHIFT_TO_INIT \
78   if ((data->__statep->__count & ~7) != ASCII_set)                            \
79     {                                                                         \
80       if (FROM_DIRECTION)                                                     \
81         {                                                                     \
82           /* It's easy, we don't have to emit anything, we just reset the     \
83              state for the input.  */                                         \
84           data->__statep->__count &= 7;                                       \
85           data->__statep->__count |= ASCII_set;                               \
86         }                                                                     \
87       else                                                                    \
88         {                                                                     \
89           /* We are not in the initial state.  To switch back we have         \
90              to write out the buffered character and/or emit the sequence     \
91              `Esc ( B'.  */                                                   \
92           size_t need =                                                       \
93             (data->__statep->__count >> 6                                     \
94              ? (data->__statep->__count >> 22 ? 3 : 0) + 2                    \
95              : 0)                                                             \
96             + ((data->__statep->__count & CURRENT_SEL_MASK) != ASCII_set      \
97                ? 3 : 0);                                                      \
98                                                                               \
99           if (__builtin_expect (outbuf + need > outend, 0))                   \
100             /* We don't have enough room in the output buffer.  */            \
101             status = __GCONV_FULL_OUTPUT;                                     \
102           else                                                                \
103             {                                                                 \
104               if (data->__statep->__count >> 6)                               \
105                 {                                                             \
106                   uint32_t lasttwo = data->__statep->__count >> 6;            \
107                                                                               \
108                   if (lasttwo >> 16)                                          \
109                     {                                                         \
110                       /* Write out the shift sequence before the last         \
111                          character.  */                                       \
112                       assert ((data->__statep->__count & CURRENT_SEL_MASK)    \
113                               == JISX0208_1983_set);                          \
114                       *outbuf++ = ESC;                                        \
115                       *outbuf++ = '$';                                        \
116                       *outbuf++ = 'B';                                        \
117                     }                                                         \
118                   /* Write out the last character.  */                        \
119                   *outbuf++ = (lasttwo >> 8) & 0xff;                          \
120                   *outbuf++ = lasttwo & 0xff;                                 \
121                 }                                                             \
122               if ((data->__statep->__count & CURRENT_SEL_MASK) != ASCII_set)  \
123                 {                                                             \
124                   /* Write out the shift sequence.  */                        \
125                   *outbuf++ = ESC;                                            \
126                   *outbuf++ = '(';                                            \
127                   *outbuf++ = 'B';                                            \
128                 }                                                             \
129               data->__statep->__count &= 7;                                   \
130               data->__statep->__count |= ASCII_set;                           \
131             }                                                                 \
132         }                                                                     \
133     }
134
135
136 /* Since we might have to reset input pointer we must be able to save
137    and retore the state.  */
138 #define SAVE_RESET_STATE(Save) \
139   if (Save)                                                                   \
140     saved_state = *statep;                                                    \
141   else                                                                        \
142     *statep = saved_state
143
144
145 /* First define the conversion function from ISO-2022-JP-3 to UCS-4.  */
146 #define MIN_NEEDED_INPUT        FROM_LOOP_MIN_NEEDED_FROM
147 #define MAX_NEEDED_INPUT        FROM_LOOP_MAX_NEEDED_FROM
148 #define MIN_NEEDED_OUTPUT       FROM_LOOP_MIN_NEEDED_TO
149 #define MAX_NEEDED_OUTPUT       FROM_LOOP_MAX_NEEDED_TO
150 #define LOOPFCT                 FROM_LOOP
151 #define BODY \
152   {                                                                           \
153     uint32_t ch = *inptr;                                                     \
154                                                                               \
155     /* Recognize escape sequences.  */                                        \
156     if (__builtin_expect (ch == ESC, 0))                                      \
157       {                                                                       \
158         /* We now must be prepared to read two to three more bytes.           \
159            If we have a match in the first byte but then the input buffer     \
160            ends we terminate with an error since we must not risk missing     \
161            an escape sequence just because it is not entirely in the          \
162            current input buffer.  */                                          \
163         if (__builtin_expect (inptr + 2 >= inend, 0)                          \
164             || (inptr[1] == '$' && inptr[2] == '('                            \
165                 && __builtin_expect (inptr + 3 >= inend, 0)))                 \
166           {                                                                   \
167             /* Not enough input available.  */                                \
168             result = __GCONV_INCOMPLETE_INPUT;                                \
169             break;                                                            \
170           }                                                                   \
171                                                                               \
172         if (inptr[1] == '(')                                                  \
173           {                                                                   \
174             if (inptr[2] == 'B')                                              \
175               {                                                               \
176                 /* ASCII selected.  */                                        \
177                 set = ASCII_set;                                              \
178                 inptr += 3;                                                   \
179                 continue;                                                     \
180               }                                                               \
181             else if (inptr[2] == 'J')                                         \
182               {                                                               \
183                 /* JIS X 0201 selected.  */                                   \
184                 set = JISX0201_Roman_set;                                     \
185                 inptr += 3;                                                   \
186                 continue;                                                     \
187               }                                                               \
188             else if (inptr[2] == 'I')                                         \
189               {                                                               \
190                 /* JIS X 0201 selected.  */                                   \
191                 set = JISX0201_Kana_set;                                      \
192                 inptr += 3;                                                   \
193                 continue;                                                     \
194               }                                                               \
195           }                                                                   \
196         else if (inptr[1] == '$')                                             \
197           {                                                                   \
198             if (inptr[2] == '@')                                              \
199               {                                                               \
200                 /* JIS X 0208-1978 selected.  */                              \
201                 set = JISX0208_1978_set;                                      \
202                 inptr += 3;                                                   \
203                 continue;                                                     \
204               }                                                               \
205             else if (inptr[2] == 'B')                                         \
206               {                                                               \
207                 /* JIS X 0208-1983 selected.  */                              \
208                 set = JISX0208_1983_set;                                      \
209                 inptr += 3;                                                   \
210                 continue;                                                     \
211               }                                                               \
212             else if (inptr[2] == '(')                                         \
213               {                                                               \
214                 if (inptr[3] == 'O' || inptr[3] == 'Q')                       \
215                   {                                                           \
216                     /* JIS X 0213 plane 1 selected.  */                       \
217                     /* In this direction we don't need to distinguish the     \
218                        versions from 2000 and 2004. */                        \
219                     set = JISX0213_1_2004_set;                                \
220                     inptr += 4;                                               \
221                     continue;                                                 \
222                   }                                                           \
223                 else if (inptr[3] == 'P')                                     \
224                   {                                                           \
225                     /* JIS X 0213 plane 2 selected.  */                       \
226                     set = JISX0213_2_set;                                     \
227                     inptr += 4;                                               \
228                     continue;                                                 \
229                   }                                                           \
230               }                                                               \
231           }                                                                   \
232       }                                                                       \
233                                                                               \
234     if (ch >= 0x80)                                                           \
235       {                                                                       \
236         STANDARD_FROM_LOOP_ERR_HANDLER (1);                                   \
237       }                                                                       \
238     else if (set == ASCII_set || (ch < 0x21 || ch == 0x7f))                   \
239       /* Almost done, just advance the input pointer.  */                     \
240       ++inptr;                                                                \
241     else if (set == JISX0201_Roman_set)                                       \
242       {                                                                       \
243         /* Use the JIS X 0201 table.  */                                      \
244         ch = jisx0201_to_ucs4 (ch);                                           \
245         if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))                 \
246           {                                                                   \
247             STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
248           }                                                                   \
249         ++inptr;                                                              \
250       }                                                                       \
251     else if (set == JISX0201_Kana_set)                                        \
252       {                                                                       \
253         /* Use the JIS X 0201 table.  */                                      \
254         ch = jisx0201_to_ucs4 (ch + 0x80);                                    \
255         if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))                 \
256           {                                                                   \
257             STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
258           }                                                                   \
259         ++inptr;                                                              \
260       }                                                                       \
261     else if (set == JISX0208_1978_set || set == JISX0208_1983_set)            \
262       {                                                                       \
263         /* XXX I don't have the tables for these two old variants of          \
264            JIS X 0208.  Therefore I'm using the tables for JIS X              \
265            0208-1990.  If somebody has problems with this please              \
266            provide the appropriate tables.  */                                \
267         ch = jisx0208_to_ucs4 (&inptr, inend - inptr, 0);                     \
268                                                                               \
269         if (__builtin_expect (ch == 0, 0))                                    \
270           {                                                                   \
271             result = __GCONV_INCOMPLETE_INPUT;                                \
272             break;                                                            \
273           }                                                                   \
274         else if (__builtin_expect (ch == __UNKNOWN_10646_CHAR, 0))            \
275           {                                                                   \
276             STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
277           }                                                                   \
278       }                                                                       \
279     else /* (set == JISX0213_1_2004_set || set == JISX0213_2_set) */          \
280       {                                                                       \
281         if (__builtin_expect (inptr + 1 >= inend, 0))                         \
282           {                                                                   \
283             result = __GCONV_INCOMPLETE_INPUT;                                \
284             break;                                                            \
285           }                                                                   \
286                                                                               \
287         ch = jisx0213_to_ucs4 (                                               \
288                ((JISX0213_1_2004_set - set + (1 << 3)) << 5) + ch,            \
289                inptr[1]);                                                     \
290         if (ch == 0)                                                          \
291           STANDARD_FROM_LOOP_ERR_HANDLER (1);                                 \
292                                                                               \
293         if (ch < 0x80)                                                        \
294           {                                                                   \
295             /* It's a combining character.  */                                \
296             uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0];             \
297             uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1];             \
298                                                                               \
299             /* See whether we have room for two characters.  */               \
300             if (outptr + 8 <= outend)                                         \
301               {                                                               \
302                 inptr += 2;                                                   \
303                 put32 (outptr, u1);                                           \
304                 outptr += 4;                                                  \
305                 put32 (outptr, u2);                                           \
306                 outptr += 4;                                                  \
307                 continue;                                                     \
308               }                                                               \
309             else                                                              \
310               {                                                               \
311                 result = __GCONV_FULL_OUTPUT;                                 \
312                 break;                                                        \
313               }                                                               \
314           }                                                                   \
315                                                                               \
316         inptr += 2;                                                           \
317       }                                                                       \
318                                                                               \
319     put32 (outptr, ch);                                                       \
320     outptr += 4;                                                              \
321   }
322 #define LOOP_NEED_FLAGS
323 #define EXTRA_LOOP_DECLS        , int *statep
324 #define INIT_PARAMS             int set = *statep
325 #define UPDATE_PARAMS           *statep = set
326 #include <iconv/loop.c>
327
328
329 /* Next, define the other direction, from UCS-4 to ISO-2022-JP-3.  */
330
331 /* Composition tables for each of the relevant combining characters.  */
332 static const struct
333 {
334   uint16_t base;
335   uint16_t composed;
336 } comp_table_data[] =
337 {
338 #define COMP_TABLE_IDX_02E5 0
339 #define COMP_TABLE_LEN_02E5 1
340   { 0x2b64, 0x2b65 }, /* 0x12B65 = 0x12B64 U+02E5 */
341 #define COMP_TABLE_IDX_02E9 (COMP_TABLE_IDX_02E5 + COMP_TABLE_LEN_02E5)
342 #define COMP_TABLE_LEN_02E9 1
343   { 0x2b60, 0x2b66 }, /* 0x12B66 = 0x12B60 U+02E9 */
344 #define COMP_TABLE_IDX_0300 (COMP_TABLE_IDX_02E9 + COMP_TABLE_LEN_02E9)
345 #define COMP_TABLE_LEN_0300 5
346   { 0x295c, 0x2b44 }, /* 0x12B44 = 0x1295C U+0300 */
347   { 0x2b38, 0x2b48 }, /* 0x12B48 = 0x12B38 U+0300 */
348   { 0x2b37, 0x2b4a }, /* 0x12B4A = 0x12B37 U+0300 */
349   { 0x2b30, 0x2b4c }, /* 0x12B4C = 0x12B30 U+0300 */
350   { 0x2b43, 0x2b4e }, /* 0x12B4E = 0x12B43 U+0300 */
351 #define COMP_TABLE_IDX_0301 (COMP_TABLE_IDX_0300 + COMP_TABLE_LEN_0300)
352 #define COMP_TABLE_LEN_0301 4
353   { 0x2b38, 0x2b49 }, /* 0x12B49 = 0x12B38 U+0301 */
354   { 0x2b37, 0x2b4b }, /* 0x12B4B = 0x12B37 U+0301 */
355   { 0x2b30, 0x2b4d }, /* 0x12B4D = 0x12B30 U+0301 */
356   { 0x2b43, 0x2b4f }, /* 0x12B4F = 0x12B43 U+0301 */
357 #define COMP_TABLE_IDX_309A (COMP_TABLE_IDX_0301 + COMP_TABLE_LEN_0301)
358 #define COMP_TABLE_LEN_309A 14
359   { 0x242b, 0x2477 }, /* 0x12477 = 0x1242B U+309A */
360   { 0x242d, 0x2478 }, /* 0x12478 = 0x1242D U+309A */
361   { 0x242f, 0x2479 }, /* 0x12479 = 0x1242F U+309A */
362   { 0x2431, 0x247a }, /* 0x1247A = 0x12431 U+309A */
363   { 0x2433, 0x247b }, /* 0x1247B = 0x12433 U+309A */
364   { 0x252b, 0x2577 }, /* 0x12577 = 0x1252B U+309A */
365   { 0x252d, 0x2578 }, /* 0x12578 = 0x1252D U+309A */
366   { 0x252f, 0x2579 }, /* 0x12579 = 0x1252F U+309A */
367   { 0x2531, 0x257a }, /* 0x1257A = 0x12531 U+309A */
368   { 0x2533, 0x257b }, /* 0x1257B = 0x12533 U+309A */
369   { 0x253b, 0x257c }, /* 0x1257C = 0x1253B U+309A */
370   { 0x2544, 0x257d }, /* 0x1257D = 0x12544 U+309A */
371   { 0x2548, 0x257e }, /* 0x1257E = 0x12548 U+309A */
372   { 0x2675, 0x2678 }, /* 0x12678 = 0x12675 U+309A */
373 };
374
375 #define MIN_NEEDED_INPUT        TO_LOOP_MIN_NEEDED_FROM
376 #define MAX_NEEDED_INPUT        TO_LOOP_MAX_NEEDED_FROM
377 #define MIN_NEEDED_OUTPUT       TO_LOOP_MIN_NEEDED_TO
378 #define MAX_NEEDED_OUTPUT       TO_LOOP_MAX_NEEDED_TO
379 #define LOOPFCT                 TO_LOOP
380 #define BODY \
381   {                                                                           \
382     uint32_t ch = get32 (inptr);                                              \
383                                                                               \
384     if (lasttwo != 0)                                                         \
385       {                                                                       \
386         /* Attempt to combine the last character with this one.  */           \
387         unsigned int idx;                                                     \
388         unsigned int len;                                                     \
389                                                                               \
390         if (ch == 0x02e5)                                                     \
391           idx = COMP_TABLE_IDX_02E5, len = COMP_TABLE_LEN_02E5;               \
392         else if (ch == 0x02e9)                                                \
393           idx = COMP_TABLE_IDX_02E9, len = COMP_TABLE_LEN_02E9;               \
394         else if (ch == 0x0300)                                                \
395           idx = COMP_TABLE_IDX_0300, len = COMP_TABLE_LEN_0300;               \
396         else if (ch == 0x0301)                                                \
397           idx = COMP_TABLE_IDX_0301, len = COMP_TABLE_LEN_0301;               \
398         else if (ch == 0x309a)                                                \
399           idx = COMP_TABLE_IDX_309A, len = COMP_TABLE_LEN_309A;               \
400         else                                                                  \
401           goto not_combining;                                                 \
402                                                                               \
403         do                                                                    \
404           if (comp_table_data[idx].base == (uint16_t) lasttwo)                \
405             break;                                                            \
406         while (++idx, --len > 0);                                             \
407                                                                               \
408         if (len > 0)                                                          \
409           {                                                                   \
410             /* Output the combined character.  */                             \
411             /* We know the combined character is in JISX0213 plane 1,         \
412                but the buffered character may have been in JISX0208 or in     \
413                JISX0213 plane 1.  */                                          \
414             size_t need =                                                     \
415               (lasttwo >> 16                                                  \
416                || (set != JISX0213_1_2000_set && set != JISX0213_1_2004_set)  \
417                ? 4 : 0);                                                      \
418                                                                               \
419             if (__builtin_expect (outptr + need + 2 > outend, 0))             \
420               {                                                               \
421                 result = __GCONV_FULL_OUTPUT;                                 \
422                 break;                                                        \
423               }                                                               \
424             if (need)                                                         \
425               {                                                               \
426                 /* But first, output the escape sequence.  */                 \
427                 *outptr++ = ESC;                                              \
428                 *outptr++ = '$';                                              \
429                 *outptr++ = '(';                                              \
430                 *outptr++ = 'O';                                              \
431                 set = JISX0213_1_2000_set;                                    \
432               }                                                               \
433             lasttwo = comp_table_data[idx].composed;                          \
434             *outptr++ = (lasttwo >> 8) & 0xff;                                \
435             *outptr++ = lasttwo & 0xff;                                       \
436             lasttwo = 0;                                                      \
437             inptr += 4;                                                       \
438             continue;                                                         \
439           }                                                                   \
440                                                                               \
441       not_combining:                                                          \
442         /* Output the buffered character.  */                                 \
443         /* We know it is in JISX0208 or in JISX0213 plane 1.  */              \
444         {                                                                     \
445           size_t need = (lasttwo >> 16 ? 3 : 0);                              \
446                                                                               \
447           if (__builtin_expect (outptr + need + 2 > outend, 0))               \
448             {                                                                 \
449               result = __GCONV_FULL_OUTPUT;                                   \
450               break;                                                          \
451             }                                                                 \
452           if (need)                                                           \
453             {                                                                 \
454               /* But first, output the escape sequence.  */                   \
455               assert (set == JISX0208_1983_set);                              \
456               *outptr++ = ESC;                                                \
457               *outptr++ = '$';                                                \
458               *outptr++ = 'B';                                                \
459             }                                                                 \
460           *outptr++ = (lasttwo >> 8) & 0xff;                                  \
461           *outptr++ = lasttwo & 0xff;                                         \
462           lasttwo = 0;                                                        \
463           continue;                                                           \
464         }                                                                     \
465       }                                                                       \
466                                                                               \
467     /* First see whether we can write the character using the currently       \
468        selected character set.  */                                            \
469     if (set == ASCII_set)                                                     \
470       {                                                                       \
471         /* Please note that the NUL byte is *not* matched if we are not       \
472            currently using the ASCII charset.  This is because we must        \
473            switch to the initial state whenever a NUL byte is written.  */    \
474         if (ch <= 0x7f)                                                       \
475           {                                                                   \
476             *outptr++ = ch;                                                   \
477             inptr += 4;                                                       \
478             continue;                                                         \
479           }                                                                   \
480       }                                                                       \
481     /* ISO-2022-JP recommends to encode the newline character always in       \
482        ASCII since this allows a context-free interpretation of the           \
483        characters at the beginning of the next line.  Otherwise it would      \
484        have to be known whether the last line ended using ASCII or            \
485        JIS X 0201.  */                                                        \
486     else if (set == JISX0201_Roman_set)                                       \
487       {                                                                       \
488         unsigned char buf[1];                                                 \
489         if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR                \
490             && buf[0] > 0x20 && buf[0] < 0x80)                                \
491           {                                                                   \
492             *outptr++ = buf[0];                                               \
493             inptr += 4;                                                       \
494             continue;                                                         \
495           }                                                                   \
496       }                                                                       \
497     else if (set == JISX0201_Kana_set)                                        \
498       {                                                                       \
499         unsigned char buf[1];                                                 \
500         if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR                \
501             && buf[0] >= 0x80)                                                \
502           {                                                                   \
503             *outptr++ = buf[0] - 0x80;                                        \
504             inptr += 4;                                                       \
505             continue;                                                         \
506           }                                                                   \
507       }                                                                       \
508     else if (/*set == JISX0208_1978_set || */ set == JISX0208_1983_set)       \
509       {                                                                       \
510         size_t written = ucs4_to_jisx0208 (ch, outptr, outend - outptr);      \
511                                                                               \
512         if (written != __UNKNOWN_10646_CHAR)                                  \
513           {                                                                   \
514             uint32_t jch = ucs4_to_jisx0213 (ch);                             \
515                                                                               \
516             if (jch & 0x0080)                                                 \
517               {                                                               \
518                 /* A possible match in comp_table_data.  Buffer it.  */       \
519                 lasttwo = jch & 0x7f7f;                                       \
520                 inptr += 4;                                                   \
521                 continue;                                                     \
522               }                                                               \
523             if (__builtin_expect (written == 0, 0))                           \
524               {                                                               \
525                 result = __GCONV_FULL_OUTPUT;                                 \
526                 break;                                                        \
527               }                                                               \
528             else                                                              \
529               {                                                               \
530                 outptr += written;                                            \
531                 inptr += 4;                                                   \
532                 continue;                                                     \
533              }                                                                \
534           }                                                                   \
535       }                                                                       \
536     else                                                                      \
537       {                                                                       \
538         /* (set == JISX0213_1_2000_set || set == JISX0213_1_2004_set          \
539             || set == JISX0213_2_set) */                                      \
540         uint32_t jch = ucs4_to_jisx0213 (ch);                                 \
541                                                                               \
542         if (jch != 0                                                          \
543             && (jch & 0x8000                                                  \
544                 ? set == JISX0213_2_set                                       \
545                 : (set == JISX0213_1_2004_set                                 \
546                    || (set == JISX0213_1_2000_set                             \
547                        && !jisx0213_added_in_2004_p (jch)))))                 \
548           {                                                                   \
549             if (jch & 0x0080)                                                 \
550               {                                                               \
551                 /* A possible match in comp_table_data.  Buffer it.  */       \
552                                                                               \
553                 /* We know it's a JISX 0213 plane 1 character.  */            \
554                 assert ((jch & 0x8000) == 0);                                 \
555                                                                               \
556                 lasttwo = jch & 0x7f7f;                                       \
557                 inptr += 4;                                                   \
558                 continue;                                                     \
559               }                                                               \
560                                                                               \
561             if (__builtin_expect (outptr + 1 >= outend, 0))                   \
562               {                                                               \
563                 result = __GCONV_FULL_OUTPUT;                                 \
564                 break;                                                        \
565               }                                                               \
566             *outptr++ = (jch >> 8) & 0x7f;                                    \
567             *outptr++ = jch & 0x7f;                                           \
568             inptr += 4;                                                       \
569             continue;                                                         \
570           }                                                                   \
571       }                                                                       \
572                                                                               \
573     /* The attempts to use the currently selected character set failed,       \
574        either because the character requires a different character set,       \
575        or because the character is unknown.  */                               \
576                                                                               \
577     if (ch <= 0x7f)                                                           \
578       {                                                                       \
579         /* We must encode using ASCII.  First write out the escape            \
580            sequence.  */                                                      \
581         if (__builtin_expect (outptr + 3 > outend, 0))                        \
582           {                                                                   \
583             result = __GCONV_FULL_OUTPUT;                                     \
584             break;                                                            \
585           }                                                                   \
586                                                                               \
587         *outptr++ = ESC;                                                      \
588         *outptr++ = '(';                                                      \
589         *outptr++ = 'B';                                                      \
590         set = ASCII_set;                                                      \
591                                                                               \
592         if (__builtin_expect (outptr >= outend, 0))                           \
593           {                                                                   \
594             result = __GCONV_FULL_OUTPUT;                                     \
595             break;                                                            \
596           }                                                                   \
597         *outptr++ = ch;                                                       \
598       }                                                                       \
599     else                                                                      \
600       {                                                                       \
601         unsigned char buf[2];                                                 \
602                                                                               \
603         /* Try JIS X 0201 Roman.  */                                          \
604         if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR                \
605             && buf[0] > 0x20 && buf[0] < 0x80)                                \
606           {                                                                   \
607             if (set != JISX0201_Roman_set)                                    \
608               {                                                               \
609                 if (__builtin_expect (outptr + 3 > outend, 0))                \
610                   {                                                           \
611                     result = __GCONV_FULL_OUTPUT;                             \
612                     break;                                                    \
613                   }                                                           \
614                 *outptr++ = ESC;                                              \
615                 *outptr++ = '(';                                              \
616                 *outptr++ = 'J';                                              \
617                 set = JISX0201_Roman_set;                                     \
618               }                                                               \
619                                                                               \
620             if (__builtin_expect (outptr >= outend, 0))                       \
621               {                                                               \
622                 result = __GCONV_FULL_OUTPUT;                                 \
623                 break;                                                        \
624               }                                                               \
625             *outptr++ = buf[0];                                               \
626           }                                                                   \
627         else                                                                  \
628           {                                                                   \
629             uint32_t jch = ucs4_to_jisx0213 (ch);                             \
630                                                                               \
631             /* Try JIS X 0208.  */                                            \
632             size_t written = ucs4_to_jisx0208 (ch, buf, 2);                   \
633             if (written != __UNKNOWN_10646_CHAR)                              \
634               {                                                               \
635                 if (jch & 0x0080)                                             \
636                   {                                                           \
637                     /* A possible match in comp_table_data.  Buffer it.  */   \
638                     lasttwo = ((set != JISX0208_1983_set ? 1 : 0) << 16)      \
639                               | (jch & 0x7f7f);                               \
640                     set = JISX0208_1983_set;                                  \
641                     inptr += 4;                                               \
642                     continue;                                                 \
643                   }                                                           \
644                                                                               \
645                 if (set != JISX0208_1983_set)                                 \
646                   {                                                           \
647                     if (__builtin_expect (outptr + 3 > outend, 0))            \
648                       {                                                       \
649                         result = __GCONV_FULL_OUTPUT;                         \
650                         break;                                                \
651                       }                                                       \
652                     *outptr++ = ESC;                                          \
653                     *outptr++ = '$';                                          \
654                     *outptr++ = 'B';                                          \
655                     set = JISX0208_1983_set;                                  \
656                   }                                                           \
657                                                                               \
658                 if (__builtin_expect (outptr + 2 > outend, 0))                \
659                   {                                                           \
660                     result = __GCONV_FULL_OUTPUT;                             \
661                     break;                                                    \
662                   }                                                           \
663                 *outptr++ = buf[0];                                           \
664                 *outptr++ = buf[1];                                           \
665               }                                                               \
666             else                                                              \
667               {                                                               \
668                 /* Try JIS X 0213.  */                                        \
669                 if (jch != 0)                                                 \
670                   {                                                           \
671                     int new_set =                                             \
672                       (jch & 0x8000                                           \
673                        ? JISX0213_2_set                                       \
674                        : jisx0213_added_in_2004_p (jch)                       \
675                          ? JISX0213_1_2004_set                                \
676                          : JISX0213_1_2000_set);                              \
677                                                                               \
678                     if (set != new_set)                                       \
679                       {                                                       \
680                         if (__builtin_expect (outptr + 4 > outend, 0))        \
681                           {                                                   \
682                             result = __GCONV_FULL_OUTPUT;                     \
683                             break;                                            \
684                           }                                                   \
685                         *outptr++ = ESC;                                      \
686                         *outptr++ = '$';                                      \
687                         *outptr++ = '(';                                      \
688                         *outptr++ =                                           \
689                           ((new_set - JISX0213_1_2000_set) >> 3) + 'O';       \
690                         set = new_set;                                        \
691                       }                                                       \
692                                                                               \
693                     if (jch & 0x0080)                                         \
694                       {                                                       \
695                         /* A possible match in comp_table_data.               \
696                            Buffer it.  */                                     \
697                                                                               \
698                         /* We know it's a JIS X 0213 plane 1 character.  */   \
699                         assert ((jch & 0x8000) == 0);                         \
700                                                                               \
701                         lasttwo = jch & 0x7f7f;                               \
702                         inptr += 4;                                           \
703                         continue;                                             \
704                       }                                                       \
705                                                                               \
706                     if (__builtin_expect (outptr + 1 >= outend, 0))           \
707                       {                                                       \
708                         result = __GCONV_FULL_OUTPUT;                         \
709                         break;                                                \
710                       }                                                       \
711                     *outptr++ = (jch >> 8) & 0x7f;                            \
712                     *outptr++ = jch & 0x7f;                                   \
713                   }                                                           \
714                 else                                                          \
715                   {                                                           \
716                     /* Try JIS X 0201 Katakana.  This is officially not part  \
717                        of ISO-2022-JP-3.  Therefore we try it after all other \
718                        attempts.  */                                          \
719                     if (ucs4_to_jisx0201 (ch, buf) != __UNKNOWN_10646_CHAR    \
720                         && buf[0] >= 0x80)                                    \
721                       {                                                       \
722                         if (set != JISX0201_Kana_set)                         \
723                           {                                                   \
724                             if (__builtin_expect (outptr + 3 > outend, 0))    \
725                               {                                               \
726                                 result = __GCONV_FULL_OUTPUT;                 \
727                                 break;                                        \
728                               }                                               \
729                             *outptr++ = ESC;                                  \
730                             *outptr++ = '(';                                  \
731                             *outptr++ = 'I';                                  \
732                             set = JISX0201_Kana_set;                          \
733                           }                                                   \
734                                                                               \
735                         if (__builtin_expect (outptr >= outend, 0))           \
736                           {                                                   \
737                             result = __GCONV_FULL_OUTPUT;                     \
738                             break;                                            \
739                           }                                                   \
740                         *outptr++ = buf[0] - 0x80;                            \
741                       }                                                       \
742                     else                                                      \
743                       {                                                       \
744                         UNICODE_TAG_HANDLER (ch, 4);                          \
745                                                                               \
746                         /* Illegal character.  */                             \
747                         STANDARD_TO_LOOP_ERR_HANDLER (4);                     \
748                       }                                                       \
749                   }                                                           \
750               }                                                               \
751           }                                                                   \
752       }                                                                       \
753                                                                               \
754     /* Now that we wrote the output increment the input pointer.  */          \
755     inptr += 4;                                                               \
756   }
757 #define LOOP_NEED_FLAGS
758 #define EXTRA_LOOP_DECLS        , int *statep
759 #define INIT_PARAMS             int set = *statep & CURRENT_SEL_MASK;         \
760                                 uint32_t lasttwo = *statep >> 6
761 #define REINIT_PARAMS           do                                            \
762                                   {                                           \
763                                     set = *statep & CURRENT_SEL_MASK;         \
764                                     lasttwo = *statep >> 6;                   \
765                                   }                                           \
766                                 while (0)
767 #define UPDATE_PARAMS           *statep = set | (lasttwo << 6)
768 #include <iconv/loop.c>
769
770
771 /* Now define the toplevel functions.  */
772 #include <iconv/skeleton.c>