Back to index

glibc  2.9
iso-2022-cn-ext.c
Go to the documentation of this file.
00001 /* Conversion module for ISO-2022-CN-EXT.
00002    Copyright (C) 2000-2002, 2004, 2007, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <dlfcn.h>
00022 #include <gconv.h>
00023 #include <stdint.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include "gb2312.h"
00027 #include "iso-ir-165.h"
00028 #include "cns11643.h"
00029 #include "cns11643l1.h"
00030 #include "cns11643l2.h"
00031 
00032 #include <assert.h>
00033 
00034 /* This makes obvious what everybody knows: 0x1b is the Esc character.  */
00035 #define ESC   0x1b
00036 
00037 /* We have single-byte shift-in and shift-out sequences, and the single
00038    shift sequences SS2 and SS3 which replaces the SS2/SS3 designation for
00039    the next two bytes.  */
00040 #define SI    0x0f
00041 #define SO    0x0e
00042 #define SS2_0 ESC
00043 #define SS2_1 0x4e
00044 #define SS3_0 ESC
00045 #define SS3_1 0x4f
00046 
00047 /* Definitions used in the body of the `gconv' function.  */
00048 #define CHARSET_NAME        "ISO-2022-CN-EXT//"
00049 #define DEFINE_INIT         1
00050 #define DEFINE_FINI         1
00051 #define FROM_LOOP           from_iso2022cn_ext_loop
00052 #define TO_LOOP                    to_iso2022cn_ext_loop
00053 #define FROM_LOOP_MIN_NEEDED_FROM  1
00054 #define FROM_LOOP_MAX_NEEDED_FROM  4
00055 #define FROM_LOOP_MIN_NEEDED_TO           4
00056 #define FROM_LOOP_MAX_NEEDED_TO           4
00057 #define TO_LOOP_MIN_NEEDED_FROM           4
00058 #define TO_LOOP_MAX_NEEDED_FROM           4
00059 #define TO_LOOP_MIN_NEEDED_TO             1
00060 #define TO_LOOP_MAX_NEEDED_TO             6
00061 #define PREPARE_LOOP \
00062   int save_set;                                                             \
00063   int *setp = &data->__statep->__count;
00064 #define EXTRA_LOOP_ARGS            , setp
00065 
00066 
00067 /* The charsets GB/T 12345-90, GB 7589-87, GB/T 13131-9X, GB 7590-87,
00068    and GB/T 13132-9X are not registered to the best of my knowledge and
00069    therefore have no escape sequence assigned.  We cannot handle them
00070    for this reason.  Tell the implementation about this.  */
00071 #define X12345       '\0'
00072 #define X7589 '\0'
00073 #define X13131       '\0'
00074 #define X7590 '\0'
00075 #define X13132       '\0'
00076 
00077 
00078 /* The COUNT element of the state keeps track of the currently selected
00079    character set.  The possible values are:  */
00080 enum
00081 {
00082   ASCII_set = 0,
00083   GB2312_set,
00084   GB12345_set,
00085   CNS11643_1_set,
00086   ISO_IR_165_set,
00087   SO_mask = 7,
00088 
00089   GB7589_set = 1 << 3,
00090   GB13131_set = 2 << 3,
00091   CNS11643_2_set = 3 << 3,
00092   SS2_mask = 3 << 3,
00093 
00094   GB7590_set = 1 << 5,
00095   GB13132_set = 2 << 5,
00096   CNS11643_3_set = 3 << 5,
00097   CNS11643_4_set = 4 << 5,
00098   CNS11643_5_set = 5 << 5,
00099   CNS11643_6_set = 6 << 5,
00100   CNS11643_7_set = 7 << 5,
00101   SS3_mask = 7 << 5,
00102 
00103 #define CURRENT_MASK (SO_mask | SS2_mask | SS3_mask)
00104 
00105   GB2312_ann = 1 << 8,
00106   GB12345_ann = 2 << 8,
00107   CNS11643_1_ann = 3 << 8,
00108   ISO_IR_165_ann = 4 << 8,
00109   SO_ann = 7 << 8,
00110 
00111   GB7589_ann = 1 << 11,
00112   GB13131_ann = 2 << 11,
00113   CNS11643_2_ann = 3 << 11,
00114   SS2_ann = 3 << 11,
00115 
00116   GB7590_ann = 1 << 13,
00117   GB13132_ann = 2 << 13,
00118   CNS11643_3_ann = 3 << 13,
00119   CNS11643_4_ann = 4 << 13,
00120   CNS11643_5_ann = 5 << 13,
00121   CNS11643_6_ann = 6 << 13,
00122   CNS11643_7_ann = 7 << 13,
00123   SS3_ann = 7 << 13
00124 };
00125 
00126 
00127 /* Since this is a stateful encoding we have to provide code which resets
00128    the output state to the initial state.  This has to be done during the
00129    flushing.  */
00130 #define EMIT_SHIFT_TO_INIT \
00131   if (data->__statep->__count >> 3 != ASCII_set)                     \
00132     {                                                                \
00133       if (FROM_DIRECTION)                                            \
00134        /* It's easy, we don't have to emit anything, we just reset the             \
00135           state for the input.  */                                   \
00136        data->__statep->__count = ASCII_set << 3;                     \
00137       else                                                           \
00138        {                                                             \
00139          /* We are not in the initial state.  To switch back we have        \
00140             to emit `SI'.  */                                               \
00141          if (__builtin_expect (outbuf == outend, 0))                        \
00142            /* We don't have enough room in the output buffer.  */           \
00143            status = __GCONV_FULL_OUTPUT;                             \
00144          else                                                        \
00145            {                                                         \
00146              /* Write out the shift sequence.  */                           \
00147              *outbuf++ = SI;                                                \
00148              if (data->__flags & __GCONV_IS_LAST)                           \
00149               *irreversible += 1;                                    \
00150              data->__statep->__count = ASCII_set << 3;                      \
00151            }                                                         \
00152        }                                                             \
00153     }
00154 
00155 
00156 /* Since we might have to reset input pointer we must be able to save
00157    and retore the state.  */
00158 #define SAVE_RESET_STATE(Save) \
00159   if (Save)                                                          \
00160     save_set = *setp;                                                       \
00161   else                                                               \
00162     *setp = save_set
00163 
00164 
00165 /* First define the conversion function from ISO-2022-CN to UCS4.  */
00166 #define MIN_NEEDED_INPUT    FROM_LOOP_MIN_NEEDED_FROM
00167 #define MAX_NEEDED_INPUT    FROM_LOOP_MAX_NEEDED_FROM
00168 #define MIN_NEEDED_OUTPUT   FROM_LOOP_MIN_NEEDED_TO
00169 #define MAX_NEEDED_OUTPUT   FROM_LOOP_MAX_NEEDED_TO
00170 #define LOOPFCT                    FROM_LOOP
00171 #define BODY \
00172   {                                                                  \
00173     uint32_t ch = *inptr;                                            \
00174                                                                      \
00175     /* This is a 7bit character set, disallow all 8bit characters.  */             \
00176     if (ch > 0x7f)                                                   \
00177       STANDARD_FROM_LOOP_ERR_HANDLER (1);                            \
00178                                                                      \
00179     /* Recognize escape sequences.  */                                      \
00180     if (ch == ESC)                                                   \
00181       {                                                                     \
00182        /* There are three kinds of escape sequences we have to handle:             \
00183           - those announcing the use of GB and CNS characters on the        \
00184             line; we can simply ignore them                                 \
00185           - the initial byte of the SS2 sequence.                           \
00186           - the initial byte of the SS3 sequence.                           \
00187        */                                                            \
00188        if (inptr + 2 > inend                                                \
00189            || (inptr[1] == '$'                                              \
00190               && (inptr + 3 > inend                                         \
00191                   || (inptr[2] == ')' && inptr + 4 > inend)                 \
00192                   || (inptr[2] == '*' && inptr + 4 > inend)                 \
00193                   || (inptr[2] == '+' && inptr + 4 > inend)))               \
00194            || (inptr[1] == SS2_1 && inptr + 4 > inend)                      \
00195            || (inptr[1] == SS3_1 && inptr + 4 > inend))              \
00196          {                                                           \
00197            result = __GCONV_INCOMPLETE_INPUT;                               \
00198            break;                                                    \
00199          }                                                           \
00200        if (inptr[1] == '$'                                           \
00201            && ((inptr[2] == ')'                                      \
00202                && (inptr[3] == 'A'                                   \
00203                    || (X12345 != '\0' && inptr[3] == X12345)                \
00204                    || inptr[3] == 'E' || inptr[3] == 'G'))                  \
00205               || (inptr[2] == '*'                                    \
00206                   && ((X7589 != '\0' && inptr[3] == X7589)                  \
00207                      || (X13131 != '\0' && inptr[3] == X13131)       \
00208                      || inptr[3] == 'H'))                            \
00209               || (inptr[2] == '+'                                    \
00210                   && ((X7590 != '\0' && inptr[3] == X7590)                  \
00211                      || (X13132 != '\0' && inptr[3] == X13132)       \
00212                      || inptr[3] == 'I' || inptr[3] == 'J'                  \
00213                      || inptr[3] == 'K' || inptr[3] == 'L'                  \
00214                      || inptr[3] == 'M'))))                                 \
00215          {                                                           \
00216            /* OK, we accept those character sets.  */                       \
00217            if (inptr[3] == 'A')                                      \
00218              ann = (ann & ~SO_ann) | GB2312_ann;                     \
00219            else if (inptr[3] == 'G')                                        \
00220              ann = (ann & ~SO_ann) | CNS11643_1_ann;                        \
00221            else if (inptr[3] == 'E')                                        \
00222              ann = (ann & ~SO_ann) | ISO_IR_165_ann;                        \
00223            else if (X12345 != '\0' && inptr[3] == X12345)                   \
00224              ann = (ann & ~SO_ann) | GB12345_ann;                           \
00225            else if (inptr[3] == 'H')                                        \
00226              ann = (ann & ~SS2_ann) | CNS11643_2_ann;                       \
00227            else if (X7589 != '\0' && inptr[3] == X7589)              \
00228              ann = (ann & ~SS2_ann) | GB7589_ann;                           \
00229            else if (X13131 != '\0' && inptr[3] == X13131)                   \
00230              ann = (ann & ~SS2_ann) | GB13131_ann;                          \
00231            else if (inptr[3] == 'I')                                        \
00232              ann = (ann & ~SS3_ann) | CNS11643_3_ann;                       \
00233            else if (inptr[3] == 'J')                                        \
00234              ann = (ann & ~SS3_ann) | CNS11643_4_ann;                       \
00235            else if (inptr[3] == 'K')                                        \
00236              ann = (ann & ~SS3_ann) | CNS11643_5_ann;                       \
00237            else if (inptr[3] == 'L')                                        \
00238              ann = (ann & ~SS3_ann) | CNS11643_6_ann;                       \
00239            else if (inptr[3] == 'M')                                        \
00240              ann = (ann & ~SS3_ann) | CNS11643_7_ann;                       \
00241            else if (X7590 != '\0' && inptr[3] == X7590)              \
00242              ann = (ann & ~SS3_ann) | GB7590_ann;                           \
00243            else if (X13132 != '\0' && inptr[3] == X13132)                   \
00244              ann = (ann & ~SS3_ann) | GB13132_ann;                          \
00245            inptr += 4;                                                      \
00246            continue;                                                 \
00247          }                                                           \
00248       }                                                                     \
00249     else if (ch == SO)                                                      \
00250       {                                                                     \
00251        /* Switch to use GB2312, GB12345, CNS 11643 plane 1, or ISO-IR-165,   \
00252           depending on which S0 designation came last.  The only problem     \
00253           is what to do with faulty input files where no designator came.    \
00254           XXX For now I'll default to use GB2312.  If this is not the       \
00255           best behavior (e.g., we should flag an error) let me know.  */     \
00256        ++inptr;                                                      \
00257        if ((ann & SO_ann) != 0)                                      \
00258          switch (ann & SO_ann)                                              \
00259            {                                                         \
00260            case GB2312_ann:                                          \
00261              set = GB2312_set;                                              \
00262              break;                                                  \
00263            case GB12345_ann:                                                \
00264              set = GB12345_set;                                      \
00265              break;                                                  \
00266            case CNS11643_1_ann:                                      \
00267              set = CNS11643_1_set;                                   \
00268              break;                                                  \
00269            case ISO_IR_165_ann:                                      \
00270              set = ISO_IR_165_set;                                   \
00271              break;                                                  \
00272            default:                                                  \
00273              abort ();                                                      \
00274            }                                                         \
00275        else                                                          \
00276          {                                                           \
00277            STANDARD_FROM_LOOP_ERR_HANDLER (1);                              \
00278          }                                                           \
00279        continue;                                                     \
00280       }                                                                     \
00281     else if (ch == SI)                                                      \
00282       {                                                                     \
00283        /* Switch to use ASCII.  */                                   \
00284        ++inptr;                                                      \
00285        set = ASCII_set;                                              \
00286        continue;                                                     \
00287       }                                                                     \
00288                                                                      \
00289     if (ch == ESC && inptr[1] == SS2_1)                                     \
00290       {                                                                     \
00291        /* This is a character from CNS 11643 plane 2.                       \
00292           XXX We could test here whether the use of this character          \
00293           set was announced.                                                \
00294           XXX Currently GB7589 and GB13131 are not supported.  */           \
00295        inptr += 2;                                                   \
00296        ch = cns11643l2_to_ucs4 (&inptr, 2, 0);                              \
00297        if (ch == __UNKNOWN_10646_CHAR)                                      \
00298          STANDARD_FROM_LOOP_ERR_HANDLER (2);                                \
00299       }                                                                     \
00300     /* Note that we can assume here that at least 4 bytes are available if    \
00301        the first byte is ESC since otherwise the first if would have been     \
00302        true.  */                                                     \
00303     else if (ch == ESC && inptr[1] == SS3_1)                                \
00304       {                                                                     \
00305        /* This is a character from CNS 11643 plane 3 or higher.             \
00306           XXX Currently GB7590 and GB13132 are not supported.  */           \
00307        unsigned char buf[3];                                                \
00308        const unsigned char *tmp = buf;                                      \
00309                                                                      \
00310        buf[1] = inptr[2];                                            \
00311        buf[2] = inptr[3];                                            \
00312        switch (ann & SS3_ann)                                               \
00313          {                                                           \
00314          case CNS11643_3_ann:                                               \
00315            buf[0] = 0x23;                                            \
00316            ch = cns11643_to_ucs4 (&tmp, 3, 0);                              \
00317            break;                                                    \
00318          case CNS11643_4_ann:                                               \
00319            buf[0] = 0x24;                                            \
00320            ch = cns11643_to_ucs4 (&tmp, 3, 0);                              \
00321            break;                                                    \
00322          case CNS11643_5_ann:                                               \
00323            buf[0] = 0x25;                                            \
00324            ch = cns11643_to_ucs4 (&tmp, 3, 0);                              \
00325            break;                                                    \
00326          case CNS11643_6_ann:                                               \
00327            buf[0] = 0x26;                                            \
00328            ch = cns11643_to_ucs4 (&tmp, 3, 0);                              \
00329            break;                                                    \
00330          case CNS11643_7_ann:                                               \
00331            buf[0] = 0x27;                                            \
00332            ch = cns11643_to_ucs4 (&tmp, 3, 0);                              \
00333            break;                                                    \
00334          default:                                                    \
00335            /* XXX Currently GB7590 and GB13132 are not supported.  */       \
00336            ch = __UNKNOWN_10646_CHAR;                                       \
00337            break;                                                    \
00338          }                                                           \
00339        if (ch == __UNKNOWN_10646_CHAR)                                      \
00340          {                                                           \
00341            STANDARD_FROM_LOOP_ERR_HANDLER (4);                              \
00342          }                                                           \
00343        assert (tmp == buf + 3);                                      \
00344        inptr += 4;                                                   \
00345       }                                                                     \
00346     else if (set == ASCII_set)                                              \
00347       {                                                                     \
00348        /* Almost done, just advance the input pointer.  */                  \
00349        ++inptr;                                                      \
00350       }                                                                     \
00351     else                                                             \
00352       {                                                                     \
00353        /* That's pretty easy, we have a dedicated functions for this.  */    \
00354        if (inend - inptr < 2)                                               \
00355          {                                                           \
00356            result = __GCONV_INCOMPLETE_INPUT;                               \
00357            break;                                                    \
00358          }                                                           \
00359        if (set == GB2312_set)                                               \
00360          ch = gb2312_to_ucs4 (&inptr, inend - inptr, 0);                    \
00361        else if (set == ISO_IR_165_set)                                      \
00362          ch = isoir165_to_ucs4 (&inptr, inend - inptr);              \
00363        else                                                          \
00364          {                                                           \
00365            assert (set == CNS11643_1_set);                                  \
00366            ch = cns11643l1_to_ucs4 (&inptr, inend - inptr, 0);              \
00367          }                                                           \
00368                                                                      \
00369        if (ch == 0)                                                  \
00370          {                                                           \
00371            result = __GCONV_INCOMPLETE_INPUT;                               \
00372            break;                                                    \
00373          }                                                           \
00374        else if (ch == __UNKNOWN_10646_CHAR)                                 \
00375          {                                                           \
00376            STANDARD_FROM_LOOP_ERR_HANDLER (2);                              \
00377          }                                                           \
00378       }                                                                     \
00379                                                                      \
00380     *((uint32_t *) outptr) = ch;                                     \
00381     outptr += sizeof (uint32_t);                                     \
00382   }
00383 #define EXTRA_LOOP_DECLS    , int *setp
00384 #define INIT_PARAMS         int set = (*setp >> 3) & CURRENT_MASK; \
00385                             int ann = (*setp >> 3) & ~CURRENT_MASK
00386 #define UPDATE_PARAMS              *setp = (set | ann) << 3
00387 #define LOOP_NEED_FLAGS
00388 #include <iconv/loop.c>
00389 
00390 
00391 /* Next, define the other direction.  */
00392 #define MIN_NEEDED_INPUT    TO_LOOP_MIN_NEEDED_FROM
00393 #define MAX_NEEDED_INPUT    TO_LOOP_MAX_NEEDED_FROM
00394 #define MIN_NEEDED_OUTPUT   TO_LOOP_MIN_NEEDED_TO
00395 #define MAX_NEEDED_OUTPUT   TO_LOOP_MAX_NEEDED_TO
00396 #define LOOPFCT                    TO_LOOP
00397 #define BODY \
00398   {                                                                  \
00399     uint32_t ch;                                                     \
00400     size_t written = 0;                                                     \
00401                                                                      \
00402     ch = *((const uint32_t *) inptr);                                       \
00403                                                                      \
00404     /* First see whether we can write the character using the currently            \
00405        selected character set.  */                                   \
00406     if (ch < 0x80)                                                   \
00407       {                                                                     \
00408        if (set != ASCII_set)                                                \
00409          {                                                           \
00410            *outptr++ = SI;                                           \
00411            set = ASCII_set;                                          \
00412            if (outptr == outend)                                     \
00413              {                                                              \
00414               result = __GCONV_FULL_OUTPUT;                                 \
00415               break;                                                 \
00416              }                                                              \
00417          }                                                           \
00418                                                                      \
00419        *outptr++ = ch;                                                      \
00420        written = 1;                                                  \
00421                                                                      \
00422        /* At the end of the line we have to clear the `ann' flags since      \
00423           every line must contain this information again.  */               \
00424        if (ch == L'\n')                                              \
00425          ann = 0;                                                    \
00426       }                                                                     \
00427     else                                                             \
00428       {                                                                     \
00429        unsigned char buf[2];                                                \
00430        int used;                                                     \
00431                                                                      \
00432        if (set == GB2312_set || ((ann & SO_ann) != CNS11643_1_ann           \
00433                               && (ann & SO_ann) != ISO_IR_165_ann))         \
00434          {                                                           \
00435            written = ucs4_to_gb2312 (ch, buf, 2);                           \
00436            used = GB2312_set;                                               \
00437          }                                                           \
00438        else if (set == ISO_IR_165_set || (ann & SO_ann) == ISO_IR_165_set)   \
00439          {                                                           \
00440            written = ucs4_to_isoir165 (ch, buf, 2);                         \
00441            used = ISO_IR_165_set;                                    \
00442          }                                                           \
00443        else                                                          \
00444          {                                                           \
00445            written = ucs4_to_cns11643l1 (ch, buf, 2);                       \
00446            used = CNS11643_1_set;                                    \
00447          }                                                           \
00448                                                                      \
00449        if (written == __UNKNOWN_10646_CHAR)                                 \
00450          {                                                           \
00451            /* Cannot convert it using the currently selected SO set.        \
00452               Next try the SS2 set.  */                              \
00453            written = ucs4_to_cns11643l2 (ch, buf, 2);                       \
00454            if (written != __UNKNOWN_10646_CHAR)                      \
00455              /* Yep, that worked.  */                                       \
00456              used = CNS11643_2_set;                                         \
00457            else                                                      \
00458              {                                                              \
00459               unsigned char tmpbuf[3];                               \
00460                                                                      \
00461               switch (0)                                             \
00462                 {                                                    \
00463                 default:                                             \
00464                   /* Well, see whether we have to change the SO set.  */    \
00465                                                                      \
00466                   if (used != GB2312_set)                            \
00467                     {                                                       \
00468                      written = ucs4_to_gb2312 (ch, buf, 2);                 \
00469                      if (written != __UNKNOWN_10646_CHAR)                   \
00470                        {                                             \
00471                          used = GB2312_set;                                 \
00472                          break;                                      \
00473                        }                                             \
00474                     }                                                       \
00475                                                                      \
00476                   if (used != ISO_IR_165_set)                               \
00477                     {                                                       \
00478                      written = ucs4_to_isoir165 (ch, buf, 2);        \
00479                      if (written != __UNKNOWN_10646_CHAR)                   \
00480                        {                                             \
00481                          used = ISO_IR_165_set;                      \
00482                          break;                                      \
00483                        }                                             \
00484                     }                                                       \
00485                                                                      \
00486                   if (used != CNS11643_1_set)                               \
00487                     {                                                       \
00488                      written = ucs4_to_cns11643l1 (ch, buf, 2);             \
00489                      if (written != __UNKNOWN_10646_CHAR)                   \
00490                        {                                             \
00491                          used = CNS11643_1_set;                      \
00492                          break;                                      \
00493                        }                                             \
00494                     }                                                       \
00495                                                                      \
00496                   written = ucs4_to_cns11643 (ch, tmpbuf, 3);               \
00497                   if (written == 3 && tmpbuf[0] >= 3 && tmpbuf[0] <= 7)     \
00498                     {                                                       \
00499                      buf[0] = tmpbuf[1];                             \
00500                      buf[1] = tmpbuf[2];                             \
00501                      switch (tmpbuf[0])                              \
00502                        {                                             \
00503                        case 3:                                       \
00504                          used = CNS11643_3_set;                      \
00505                          break;                                      \
00506                        case 4:                                       \
00507                          used = CNS11643_4_set;                      \
00508                          break;                                      \
00509                        case 5:                                       \
00510                          used = CNS11643_5_set;                      \
00511                          break;                                      \
00512                        case 6:                                       \
00513                          used = CNS11643_6_set;                      \
00514                          break;                                      \
00515                        case 7:                                       \
00516                          used = CNS11643_7_set;                      \
00517                          break;                                      \
00518                        default:                                      \
00519                          abort ();                                   \
00520                        }                                             \
00521                      written = 2;                                    \
00522                      break;                                          \
00523                     }                                                       \
00524                                                                      \
00525                   /* XXX Currently GB7590 and GB13132 are not supported.  */\
00526                                                                      \
00527                   /* Even this does not work.  Error.  */                   \
00528                   used = ASCII_set;                                         \
00529                 }                                                    \
00530               if (used == ASCII_set)                                        \
00531                 {                                                    \
00532                   UNICODE_TAG_HANDLER (ch, 4);                       \
00533                   STANDARD_TO_LOOP_ERR_HANDLER (4);                         \
00534                 }                                                    \
00535              }                                                              \
00536          }                                                           \
00537        assert (written == 2);                                               \
00538                                                                      \
00539        /* See whether we have to emit an escape sequence.  */               \
00540        if (set != used)                                              \
00541          {                                                           \
00542            /* First see whether we announced that we use this               \
00543               character set.  */                                     \
00544            if ((used & SO_mask) != 0 && (ann & SO_ann) != (used << 8))             \
00545              {                                                              \
00546               const char *escseq;                                    \
00547                                                                      \
00548               if (outptr + 4 > outend)                               \
00549                 {                                                    \
00550                   result = __GCONV_FULL_OUTPUT;                      \
00551                   break;                                             \
00552                 }                                                    \
00553                                                                      \
00554               assert (used >= 1 && used <= 4);                       \
00555               escseq = ")A\0\0)G)E" + (used - 1) * 2;                       \
00556               *outptr++ = ESC;                                       \
00557               *outptr++ = '$';                                       \
00558               *outptr++ = *escseq++;                                        \
00559               *outptr++ = *escseq++;                                        \
00560                                                                      \
00561               ann = (ann & ~SO_ann) | (used << 8);                          \
00562              }                                                              \
00563            else if ((used & SS2_mask) != 0 && (ann & SS2_ann) != (used << 8))\
00564              {                                                              \
00565               const char *escseq;                                    \
00566                                                                      \
00567               assert (used == CNS11643_2_set); /* XXX */                    \
00568               escseq = "*H";                                                \
00569               *outptr++ = ESC;                                       \
00570               *outptr++ = '$';                                       \
00571               *outptr++ = *escseq++;                                        \
00572               *outptr++ = *escseq++;                                        \
00573                                                                      \
00574               ann = (ann & ~SS2_ann) | (used << 8);                         \
00575              }                                                              \
00576            else if ((used & SS3_mask) != 0 && (ann & SS3_ann) != (used << 8))\
00577              {                                                              \
00578               const char *escseq;                                    \
00579                                                                      \
00580               assert ((used >> 5) >= 3 && (used >> 5) <= 7);                \
00581               escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2;                \
00582               *outptr++ = ESC;                                       \
00583               *outptr++ = '$';                                       \
00584               *outptr++ = *escseq++;                                        \
00585               *outptr++ = *escseq++;                                        \
00586                                                                      \
00587               ann = (ann & ~SS3_ann) | (used << 8);                         \
00588              }                                                              \
00589                                                                      \
00590            if (used == CNS11643_2_set)                                      \
00591              {                                                              \
00592               if (outptr + 2 > outend)                               \
00593                 {                                                    \
00594                   result = __GCONV_FULL_OUTPUT;                      \
00595                   break;                                             \
00596                 }                                                    \
00597               *outptr++ = SS2_0;                                     \
00598               *outptr++ = SS2_1;                                     \
00599              }                                                              \
00600            else if (used >= CNS11643_3_set && used <= CNS11643_7_set)       \
00601              {                                                              \
00602               if (outptr + 2 > outend)                               \
00603                 {                                                    \
00604                   result = __GCONV_FULL_OUTPUT;                      \
00605                   break;                                             \
00606                 }                                                    \
00607               *outptr++ = SS3_0;                                     \
00608               *outptr++ = SS3_1;                                     \
00609              }                                                              \
00610            else                                                      \
00611              {                                                              \
00612               /* We only have to emit something if currently ASCII is       \
00613                  selected.  Otherwise we are switching within the           \
00614                  SO charset.  */                                     \
00615               if (set == ASCII_set)                                         \
00616                 {                                                    \
00617                   if (outptr + 1 > outend)                                  \
00618                     {                                                       \
00619                      result = __GCONV_FULL_OUTPUT;                          \
00620                      break;                                          \
00621                     }                                                       \
00622                   *outptr++ = SO;                                    \
00623                 }                                                    \
00624              }                                                              \
00625                                                                      \
00626            /* Always test the length here since we have used up all the      \
00627               guaranteed output buffer slots.  */                           \
00628            if (outptr + 2 > outend)                                         \
00629              {                                                              \
00630               result = __GCONV_FULL_OUTPUT;                                 \
00631               break;                                                 \
00632              }                                                              \
00633          }                                                           \
00634        else if (outptr + 2 > outend)                                        \
00635          {                                                           \
00636            result = __GCONV_FULL_OUTPUT;                             \
00637            break;                                                    \
00638          }                                                           \
00639                                                                      \
00640        *outptr++ = buf[0];                                           \
00641        *outptr++ = buf[1];                                           \
00642        set = used;                                                   \
00643       }                                                                     \
00644                                                                      \
00645     /* Now that we wrote the output increment the input pointer.  */        \
00646     inptr += 4;                                                             \
00647   }
00648 #define EXTRA_LOOP_DECLS    , int *setp
00649 #define INIT_PARAMS         int set = (*setp >> 3) & CURRENT_MASK; \
00650                             int ann = (*setp >> 3) & ~CURRENT_MASK
00651 #define REINIT_PARAMS              do                                       \
00652                               {                                      \
00653                                 set = (*setp >> 3) & CURRENT_MASK;          \
00654                                 ann = (*setp >> 3) & ~CURRENT_MASK;         \
00655                               }                                      \
00656                             while (0)
00657 #define UPDATE_PARAMS              *setp = (set | ann) << 3
00658 #define LOOP_NEED_FLAGS
00659 #include <iconv/loop.c>
00660 
00661 
00662 /* Now define the toplevel functions.  */
00663 #include <iconv/skeleton.c>