Update BIG5-HKSCS charmap to HKSCS-2008
[platform/upstream/glibc.git] / iconvdata / iso-2022-cn-ext.c
1 /* Conversion module for ISO-2022-CN-EXT.
2    Copyright (C) 2000-2013 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the 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    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <dlfcn.h>
21 #include <gconv.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "gb2312.h"
26 #include "iso-ir-165.h"
27 #include "cns11643.h"
28 #include "cns11643l1.h"
29 #include "cns11643l2.h"
30
31 #include <assert.h>
32
33 /* This makes obvious what everybody knows: 0x1b is the Esc character.  */
34 #define ESC     0x1b
35
36 /* We have single-byte shift-in and shift-out sequences, and the single
37    shift sequences SS2 and SS3 which replaces the SS2/SS3 designation for
38    the next two bytes.  */
39 #define SI      0x0f
40 #define SO      0x0e
41 #define SS2_0   ESC
42 #define SS2_1   0x4e
43 #define SS3_0   ESC
44 #define SS3_1   0x4f
45
46 /* Definitions used in the body of the `gconv' function.  */
47 #define CHARSET_NAME            "ISO-2022-CN-EXT//"
48 #define DEFINE_INIT             1
49 #define DEFINE_FINI             1
50 #define FROM_LOOP               from_iso2022cn_ext_loop
51 #define TO_LOOP                 to_iso2022cn_ext_loop
52 #define FROM_LOOP_MIN_NEEDED_FROM       1
53 #define FROM_LOOP_MAX_NEEDED_FROM       4
54 #define FROM_LOOP_MIN_NEEDED_TO         4
55 #define FROM_LOOP_MAX_NEEDED_TO         4
56 #define TO_LOOP_MIN_NEEDED_FROM         4
57 #define TO_LOOP_MAX_NEEDED_FROM         4
58 #define TO_LOOP_MIN_NEEDED_TO           1
59 #define TO_LOOP_MAX_NEEDED_TO           6
60 #define PREPARE_LOOP \
61   int save_set;                                                               \
62   int *setp = &data->__statep->__count;
63 #define EXTRA_LOOP_ARGS         , setp
64
65
66 /* The charsets GB/T 12345-90, GB 7589-87, GB/T 13131-9X, GB 7590-87,
67    and GB/T 13132-9X are not registered to the best of my knowledge and
68    therefore have no escape sequence assigned.  We cannot handle them
69    for this reason.  Tell the implementation about this.  */
70 #define X12345  '\0'
71 #define X7589   '\0'
72 #define X13131  '\0'
73 #define X7590   '\0'
74 #define X13132  '\0'
75
76
77 /* The COUNT element of the state keeps track of the currently selected
78    character set.  The possible values are:  */
79 enum
80 {
81   ASCII_set = 0,
82   GB2312_set,
83   GB12345_set,
84   CNS11643_1_set,
85   ISO_IR_165_set,
86   SO_mask = 7,
87
88   GB7589_set = 1 << 3,
89   GB13131_set = 2 << 3,
90   CNS11643_2_set = 3 << 3,
91   SS2_mask = 3 << 3,
92
93   GB7590_set = 1 << 5,
94   GB13132_set = 2 << 5,
95   CNS11643_3_set = 3 << 5,
96   CNS11643_4_set = 4 << 5,
97   CNS11643_5_set = 5 << 5,
98   CNS11643_6_set = 6 << 5,
99   CNS11643_7_set = 7 << 5,
100   SS3_mask = 7 << 5,
101
102 #define CURRENT_MASK (SO_mask | SS2_mask | SS3_mask)
103
104   GB2312_ann = 1 << 8,
105   GB12345_ann = 2 << 8,
106   CNS11643_1_ann = 3 << 8,
107   ISO_IR_165_ann = 4 << 8,
108   SO_ann = 7 << 8,
109
110   GB7589_ann = 1 << 11,
111   GB13131_ann = 2 << 11,
112   CNS11643_2_ann = 3 << 11,
113   SS2_ann = 3 << 11,
114
115   GB7590_ann = 1 << 13,
116   GB13132_ann = 2 << 13,
117   CNS11643_3_ann = 3 << 13,
118   CNS11643_4_ann = 4 << 13,
119   CNS11643_5_ann = 5 << 13,
120   CNS11643_6_ann = 6 << 13,
121   CNS11643_7_ann = 7 << 13,
122   SS3_ann = 7 << 13
123 };
124
125
126 /* Since this is a stateful encoding we have to provide code which resets
127    the output state to the initial state.  This has to be done during the
128    flushing.  */
129 #define EMIT_SHIFT_TO_INIT \
130   if (data->__statep->__count >> 3 != ASCII_set)                              \
131     {                                                                         \
132       if (FROM_DIRECTION)                                                     \
133         /* It's easy, we don't have to emit anything, we just reset the       \
134            state for the input.  */                                           \
135         data->__statep->__count = ASCII_set << 3;                             \
136       else                                                                    \
137         {                                                                     \
138           /* We are not in the initial state.  To switch back we have         \
139              to emit `SI'.  */                                                \
140           if (__builtin_expect (outbuf == outend, 0))                         \
141             /* We don't have enough room in the output buffer.  */            \
142             status = __GCONV_FULL_OUTPUT;                                     \
143           else                                                                \
144             {                                                                 \
145               /* Write out the shift sequence.  */                            \
146               *outbuf++ = SI;                                                 \
147               if (data->__flags & __GCONV_IS_LAST)                            \
148                 *irreversible += 1;                                           \
149               data->__statep->__count = ASCII_set << 3;                       \
150             }                                                                 \
151         }                                                                     \
152     }
153
154
155 /* Since we might have to reset input pointer we must be able to save
156    and retore the state.  */
157 #define SAVE_RESET_STATE(Save) \
158   if (Save)                                                                   \
159     save_set = *setp;                                                         \
160   else                                                                        \
161     *setp = save_set
162
163
164 /* First define the conversion function from ISO-2022-CN to UCS4.  */
165 #define MIN_NEEDED_INPUT        FROM_LOOP_MIN_NEEDED_FROM
166 #define MAX_NEEDED_INPUT        FROM_LOOP_MAX_NEEDED_FROM
167 #define MIN_NEEDED_OUTPUT       FROM_LOOP_MIN_NEEDED_TO
168 #define MAX_NEEDED_OUTPUT       FROM_LOOP_MAX_NEEDED_TO
169 #define LOOPFCT                 FROM_LOOP
170 #define BODY \
171   {                                                                           \
172     uint32_t ch = *inptr;                                                     \
173                                                                               \
174     /* This is a 7bit character set, disallow all 8bit characters.  */        \
175     if (ch > 0x7f)                                                            \
176       STANDARD_FROM_LOOP_ERR_HANDLER (1);                                     \
177                                                                               \
178     /* Recognize escape sequences.  */                                        \
179     if (ch == ESC)                                                            \
180       {                                                                       \
181         /* There are three kinds of escape sequences we have to handle:       \
182            - those announcing the use of GB and CNS characters on the         \
183              line; we can simply ignore them                                  \
184            - the initial byte of the SS2 sequence.                            \
185            - the initial byte of the SS3 sequence.                            \
186         */                                                                    \
187         if (inptr + 2 > inend                                                 \
188             || (inptr[1] == '$'                                               \
189                 && (inptr + 3 > inend                                         \
190                     || (inptr[2] == ')' && inptr + 4 > inend)                 \
191                     || (inptr[2] == '*' && inptr + 4 > inend)                 \
192                     || (inptr[2] == '+' && inptr + 4 > inend)))               \
193             || (inptr[1] == SS2_1 && inptr + 4 > inend)                       \
194             || (inptr[1] == SS3_1 && inptr + 4 > inend))                      \
195           {                                                                   \
196             result = __GCONV_INCOMPLETE_INPUT;                                \
197             break;                                                            \
198           }                                                                   \
199         if (inptr[1] == '$'                                                   \
200             && ((inptr[2] == ')'                                              \
201                  && (inptr[3] == 'A'                                          \
202                      || (X12345 != '\0' && inptr[3] == X12345)                \
203                      || inptr[3] == 'E' || inptr[3] == 'G'))                  \
204                 || (inptr[2] == '*'                                           \
205                     && ((X7589 != '\0' && inptr[3] == X7589)                  \
206                         || (X13131 != '\0' && inptr[3] == X13131)             \
207                         || inptr[3] == 'H'))                                  \
208                 || (inptr[2] == '+'                                           \
209                     && ((X7590 != '\0' && inptr[3] == X7590)                  \
210                         || (X13132 != '\0' && inptr[3] == X13132)             \
211                         || inptr[3] == 'I' || inptr[3] == 'J'                 \
212                         || inptr[3] == 'K' || inptr[3] == 'L'                 \
213                         || inptr[3] == 'M'))))                                \
214           {                                                                   \
215             /* OK, we accept those character sets.  */                        \
216             if (inptr[3] == 'A')                                              \
217               ann = (ann & ~SO_ann) | GB2312_ann;                             \
218             else if (inptr[3] == 'G')                                         \
219               ann = (ann & ~SO_ann) | CNS11643_1_ann;                         \
220             else if (inptr[3] == 'E')                                         \
221               ann = (ann & ~SO_ann) | ISO_IR_165_ann;                         \
222             else if (X12345 != '\0' && inptr[3] == X12345)                    \
223               ann = (ann & ~SO_ann) | GB12345_ann;                            \
224             else if (inptr[3] == 'H')                                         \
225               ann = (ann & ~SS2_ann) | CNS11643_2_ann;                        \
226             else if (X7589 != '\0' && inptr[3] == X7589)                      \
227               ann = (ann & ~SS2_ann) | GB7589_ann;                            \
228             else if (X13131 != '\0' && inptr[3] == X13131)                    \
229               ann = (ann & ~SS2_ann) | GB13131_ann;                           \
230             else if (inptr[3] == 'I')                                         \
231               ann = (ann & ~SS3_ann) | CNS11643_3_ann;                        \
232             else if (inptr[3] == 'J')                                         \
233               ann = (ann & ~SS3_ann) | CNS11643_4_ann;                        \
234             else if (inptr[3] == 'K')                                         \
235               ann = (ann & ~SS3_ann) | CNS11643_5_ann;                        \
236             else if (inptr[3] == 'L')                                         \
237               ann = (ann & ~SS3_ann) | CNS11643_6_ann;                        \
238             else if (inptr[3] == 'M')                                         \
239               ann = (ann & ~SS3_ann) | CNS11643_7_ann;                        \
240             else if (X7590 != '\0' && inptr[3] == X7590)                      \
241               ann = (ann & ~SS3_ann) | GB7590_ann;                            \
242             else if (X13132 != '\0' && inptr[3] == X13132)                    \
243               ann = (ann & ~SS3_ann) | GB13132_ann;                           \
244             inptr += 4;                                                       \
245             continue;                                                         \
246           }                                                                   \
247       }                                                                       \
248     else if (ch == SO)                                                        \
249       {                                                                       \
250         /* Switch to use GB2312, GB12345, CNS 11643 plane 1, or ISO-IR-165,   \
251            depending on which S0 designation came last.  The only problem     \
252            is what to do with faulty input files where no designator came.    \
253            XXX For now I'll default to use GB2312.  If this is not the        \
254            best behavior (e.g., we should flag an error) let me know.  */     \
255         ++inptr;                                                              \
256         if ((ann & SO_ann) != 0)                                              \
257           switch (ann & SO_ann)                                               \
258             {                                                                 \
259             case GB2312_ann:                                                  \
260               set = GB2312_set;                                               \
261               break;                                                          \
262             case GB12345_ann:                                                 \
263               set = GB12345_set;                                              \
264               break;                                                          \
265             case CNS11643_1_ann:                                              \
266               set = CNS11643_1_set;                                           \
267               break;                                                          \
268             case ISO_IR_165_ann:                                              \
269               set = ISO_IR_165_set;                                           \
270               break;                                                          \
271             default:                                                          \
272               abort ();                                                       \
273             }                                                                 \
274         else                                                                  \
275           {                                                                   \
276             STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
277           }                                                                   \
278         continue;                                                             \
279       }                                                                       \
280     else if (ch == SI)                                                        \
281       {                                                                       \
282         /* Switch to use ASCII.  */                                           \
283         ++inptr;                                                              \
284         set = ASCII_set;                                                      \
285         continue;                                                             \
286       }                                                                       \
287                                                                               \
288     if (ch == ESC && inptr[1] == SS2_1)                                       \
289       {                                                                       \
290         /* This is a character from CNS 11643 plane 2.                        \
291            XXX We could test here whether the use of this character           \
292            set was announced.                                                 \
293            XXX Currently GB7589 and GB13131 are not supported.  */            \
294         inptr += 2;                                                           \
295         ch = cns11643l2_to_ucs4 (&inptr, 2, 0);                               \
296         if (ch == __UNKNOWN_10646_CHAR)                                       \
297           STANDARD_FROM_LOOP_ERR_HANDLER (2);                                 \
298       }                                                                       \
299     /* Note that we can assume here that at least 4 bytes are available if    \
300        the first byte is ESC since otherwise the first if would have been     \
301        true.  */                                                              \
302     else if (ch == ESC && inptr[1] == SS3_1)                                  \
303       {                                                                       \
304         /* This is a character from CNS 11643 plane 3 or higher.              \
305            XXX Currently GB7590 and GB13132 are not supported.  */            \
306         unsigned char buf[3];                                                 \
307         const unsigned char *tmp = buf;                                       \
308                                                                               \
309         buf[1] = inptr[2];                                                    \
310         buf[2] = inptr[3];                                                    \
311         switch (ann & SS3_ann)                                                \
312           {                                                                   \
313           case CNS11643_3_ann:                                                \
314             buf[0] = 0x23;                                                    \
315             ch = cns11643_to_ucs4 (&tmp, 3, 0);                               \
316             break;                                                            \
317           case CNS11643_4_ann:                                                \
318             buf[0] = 0x24;                                                    \
319             ch = cns11643_to_ucs4 (&tmp, 3, 0);                               \
320             break;                                                            \
321           case CNS11643_5_ann:                                                \
322             buf[0] = 0x25;                                                    \
323             ch = cns11643_to_ucs4 (&tmp, 3, 0);                               \
324             break;                                                            \
325           case CNS11643_6_ann:                                                \
326             buf[0] = 0x26;                                                    \
327             ch = cns11643_to_ucs4 (&tmp, 3, 0);                               \
328             break;                                                            \
329           case CNS11643_7_ann:                                                \
330             buf[0] = 0x27;                                                    \
331             ch = cns11643_to_ucs4 (&tmp, 3, 0);                               \
332             break;                                                            \
333           default:                                                            \
334             /* XXX Currently GB7590 and GB13132 are not supported.  */        \
335             ch = __UNKNOWN_10646_CHAR;                                        \
336             break;                                                            \
337           }                                                                   \
338         if (ch == __UNKNOWN_10646_CHAR)                                       \
339           {                                                                   \
340             STANDARD_FROM_LOOP_ERR_HANDLER (4);                               \
341           }                                                                   \
342         assert (tmp == buf + 3);                                              \
343         inptr += 4;                                                           \
344       }                                                                       \
345     else if (set == ASCII_set)                                                \
346       {                                                                       \
347         /* Almost done, just advance the input pointer.  */                   \
348         ++inptr;                                                              \
349       }                                                                       \
350     else                                                                      \
351       {                                                                       \
352         /* That's pretty easy, we have a dedicated functions for this.  */    \
353         if (inend - inptr < 2)                                                \
354           {                                                                   \
355             result = __GCONV_INCOMPLETE_INPUT;                                \
356             break;                                                            \
357           }                                                                   \
358         if (set == GB2312_set)                                                \
359           ch = gb2312_to_ucs4 (&inptr, inend - inptr, 0);                     \
360         else if (set == ISO_IR_165_set)                                       \
361           ch = isoir165_to_ucs4 (&inptr, inend - inptr);                      \
362         else                                                                  \
363           {                                                                   \
364             assert (set == CNS11643_1_set);                                   \
365             ch = cns11643l1_to_ucs4 (&inptr, inend - inptr, 0);               \
366           }                                                                   \
367                                                                               \
368         if (ch == 0)                                                          \
369           {                                                                   \
370             result = __GCONV_INCOMPLETE_INPUT;                                \
371             break;                                                            \
372           }                                                                   \
373         else if (ch == __UNKNOWN_10646_CHAR)                                  \
374           {                                                                   \
375             STANDARD_FROM_LOOP_ERR_HANDLER (2);                               \
376           }                                                                   \
377       }                                                                       \
378                                                                               \
379     *((uint32_t *) outptr) = ch;                                              \
380     outptr += sizeof (uint32_t);                                              \
381   }
382 #define EXTRA_LOOP_DECLS        , int *setp
383 #define INIT_PARAMS             int set = (*setp >> 3) & CURRENT_MASK; \
384                                 int ann = (*setp >> 3) & ~CURRENT_MASK
385 #define UPDATE_PARAMS           *setp = (set | ann) << 3
386 #define LOOP_NEED_FLAGS
387 #include <iconv/loop.c>
388
389
390 /* Next, define the other direction.  */
391 #define MIN_NEEDED_INPUT        TO_LOOP_MIN_NEEDED_FROM
392 #define MAX_NEEDED_INPUT        TO_LOOP_MAX_NEEDED_FROM
393 #define MIN_NEEDED_OUTPUT       TO_LOOP_MIN_NEEDED_TO
394 #define MAX_NEEDED_OUTPUT       TO_LOOP_MAX_NEEDED_TO
395 #define LOOPFCT                 TO_LOOP
396 #define BODY \
397   {                                                                           \
398     uint32_t ch;                                                              \
399     size_t written = 0;                                                       \
400                                                                               \
401     ch = *((const uint32_t *) inptr);                                         \
402                                                                               \
403     /* First see whether we can write the character using the currently       \
404        selected character set.  */                                            \
405     if (ch < 0x80)                                                            \
406       {                                                                       \
407         if (set != ASCII_set)                                                 \
408           {                                                                   \
409             *outptr++ = SI;                                                   \
410             set = ASCII_set;                                                  \
411             if (outptr == outend)                                             \
412               {                                                               \
413                 result = __GCONV_FULL_OUTPUT;                                 \
414                 break;                                                        \
415               }                                                               \
416           }                                                                   \
417                                                                               \
418         *outptr++ = ch;                                                       \
419         written = 1;                                                          \
420                                                                               \
421         /* At the end of the line we have to clear the `ann' flags since      \
422            every line must contain this information again.  */                \
423         if (ch == L'\n')                                                      \
424           ann = 0;                                                            \
425       }                                                                       \
426     else                                                                      \
427       {                                                                       \
428         unsigned char buf[2];                                                 \
429         int used;                                                             \
430                                                                               \
431         if (set == GB2312_set || ((ann & SO_ann) != CNS11643_1_ann            \
432                                   && (ann & SO_ann) != ISO_IR_165_ann))       \
433           {                                                                   \
434             written = ucs4_to_gb2312 (ch, buf, 2);                            \
435             used = GB2312_set;                                                \
436           }                                                                   \
437         else if (set == ISO_IR_165_set || (ann & SO_ann) == ISO_IR_165_set)   \
438           {                                                                   \
439             written = ucs4_to_isoir165 (ch, buf, 2);                          \
440             used = ISO_IR_165_set;                                            \
441           }                                                                   \
442         else                                                                  \
443           {                                                                   \
444             written = ucs4_to_cns11643l1 (ch, buf, 2);                        \
445             used = CNS11643_1_set;                                            \
446           }                                                                   \
447                                                                               \
448         if (written == __UNKNOWN_10646_CHAR)                                  \
449           {                                                                   \
450             /* Cannot convert it using the currently selected SO set.         \
451                Next try the SS2 set.  */                                      \
452             written = ucs4_to_cns11643l2 (ch, buf, 2);                        \
453             if (written != __UNKNOWN_10646_CHAR)                              \
454               /* Yep, that worked.  */                                        \
455               used = CNS11643_2_set;                                          \
456             else                                                              \
457               {                                                               \
458                 unsigned char tmpbuf[3];                                      \
459                                                                               \
460                 switch (0)                                                    \
461                   {                                                           \
462                   default:                                                    \
463                     /* Well, see whether we have to change the SO set.  */    \
464                                                                               \
465                     if (used != GB2312_set)                                   \
466                       {                                                       \
467                         written = ucs4_to_gb2312 (ch, buf, 2);                \
468                         if (written != __UNKNOWN_10646_CHAR)                  \
469                           {                                                   \
470                             used = GB2312_set;                                \
471                             break;                                            \
472                           }                                                   \
473                       }                                                       \
474                                                                               \
475                     if (used != ISO_IR_165_set)                               \
476                       {                                                       \
477                         written = ucs4_to_isoir165 (ch, buf, 2);              \
478                         if (written != __UNKNOWN_10646_CHAR)                  \
479                           {                                                   \
480                             used = ISO_IR_165_set;                            \
481                             break;                                            \
482                           }                                                   \
483                       }                                                       \
484                                                                               \
485                     if (used != CNS11643_1_set)                               \
486                       {                                                       \
487                         written = ucs4_to_cns11643l1 (ch, buf, 2);            \
488                         if (written != __UNKNOWN_10646_CHAR)                  \
489                           {                                                   \
490                             used = CNS11643_1_set;                            \
491                             break;                                            \
492                           }                                                   \
493                       }                                                       \
494                                                                               \
495                     written = ucs4_to_cns11643 (ch, tmpbuf, 3);               \
496                     if (written == 3 && tmpbuf[0] >= 3 && tmpbuf[0] <= 7)     \
497                       {                                                       \
498                         buf[0] = tmpbuf[1];                                   \
499                         buf[1] = tmpbuf[2];                                   \
500                         switch (tmpbuf[0])                                    \
501                           {                                                   \
502                           case 3:                                             \
503                             used = CNS11643_3_set;                            \
504                             break;                                            \
505                           case 4:                                             \
506                             used = CNS11643_4_set;                            \
507                             break;                                            \
508                           case 5:                                             \
509                             used = CNS11643_5_set;                            \
510                             break;                                            \
511                           case 6:                                             \
512                             used = CNS11643_6_set;                            \
513                             break;                                            \
514                           case 7:                                             \
515                             used = CNS11643_7_set;                            \
516                             break;                                            \
517                           default:                                            \
518                             abort ();                                         \
519                           }                                                   \
520                         written = 2;                                          \
521                         break;                                                \
522                       }                                                       \
523                                                                               \
524                     /* XXX Currently GB7590 and GB13132 are not supported.  */\
525                                                                               \
526                     /* Even this does not work.  Error.  */                   \
527                     used = ASCII_set;                                         \
528                   }                                                           \
529                 if (used == ASCII_set)                                        \
530                   {                                                           \
531                     UNICODE_TAG_HANDLER (ch, 4);                              \
532                     STANDARD_TO_LOOP_ERR_HANDLER (4);                         \
533                   }                                                           \
534               }                                                               \
535           }                                                                   \
536         assert (written == 2);                                                \
537                                                                               \
538         /* See whether we have to emit an escape sequence.  */                \
539         if (set != used)                                                      \
540           {                                                                   \
541             /* First see whether we announced that we use this                \
542                character set.  */                                             \
543             if ((used & SO_mask) != 0 && (ann & SO_ann) != (used << 8))       \
544               {                                                               \
545                 const char *escseq;                                           \
546                                                                               \
547                 if (outptr + 4 > outend)                                      \
548                   {                                                           \
549                     result = __GCONV_FULL_OUTPUT;                             \
550                     break;                                                    \
551                   }                                                           \
552                                                                               \
553                 assert (used >= 1 && used <= 4);                              \
554                 escseq = ")A\0\0)G)E" + (used - 1) * 2;                       \
555                 *outptr++ = ESC;                                              \
556                 *outptr++ = '$';                                              \
557                 *outptr++ = *escseq++;                                        \
558                 *outptr++ = *escseq++;                                        \
559                                                                               \
560                 ann = (ann & ~SO_ann) | (used << 8);                          \
561               }                                                               \
562             else if ((used & SS2_mask) != 0 && (ann & SS2_ann) != (used << 8))\
563               {                                                               \
564                 const char *escseq;                                           \
565                                                                               \
566                 assert (used == CNS11643_2_set); /* XXX */                    \
567                 escseq = "*H";                                                \
568                 *outptr++ = ESC;                                              \
569                 *outptr++ = '$';                                              \
570                 *outptr++ = *escseq++;                                        \
571                 *outptr++ = *escseq++;                                        \
572                                                                               \
573                 ann = (ann & ~SS2_ann) | (used << 8);                         \
574               }                                                               \
575             else if ((used & SS3_mask) != 0 && (ann & SS3_ann) != (used << 8))\
576               {                                                               \
577                 const char *escseq;                                           \
578                                                                               \
579                 assert ((used >> 5) >= 3 && (used >> 5) <= 7);                \
580                 escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2;                \
581                 *outptr++ = ESC;                                              \
582                 *outptr++ = '$';                                              \
583                 *outptr++ = *escseq++;                                        \
584                 *outptr++ = *escseq++;                                        \
585                                                                               \
586                 ann = (ann & ~SS3_ann) | (used << 8);                         \
587               }                                                               \
588                                                                               \
589             if (used == CNS11643_2_set)                                       \
590               {                                                               \
591                 if (outptr + 2 > outend)                                      \
592                   {                                                           \
593                     result = __GCONV_FULL_OUTPUT;                             \
594                     break;                                                    \
595                   }                                                           \
596                 *outptr++ = SS2_0;                                            \
597                 *outptr++ = SS2_1;                                            \
598               }                                                               \
599             else if (used >= CNS11643_3_set && used <= CNS11643_7_set)        \
600               {                                                               \
601                 if (outptr + 2 > outend)                                      \
602                   {                                                           \
603                     result = __GCONV_FULL_OUTPUT;                             \
604                     break;                                                    \
605                   }                                                           \
606                 *outptr++ = SS3_0;                                            \
607                 *outptr++ = SS3_1;                                            \
608               }                                                               \
609             else                                                              \
610               {                                                               \
611                 /* We only have to emit something if currently ASCII is       \
612                    selected.  Otherwise we are switching within the           \
613                    SO charset.  */                                            \
614                 if (set == ASCII_set)                                         \
615                   {                                                           \
616                     if (outptr + 1 > outend)                                  \
617                       {                                                       \
618                         result = __GCONV_FULL_OUTPUT;                         \
619                         break;                                                \
620                       }                                                       \
621                     *outptr++ = SO;                                           \
622                   }                                                           \
623               }                                                               \
624                                                                               \
625             /* Always test the length here since we have used up all the      \
626                guaranteed output buffer slots.  */                            \
627             if (outptr + 2 > outend)                                          \
628               {                                                               \
629                 result = __GCONV_FULL_OUTPUT;                                 \
630                 break;                                                        \
631               }                                                               \
632           }                                                                   \
633         else if (outptr + 2 > outend)                                         \
634           {                                                                   \
635             result = __GCONV_FULL_OUTPUT;                                     \
636             break;                                                            \
637           }                                                                   \
638                                                                               \
639         *outptr++ = buf[0];                                                   \
640         *outptr++ = buf[1];                                                   \
641         set = used;                                                           \
642       }                                                                       \
643                                                                               \
644     /* Now that we wrote the output increment the input pointer.  */          \
645     inptr += 4;                                                               \
646   }
647 #define EXTRA_LOOP_DECLS        , int *setp
648 #define INIT_PARAMS             int set = (*setp >> 3) & CURRENT_MASK; \
649                                 int ann = (*setp >> 3) & ~CURRENT_MASK
650 #define REINIT_PARAMS           do                                            \
651                                   {                                           \
652                                     set = (*setp >> 3) & CURRENT_MASK;        \
653                                     ann = (*setp >> 3) & ~CURRENT_MASK;       \
654                                   }                                           \
655                                 while (0)
656 #define UPDATE_PARAMS           *setp = (set | ann) << 3
657 #define LOOP_NEED_FLAGS
658 #include <iconv/loop.c>
659
660
661 /* Now define the toplevel functions.  */
662 #include <iconv/skeleton.c>