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