9b22ddd6b398bc5e40acf7fe1dab73aacd5db509
[platform/upstream/glibc.git] / iconvdata / iso-2022-jp.c
1 /* Conversion module for ISO-2022-JP.
2    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <gconv.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "jis0201.h"
26 #include "jis0208.h"
27 #include "jis0212.h"
28 #include "gb2312.h"
29 #include "ksc5601.h"
30
31 struct gap
32 {
33   uint16_t start;
34   uint16_t end;
35   int32_t idx;
36 };
37
38 #include "iso8859-7jp.h"
39
40 /* This makes obvious what everybody knows: 0x1b is the Esc character.  */
41 #define ESC 0x1b
42
43 /* We provide our own initialization and destructor function.  */
44 #define DEFINE_INIT     0
45 #define DEFINE_FINI     0
46
47 /* Definitions used in the body of the `gconv' function.  */
48 #define FROM_LOOP               from_iso2022jp_loop
49 #define TO_LOOP                 to_iso2022jp_loop
50 #define MIN_NEEDED_FROM         1
51 #define MAX_NEEDED_FROM         4
52 #define MIN_NEEDED_TO           4
53 #define MAX_NEEDED_TO           4
54 #define FROM_DIRECTION          (dir == from_iso2022jp)
55 #define PREPARE_LOOP \
56   enum direction dir = ((struct iso2022jp_data *) step->__data)->dir;         \
57   enum variant var = ((struct iso2022jp_data *) step->__data)->var;           \
58   int save_set;                                                               \
59   int *setp = &data->__statep->__count;
60 #define EXTRA_LOOP_ARGS         , var, setp
61
62
63 /* Direction of the transformation.  */
64 enum direction
65 {
66   illegal_dir,
67   to_iso2022jp,
68   from_iso2022jp
69 };
70
71 /* We handle ISO-2022-jp and ISO-2022-JP-2 here.  */
72 enum variant
73 {
74   illegal_var,
75   iso2022jp,
76   iso2022jp2
77 };
78
79
80 struct iso2022jp_data
81 {
82   enum direction dir;
83   enum variant var;
84 };
85
86
87 /* The COUNT element of the state keeps track of the currently selected
88    character set.  The possible values are:  */
89 enum
90 {
91   ASCII_set = 0,
92   JISX0208_1978_set = 8,
93   JISX0208_1983_set = 16,
94   JISX0201_Roman_set = 24,
95   JISX0201_Kana_set = 32,
96   GB2312_set = 40,
97   KSC5601_set = 48,
98   JISX0212_set = 56,
99   CURRENT_SEL_MASK = 56
100 };
101
102 /* The second value stored is the designation of the G2 set.  The following
103    values are possible:  */
104 enum
105 {
106   UNSPECIFIED_set = 0,
107   ISO88591_set = 64,
108   ISO88597_set = 128,
109   CURRENT_ASSIGN_MASK = 192
110 };
111
112
113 int
114 gconv_init (struct __gconv_step *step)
115 {
116   /* Determine which direction.  */
117   struct iso2022jp_data *new_data;
118   enum direction dir = illegal_dir;
119   enum variant var = illegal_var;
120   int result;
121
122   if (__strcasecmp (step->__from_name, "ISO-2022-JP//") == 0)
123     {
124       dir = from_iso2022jp;
125       var = iso2022jp;
126     }
127   else if (__strcasecmp (step->__to_name, "ISO-2022-JP//") == 0)
128     {
129       dir = to_iso2022jp;
130       var = iso2022jp;
131     }
132   else if (__strcasecmp (step->__from_name, "ISO-2022-JP-2//") == 0)
133     {
134       dir = from_iso2022jp;
135       var = iso2022jp2;
136     }
137   else if (__strcasecmp (step->__to_name, "ISO-2022-JP-2//") == 0)
138     {
139       dir = to_iso2022jp;
140       var = iso2022jp2;
141     }
142
143   result = __GCONV_NOCONV;
144   if (__builtin_expect (dir, from_iso2022jp) != illegal_dir)
145     {
146       new_data
147         = (struct iso2022jp_data *) malloc (sizeof (struct iso2022jp_data));
148
149       result = __GCONV_NOMEM;
150       if (new_data != NULL)
151         {
152           new_data->dir = dir;
153           new_data->var = var;
154           step->__data = new_data;
155
156           if (dir == from_iso2022jp)
157             {
158               step->__min_needed_from = MIN_NEEDED_FROM;
159               step->__max_needed_from = MAX_NEEDED_FROM;
160               step->__min_needed_to = MIN_NEEDED_TO;
161               step->__max_needed_to = MAX_NEEDED_TO;
162             }
163           else
164             {
165               step->__min_needed_from = MIN_NEEDED_TO;
166               step->__max_needed_from = MAX_NEEDED_TO;
167               step->__min_needed_to = MIN_NEEDED_FROM;
168               step->__max_needed_to = MAX_NEEDED_FROM + 2;
169             }
170
171           /* Yes, this is a stateful encoding.  */
172           step->__stateful = 1;
173
174           result = __GCONV_OK;
175         }
176     }
177
178   return result;
179 }
180
181
182 void
183 gconv_end (struct __gconv_step *data)
184 {
185   free (data->__data);
186 }
187
188
189 /* Since this is a stateful encoding we have to provide code which resets
190    the output state to the initial state.  This has to be done during the
191    flushing.  */
192 #define EMIT_SHIFT_TO_INIT \
193   if ((data->__statep->__count & ~7) != ASCII_set)                            \
194     {                                                                         \
195       enum direction dir = ((struct iso2022jp_data *) step->__data)->dir;     \
196                                                                               \
197       if (dir == from_iso2022jp)                                              \
198         {                                                                     \
199           /* It's easy, we don't have to emit anything, we just reset the     \
200              state for the input.  Note that this also clears the G2          \
201              designation.  */                                                 \
202           data->__statep->__count &= 7;                                       \
203           data->__statep->__count |= ASCII_set;                               \
204         }                                                                     \
205       else                                                                    \
206         {                                                                     \
207           unsigned char *outbuf = data->__outbuf;                             \
208                                                                               \
209           /* We are not in the initial state.  To switch back we have         \
210              to emit the sequence `Esc ( B'.  */                              \
211           if (__builtin_expect (outbuf + 3 > data->__outbufend, 0))           \
212             /* We don't have enough room in the output buffer.  */            \
213             status = __GCONV_FULL_OUTPUT;                                     \
214           else                                                                \
215             {                                                                 \
216               /* Write out the shift sequence.  */                            \
217               *outbuf++ = ESC;                                                \
218               *outbuf++ = '(';                                                \
219               *outbuf++ = 'B';                                                \
220               data->__outbuf = outbuf;                                        \
221               /* Note that this also clears the G2 designation.  */           \
222               data->__statep->__count &= ~7;                                  \
223               data->__statep->__count |= ASCII_set;                           \
224             }                                                                 \
225         }                                                                     \
226     }
227
228
229 /* Since we might have to reset input pointer we must be able to save
230    and retore the state.  */
231 #define SAVE_RESET_STATE(Save) \
232   if (Save)                                                                   \
233     save_set = *setp;                                                         \
234   else                                                                        \
235     *setp = save_set
236
237
238 /* First define the conversion function from ISO-2022-JP to UCS4.  */
239 #define MIN_NEEDED_INPUT        MIN_NEEDED_FROM
240 #define MAX_NEEDED_INPUT        MAX_NEEDED_FROM
241 #define MIN_NEEDED_OUTPUT       MIN_NEEDED_TO
242 #define LOOPFCT                 FROM_LOOP
243 #define BODY \
244   {                                                                           \
245     uint32_t ch = *inptr;                                                     \
246                                                                               \
247     /* Recognize escape sequences.  */                                        \
248     if (__builtin_expect (ch, 0) == ESC)                                      \
249       {                                                                       \
250         /* We now must be prepared to read two to three more                  \
251            chracters.  If we have a match in the first character but          \
252            then the input buffer ends we terminate with an error since        \
253            we must not risk missing an escape sequence just because it        \
254            is not entirely in the current input buffer.  */                   \
255         if (__builtin_expect (inptr + 2 >= inend, 0)                          \
256             || (var == iso2022jp2 && inptr[1] == '$' && inptr[2] == '('       \
257                 && __builtin_expect (inptr + 3 >= inend, 0)))                 \
258           {                                                                   \
259             /* Not enough input available.  */                                \
260             result = __GCONV_EMPTY_INPUT;                                     \
261             break;                                                            \
262           }                                                                   \
263                                                                               \
264         if (inptr[1] == '(')                                                  \
265           {                                                                   \
266             if (inptr[2] == 'B')                                              \
267               {                                                               \
268                 /* ASCII selected.  */                                        \
269                 set = ASCII_set;                                              \
270                 inptr += 3;                                                   \
271                 continue;                                                     \
272               }                                                               \
273             else if (inptr[2] == 'J')                                         \
274               {                                                               \
275                 /* JIS X 0201 selected.  */                                   \
276                 set = JISX0201_Roman_set;                                     \
277                 inptr += 3;                                                   \
278                 continue;                                                     \
279               }                                                               \
280             else if (var == iso2022jp2 && inptr[2] == 'I')                    \
281               {                                                               \
282                 /* JIS X 0201 selected.  */                                   \
283                 set = JISX0201_Kana_set;                                      \
284                 inptr += 3;                                                   \
285                 continue;                                                     \
286               }                                                               \
287           }                                                                   \
288         else if (inptr[1] == '$')                                             \
289           {                                                                   \
290             if (inptr[2] == '@')                                              \
291               {                                                               \
292                 /* JIS X 0208-1978 selected.  */                              \
293                 set = JISX0208_1978_set;                                      \
294                 inptr += 3;                                                   \
295                 continue;                                                     \
296               }                                                               \
297             else if (inptr[2] == 'B')                                         \
298               {                                                               \
299                 /* JIS X 0208-1983 selected.  */                              \
300                 set = JISX0208_1983_set;                                      \
301                 inptr += 3;                                                   \
302                 continue;                                                     \
303               }                                                               \
304             else if (var == iso2022jp2)                                       \
305               {                                                               \
306                 if (inptr[2] == 'A')                                          \
307                   {                                                           \
308                     /* GB 2312-1980 selected.  */                             \
309                     set = GB2312_set;                                         \
310                     inptr += 3;                                               \
311                     continue;                                                 \
312                   }                                                           \
313                 else if (inptr[2] == '(')                                     \
314                   {                                                           \
315                     if (inptr[3] == 'C')                                      \
316                       {                                                       \
317                         /* KSC 5601-1987 selected.  */                        \
318                         set = KSC5601_set;                                    \
319                         inptr += 4;                                           \
320                         continue;                                             \
321                       }                                                       \
322                     else if (inptr[3] == 'D')                                 \
323                       {                                                       \
324                         /* JIS X 0212-1990 selected.  */                      \
325                         set = JISX0212_set;                                   \
326                         inptr += 4;                                           \
327                         continue;                                             \
328                       }                                                       \
329                   }                                                           \
330               }                                                               \
331           }                                                                   \
332         else if (var == iso2022jp2 && inptr[1] == '.')                        \
333           {                                                                   \
334             if (inptr[2] == 'A')                                              \
335               {                                                               \
336                 /* ISO 8859-1-GR selected.  */                                \
337                 set2 = ISO88591_set;                                          \
338                 inptr += 3;                                                   \
339                 continue;                                                     \
340               }                                                               \
341             else if (inptr[2] == 'F')                                         \
342               {                                                               \
343                 /* ISO 8859-7-GR selected.  */                                \
344                 set2 = ISO88597_set;                                          \
345                 inptr += 3;                                                   \
346                 continue;                                                     \
347               }                                                               \
348           }                                                                   \
349       }                                                                       \
350                                                                               \
351     if (ch == ESC && var == iso2022jp2 && inptr[1] == 'N')                    \
352       {                                                                       \
353         if (set2 == ISO88591_set)                                             \
354           {                                                                   \
355             ch = inptr[2] | 0x80;                                             \
356             inptr += 3;                                                       \
357           }                                                                   \
358         else if (__builtin_expect (set2, ISO88597_set) == ISO88597_set)       \
359           {                                                                   \
360             /* We use the table from the ISO 8859-7 module.  */               \
361             if (inptr[2] < 0x20 || inptr[2] > 0x80)                           \
362               {                                                               \
363                 if (! ignore_errors_p ())                                     \
364                   {                                                           \
365                     result = __GCONV_ILLEGAL_INPUT;                           \
366                     break;                                                    \
367                   }                                                           \
368                                                                               \
369                 ++inptr;                                                      \
370                 ++*irreversible;                                              \
371                 continue;                                                     \
372               }                                                               \
373             ch = iso88597_to_ucs4[inptr[2] - 0x20];                           \
374             if (ch == 0)                                                      \
375               {                                                               \
376                 if (! ignore_errors_p ())                                     \
377                   {                                                           \
378                     result = __GCONV_ILLEGAL_INPUT;                           \
379                     break;                                                    \
380                   }                                                           \
381                                                                               \
382                 inptr += 3;                                                   \
383                 ++*irreversible;                                              \
384                 continue;                                                     \
385               }                                                               \
386             inptr += 3;                                                       \
387           }                                                                   \
388         else                                                                  \
389           {                                                                   \
390             if (! ignore_errors_p ())                                         \
391               {                                                               \
392                 result = __GCONV_ILLEGAL_INPUT;                               \
393                 break;                                                        \
394               }                                                               \
395                                                                               \
396             ++inptr;                                                          \
397             ++*irreversible;                                                  \
398             continue;                                                         \
399           }                                                                   \
400       }                                                                       \
401     else if (set == ASCII_set || (ch < 0x21 || ch == 0x7f))                   \
402       /* Almost done, just advance the input pointer.  */                     \
403       ++inptr;                                                                \
404     else if (set == JISX0201_Roman_set)                                       \
405       {                                                                       \
406         /* Use the JIS X 0201 table.  */                                      \
407         ch = jisx0201_to_ucs4 (ch);                                           \
408         if (__builtin_expect (ch, 0) == __UNKNOWN_10646_CHAR)                 \
409           {                                                                   \
410             if (! ignore_errors_p ())                                         \
411               {                                                               \
412                 result = __GCONV_ILLEGAL_INPUT;                               \
413                 break;                                                        \
414               }                                                               \
415                                                                               \
416             ++inptr;                                                          \
417             ++*irreversible;                                                  \
418             continue;                                                         \
419           }                                                                   \
420         ++inptr;                                                              \
421       }                                                                       \
422     else if (set == JISX0201_Kana_set)                                        \
423       {                                                                       \
424         /* Use the JIS X 0201 table.  */                                      \
425         ch = jisx0201_to_ucs4 (ch + 0x80);                                    \
426         if (__builtin_expect (ch, 0) == __UNKNOWN_10646_CHAR)                 \
427           {                                                                   \
428             if (! ignore_errors_p ())                                         \
429               {                                                               \
430                 result = __GCONV_ILLEGAL_INPUT;                               \
431                 break;                                                        \
432               }                                                               \
433                                                                               \
434             ++inptr;                                                          \
435             ++*irreversible;                                                  \
436             continue;                                                         \
437           }                                                                   \
438         ++inptr;                                                              \
439       }                                                                       \
440     else                                                                      \
441       {                                                                       \
442         if (set == JISX0208_1978_set || set == JISX0208_1983_set)             \
443           /* XXX I don't have the tables for these two old variants of        \
444              JIS X 0208.  Therefore I'm using the tables for JIS X            \
445              0208-1990.  If somebody has problems with this please            \
446              provide the appropriate tables.  */                              \
447           ch = jisx0208_to_ucs4 (&inptr,                                      \
448                                  NEED_LENGTH_TEST ? inend - inptr : 2, 0);    \
449         else if (set == JISX0212_set)                                         \
450           /* Use the JIS X 0212 table.  */                                    \
451           ch = jisx0212_to_ucs4 (&inptr,                                      \
452                                  NEED_LENGTH_TEST ? inend - inptr : 2, 0);    \
453         else if (set == GB2312_set)                                           \
454           /* Use the GB 2312 table.  */                                       \
455           ch = gb2312_to_ucs4 (&inptr,                                        \
456                                NEED_LENGTH_TEST ? inend - inptr : 2, 0);      \
457         else                                                                  \
458           {                                                                   \
459             assert (set == KSC5601_set);                                      \
460                                                                               \
461             /* Use the KSC 5601 table.  */                                    \
462             ch = ksc5601_to_ucs4 (&inptr,                                     \
463                                   NEED_LENGTH_TEST ? inend - inptr : 2, 0);   \
464           }                                                                   \
465                                                                               \
466         if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)                \
467           {                                                                   \
468             result = __GCONV_EMPTY_INPUT;                                     \
469             break;                                                            \
470           }                                                                   \
471         else if (__builtin_expect (ch, 0) == __UNKNOWN_10646_CHAR)            \
472           {                                                                   \
473             if (! ignore_errors_p ())                                         \
474               {                                                               \
475                 result = __GCONV_ILLEGAL_INPUT;                               \
476                 break;                                                        \
477               }                                                               \
478                                                                               \
479             ++inptr;                                                          \
480             ++*irreversible;                                                  \
481             continue;                                                         \
482           }                                                                   \
483       }                                                                       \
484                                                                               \
485     put32 (outptr, ch);                                                       \
486     outptr += 4;                                                              \
487   }
488 #define EXTRA_LOOP_DECLS        , enum variant var, int *setp
489 #define INIT_PARAMS             int set = *setp & CURRENT_SEL_MASK;           \
490                                 int set2 = *setp & CURRENT_ASSIGN_MASK
491 #define UPDATE_PARAMS           *setp = set | set2
492 #include <iconv/loop.c>
493
494
495 /* Next, define the other direction.  */
496 #define MIN_NEEDED_INPUT        MIN_NEEDED_TO
497 #define MIN_NEEDED_OUTPUT       MIN_NEEDED_FROM
498 #define MAX_NEEDED_OUTPUT       (MAX_NEEDED_FROM + 2)
499 #define LOOPFCT                 TO_LOOP
500 #define BODY \
501   {                                                                           \
502     uint32_t ch;                                                              \
503     size_t written = 0;                                                       \
504                                                                               \
505     ch = get32 (inptr);                                                       \
506                                                                               \
507     /* First see whether we can write the character using the currently       \
508        selected character set.  */                                            \
509     if (set == ASCII_set)                                                     \
510       {                                                                       \
511         /* Please note that the NUL byte is *not* matched if we are not       \
512            currently using the ASCII charset.  This is because we must        \
513            switch to the initial state whenever a NUL byte is written.  */    \
514         if (ch <= 0x7f)                                                       \
515           {                                                                   \
516             *outptr++ = ch;                                                   \
517             written = 1;                                                      \
518           }                                                                   \
519         /* At the beginning of a line, G2 designation is cleared.  */         \
520         if (var == iso2022jp2 && ch == 0x0a)                                  \
521           set2 = UNSPECIFIED_set;                                             \
522       }                                                                       \
523     /* ISO-2022-JP recommends to encode the newline character always in       \
524        ASCII since this allows a context-free interpretation of the           \
525        characters at the beginning of the next line.  Otherwise it would      \
526        have to be known whether the last line ended using ASCII or            \
527        JIS X 0201.  */                                                        \
528     else if (set == JISX0201_Roman_set)                                       \
529       {                                                                       \
530         unsigned char buf[2];                                                 \
531         written = ucs4_to_jisx0201 (ch, buf);                                 \
532         if (written != __UNKNOWN_10646_CHAR && buf[0] > 0x20                  \
533             && buf[0] < 0x80)                                                 \
534           {                                                                   \
535             *outptr++ = buf[0];                                               \
536             written = 1;                                                      \
537           }                                                                   \
538         else                                                                  \
539           written = __UNKNOWN_10646_CHAR;                                     \
540       }                                                                       \
541     else if (set == JISX0201_Kana_set)                                        \
542       {                                                                       \
543         unsigned char buf[2];                                                 \
544         written = ucs4_to_jisx0201 (ch, buf);                                 \
545         if (written != __UNKNOWN_10646_CHAR && buf[0] > 0xa0                  \
546             && buf[0] < 0xe0)                                                 \
547           {                                                                   \
548             *outptr++ = buf[0] - 0x80;                                        \
549             written = 1;                                                      \
550           }                                                                   \
551         else                                                                  \
552           written = __UNKNOWN_10646_CHAR;                                     \
553       }                                                                       \
554     else                                                                      \
555       {                                                                       \
556         if (set == JISX0208_1978_set || set == JISX0208_1983_set)             \
557           written = ucs4_to_jisx0208 (ch, outptr,                             \
558                                       (NEED_LENGTH_TEST                       \
559                                        ? outend - outptr : 2));               \
560         else if (set == JISX0212_set)                                         \
561           written = ucs4_to_jisx0212 (ch, outptr,                             \
562                                       (NEED_LENGTH_TEST                       \
563                                        ? outend - outptr : 2));               \
564         else if (set == GB2312_set)                                           \
565           written = ucs4_to_gb2312 (ch, outptr, (NEED_LENGTH_TEST             \
566                                                  ? outend - outptr : 2));     \
567         else                                                                  \
568           {                                                                   \
569             assert (set == KSC5601_set);                                      \
570                                                                               \
571             written = ucs4_to_ksc5601 (ch, outptr,                            \
572                                        (NEED_LENGTH_TEST                      \
573                                         ? outend - outptr : 2));              \
574           }                                                                   \
575                                                                               \
576         if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)           \
577           {                                                                   \
578             result = __GCONV_FULL_OUTPUT;                                     \
579             break;                                                            \
580           }                                                                   \
581         else if (written != __UNKNOWN_10646_CHAR)                             \
582           outptr += written;                                                  \
583       }                                                                       \
584                                                                               \
585     if (written == __UNKNOWN_10646_CHAR || written == 0)                      \
586       {                                                                       \
587         if (set2 == ISO88591_set)                                             \
588           {                                                                   \
589             if (ch >= 0x80 && ch <= 0xff)                                     \
590               {                                                               \
591                 *outptr++ = ESC;                                              \
592                 *outptr++ = 'N';                                              \
593                 *outptr++ = ch & 0x7f;                                        \
594                 written = 3;                                                  \
595               }                                                               \
596           }                                                                   \
597         else if (set2 == ISO88597_set)                                        \
598           {                                                                   \
599             const struct gap *rp = from_idx;                                  \
600                                                                               \
601             while (ch > rp->end)                                              \
602               ++rp;                                                           \
603             if (ch >= rp->start)                                              \
604               {                                                               \
605                 unsigned char res = iso88597_from_ucs4[ch - 0xa0 + rp->idx];  \
606                 if (res != '\0')                                              \
607                   {                                                           \
608                     *outptr++ = ESC;                                          \
609                     *outptr++ = 'N';                                          \
610                     *outptr++ = res;                                          \
611                     written = 3;                                              \
612                   }                                                           \
613               }                                                               \
614           }                                                                   \
615       }                                                                       \
616                                                                               \
617     if (written == __UNKNOWN_10646_CHAR || written == 0)                      \
618       {                                                                       \
619         /* Either this is an unknown character or we have to switch           \
620            the currently selected character set.  The character sets          \
621            do not code entirely separate parts of ISO 10646 and               \
622            therefore there is no single correct result.  If we choose         \
623            the character set to use wrong we might be end up with             \
624            using yet another character set for the next character             \
625            though the current and the next could be encoded with one          \
626            character set.  We leave this kind of optimization for             \
627            later and now simply use a fixed order in which we test for        \
628            availability  */                                                   \
629                                                                               \
630         if (ch <= 0x7f)                                                       \
631           {                                                                   \
632             /* We must encode using ASCII.  First write out the               \
633                escape sequence.  */                                           \
634             if (NEED_LENGTH_TEST && __builtin_expect (outptr + 3 > outend, 0))\
635               {                                                               \
636                 result = __GCONV_FULL_OUTPUT;                                 \
637                 break;                                                        \
638               }                                                               \
639                                                                               \
640             *outptr++ = ESC;                                                  \
641             *outptr++ = '(';                                                  \
642             *outptr++ = 'B';                                                  \
643             set = ASCII_set;                                                  \
644                                                                               \
645             if (NEED_LENGTH_TEST && __builtin_expect (outptr + 1 > outend, 0))\
646               {                                                               \
647                 result = __GCONV_FULL_OUTPUT;                                 \
648                 break;                                                        \
649               }                                                               \
650             *outptr++ = ch;                                                   \
651                                                                               \
652             /* At the beginning of a line, G2 designation is cleared.  */     \
653             if (var == iso2022jp2 && ch == 0x0a)                              \
654               set2 = UNSPECIFIED_set;                                         \
655           }                                                                   \
656         else                                                                  \
657           {                                                                   \
658             /* Now it becomes difficult.  We must search the other            \
659                character sets one by one and we cannot use simple             \
660                arithmetic to determine whether the character can be           \
661                encoded using this set.  */                                    \
662             size_t written;                                                   \
663             unsigned char buf[2];                                             \
664                                                                               \
665             written = ucs4_to_jisx0201 (ch, buf);                             \
666             if (written != __UNKNOWN_10646_CHAR && buf[0] < 0x80)             \
667               {                                                               \
668                 /* We use JIS X 0201.  */                                     \
669                 if (NEED_LENGTH_TEST                                          \
670                     && __builtin_expect (outptr + 3 > outend, 0))             \
671                   {                                                           \
672                     result = __GCONV_FULL_OUTPUT;                             \
673                     break;                                                    \
674                   }                                                           \
675                                                                               \
676                 *outptr++ = ESC;                                              \
677                 *outptr++ = '(';                                              \
678                 *outptr++ = 'J';                                              \
679                 set = JISX0201_Roman_set;                                     \
680                                                                               \
681                 if (NEED_LENGTH_TEST                                          \
682                     && __builtin_expect (outptr + 1 > outend, 0))             \
683                   {                                                           \
684                     result = __GCONV_FULL_OUTPUT;                             \
685                     break;                                                    \
686                   }                                                           \
687                 *outptr++ = buf[0];                                           \
688               }                                                               \
689             else                                                              \
690               {                                                               \
691                 written = ucs4_to_jisx0208 (ch, buf, 2);                      \
692                 if (written != __UNKNOWN_10646_CHAR)                          \
693                   {                                                           \
694                     /* We use JIS X 0208.  */                                 \
695                     if (NEED_LENGTH_TEST                                      \
696                         && __builtin_expect (outptr + 3 > outend, 0))         \
697                       {                                                       \
698                         result = __GCONV_FULL_OUTPUT;                         \
699                         break;                                                \
700                       }                                                       \
701                                                                               \
702                     *outptr++ = ESC;                                          \
703                     *outptr++ = '$';                                          \
704                     *outptr++ = 'B';                                          \
705                     set = JISX0208_1983_set;                                  \
706                                                                               \
707                     if (NEED_LENGTH_TEST                                      \
708                         && __builtin_expect (outptr + 2 > outend, 0))         \
709                       {                                                       \
710                         result = __GCONV_FULL_OUTPUT;                         \
711                         break;                                                \
712                       }                                                       \
713                     *outptr++ = buf[0];                                       \
714                     *outptr++ = buf[1];                                       \
715                   }                                                           \
716                 else if (__builtin_expect (var, iso2022jp2) == iso2022jp)     \
717                   {                                                           \
718                     /* We have no other choice.  */                           \
719                     if (! ignore_errors_p ())                                 \
720                       {                                                       \
721                         result = __GCONV_ILLEGAL_INPUT;                       \
722                         break;                                                \
723                       }                                                       \
724                                                                               \
725                     ++*irreversible;                                          \
726                   }                                                           \
727                 else                                                          \
728                   {                                                           \
729                     written = ucs4_to_jisx0212 (ch, buf, 2);                  \
730                     if (written != __UNKNOWN_10646_CHAR)                      \
731                       {                                                       \
732                         /* We use JIS X 0212.  */                             \
733                         if (NEED_LENGTH_TEST                                  \
734                             && __builtin_expect (outptr + 4 > outend, 0))     \
735                           {                                                   \
736                             result = __GCONV_FULL_OUTPUT;                     \
737                             break;                                            \
738                           }                                                   \
739                         *outptr++ = ESC;                                      \
740                         *outptr++ = '$';                                      \
741                         *outptr++ = '(';                                      \
742                         *outptr++ = 'D';                                      \
743                         set = JISX0212_set;                                   \
744                                                                               \
745                         if (NEED_LENGTH_TEST                                  \
746                             && __builtin_expect (outptr + 2 > outend, 0))     \
747                           {                                                   \
748                             result = __GCONV_FULL_OUTPUT;                     \
749                             break;                                            \
750                           }                                                   \
751                         *outptr++ = buf[0];                                   \
752                         *outptr++ = buf[1];                                   \
753                       }                                                       \
754                     else                                                      \
755                       {                                                       \
756                         written = ucs4_to_jisx0201 (ch, buf);                 \
757                         if (written != __UNKNOWN_10646_CHAR                   \
758                             && buf[0] >= 0x80)                                \
759                           {                                                   \
760                             /* We use JIS X 0201.  */                         \
761                             if (NEED_LENGTH_TEST                              \
762                                 && __builtin_expect (outptr + 3 > outend, 0)) \
763                               {                                               \
764                                 result = __GCONV_FULL_OUTPUT;                 \
765                                 break;                                        \
766                               }                                               \
767                                                                               \
768                             *outptr++ = ESC;                                  \
769                             *outptr++ = '(';                                  \
770                             *outptr++ = 'I';                                  \
771                             set = JISX0201_Kana_set;                          \
772                                                                               \
773                             if (NEED_LENGTH_TEST                              \
774                                 && __builtin_expect (outptr + 1 > outend, 0)) \
775                               {                                               \
776                                 result = __GCONV_FULL_OUTPUT;                 \
777                                 break;                                        \
778                               }                                               \
779                             *outptr++ = buf[0] - 0x80;                        \
780                           }                                                   \
781                         else if (ch != 0xa5 && ch >= 0x80 && ch <= 0xff)      \
782                           {                                                   \
783                             /* ISO 8859-1 upper half.   */                    \
784                             if (NEED_LENGTH_TEST                              \
785                                 && __builtin_expect (outptr + 3 > outend, 0)) \
786                               {                                               \
787                                 result = __GCONV_FULL_OUTPUT;                 \
788                                 break;                                        \
789                               }                                               \
790                                                                               \
791                             *outptr++ = ESC;                                  \
792                             *outptr++ = '.';                                  \
793                             *outptr++ = 'A';                                  \
794                             set2 = ISO88591_set;                              \
795                                                                               \
796                             if (NEED_LENGTH_TEST                              \
797                                 && __builtin_expect (outptr + 3 > outend, 0)) \
798                               {                                               \
799                                 result = __GCONV_FULL_OUTPUT;                 \
800                                 break;                                        \
801                               }                                               \
802                             *outptr++ = ESC;                                  \
803                             *outptr++ = 'N';                                  \
804                             *outptr++ = ch;                                   \
805                           }                                                   \
806                         else                                                  \
807                           {                                                   \
808                             written = ucs4_to_gb2312 (ch, buf, 2);            \
809                             if (written != __UNKNOWN_10646_CHAR)              \
810                               {                                               \
811                                 /* We use GB 2312.  */                        \
812                                 if (NEED_LENGTH_TEST                          \
813                                     && __builtin_expect (outptr + 3 > outend, \
814                                                          0))                  \
815                                   {                                           \
816                                     result = __GCONV_FULL_OUTPUT;             \
817                                     break;                                    \
818                                   }                                           \
819                                                                               \
820                                 *outptr++ = ESC;                              \
821                                 *outptr++ = '$';                              \
822                                 *outptr++ = 'A';                              \
823                                 set = GB2312_set;                             \
824                                                                               \
825                                 if (NEED_LENGTH_TEST                          \
826                                     && __builtin_expect (outptr + 2 > outend, \
827                                                          0))                  \
828                                   {                                           \
829                                     result = __GCONV_FULL_OUTPUT;             \
830                                     break;                                    \
831                                   }                                           \
832                                 *outptr++ = buf[0];                           \
833                                 *outptr++ = buf[1];                           \
834                               }                                               \
835                             else                                              \
836                               {                                               \
837                                 written = ucs4_to_ksc5601 (ch, buf, 2);       \
838                                 if (written != __UNKNOWN_10646_CHAR)          \
839                                   {                                           \
840                                     /* We use KSC 5601.  */                   \
841                                     if (NEED_LENGTH_TEST                      \
842                                         && __builtin_expect (outptr + 4       \
843                                                              > outend, 0))    \
844                                       {                                       \
845                                         result = __GCONV_FULL_OUTPUT;         \
846                                         break;                                \
847                                       }                                       \
848                                     *outptr++ = ESC;                          \
849                                     *outptr++ = '$';                          \
850                                     *outptr++ = '(';                          \
851                                     *outptr++ = 'C';                          \
852                                     set = KSC5601_set;                        \
853                                                                               \
854                                     if (NEED_LENGTH_TEST                      \
855                                         && __builtin_expect (outptr + 2       \
856                                                              > outend, 0))    \
857                                       {                                       \
858                                         result = __GCONV_FULL_OUTPUT;         \
859                                         break;                                \
860                                       }                                       \
861                                     *outptr++ = buf[0];                       \
862                                     *outptr++ = buf[1];                       \
863                                   }                                           \
864                                 else                                          \
865                                   {                                           \
866                                     const struct gap *rp = from_idx;          \
867                                     unsigned char gch = 0;                    \
868                                                                               \
869                                     while (ch > rp->end)                      \
870                                       ++rp;                                   \
871                                     if (ch >= rp->start)                      \
872                                       {                                       \
873                                         ch = ch - 0xa0 + rp->idx;             \
874                                         gch = iso88597_from_ucs4[ch];         \
875                                       }                                       \
876                                                                               \
877                                     if (__builtin_expect (gch, 1) != 0)       \
878                                       {                                       \
879                                         /* We use ISO 8859-7 greek.  */       \
880                                         if (NEED_LENGTH_TEST                  \
881                                             && __builtin_expect (outptr + 3   \
882                                                                  > outend, 0))\
883                                           {                                   \
884                                             result = __GCONV_FULL_OUTPUT;     \
885                                             break;                            \
886                                           }                                   \
887                                         *outptr++ = ESC;                      \
888                                         *outptr++ = '.';                      \
889                                         *outptr++ = 'F';                      \
890                                         set2 = ISO88597_set;                  \
891                                                                               \
892                                         if (NEED_LENGTH_TEST                  \
893                                             && __builtin_expect (outptr + 3   \
894                                                                  > outend, 0))\
895                                           {                                   \
896                                             result = __GCONV_FULL_OUTPUT;     \
897                                             break;                            \
898                                           }                                   \
899                                         *outptr++ = ESC;                      \
900                                         *outptr++ = 'N';                      \
901                                         *outptr++ = gch;                      \
902                                       }                                       \
903                                     else                                      \
904                                       {                                       \
905                                         if (! ignore_errors_p ())             \
906                                           {                                   \
907                                              result = __GCONV_ILLEGAL_INPUT;  \
908                                              break;                           \
909                                           }                                   \
910                                                                               \
911                                         ++*irreversible;                      \
912                                       }                                       \
913                                   }                                           \
914                               }                                               \
915                           }                                                   \
916                       }                                                       \
917                   }                                                           \
918               }                                                               \
919           }                                                                   \
920       }                                                                       \
921                                                                               \
922     /* Now that we wrote the output increment the input pointer.  */          \
923     inptr += 4;                                                               \
924   }
925 #define EXTRA_LOOP_DECLS        , enum variant var, int *setp
926 #define INIT_PARAMS             int set = *setp & CURRENT_SEL_MASK;           \
927                                 int set2 = *setp & CURRENT_ASSIGN_MASK
928 #define UPDATE_PARAMS           *setp = set | set2
929 #include <iconv/loop.c>
930
931
932 /* Now define the toplevel functions.  */
933 #include <iconv/skeleton.c>