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