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