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