(mfont__ft_init): Add oblique and boldoblique.
[m17n/m17n-lib.git] / src / coding.c
1 /* coding.c -- code conversion module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nConv
25     @brief Coding system objects and API for them.
26
27     The m17n library represents a character encoding scheme (CES) of
28     coded character sets (CCS) as an object called @e coding @e
29     system.  Application programs can add original coding systems.
30
31     To @e encode means converting code-points to character codes and
32     to @e decode means converting character codes back to code-points.
33
34     Application programs can decode a byte sequence with a specified
35     coding system into an M-text, and inversely, can encode an M-text
36     into a byte sequence.  */
37
38 /***ja
39     @addtogroup m17nConv
40     @brief ¥³¡¼¥É·Ï¥ª¥Ö¥¸¥§¥¯¥È¤È¤½¤ì¤Ë´Ø¤¹¤ë API
41
42     m17n ¥é¥¤¥Ö¥é¥ê¤Ï¡¢Éä¹æ²½Ê¸»ú½¸¹ç (coded character sets; CCS) ¤Îʸ
43     »úÉä¹ç²½Êý¼° (character encoding scheme; CES) ¤ò @e ¥³¡¼¥É·Ï ¤È¸Æ
44     ¤Ö¥ª¥Ö¥¸¥§¥¯¥È¤Çɽ¸½¤¹¤ë¡£m17n ¥é¥¤¥Ö¥é¥ê¤¬¥µ¥Ý¡¼¥È¤¹¤ëCES ¤Ï¡¢
45     UTF-8, UTF-16, ISO-2022, DIRECT-CHARSET, ¤½¤Î¾¡¢¤ËÂçÊ̤µ¤ì¤ë¡£¥¢
46     ¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬Æȼ«¤Ë¥³¡¼¥É·Ï¤òÄɲ乤뤳¤È¤â²Äǽ¤Ç¤¢¤ë¡£
47
48     ¥³¡¼¥É¥Ý¥¤¥ó¥È¤«¤éʸ»ú¥³¡¼¥É¤Ø¤ÎÊÑ´¹¤ò @e ¥¨¥ó¥³¡¼¥É ¤È¸Æ¤Ó¡¢Ê¸»ú
49     ¥³¡¼¥É¤«¤é¥³¡¼¥É¥Ý¥¤¥ó¥È¤Ø¤ÎÊÑ´¹¤ò @e ¥Ç¥³¡¼¥É ¤È¸Æ¤Ö¡£
50
51     ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¡¢»ØÄꤵ¤ì¤¿¥³¡¼¥É·Ï¤Ç¥Ð¥¤¥ÈÎó¤ò¥Ç¥³¡¼
52     ¥É¤¹¤ë¤³¤È¤Ç M-text ¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¤Þ¤¿µÕ¤Ë¡¢»ØÄꤵ¤ì¤¿¥³¡¼¥É
53     ·Ï¤Ç M-text ¤ò¥¨¥ó¥³¡¼¥É¤·¤¹¤ë¤³¤È¤Ç¥Ð¥¤¥ÈÎó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£  */
54
55 /*=*/
56
57 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
58 /*** @addtogroup m17nInternal
59      @{ */
60
61 #include <config.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <ctype.h>
65 #include <string.h>
66 #include <sys/types.h>
67 #include <unistd.h>
68 #include <errno.h>
69
70 #include "m17n.h"
71 #include "m17n-misc.h"
72 #include "internal.h"
73 #include "plist.h"
74 #include "character.h"
75 #include "charset.h"
76 #include "coding.h"
77 #include "mtext.h"
78 #include "symbol.h"
79 #include "mlocale.h"
80
81 #define NUM_SUPPORTED_CHARSETS 32
82
83 /** Structure for coding system object.  */
84
85 typedef struct
86 {
87   /** Name of the coding system.  */
88   MSymbol name;
89
90   /** Type of the coding system.  */
91   MSymbol type;
92
93   /* Number of supported charsets.  */
94   int ncharsets;
95
96   /** Array of supported charsets.  */
97   MCharset *charsets[NUM_SUPPORTED_CHARSETS];
98
99   /** If non-NULL, function to call at the time of creating and
100       reseting a converter.  */
101   int (*resetter) (MConverter *converter);
102
103   int (*decoder) (unsigned char *str, int str_bytes, MText *mt,
104                   MConverter *converter);
105
106   int (*encoder) (MText *mt, int from, int to,
107                   unsigned char *str, int str_bytes,
108                   MConverter *converter);
109
110   /** If non-zero, the coding system decode/encode ASCII characters as
111       is.  */
112   int ascii_compatible;
113
114   /** Pointer to extra information given when the coding system is
115       defined.  The meaning depends on <type>.  */
116   void *extra_info;
117
118   /** Pointer to information referred on conversion.  The meaning
119       depends on <type>.  The value NULL means that the coding system
120       is not yet setup.  */
121   void *extra_spec;
122
123   int ready;
124 } MCodingSystem;
125
126 struct MCodingList
127 {
128   int size, inc, used;
129   MCodingSystem **codings;
130 };
131
132 static struct MCodingList coding_list;
133
134 static MPlist *coding_definition_list;
135
136 typedef struct {
137   /**en
138      Pointer to a structure of a coding system.  */
139   /**ja
140      ¥³¡¼¥É·Ï¤òɽ¤ï¤¹¥Ç¡¼¥¿¹½Â¤¤Ø¤Î¥Ý¥¤¥ó¥¿ */
141   MCodingSystem *coding;
142
143   /**en
144      Buffer for carryover bytes generated while decoding. */
145   /**ja
146      ¥Ç¥³¡¼¥ÉÃæ¤Î¥­¥ã¥ê¥£¥ª¡¼¥Ð¡¼¥Ð¥¤¥ÈÍѥХåե¡ */
147   unsigned char carryover[256];
148
149   /**en
150      Number of carryover bytes. */
151   /**ja
152      ¥­¥ã¥ê¥£¥ª¡¼¥Ð¡¼¥Ð¥¤¥È¿ô */
153   int carryover_bytes;
154
155   /**en
156      Beginning of the byte sequence bound to this converter. */
157   /**ja
158      ¤³¤Î¥³¥ó¥Ð¡¼¥¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥Ð¥¤¥ÈÎó¤ÎÀèƬ°ÌÃÖ */
159   unsigned char *buf;
160
161   /**en
162      Size of buf. */
163   /**ja
164      buf ¤ÎÂ礭¤µ */
165   int bufsize;
166
167   /**en
168      Number of bytes already consumed in buf. */
169   /**ja
170      buf Æâ¤Ç¤¹¤Ç¤Ë¾ÃÈñ¤µ¤ì¤¿¥Ð¥¤¥È¿ô */
171   int used;
172
173   /**en
174      Stream bound to this converter. */
175   /**ja
176      ¤³¤Î¥³¥ó¥Ð¡¼¥¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥¹¥È¥ê¡¼¥à */
177   FILE *fp;
178
179   /**en
180      Which of above two is in use. */
181   /**ja
182      ¾åµ­2¼Ô¤Î¤¤¤º¤ì¤¬»È¤ï¤ì¤Æ¤¤¤ë¤« */
183   int binding;
184
185   /**en
186      Buffer for unget. */
187   /**ja
188      Unget ÍѥХåե¡ */
189   MText *unread;
190
191   /*en
192     Working area. */
193   /*ja
194     ºî¶ÈÎΰè */
195   MText *work_mt;
196
197   int seekable;
198 } MConverterStatus;
199
200
201 \f
202 /* Local macros and functions.  */
203
204 /** At first, set SRC_BASE to SRC.  Then check if we have already
205     produced AT_MOST chars.  If so, set SRC_END to SRC, and jump to
206     source_end.  Otherwise, get one more byte C from SRC.  In that
207     case, if SRC == SRC_END, jump to the label source_end.  */
208
209 #define ONE_MORE_BASE_BYTE(c)           \
210   do {                                  \
211     src_base = src;                     \
212     if (nchars == at_most)              \
213       {                                 \
214         src_end = src;                  \
215         goto source_end;                \
216       }                                 \
217     if (src == src_stop)                \
218       {                                 \
219         if (src == src_end)             \
220           goto source_end;              \
221         src_base = src = source;        \
222         if (src == src_end)             \
223           goto source_end;              \
224         src_stop = src_end;             \
225       }                                 \
226     (c) = *src++;                       \
227   } while (0)
228
229
230 /** Get one more byte C from SRC.  If SRC == SRC_END, jump to the
231    label source_end.  */
232
233 #define ONE_MORE_BYTE(c)        \
234   do {                          \
235     if (src == src_stop)        \
236       {                         \
237         if (src == src_end)     \
238           goto source_end;      \
239         src = source;           \
240         if (src == src_end)     \
241           goto source_end;      \
242         src_stop = src_end;     \
243       }                         \
244     (c) = *src++;               \
245   } while (0)
246
247
248 #define REWIND_SRC_TO_BASE()                                            \
249   do {                                                                  \
250     if (src_base < source || src_base >= src_end)                       \
251       src_stop = internal->carryover + internal->carryover_bytes;       \
252     src = src_base;                                                     \
253   } while (0)
254
255
256 /** Push back byte C to SRC.  */
257
258 #define UNGET_ONE_BYTE(c)               \
259   do {                                  \
260     if (src > source)                   \
261       src--;                            \
262     else                                \
263       {                                 \
264         internal->carryover[0] = c;     \
265         internal->carryover_bytes = 1;  \
266         src = internal->carryover;      \
267         src_stop = src + 1;             \
268       }                                 \
269   } while  (0);
270
271
272 /** Store multibyte representation of character C at DST and increment
273     DST to the next of the produced bytes.  DST must be a pointer to
274     data area of M-text MT.  If the produced bytes are going to exceed
275     DST_END, enlarge the data area of MT.  */
276
277 #define EMIT_CHAR(c)                                            \
278   do {                                                          \
279     int bytes = CHAR_BYTES (c);                                 \
280     int len;                                                    \
281                                                                 \
282     if (dst + bytes + 1 > dst_end)                              \
283       {                                                         \
284         len = dst - mt->data;                                   \
285         bytes = mt->allocated + bytes + (src_stop - src);       \
286         mtext__enlarge (mt, bytes);                             \
287         dst = mt->data + len;                                   \
288         dst_end = mt->data + mt->allocated;                     \
289       }                                                         \
290     dst += CHAR_STRING (c, dst);                                \
291     nchars++;                                                   \
292   } while (0)
293
294
295 /* Check if there is enough room to produce LEN bytes at DST.  If not,
296    go to the label insufficient_destination.  */
297
298 #define CHECK_DST(len)                  \
299   do {                                  \
300     if (dst + (len) > dst_end)          \
301       goto insufficient_destination;    \
302   } while (0)
303
304
305 /** Take NUM_CHARS characters (NUM_BYTES bytes) already stored at
306     (MT->data + MT->nbytes) into MT, and put charset property on
307     them with CHARSET->name.  */
308
309 #define TAKEIN_CHARS(mt, num_chars, num_bytes, charset)                 \
310   do {                                                                  \
311     int chars = (num_chars);                                            \
312                                                                         \
313     if (chars > 0)                                                      \
314       {                                                                 \
315         mtext__takein ((mt), chars, (num_bytes));                       \
316         if (charset)                                                    \
317           mtext_put_prop ((mt), (mt)->nchars - chars, (mt)->nchars,     \
318                           Mcharset, (void *) ((charset)->name));        \
319       }                                                                 \
320   } while (0)
321
322
323 #define SET_SRC(mt, format, from, to)                                   \
324   do {                                                                  \
325     if (format <= MTEXT_FORMAT_UTF_8)                                   \
326       {                                                                 \
327         src = mt->data + POS_CHAR_TO_BYTE (mt, from);                   \
328         src_end = mt->data + POS_CHAR_TO_BYTE (mt, to);                 \
329       }                                                                 \
330     else if (format <= MTEXT_FORMAT_UTF_16BE)                           \
331       {                                                                 \
332         src                                                             \
333           = mt->data + (sizeof (short)) * POS_CHAR_TO_BYTE (mt, from);  \
334         src_end                                                         \
335           = mt->data + (sizeof (short)) * POS_CHAR_TO_BYTE (mt, to);    \
336       }                                                                 \
337     else                                                                \
338       {                                                                 \
339         src = mt->data + (sizeof (int)) * from;                         \
340         src_end = mt->data + (sizeof (int)) * to;                       \
341       }                                                                 \
342   } while (0)
343
344
345 #define ONE_MORE_CHAR(c, bytes, format)                         \
346   do {                                                          \
347     if (src == src_end)                                         \
348       goto finish;                                              \
349     if (format <= MTEXT_FORMAT_UTF_8)                           \
350       c = STRING_CHAR_AND_BYTES (src, bytes);                   \
351     else if (format <= MTEXT_FORMAT_UTF_16BE)                   \
352       {                                                         \
353         c = mtext_ref_char (mt, from++);                        \
354         bytes = (sizeof (short)) * CHAR_UNITS_UTF16 (c);        \
355       }                                                         \
356     else                                                        \
357       {                                                         \
358         c = ((unsigned *) (mt->data))[from++];                  \
359         bytes = sizeof (int);                                   \
360       }                                                         \
361   } while (0)
362
363
364 static int
365 encode_unsupporeted_char (int c, unsigned char *dst, unsigned char *dst_end,
366                           MText *mt, int pos)
367 {
368   int len;
369   char *format;
370
371   len = c < 0x10000 ? 8 : 10;
372   if (dst + len > dst_end)
373     return 0;
374
375   mtext_put_prop (mt, pos, pos + 1, Mcoding, Mnil);
376   format = (c < 0xD800 ? "<U+%04X>"
377             : c < 0xE000 ? "<M+%04X>"
378             : c < 0x10000 ? "<U+%04X>"
379             : c < 0x110000 ? "<U+%06X>"
380             : "<M+%06X>");
381   sprintf ((char *) dst, format, c);
382   return len;
383 }
384
385
386
387 /** Finish decoding of bytes at SOURCE (ending at SRC_END) into NCHARS
388     characters by CONVERTER into M-text MT.  SRC is a pointer to the
389     not-yet processed bytes.  ERROR is 1 iff an invalid byte was
390     found.  */
391
392 static int
393 finish_decoding (MText *mt, MConverter *converter, int nchars,
394                  unsigned char *source, unsigned char *src_end,
395                  unsigned char *src,
396                  int error)
397 {
398   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
399
400   if (src == src_end)
401     internal->carryover_bytes = 0;
402   else if (error
403            || (converter->last_block
404                && ! converter->lenient))
405     converter->result = MCONVERSION_RESULT_INVALID_BYTE;
406   else if (! converter->last_block)
407     {
408       unsigned char *dst = internal->carryover;
409
410       if (src < source || src > src_end)
411         {
412           dst += internal->carryover_bytes;
413           src = source;
414         }
415       while (src < src_end)
416         *dst++ = *src++;
417       internal->carryover_bytes = dst - internal->carryover;
418       converter->result = MCONVERSION_RESULT_INSUFFICIENT_SRC;
419     }
420   else
421     {
422       unsigned char *dst = mt->data + mt->nbytes;
423       unsigned char *dst_end = mt->data + mt->allocated;
424       unsigned char *src_stop = src_end;
425       int c;
426       int last_nchars = nchars;
427
428       if (src < source || src > src_end)
429         src_stop = internal->carryover + internal->carryover_bytes;
430       while (1)
431         {
432           if (converter->at_most && nchars == converter->at_most)
433             break;
434           if (src == src_stop)
435             {
436               if (src == src_end)
437                 break;
438               src = source;
439               if (src == src_end)
440                 break;
441               src_stop = src_end;
442             }
443           c = *src++;
444           EMIT_CHAR (c);
445         }
446       TAKEIN_CHARS (mt, nchars - last_nchars, dst - (mt->data + mt->nbytes),
447                     mcharset__binary);
448       internal->carryover_bytes = 0;
449     }
450
451   converter->nchars += nchars;
452   converter->nbytes += ((src < source || src > src_end) ? 0 : src - source);
453   return (converter->result == MCONVERSION_RESULT_INVALID_BYTE ? -1 : 0);
454 }
455
456
457 \f
458 /* Staffs for coding-systems of type MCODING_TYPE_CHARSET.  */
459
460 static int
461 setup_coding_charset (MCodingSystem *coding)
462 {
463   int ncharsets = coding->ncharsets;
464   unsigned *code_charset_table;
465
466   if (ncharsets > 1)
467     {
468       /* At first, reorder charset list by dimensions (a charset of
469          smaller dimension comes first).  As the number of charsets is
470          usually very small (at most 32), we do a simple sort.  */
471       MCharset **charsets;
472       int idx = 0;
473       int i, j;
474
475       MTABLE_ALLOCA (charsets, NUM_SUPPORTED_CHARSETS, MERROR_CODING);
476       memcpy (charsets, coding->charsets,
477               sizeof (MCharset *) * NUM_SUPPORTED_CHARSETS);
478       for (i = 0; i < 4; i++)
479         for (j = 0; j < ncharsets; j++)
480           if (charsets[j]->dimension == i)
481             coding->charsets[idx++] = charsets[j];
482     }
483
484   MTABLE_CALLOC (code_charset_table, 256, MERROR_CODING);
485   while (ncharsets--)
486     {
487       int dim = coding->charsets[ncharsets]->dimension;
488       int from = coding->charsets[ncharsets]->code_range[(dim - 1) * 4];
489       int to = coding->charsets[ncharsets]->code_range[(dim - 1) * 4 + 1];
490
491       if (coding->charsets[ncharsets]->ascii_compatible)
492         coding->ascii_compatible = 1;
493       while (from <= to)
494         code_charset_table[from++] |= 1 << ncharsets;
495     }
496
497   coding->extra_spec = (void *) code_charset_table;
498   return 0;
499 }
500
501 static int
502 reset_coding_charset (MConverter *converter)
503 {
504   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
505   MCodingSystem *coding = internal->coding;
506
507   if (! coding->ready
508       && setup_coding_charset (coding) < 0)
509     return -1;
510   coding->ready = 1;
511   return 0;
512 }
513
514 static int
515 decode_coding_charset (unsigned char *source, int src_bytes, MText *mt,
516                        MConverter *converter)
517 {
518   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
519   MCodingSystem *coding = internal->coding;
520   unsigned char *src = internal->carryover;
521   unsigned char *src_stop = src + internal->carryover_bytes;
522   unsigned char *src_end = source + src_bytes;
523   unsigned char *src_base;
524   unsigned char *dst = mt->data + mt->nbytes;
525   unsigned char *dst_end = mt->data + mt->allocated;
526   int nchars = 0;
527   int last_nchars = 0;
528   int at_most = converter->at_most > 0 ? converter->at_most : -1;
529
530   unsigned *code_charset_table = (unsigned *) coding->extra_spec;
531   MCharset **charsets = coding->charsets;
532   MCharset *charset = mcharset__ascii;
533   int error = 0;
534
535   while (1)
536     {
537       MCharset *this_charset = NULL;
538       int c;
539       unsigned mask;
540
541       ONE_MORE_BASE_BYTE (c);
542       mask = code_charset_table[c];
543       if (mask)
544         {
545           int idx = 0;
546           unsigned code = c;
547           int nbytes = 1;
548           int dim;
549           
550           while (mask)
551             {
552               while (! (mask & 1)) mask >>= 1, idx++;
553               this_charset = charsets[idx];
554               dim = this_charset->dimension;
555               while (nbytes < dim)
556                 {
557                   ONE_MORE_BYTE (c);
558                   code = (code << 8) | c;
559                   nbytes++;
560                 }
561               c = DECODE_CHAR (this_charset, code);
562               if (c >= 0)
563                 goto emit_char;
564               mask >>= 1, idx++;
565             }
566         }
567
568       if (! converter->lenient)
569         break;
570       REWIND_SRC_TO_BASE ();
571       c = *src++;
572       this_charset = mcharset__binary;
573
574     emit_char:
575       if (this_charset != mcharset__ascii
576           && this_charset != charset)
577         {
578           TAKEIN_CHARS (mt, nchars - last_nchars, 
579                         dst - (mt->data + mt->nbytes), charset);
580           charset = this_charset;
581           last_nchars = nchars;
582         }
583       EMIT_CHAR (c);
584     }
585   /* We reach here because of an invalid byte.  */
586   error = 1;
587
588  source_end:
589   TAKEIN_CHARS (mt, nchars - last_nchars,
590                 dst - (mt->data + mt->nbytes), charset);
591   return finish_decoding (mt, converter, nchars,
592                           source, src_end, src_base, error);
593 }
594
595 static int
596 encode_coding_charset (MText *mt, int from, int to,
597                        unsigned char *destination, int dst_bytes,
598                        MConverter *converter)
599 {
600   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
601   MCodingSystem *coding = internal->coding;
602   unsigned char *src, *src_end;
603   unsigned char *dst = destination;
604   unsigned char *dst_end = dst + dst_bytes;
605   int nchars = 0;
606   int ncharsets = coding->ncharsets;
607   MCharset **charsets = coding->charsets;
608   int ascii_compatible = coding->ascii_compatible;
609   enum MTextFormat format = mt->format;
610
611   SET_SRC (mt, format, from, to);
612   while (1)
613     {
614       int c, bytes;
615
616       ONE_MORE_CHAR (c, bytes, format);
617
618       if (c < 0x80 && ascii_compatible)
619         {
620           CHECK_DST (1);
621           *dst++ = c;
622         }
623       else
624         {
625           unsigned code;
626           MCharset *charset = NULL;
627           int i = 0;
628
629           while (1)
630             {
631               charset = charsets[i];
632               code = ENCODE_CHAR (charset, c);
633               if (code != MCHAR_INVALID_CODE)
634                 break;
635               if (++i == ncharsets)
636                 goto unsupported_char;
637             }
638
639           CHECK_DST (charset->dimension);
640           if (charset->dimension == 1)
641             {
642               *dst++ = code;
643             }
644           else if (charset->dimension == 2)
645             {
646               *dst++ = code >> 8;
647               *dst++ = code & 0xFF;
648             }
649           else if (charset->dimension == 3)
650             {
651               *dst++ = code >> 16;
652               *dst++ = (code >> 8) & 0xFF;
653               *dst++ = code & 0xFF;
654             }
655           else
656             {
657               *dst++ = code >> 24;
658               *dst++ = (code >> 16) & 0xFF;
659               *dst++ = (code >> 8) & 0xFF;
660               *dst++ = code & 0xFF;
661             }
662         }
663       src += bytes;
664       nchars++;
665       continue;
666
667     unsupported_char:
668       {
669         int len;
670
671         if (! converter->lenient)
672           break;
673         len = encode_unsupporeted_char (c, dst, dst_end, mt, from + nchars);
674         if (len == 0)
675           goto insufficient_destination;
676         dst += len;
677         src += bytes;
678         nchars++;
679       }
680     }
681   /* We reach here because of an unsupported char.  */
682   converter->result = MCONVERSION_RESULT_INVALID_CHAR;
683   goto finish;
684
685  insufficient_destination:
686   converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
687
688  finish:
689   converter->nchars += nchars;
690   converter->nbytes += dst - destination;
691   return (converter->result == MCONVERSION_RESULT_INVALID_CHAR ? -1 : 0);
692 }
693
694 \f
695 /* Staffs for coding-systems of type MCODING_TYPE_UTF (8).  */
696
697 #define UTF8_CHARSET(p)                                 \
698   (! ((p)[0] & 0x80) ? (mcharset__unicode)                      \
699    : CHAR_HEAD_P ((p) + 1) ? (mcharset__binary)                 \
700    : ! ((p)[0] & 0x20) ? (mcharset__unicode)                    \
701    : CHAR_HEAD_P ((p) + 2) ? (mcharset__binary)                 \
702    : ! ((p)[0] & 0x10) ? (mcharset__unicode)                    \
703    : CHAR_HEAD_P ((p) + 3) ? (mcharset__binary)                 \
704    : ! ((p)[0] & 0x08) ? ((((((p)[0] & 0x07) << 2)              \
705                             & (((p)[1] & 0x30) >> 4)) <= 0x10)  \
706                           ? (mcharset__unicode)                 \
707                           : (mcharset__m17n))                   \
708    : CHAR_HEAD_P ((p) + 4) ? (mcharset__binary)                 \
709    : ! ((p)[0] & 0x04) ? (mcharset__m17n)                       \
710    : CHAR_HEAD_P ((p) + 5) ? (mcharset__binary)                 \
711    : ! ((p)[0] & 0x02) ? (mcharset__m17n)                       \
712    : (mcharset__binary))
713
714
715 static int
716 decode_coding_utf_8 (unsigned char *source, int src_bytes, MText *mt,
717                      MConverter *converter)
718 {
719   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
720   MCodingSystem *coding = internal->coding;
721   unsigned char *src = internal->carryover;
722   unsigned char *src_stop = src + internal->carryover_bytes;
723   unsigned char *src_end = source + src_bytes;
724   unsigned char *src_base;
725   unsigned char *dst = mt->data + mt->nbytes;
726   unsigned char *dst_end = mt->data + mt->allocated;
727   int nchars = 0;
728   int last_nchars = 0;
729   int at_most = converter->at_most > 0 ? converter->at_most : -1;
730   int error = 0;
731   int full = converter->lenient || (coding->charsets[0] == mcharset__m17n);
732   MCharset *charset = NULL;
733
734   while (1)
735     {
736       int c, c1, bytes;
737       MCharset *this_charset = NULL;
738
739       ONE_MORE_BASE_BYTE (c);
740
741       if (!(c & 0x80))
742         bytes = 1;
743       else if (!(c & 0x40))
744         goto invalid_byte;
745       else if (!(c & 0x20))
746         bytes = 2, c &= 0x1F;
747       else if (!(c & 0x10))
748         bytes = 3, c &= 0x0F;
749       else if (!(c & 0x08))
750         bytes = 4, c &= 0x07;
751       else if (!(c & 0x04))
752         bytes = 5, c &= 0x03;
753       else if (!(c & 0x02))
754         bytes = 6, c &= 0x01;
755       else
756         goto invalid_byte;
757
758       while (bytes-- > 1)
759         {
760           ONE_MORE_BYTE (c1);
761           if ((c1 & 0xC0) != 0x80)
762             goto invalid_byte;
763           c = (c << 6) | (c1 & 0x3F);
764         }
765
766       if (full
767           || c < 0xD800 || (c >= 0xE000 && c < 0x110000))
768         goto emit_char;
769
770     invalid_byte:
771       if (! converter->lenient)
772         break;
773       REWIND_SRC_TO_BASE ();
774       c = *src++;
775       this_charset = mcharset__binary;
776
777     emit_char:
778       if (this_charset != charset)
779         {
780           TAKEIN_CHARS (mt, nchars - last_nchars, 
781                         dst - (mt->data + mt->nbytes), charset);
782           charset = this_charset;
783           last_nchars = nchars;
784         }
785       EMIT_CHAR (c);
786     }
787   /* We reach here because of an invalid byte.  */
788   error = 1;
789
790  source_end:
791   TAKEIN_CHARS (mt, nchars - last_nchars,
792                 dst - (mt->data + mt->nbytes), charset);
793   return finish_decoding (mt, converter, nchars,
794                           source, src_end, src_base, error);
795 }
796
797 static int
798 encode_coding_utf_8 (MText *mt, int from, int to,
799                      unsigned char *destination, int dst_bytes,
800                      MConverter *converter)
801 {
802   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
803   MCodingSystem *coding = internal->coding;
804   unsigned char *src, *src_end;
805   unsigned char *dst = destination;
806   unsigned char *dst_end = dst + dst_bytes;
807   int nchars = 0;
808   enum MTextFormat format = mt->format;
809
810   SET_SRC (mt, format, from, to);
811
812   if (format <= MTEXT_FORMAT_UTF_8
813       && (converter->lenient
814           || coding->charsets[0] == mcharset__m17n))
815     {
816       if (dst_bytes < src_end - src)
817         {
818           int byte_pos = (src + dst_bytes) - mt->data;
819
820           to = POS_BYTE_TO_CHAR (mt, byte_pos);
821           byte_pos = POS_CHAR_TO_BYTE (mt, to);
822           src_end = mt->data + byte_pos;
823           converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
824         }
825       memcpy (destination, src, src_end - src);
826       nchars = to - from;
827       dst += src_end - src;
828       goto finish;
829     }
830
831   while (1)
832     {
833       int c, bytes;
834
835       ONE_MORE_CHAR (c, bytes, format);
836
837       if ((c >= 0xD800 && c < 0xE000) || c >= 0x110000)
838         break;
839       CHECK_DST (bytes);
840       dst += CHAR_STRING (c, dst);
841       src += bytes;
842       nchars++;
843     }
844   /* We reach here because of an unsupported char.  */
845   converter->result = MCONVERSION_RESULT_INVALID_CHAR;
846   goto finish;
847
848  insufficient_destination:
849   converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
850
851  finish:
852   converter->nchars += nchars;
853   converter->nbytes += dst - destination;
854   return (converter->result == MCONVERSION_RESULT_INVALID_CHAR ? -1 : 0);
855 }
856
857 \f
858 /* Staffs for coding-systems of type MCODING_TYPE_UTF (16 & 32).  */
859
860 enum utf_bom
861   {
862     UTF_BOM_MAYBE,
863     UTF_BOM_NO,
864     UTF_BOM_YES,
865     UTF_BOM_MAX
866   };
867
868 enum utf_endian
869   {
870     UTF_BIG_ENDIAN,
871     UTF_LITTLE_ENDIAN,
872     UTF_ENDIAN_MAX
873   };
874
875 struct utf_status
876 {
877   int surrogate;
878   enum utf_bom bom;
879   enum utf_endian endian;
880 };
881
882 static int
883 setup_coding_utf (MCodingSystem *coding)
884 {
885   MCodingInfoUTF *info = (MCodingInfoUTF *) (coding->extra_info);
886   MCodingInfoUTF *spec;
887
888   if (info->code_unit_bits == 8)
889     coding->ascii_compatible = 1;
890   else if (info->code_unit_bits == 16
891            || info->code_unit_bits == 32)
892     {
893       if (info->bom < 0 || info->bom > 2
894           || info->endian < 0 || info->endian > 1)
895         MERROR (MERROR_CODING, -1);
896     }
897   else
898     return -1;
899
900   MSTRUCT_CALLOC (spec, MERROR_CODING);
901   *spec = *info;
902   coding->extra_spec = (void *) (spec);
903   return 0;
904 }
905
906 static int
907 reset_coding_utf (MConverter *converter)
908 {
909   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
910   MCodingSystem *coding = internal->coding;
911   struct utf_status *status = (struct utf_status *) &(converter->status);
912
913   if (! coding->ready
914       && setup_coding_utf (coding) < 0)
915     return -1;
916   coding->ready = 1;
917
918   status->surrogate = 0;
919   status->bom = ((MCodingInfoUTF *) (coding->extra_spec))->bom;
920   status->endian = ((MCodingInfoUTF *) (coding->extra_spec))->endian;
921   return 0;
922 }
923
924 static int
925 decode_coding_utf_16 (unsigned char *source, int src_bytes, MText *mt,
926                       MConverter *converter)
927 {
928   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
929   unsigned char *src = internal->carryover;
930   unsigned char *src_stop = src + internal->carryover_bytes;
931   unsigned char *src_end = source + src_bytes;
932   unsigned char *src_base;
933   unsigned char *dst = mt->data + mt->nbytes;
934   unsigned char *dst_end = mt->data + mt->allocated;
935   int nchars = 0;
936   int last_nchars = 0;
937   int at_most = converter->at_most > 0 ? converter->at_most : -1;
938   struct utf_status *status = (struct utf_status *) &(converter->status);
939   unsigned char b1, b2;
940   MCharset *charset = NULL;
941   int error = 0;
942
943   if (status->bom != UTF_BOM_NO)
944     {
945       int c;
946
947       ONE_MORE_BASE_BYTE (b1);
948       ONE_MORE_BYTE (b2);
949       c = (b1 << 8) | b2;
950       if (c == 0xFEFF)
951         status->endian = UTF_BIG_ENDIAN;
952       else if (c == 0xFFFE)
953         status->endian = UTF_LITTLE_ENDIAN;
954       else if (status->bom == UTF_BOM_MAYBE
955                || converter->lenient)
956         {
957           status->endian = UTF_BIG_ENDIAN;
958           REWIND_SRC_TO_BASE ();
959         }
960       else
961         {
962           error = 1;
963           goto source_end;
964         }
965       status->bom = UTF_BOM_NO;
966     }
967
968   while (1)
969     {
970       int c, c1;
971       MCharset *this_charset = NULL;
972
973       ONE_MORE_BASE_BYTE (b1);
974       ONE_MORE_BYTE (b2);
975       if (status->endian == UTF_BIG_ENDIAN)
976         c = ((b1 << 8) | b2);
977       else
978         c = ((b2 << 8) | b1);
979       if (c < 0xD800 || c >= 0xE000)
980         goto emit_char;
981       else if (c < 0xDC00)
982         {
983           ONE_MORE_BYTE (b1);
984           ONE_MORE_BYTE (b2);
985           if (status->endian == UTF_BIG_ENDIAN)
986             c1 = ((b1 << 8) | b2);
987           else
988             c1 = ((b2 << 8) | b1);
989           if (c1 < 0xDC00 || c1 >= 0xE000)
990             goto invalid_byte;
991           c = 0x10000 + ((c - 0xD800) << 10) + (c1 - 0xDC00);
992           goto emit_char;
993         }
994
995     invalid_byte:
996       if (! converter->lenient)
997         break;
998       REWIND_SRC_TO_BASE ();
999       ONE_MORE_BYTE (b1);
1000       ONE_MORE_BYTE (b2);
1001       if (status->endian == UTF_BIG_ENDIAN)
1002         c = ((b1 << 8) | b2);
1003       else
1004         c = ((b2 << 8) | b1);
1005       this_charset = mcharset__binary;
1006
1007     emit_char:
1008       if (this_charset != charset)
1009         {
1010           TAKEIN_CHARS (mt, nchars - last_nchars, 
1011                         dst - (mt->data + mt->nbytes), charset);
1012           charset = this_charset;
1013           last_nchars = nchars;
1014         }
1015       EMIT_CHAR (c);
1016     }
1017   /* We reach here because of an invalid byte.  */
1018   error = 1;
1019
1020  source_end:
1021   TAKEIN_CHARS (mt, nchars - last_nchars,
1022                 dst - (mt->data + mt->nbytes), charset);
1023   return finish_decoding (mt, converter, nchars,
1024                           source, src_end, src_base, error);
1025 }
1026
1027
1028 static int
1029 decode_coding_utf_32 (unsigned char *source, int src_bytes, MText *mt,
1030                       MConverter *converter)
1031 {
1032   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
1033   unsigned char *src = internal->carryover;
1034   unsigned char *src_stop = src + internal->carryover_bytes;
1035   unsigned char *src_end = source + src_bytes;
1036   unsigned char *src_base;
1037   unsigned char *dst = mt->data + mt->nbytes;
1038   unsigned char *dst_end = mt->data + mt->allocated;
1039   int nchars = 0;
1040   int last_nchars = 0;
1041   int at_most = converter->at_most > 0 ? converter->at_most : -1;
1042   struct utf_status *status = (struct utf_status *) &(converter->status);
1043   unsigned char b1, b2, b3, b4;
1044   MCharset *charset = NULL;
1045   int error = 0;
1046
1047   if (status->bom != UTF_BOM_NO)
1048     {
1049       unsigned c;
1050
1051       ONE_MORE_BASE_BYTE (b1);
1052       ONE_MORE_BYTE (b2);
1053       ONE_MORE_BYTE (b3);
1054       ONE_MORE_BYTE (b4);
1055       c = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
1056       if (c == 0x0000FEFF)
1057         status->endian = UTF_BIG_ENDIAN;
1058       else if (c == 0xFFFE0000)
1059         status->endian = UTF_LITTLE_ENDIAN;
1060       else if (status->bom == UTF_BOM_MAYBE
1061                || converter->lenient)
1062         {
1063           status->endian = UTF_BIG_ENDIAN;
1064           REWIND_SRC_TO_BASE ();
1065         }
1066       else
1067         {
1068           error = 1;
1069           goto source_end;
1070         }
1071       status->bom = UTF_BOM_NO;
1072     }
1073
1074   while (1)
1075     {
1076       unsigned c;
1077       MCharset *this_charset = NULL;
1078
1079       ONE_MORE_BASE_BYTE (b1);
1080       ONE_MORE_BYTE (b2);
1081       ONE_MORE_BYTE (b3);
1082       ONE_MORE_BYTE (b4);
1083       if (status->endian == UTF_BIG_ENDIAN)
1084         c = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
1085       else
1086         c = (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
1087       if (c < 0xD800 || (c >= 0xE000 && c < 0x110000))
1088         goto emit_char;
1089
1090       if (! converter->lenient)
1091         break;
1092       REWIND_SRC_TO_BASE ();
1093       ONE_MORE_BYTE (c);
1094       this_charset = mcharset__binary;
1095
1096     emit_char:
1097       if (this_charset != charset)
1098         {
1099           TAKEIN_CHARS (mt, nchars - last_nchars, 
1100                         dst - (mt->data + mt->nbytes), charset);
1101           charset = this_charset;
1102           last_nchars = nchars;
1103         }
1104       EMIT_CHAR (c);
1105     }
1106   /* We reach here because of an invalid byte.  */
1107   error = 1;
1108
1109  source_end:
1110   TAKEIN_CHARS (mt, nchars - last_nchars,
1111                 dst - (mt->data + mt->nbytes), charset);
1112   return finish_decoding (mt, converter, nchars,
1113                           source, src_end, src_base, error);
1114 }
1115
1116
1117 static int
1118 encode_coding_utf_16 (MText *mt, int from, int to,
1119                       unsigned char *destination, int dst_bytes,
1120                       MConverter *converter)
1121 {
1122   unsigned char *src, *src_end;
1123   unsigned char *dst = destination;
1124   unsigned char *dst_end = dst + dst_bytes;
1125   int nchars = 0;
1126   struct utf_status *status = (struct utf_status *) &(converter->status);
1127   int big_endian = status->endian == UTF_BIG_ENDIAN;
1128   enum MTextFormat format = mt->format;
1129
1130   SET_SRC (mt, format, from, to);
1131
1132   if (status->bom != UTF_BOM_NO)
1133     {
1134       CHECK_DST (2);
1135       if (big_endian)
1136         *dst++ = 0xFE, *dst++ = 0xFF;
1137       else
1138         *dst++ = 0xFF, *dst++ = 0xFE;
1139       status->bom = UTF_BOM_NO;
1140     }
1141
1142   while (1)
1143     {
1144       int c, bytes;
1145
1146       ONE_MORE_CHAR (c, bytes, format);
1147
1148       if (c < 0xD800 || (c >= 0xE000 && c < 0x10000))
1149         {
1150           CHECK_DST (2);
1151           if (big_endian)
1152             *dst++ = c >> 8, *dst++ = c & 0xFF;
1153           else
1154             *dst++ = c & 0xFF, *dst++ = c >> 8;
1155         }
1156       else if (c >= 0x10000 && c < 0x110000)
1157         {
1158           int c1, c2;
1159
1160           CHECK_DST (4);
1161           c -= 0x10000;
1162           c1 = (c >> 10) + 0xD800;
1163           c2 = (c & 0x3FF) + 0xDC00;
1164           if (big_endian)
1165             *dst++ = c1 >> 8, *dst++ = c1 & 0xFF,
1166               *dst++ = c2 >> 8, *dst++ = c2 & 0xFF;
1167           else
1168             *dst++ = c1 & 0xFF, *dst++ = c1 >> 8,
1169               *dst++ = c2 & 0xFF, *dst++ = c2 >> 8;
1170         }
1171       else
1172         {
1173           unsigned char buf[11];
1174           int len, i;
1175
1176           if (! converter->lenient)
1177             break;
1178           len = encode_unsupporeted_char (c, buf, buf + (dst_end - dst),
1179                                           mt, from + nchars);
1180           if (len == 0)
1181             goto insufficient_destination;
1182           if (big_endian)
1183             for (i = 0; i < len; i++)
1184               *dst++ = 0, *dst++ = buf[i];
1185           else
1186             for (i = 0; i < len; i++)
1187               *dst++ = buf[i], *dst++ = 0;
1188         }
1189       src += bytes;
1190       nchars++;
1191     }
1192   /* We reach here because of an unsupported char.  */
1193   converter->result = MCONVERSION_RESULT_INVALID_CHAR;
1194   goto finish;
1195
1196  insufficient_destination:
1197   converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
1198
1199  finish:
1200   converter->nchars += nchars;
1201   converter->nbytes += dst - destination;
1202   return (converter->result == MCONVERSION_RESULT_INVALID_CHAR ? -1 : 0);
1203 }
1204
1205 static int
1206 encode_coding_utf_32 (MText *mt, int from, int to,
1207                       unsigned char *destination, int dst_bytes,
1208                       MConverter *converter)
1209 {
1210   unsigned char *src, *src_end;
1211   unsigned char *dst = destination;
1212   unsigned char *dst_end = dst + dst_bytes;
1213   int nchars = 0;
1214   struct utf_status *status = (struct utf_status *) &(converter->status);
1215   int big_endian = status->endian == UTF_BIG_ENDIAN;
1216   enum MTextFormat format = mt->format;
1217
1218   SET_SRC (mt, format, from, to);
1219
1220   if (status->bom != UTF_BOM_NO)
1221     {
1222       CHECK_DST (4);
1223       if (big_endian)
1224         *dst++ = 0x00, *dst++ = 0x00, *dst++ = 0xFE, *dst++ = 0xFF;
1225       else
1226         *dst++ = 0xFF, *dst++ = 0xFE, *dst++ = 0x00, *dst++ = 0x00;
1227       status->bom = UTF_BOM_NO;
1228     }
1229
1230   while (1)
1231     {
1232       int c, bytes;
1233
1234       ONE_MORE_CHAR (c, bytes, format);
1235
1236       if (c < 0xD800 || (c >= 0xE000 && c < 0x110000))
1237         {
1238           CHECK_DST (4);
1239           if (big_endian)
1240             *dst++ = 0x00, *dst++ = c >> 16,
1241               *dst++ = (c >> 8) & 0xFF, *dst++ = c & 0xFF;
1242           else
1243             *dst++ = c & 0xFF, *dst++ = (c >> 8) & 0xFF,
1244               *dst++ = c >> 16, *dst++ = 0x00;
1245         }
1246       else
1247         {
1248           unsigned char buf[11];
1249           int len, i;
1250
1251           if (! converter->lenient)
1252             break;
1253           len = encode_unsupporeted_char (c, buf, buf + (dst_end - dst),
1254                                           mt, from + nchars);
1255           if (len == 0)
1256             goto insufficient_destination;
1257           if (big_endian)
1258             for (i = 0; i < len; i++)
1259               *dst++ = 0, *dst++ = buf[i];
1260           else
1261             for (i = 0; i < len; i++)
1262               *dst++ = buf[i], *dst++ = 0;
1263         }
1264       src += bytes;
1265       nchars++;
1266     }
1267   /* We reach here because of an unsupported char.  */
1268   converter->result = MCONVERSION_RESULT_INVALID_CHAR;
1269   goto finish;
1270
1271  insufficient_destination:
1272   converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
1273
1274  finish:
1275   converter->nchars += nchars;
1276   converter->nbytes += dst - destination;
1277   return (converter->result == MCONVERSION_RESULT_INVALID_CHAR ? -1 : 0);
1278 }
1279
1280 \f
1281 /* Staffs for coding-systems of type MCODING_TYPE_ISO_2022.  */
1282
1283 #define ISO_CODE_STX    0x02            /* start text */
1284 #define ISO_CODE_SO     0x0E            /* shift-out */
1285 #define ISO_CODE_SI     0x0F            /* shift-in */
1286 #define ISO_CODE_SS2_7  0x19            /* single-shift-2 for 7-bit code */
1287 #define ISO_CODE_ESC    0x1B            /* escape */
1288 #define ISO_CODE_SS2    0x8E            /* single-shift-2 */
1289 #define ISO_CODE_SS3    0x8F            /* single-shift-3 */
1290
1291 /** Structure pointed by MCodingSystem.extra_spec.  */
1292
1293 struct iso_2022_spec
1294 {
1295   unsigned flags;
1296
1297   /** Initial graphic registers (0..3) invoked to each graphic
1298       plane left and right. */
1299   int initial_invocation[2];
1300
1301   /** Initially designated charsets for each graphic register.  */
1302   MCharset *initial_designation[4];
1303
1304   int n_designations;
1305   char *designations;
1306
1307   int use_esc;
1308 };
1309
1310 struct iso_2022_status
1311 {
1312   int invocation[2];
1313   MCharset *designation[4];
1314   unsigned single_shifting : 1;
1315   unsigned bol : 1;
1316   unsigned r2l : 1;
1317   unsigned utf8_shifting : 1;
1318   MCharset *non_standard_charset;
1319   int non_standard_charset_bytes;
1320   int non_standard_encoding;
1321 };
1322
1323 enum iso_2022_code_class {
1324   ISO_control_0,                /* Control codes in the range
1325                                    0x00..0x1F and 0x7F, except for the
1326                                    following 4 codes.  */
1327   ISO_shift_out,                /* ISO_CODE_SO (0x0E) */
1328   ISO_shift_in,                 /* ISO_CODE_SI (0x0F) */
1329   ISO_single_shift_2_7,         /* ISO_CODE_SS2_7 (0x19) */
1330   ISO_escape,                   /* ISO_CODE_SO (0x1B) */
1331   ISO_control_1,                /* Control codes in the range
1332                                    0x80..0x9F, except for the
1333                                    following 3 codes.  */
1334   ISO_single_shift_2,           /* ISO_CODE_SS2 (0x8E) */
1335   ISO_single_shift_3,           /* ISO_CODE_SS3 (0x8F) */
1336   ISO_control_sequence_introducer, /* ISO_CODE_CSI (0x9B) */
1337   ISO_0x20_or_0x7F,           /* Codes of the values 0x20 or 0x7F.  */
1338   ISO_graphic_plane_0,   /* Graphic codes in the range 0x21..0x7E.  */
1339   ISO_0xA0_or_0xFF,           /* Codes of the values 0xA0 or 0xFF.  */
1340   ISO_graphic_plane_1    /* Graphic codes in the range 0xA1..0xFE.  */
1341 } iso_2022_code_class[256];
1342
1343
1344 #define MCODING_ISO_DESIGNATION_MASK    \
1345   (MCODING_ISO_DESIGNATION_G0           \
1346    | MCODING_ISO_DESIGNATION_G1         \
1347    | MCODING_ISO_DESIGNATION_CTEXT      \
1348    | MCODING_ISO_DESIGNATION_CTEXT_EXT)
1349
1350 static int
1351 setup_coding_iso_2022 (MCodingSystem *coding)
1352 {
1353   MCodingInfoISO2022 *info = (MCodingInfoISO2022 *) (coding->extra_info);
1354   int ncharsets = coding->ncharsets;
1355   struct iso_2022_spec *spec;
1356   int designation_policy = info->flags & MCODING_ISO_DESIGNATION_MASK;
1357   int i;
1358
1359   coding->ascii_compatible = 0;
1360
1361   MSTRUCT_CALLOC (spec, MERROR_CODING);
1362
1363   spec->flags = info->flags;
1364   spec->initial_invocation[0] = info->initial_invocation[0];
1365   spec->initial_invocation[1] = info->initial_invocation[1];
1366   for (i = 0; i < 4; i++)
1367     spec->initial_designation[i] = NULL;
1368   if (designation_policy)
1369     {
1370       spec->n_designations = ncharsets;
1371       if (spec->flags & MCODING_ISO_FULL_SUPPORT)
1372         spec->n_designations += mcharset__iso_2022_table.used;
1373       MTABLE_CALLOC (spec->designations, spec->n_designations, MERROR_CODING);
1374       for (i = 0; i < spec->n_designations; i++)
1375         spec->designations[i] = -1;
1376     }
1377   else
1378     {
1379       if (spec->flags & MCODING_ISO_FULL_SUPPORT)
1380         MERROR (MERROR_CODING, -1);
1381       spec->designations = NULL;
1382     }
1383
1384   for (i = 0; i < ncharsets; i++)
1385     {
1386       int reg = info->designations[i];
1387
1388       if (reg != -5
1389           && coding->charsets[i]->final_byte > 0
1390           && (reg < -4 || reg > 3))
1391         MERROR (MERROR_CODING, -1);
1392       if (reg >= 0)
1393         {
1394           if (spec->initial_designation[reg])
1395             MERROR (MERROR_CODING, -1);
1396           spec->initial_designation[reg] = coding->charsets[i];
1397         }
1398       else if (reg >= -4)
1399         {
1400           if (! designation_policy
1401               && ! (spec->flags & MCODING_ISO_EUC_TW_SHIFT))
1402             MERROR (MERROR_CODING, -1);
1403           reg += 4;
1404         }
1405
1406       if (designation_policy)
1407         spec->designations[i] = reg;
1408       if (coding->charsets[i] == mcharset__ascii)
1409         coding->ascii_compatible = 1;
1410     }
1411
1412   if (coding->ascii_compatible
1413       && (spec->flags & (MCODING_ISO_DESIGNATION_G0
1414                          | MCODING_ISO_DESIGNATION_CTEXT
1415                          | MCODING_ISO_DESIGNATION_CTEXT_EXT
1416                          | MCODING_ISO_LOCKING_SHIFT)))
1417     coding->ascii_compatible = 0;
1418
1419   if (spec->flags & MCODING_ISO_FULL_SUPPORT)
1420     for (i = 0; i < mcharset__iso_2022_table.used; i++)
1421       {
1422         MCharset *charset = mcharset__iso_2022_table.charsets[i];
1423
1424         spec->designations[ncharsets + i]
1425           = ((designation_policy == MCODING_ISO_DESIGNATION_CTEXT
1426               || designation_policy == MCODING_ISO_DESIGNATION_CTEXT_EXT)
1427              ? (charset->code_range[0] == 32
1428                 || charset->code_range[1] == 255)
1429              : designation_policy == MCODING_ISO_DESIGNATION_G1);
1430       }
1431
1432   spec->use_esc = ((spec->flags & MCODING_ISO_DESIGNATION_MASK)
1433                    || ((spec->flags & MCODING_ISO_LOCKING_SHIFT)
1434                        && (spec->initial_designation[2]
1435                            || spec->initial_designation[3]))
1436                    || (! (spec->flags & MCODING_ISO_EIGHT_BIT)
1437                        && (spec->flags & MCODING_ISO_SINGLE_SHIFT))
1438                    || (spec->flags & MCODING_ISO_ISO6429));
1439
1440   coding->extra_spec = (void *) spec;
1441
1442   return 0;
1443 }
1444
1445 static int
1446 reset_coding_iso_2022 (MConverter *converter)
1447 {
1448   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
1449   MCodingSystem *coding = internal->coding;
1450   struct iso_2022_status *status
1451     = (struct iso_2022_status *) &(converter->status);
1452   struct iso_2022_spec *spec;
1453   int i;
1454
1455   if (! coding->ready
1456       && setup_coding_iso_2022 (coding) < 0)
1457     return -1;
1458   coding->ready = 1;
1459
1460   spec = (struct iso_2022_spec *) coding->extra_spec;
1461   status->invocation[0] = spec->initial_invocation[0];
1462   status->invocation[1] = spec->initial_invocation[1];
1463   for (i = 0; i < 4; i++)
1464     status->designation[i] = spec->initial_designation[i];
1465   status->single_shifting = 0;
1466   status->bol = 1;
1467   status->r2l = 0;
1468
1469   return 0;
1470 }
1471
1472 #define ISO2022_DECODE_DESIGNATION(reg, dim, chars, final, rev)           \
1473   do {                                                                    \
1474     MCharset *charset;                                                    \
1475                                                                           \
1476     if ((final) < '0' || (final) >= 128)                                  \
1477       goto invalid_byte;                                                  \
1478     if (rev < 0)                                                          \
1479       {                                                                   \
1480         charset = MCHARSET_ISO_2022 ((dim), (chars), (final));            \
1481         if (! (spec->flags & MCODING_ISO_FULL_SUPPORT))                   \
1482           {                                                               \
1483             int i;                                                        \
1484                                                                           \
1485             for (i = 0; i < coding->ncharsets; i++)                       \
1486               if (charset == coding->charsets[i])                         \
1487                 break;                                                    \
1488             if (i == coding->ncharsets)                                   \
1489               goto invalid_byte;                                          \
1490           }                                                               \
1491       }                                                                   \
1492     else                                                                  \
1493       {                                                                   \
1494         int i;                                                            \
1495                                                                           \
1496         for (i = 0; i < mcharset__iso_2022_table.used; i++)               \
1497           {                                                               \
1498             charset = mcharset__iso_2022_table.charsets[i];               \
1499             if (charset->revision == (rev)                                \
1500                 && charset->dimension == (dim)                            \
1501                 && charset->final_byte == (final)                         \
1502                 && (charset->code_range[1] == (chars)                     \
1503                     || ((chars) == 96 && charset->code_range[1] == 255))) \
1504               break;                                                      \
1505           }                                                               \
1506         if (i == mcharset__iso_2022_table.used)                           \
1507           goto invalid_byte;                                              \
1508       }                                                                   \
1509     status->designation[reg] = charset;                                   \
1510   } while (0)
1511
1512
1513 static MCharset *
1514 find_ctext_non_standard_charset (char *charset_name)
1515 {
1516   MCharset *charset;
1517
1518   if (! strcmp (charset_name, "koi8-r"))
1519     charset = MCHARSET (msymbol ("koi8-r"));
1520   else if  (! strcmp (charset_name, "big5-0"))
1521     charset = MCHARSET (msymbol ("big5"));    
1522   else
1523     charset = NULL;
1524   return charset;
1525 }
1526
1527 static int
1528 decode_coding_iso_2022 (unsigned char *source, int src_bytes, MText *mt,
1529                        MConverter *converter)
1530 {
1531   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
1532   MCodingSystem *coding = internal->coding;
1533   unsigned char *src = internal->carryover;
1534   unsigned char *src_stop = src + internal->carryover_bytes;
1535   unsigned char *src_end = source + src_bytes;
1536   unsigned char *src_base;
1537   unsigned char *dst = mt->data + mt->nbytes;
1538   unsigned char *dst_end = mt->data + mt->allocated;
1539   int nchars = 0;
1540   int last_nchars = 0;
1541   int at_most = converter->at_most > 0 ? converter->at_most : -1;
1542   struct iso_2022_spec *spec = (struct iso_2022_spec *) coding->extra_spec;
1543   struct iso_2022_status *status
1544     = (struct iso_2022_status *) &(converter->status);
1545   MCharset *charset0, *charset1, *charset;
1546   int error = 0;
1547   MCharset *cns_charsets[15];
1548
1549   charset0 = (status->invocation[0] >= 0
1550               ? status->designation[status->invocation[0]] : NULL);
1551   charset1 = (status->invocation[1] >= 0
1552               ? status->designation[status->invocation[1]] : NULL);
1553   charset = mcharset__ascii;
1554
1555   if (spec->flags & MCODING_ISO_EUC_TW_SHIFT)
1556     {
1557       int i;
1558
1559       memset (cns_charsets, 0, sizeof (cns_charsets));
1560       for (i = 0; i < coding->ncharsets; i++)
1561         if (coding->charsets[i]->dimension == 2
1562             && coding->charsets[i]->code_range[1] == 126)
1563           {
1564             int final = coding->charsets[i]->final_byte;
1565
1566             if (final >= 'G' && final <= 'M')
1567               cns_charsets[final - 'G'] = coding->charsets[i];
1568             else if (final < 0)
1569               cns_charsets[14] = coding->charsets[i];
1570           }
1571     }
1572
1573   while (1)
1574     {
1575       MCharset *this_charset = NULL;
1576       int c1, c2, c3;
1577
1578       ONE_MORE_BASE_BYTE (c1);
1579
1580       if (status->utf8_shifting)
1581         {
1582           int buf[6];
1583           int bytes = CHAR_BYTES_BY_HEAD (c1);
1584           int i;
1585           
1586           buf[0] = c1;
1587           for (i = 1; i < bytes; i++)
1588             {
1589               ONE_MORE_BYTE (c1);
1590               buf[i] = c1;
1591             }
1592           this_charset = UTF8_CHARSET (buf);
1593           c1 = STRING_CHAR_UTF8 (buf);
1594           goto emit_char;
1595         }
1596
1597       if (status->non_standard_encoding > 0)
1598         {
1599           int i;
1600
1601           this_charset = status->non_standard_charset;
1602           for (i = 1; i < status->non_standard_charset_bytes; i++)
1603             {
1604               ONE_MORE_BYTE (c2);
1605               c1 = (c1 << 8) | c2;
1606             }
1607           c1 = DECODE_CHAR (this_charset, c1);
1608           goto emit_char;
1609         }
1610
1611       switch (iso_2022_code_class[c1])
1612         {
1613         case ISO_graphic_plane_0:
1614           this_charset = charset0;
1615           break;
1616
1617         case ISO_0x20_or_0x7F:
1618           if (! charset0
1619               || (charset0->code_range[0] != 32
1620                   && charset0->code_range[1] != 255))
1621             /* This is SPACE or DEL.  */
1622             this_charset = mcharset__ascii;
1623           else
1624             /* This is a graphic character of plane 0.  */        
1625             this_charset = charset0;
1626           break;
1627
1628         case ISO_graphic_plane_1:
1629           if (!charset1)
1630             goto invalid_byte;
1631           this_charset = charset1;
1632           break;
1633
1634         case ISO_0xA0_or_0xFF:
1635           if (! charset1
1636               || charset1->code_range[0] == 33
1637               || ! (spec->flags & MCODING_ISO_EIGHT_BIT))
1638             goto invalid_byte;
1639           /* This is a graphic character of plane 1. */
1640           if (! charset1)
1641             goto invalid_byte;
1642           this_charset = charset1;
1643           break;
1644
1645         case ISO_control_0:
1646           this_charset = mcharset__ascii;
1647           break;
1648
1649         case ISO_control_1:
1650           goto invalid_byte;
1651
1652         case ISO_shift_out:
1653           if ((spec->flags & MCODING_ISO_LOCKING_SHIFT)
1654               &&  status->designation[1])
1655             {
1656               status->invocation[0] = 1;
1657               charset0 = status->designation[1];
1658               continue;
1659             }
1660           this_charset = mcharset__ascii;
1661           break;
1662
1663         case ISO_shift_in:
1664           if (spec->flags & MCODING_ISO_LOCKING_SHIFT)
1665             {
1666               status->invocation[0] = 0;
1667               charset0 = status->designation[0];
1668               continue;
1669             }
1670           this_charset = mcharset__ascii;
1671           break;
1672
1673         case ISO_single_shift_2_7:
1674           if (! (spec->flags & MCODING_ISO_SINGLE_SHIFT_7))
1675             {
1676               this_charset = mcharset__ascii;
1677               break;
1678             }
1679           c1 = 'N';
1680           goto label_escape_sequence;
1681
1682         case ISO_single_shift_2:
1683           if (spec->flags & MCODING_ISO_EUC_TW_SHIFT)
1684             {
1685               ONE_MORE_BYTE (c1);
1686               if (c1 < 0xA1 || (c1 > 0xA7 && c1 < 0xAF) || c1 > 0xAF
1687                   || ! cns_charsets[c1 - 0xA1])
1688                 goto invalid_byte;
1689               status->designation[2] = cns_charsets[c1 - 0xA1];
1690             }
1691           else if (! (spec->flags & MCODING_ISO_SINGLE_SHIFT))
1692             goto invalid_byte;
1693           /* SS2 is handled as an escape sequence of ESC 'N' */
1694           c1 = 'N';
1695           goto label_escape_sequence;
1696
1697         case ISO_single_shift_3:
1698           if (! (spec->flags & MCODING_ISO_SINGLE_SHIFT))
1699             goto invalid_byte;
1700           /* SS2 is handled as an escape sequence of ESC 'O' */
1701           c1 = 'O';
1702           goto label_escape_sequence;
1703
1704         case ISO_control_sequence_introducer:
1705           /* CSI is handled as an escape sequence of ESC '[' ...  */
1706           c1 = '[';
1707           goto label_escape_sequence;
1708
1709         case ISO_escape:
1710           if (! spec->use_esc)
1711             {
1712               this_charset = mcharset__ascii;
1713               break;
1714             }
1715           ONE_MORE_BYTE (c1);
1716         label_escape_sequence:
1717           /* Escape sequences handled here are invocation,
1718              designation, and direction specification.  */
1719           switch (c1)
1720             {
1721             case '&':        /* revision of following character set */
1722               if (! (spec->flags & MCODING_ISO_DESIGNATION_MASK))
1723                 goto unused_escape_sequence;
1724               ONE_MORE_BYTE (c1);
1725               if (c1 < '@' || c1 > '~')
1726                 goto invalid_byte;
1727               ONE_MORE_BYTE (c1);
1728               if (c1 != ISO_CODE_ESC)
1729                 goto invalid_byte;
1730               ONE_MORE_BYTE (c1);
1731               goto label_escape_sequence;
1732
1733             case '$':        /* designation of 2-byte character set */
1734               if (! (spec->flags & MCODING_ISO_DESIGNATION_MASK))
1735                 goto unused_escape_sequence;
1736               ONE_MORE_BYTE (c1);
1737               if (c1 >= '@' && c1 <= 'B')
1738                 { /* designation of JISX0208.1978, GB2312.1980, or
1739                      JISX0208.1980 */
1740                   ISO2022_DECODE_DESIGNATION (0, 2, 94, c1, -1);
1741                 }
1742               else if (c1 >= 0x28 && c1 <= 0x2B)
1743                 { /* designation of (dimension 2, chars 94) character set */
1744                   ONE_MORE_BYTE (c2);
1745                   ISO2022_DECODE_DESIGNATION (c1 - 0x28, 2, 94, c2, -1);
1746                 }
1747               else if (c1 >= 0x2C && c1 <= 0x2F)
1748                 { /* designation of (dimension 2, chars 96) character set */
1749                   ONE_MORE_BYTE (c2);
1750                   ISO2022_DECODE_DESIGNATION (c1 - 0x2C, 2, 96, c2, -1);
1751                 }
1752               else
1753                 goto invalid_byte;
1754               /* We must update these variables now.  */
1755               charset0 = status->designation[status->invocation[0]];
1756               charset1 = status->designation[status->invocation[1]];
1757               continue;
1758
1759             case 'n':           /* invocation of locking-shift-2 */
1760               if (! (spec->flags & MCODING_ISO_LOCKING_SHIFT)
1761                   || ! status->designation[2])
1762                 goto invalid_byte;
1763               status->invocation[0] = 2;
1764               charset0 = status->designation[2];
1765               continue;
1766
1767             case 'o':           /* invocation of locking-shift-3 */
1768               if (! (spec->flags & MCODING_ISO_LOCKING_SHIFT)
1769                   || ! status->designation[3])
1770                 goto invalid_byte;
1771               status->invocation[0] = 3;
1772               charset0 = status->designation[3];
1773               continue;
1774
1775             case 'N':           /* invocation of single-shift-2 */
1776               if (! ((spec->flags & MCODING_ISO_SINGLE_SHIFT)
1777                      || (spec->flags & MCODING_ISO_EUC_TW_SHIFT))
1778                   || ! status->designation[2])
1779                 goto invalid_byte;
1780               this_charset = status->designation[2];
1781               ONE_MORE_BYTE (c1);
1782               if (c1 < 0x20 || (c1 >= 0x80 && c1 < 0xA0))
1783                 goto invalid_byte;
1784               break;
1785
1786             case 'O':           /* invocation of single-shift-3 */
1787               if (! (spec->flags & MCODING_ISO_SINGLE_SHIFT)
1788                   || ! status->designation[3])
1789                 goto invalid_byte;
1790               this_charset = status->designation[3];
1791               ONE_MORE_BYTE (c1);
1792               if (c1 < 0x20 || (c1 >= 0x80 && c1 < 0xA0))
1793                 goto invalid_byte;
1794               break;
1795
1796             case '[':           /* specification of direction */
1797               if (! (spec->flags & MCODING_ISO_ISO6429))
1798                 goto invalid_byte;
1799               /* For the moment, nested direction is not supported.
1800                  So, (coding->mode & CODING_MODE_DIRECTION) zero means
1801                  left-to-right, and nonzero means right-to-left.  */
1802               ONE_MORE_BYTE (c1);
1803               switch (c1)
1804                 {
1805                 case ']':       /* end of the current direction */
1806                 case '0':       /* end of the current direction */
1807                   status->r2l = 0;
1808                   break;
1809
1810                 case '1':       /* start of left-to-right direction */
1811                   ONE_MORE_BYTE (c1);
1812                   if (c1 != ']')
1813                     goto invalid_byte;
1814                   status->r2l = 0;
1815                   break;
1816
1817                 case '2':       /* start of right-to-left direction */
1818                   ONE_MORE_BYTE (c1);
1819                   if (c1 != ']')
1820                     goto invalid_byte;
1821                   status->r2l = 1;
1822                   break;
1823
1824                 default:
1825                   goto invalid_byte;
1826                 }
1827               continue;
1828
1829             case '%':
1830               {
1831                 char charset_name[16];
1832                 int bytes;
1833                 int i;
1834
1835                 if (! spec->flags & MCODING_ISO_DESIGNATION_CTEXT_EXT)
1836                   goto invalid_byte;
1837                 /* Compound-text uses these escape sequences:
1838
1839                 ESC % G  -- utf-8 bytes -- ESC % @
1840                 ESC % / 1 M L -- charset name -- STX -- bytes --
1841                 ESC % / 2 M L -- charset name -- STX -- bytes --
1842                 ESC % / 3 M L -- charset name -- STX -- bytes --
1843                 ESC % / 4 M L -- charset name -- STX -- bytes --
1844
1845                 It also uses this sequence but that is not yet
1846                 supported here.
1847
1848                 ESC % / 0 M L -- charset name -- STX -- bytes -- */
1849
1850                 ONE_MORE_BYTE (c1);
1851                 if (c1 == 'G')
1852                   {
1853                     status->utf8_shifting = 1;
1854                     continue;
1855                   }
1856                 if (c1 == '@')
1857                   {
1858                     if (! status->utf8_shifting)
1859                       goto invalid_byte;
1860                     status->utf8_shifting = 0;
1861                     continue;
1862                   }
1863                 if (c1 != '/')
1864                   goto invalid_byte;
1865                 ONE_MORE_BYTE (c1);
1866                 if (c1 < '1' || c1 > '4')
1867                   goto invalid_byte;
1868                 status->non_standard_charset_bytes = c1 - '0';
1869                 ONE_MORE_BYTE (c1);
1870                 ONE_MORE_BYTE (c2);
1871                 if (c1 < 128 || c2 < 128)
1872                   goto invalid_byte;
1873                 bytes = (c1 - 128) * 128 + (c2 - 128);
1874                 for (i = 0; i < 16; i++)
1875                   {
1876                     ONE_MORE_BYTE (c1);
1877                     if (c1 == ISO_CODE_STX)
1878                       break;
1879                     charset_name[i] = TOLOWER (c1);
1880                   }
1881                 if (i == 16)
1882                   goto invalid_byte;
1883                 charset_name[i++] = '\0';
1884                 this_charset = find_ctext_non_standard_charset (charset_name);
1885                 if (! this_charset)
1886                   goto invalid_byte;
1887                 status->non_standard_charset = this_charset;
1888                 status->non_standard_encoding = bytes - i;
1889                 continue;
1890               }
1891
1892             default:
1893               if (! (spec->flags & MCODING_ISO_DESIGNATION_MASK))
1894                 goto unused_escape_sequence;
1895               if (c1 >= 0x28 && c1 <= 0x2B)
1896                 { /* designation of (dimension 1, chars 94) charset */
1897                   ONE_MORE_BYTE (c2);
1898                   ISO2022_DECODE_DESIGNATION (c1 - 0x28, 1, 94, c2, -1);
1899                 }
1900               else if (c1 >= 0x2C && c1 <= 0x2F)
1901                 { /* designation of (dimension 1, chars 96) charset */
1902                   ONE_MORE_BYTE (c2);
1903                   ISO2022_DECODE_DESIGNATION (c1 - 0x2C, 1, 96, c2, -1);
1904                 }
1905               else
1906                 goto invalid_byte;
1907               /* We must update these variables now.  */
1908               charset0 = status->designation[status->invocation[0]];
1909               charset1 = status->designation[status->invocation[1]];
1910               continue;
1911
1912             unused_escape_sequence:
1913               UNGET_ONE_BYTE (c1);
1914               c1 = ISO_CODE_ESC;
1915               this_charset = mcharset__ascii;
1916             }
1917         }
1918
1919       if (this_charset->dimension == 1)
1920         {
1921           if (this_charset->code_range[1] <= 128)
1922             c1 &= 0x7F;
1923         }
1924       else if (this_charset->dimension == 2)
1925         {
1926           ONE_MORE_BYTE (c2);
1927           c1 = ((c1 & 0x7F) << 8) | (c2 & 0x7F);
1928         }
1929       else                      /* i.e.  (dimension == 3) */
1930         {
1931           ONE_MORE_BYTE (c2);
1932           ONE_MORE_BYTE (c3);
1933           c1 = ((c1 & 0x7F) << 16) | ((c2 & 0x7F) << 8) | (c3 & 0x7F);
1934         }
1935       c1 = DECODE_CHAR (this_charset, c1);
1936       goto emit_char;
1937
1938     invalid_byte:
1939       if (! converter->lenient)
1940         break;
1941       REWIND_SRC_TO_BASE ();
1942       c1 = *src++;
1943       this_charset = mcharset__binary;
1944
1945     emit_char:
1946       if (this_charset != mcharset__ascii
1947           && this_charset != charset)
1948         {
1949           TAKEIN_CHARS (mt, nchars - last_nchars,
1950                         dst - (mt->data + mt->nbytes), charset);
1951           charset = this_charset;
1952           last_nchars = nchars;
1953         }
1954       EMIT_CHAR (c1);
1955       if (status->non_standard_encoding > 0)
1956         status->non_standard_encoding -= status->non_standard_charset_bytes;
1957     }
1958   /* We reach here because of an invalid byte.  */
1959   error = 1;
1960
1961
1962
1963  source_end:
1964   TAKEIN_CHARS (mt, nchars - last_nchars,
1965                 dst - (mt->data + mt->nbytes), charset);
1966   return finish_decoding (mt, converter, nchars,
1967                           source, src_end, src_base, error);
1968
1969 }
1970
1971 /* Produce codes (escape sequence) for designating CHARSET to graphic
1972    register REG at DST, and increment DST.  If CHARSET->final-char is
1973    '@', 'A', or 'B' and SHORT_FORM is nonzero, produce designation
1974    sequence of short-form.  Update STATUS->designation.  */
1975
1976 #define ISO2022_ENCODE_DESIGNATION(reg, charset, spec, status)             \
1977   do {                                                                     \
1978     char *intermediate_char_94 = "()*+";                                   \
1979     char *intermediate_char_96 = ",-./";                                   \
1980                                                                            \
1981     if (dst + 4 > dst_end)                                                 \
1982       goto memory_shortage;                                                \
1983     *dst++ = ISO_CODE_ESC;                                                 \
1984     if (charset->dimension == 1)                                           \
1985       {                                                                    \
1986         if (charset->code_range[0] != 32                                   \
1987             && charset->code_range[1] != 255)                              \
1988           *dst++ = (unsigned char) (intermediate_char_94[reg]);            \
1989         else                                                               \
1990           *dst++ = (unsigned char) (intermediate_char_96[reg]);            \
1991       }                                                                    \
1992     else                                                                   \
1993       {                                                                    \
1994         *dst++ = '$';                                                      \
1995         if (charset->code_range[0] != 32                                   \
1996             && charset->code_range[1] != 255)                              \
1997           {                                                                \
1998             if (spec->flags & MCODING_ISO_LONG_FORM                        \
1999                 || reg != 0                                                \
2000                 || charset->final_byte < '@' || charset->final_byte > 'B') \
2001               *dst++ = (unsigned char) (intermediate_char_94[reg]);        \
2002           }                                                                \
2003         else                                                               \
2004           *dst++ = (unsigned char) (intermediate_char_96[reg]);            \
2005       }                                                                    \
2006     *dst++ = charset->final_byte;                                          \
2007                                                                            \
2008     status->designation[reg] = charset;                                    \
2009   } while (0)
2010
2011
2012 /* The following two macros produce codes (control character or escape
2013    sequence) for ISO-2022 single-shift functions (single-shift-2 and
2014    single-shift-3).  */
2015
2016 #define ISO2022_ENCODE_SINGLE_SHIFT_2(spec, status)     \
2017   do {                                                  \
2018     if (dst + 2 > dst_end)                              \
2019       goto memory_shortage;                             \
2020     if (! (spec->flags & MCODING_ISO_EIGHT_BIT))        \
2021       *dst++ = ISO_CODE_ESC, *dst++ = 'N';              \
2022     else                                                \
2023       *dst++ = ISO_CODE_SS2;                            \
2024     status->single_shifting = 1;                        \
2025   } while (0)
2026
2027
2028 #define ISO2022_ENCODE_SINGLE_SHIFT_3(spec, status)     \
2029   do {                                                  \
2030     if (dst + 2 > dst_end)                              \
2031       goto memory_shortage;                             \
2032     if (! (spec->flags & MCODING_ISO_EIGHT_BIT))        \
2033       *dst++ = ISO_CODE_ESC, *dst++ = 'O';              \
2034     else                                                \
2035       *dst++ = ISO_CODE_SS3;                            \
2036     status->single_shifting = 1;                        \
2037   } while (0)
2038
2039
2040 /* The following four macros produce codes (control character or
2041    escape sequence) for ISO-2022 locking-shift functions (shift-in,
2042    shift-out, locking-shift-2, and locking-shift-3).  */
2043
2044 #define ISO2022_ENCODE_SHIFT_IN(status)         \
2045   do {                                          \
2046     if (dst + 1 > dst_end)                      \
2047       goto memory_shortage;                     \
2048     *dst++ = ISO_CODE_SI;                       \
2049     status->invocation[0] = 0;                  \
2050   } while (0)
2051
2052
2053 #define ISO2022_ENCODE_SHIFT_OUT(status)        \
2054   do {                                          \
2055     if (dst + 1 > dst_end)                      \
2056       goto memory_shortage;                     \
2057     *dst++ = ISO_CODE_SO;                       \
2058     status->invocation[0] = 1;                  \
2059   } while (0)
2060
2061
2062 #define ISO2022_ENCODE_LOCKING_SHIFT_2(status)  \
2063   do {                                          \
2064     if (dst + 2 > dst_end)                      \
2065       goto memory_shortage;                     \
2066     *dst++ = ISO_CODE_ESC, *dst++ = 'n';        \
2067     status->invocation[0] = 2;                  \
2068   } while (0)
2069
2070
2071 #define ISO2022_ENCODE_LOCKING_SHIFT_3(status)  \
2072   do {                                          \
2073     if (dst + 2 > dst_end)                      \
2074       goto memory_shortage;                     \
2075     *dst++ = ISO_CODE_ESC, *dst++ = 'o';        \
2076     status->invocation[0] = 3;                  \
2077   } while (0)
2078
2079 #define ISO2022_ENCODE_UTF8_SHIFT_START(len)    \
2080   do {                                          \
2081     CHECK_DST (3 + len);                        \
2082     *dst++ = ISO_CODE_ESC;                      \
2083     *dst++ = '%';                               \
2084     *dst++ = 'G';                               \
2085     status->utf8_shifting = 1;                  \
2086   } while (0)
2087
2088
2089 #define ISO2022_ENCODE_UTF8_SHIFT_END() \
2090   do {                                  \
2091     CHECK_DST (3);                      \
2092     *dst++ = ISO_CODE_ESC;              \
2093     *dst++ = '%';                       \
2094     *dst++ = '@';                       \
2095     status->utf8_shifting = 0;          \
2096   } while (0)
2097
2098
2099 #define ISO2022_ENCODE_NON_STANDARD(name, len)                  \
2100   do {                                                          \
2101     CHECK_DST (6 + len + 1 + non_standard_charset_bytes);       \
2102     non_standard_begin = dst;                                   \
2103     *dst++ = ISO_CODE_ESC;                                      \
2104     *dst++ = '%';                                               \
2105     *dst++ = '/';                                               \
2106     *dst++ = '0' + non_standard_charset_bytes;                  \
2107     *dst++ = 0, *dst++ = 0;     /* filled later */              \
2108     memcpy (dst, name, len);                                    \
2109     dst += len;                                                 \
2110     *dst++ = ISO_CODE_STX;                                      \
2111     non_standard_bytes = len + 1;                               \
2112   } while (0)
2113
2114
2115 static char *
2116 find_ctext_non_standard_name (MCharset *charset, int *bytes)
2117 {
2118   char *name = msymbol_name (charset->name);
2119
2120   if (! strcmp (name, "koi8-r"))
2121     *bytes = 1;
2122   else if (! strcmp (name, "big5"))
2123     name = "big5-0", *bytes = 2;
2124   else
2125     return NULL;
2126   return name;
2127 }
2128
2129 /* Designate CHARSET to a graphic register specified in
2130    SPEC->designation.  If the register is not yet invoked to graphic
2131    left not right, invoke it to graphic left.  DSTP points to a
2132    variable containing a memory address where the output must go.
2133    DST_END is the limit of that memory.
2134
2135    Return 0 if it succeeds.  Return -1 otherwise, which means that the
2136    memory area is too short.  By side effect, update the variable that
2137    DSTP points to.  */
2138
2139 static int
2140 iso_2022_designate_invoke_charset (MCodingSystem *coding,
2141                                    MCharset *charset,
2142                                    struct iso_2022_spec *spec,
2143                                    struct iso_2022_status *status,
2144                                    unsigned char **dstp,
2145                                    unsigned char *dst_end)
2146 {
2147   int i;
2148   unsigned char *dst = *dstp;
2149
2150   for (i = 0; i < 4; i++)
2151     if (charset == status->designation[i])
2152       break;
2153
2154   if (i >= 4)
2155     {
2156       /* CHARSET is not yet designated to any graphic registers.  */
2157       for (i = 0; i < coding->ncharsets; i++)
2158         if (charset == coding->charsets[i])
2159           break;
2160       if (i == coding->ncharsets)
2161         {
2162           for (i = 0; i < mcharset__iso_2022_table.used; i++)
2163             if (charset == mcharset__iso_2022_table.charsets[i])
2164               break;
2165           i += coding->ncharsets;
2166         }
2167       i = spec->designations[i];
2168       ISO2022_ENCODE_DESIGNATION (i, charset, spec, status);
2169     }
2170
2171   if (status->invocation[0] != i
2172       && status->invocation[1] != i)
2173     {
2174       /* Graphic register I is not yet invoked.  */
2175       switch (i)
2176         {
2177         case 0:                 /* graphic register 0 */
2178           ISO2022_ENCODE_SHIFT_IN (status);
2179           break;
2180
2181         case 1:                 /* graphic register 1 */
2182           ISO2022_ENCODE_SHIFT_OUT (status);
2183           break;
2184
2185         case 2:                 /* graphic register 2 */
2186           if (spec->flags & MCODING_ISO_SINGLE_SHIFT)
2187             ISO2022_ENCODE_SINGLE_SHIFT_2 (spec, status);
2188           else
2189             ISO2022_ENCODE_LOCKING_SHIFT_2 (status);
2190           break;
2191
2192         case 3:                 /* graphic register 3 */
2193           if (spec->flags & MCODING_ISO_SINGLE_SHIFT)
2194             ISO2022_ENCODE_SINGLE_SHIFT_3 (spec, status);
2195           else
2196             ISO2022_ENCODE_LOCKING_SHIFT_3 (status);
2197           break;
2198         }
2199     }
2200   *dstp = dst;
2201   return 0;
2202
2203  memory_shortage:
2204   *dstp = dst;
2205   return -1;
2206 }
2207
2208
2209 /* Reset the invocation/designation status to the initial one.  SPEC
2210    and STATUS contain information about the current and initial
2211    invocation /designation status respectively.  DSTP points to a
2212    variable containing a memory address where the output must go.
2213    DST_END is the limit of that memory.
2214
2215    Return 0 if it succeeds.  Return -1 otherwise, which means that the
2216    memory area is too short.  By side effect, update the variable that
2217    DSTP points to.  */
2218
2219 static int
2220 iso_2022_reset_invocation_designation (struct iso_2022_spec *spec,
2221                                        struct iso_2022_status *status,
2222                                        unsigned char **dstp,
2223                                        unsigned char *dst_end)
2224 {
2225   unsigned char *dst = *dstp;
2226   int i;
2227
2228   /* Reset the invocation status of GL.  We have not yet supported GR
2229      invocation.  */
2230   if (status->invocation[0] != spec->initial_invocation[0]
2231         && spec->initial_invocation[0] >= 0)
2232     {
2233       if (spec->initial_invocation[0] == 0)
2234         ISO2022_ENCODE_SHIFT_IN (status);
2235       else if (spec->initial_invocation[0] == 1)
2236         ISO2022_ENCODE_SHIFT_OUT (status);
2237       else if (spec->initial_invocation[0] == 2)
2238         ISO2022_ENCODE_LOCKING_SHIFT_2 (status);
2239       else                      /* i.e. spec->initial_invocation[0] == 3 */
2240         ISO2022_ENCODE_LOCKING_SHIFT_3 (status);
2241     }
2242
2243   /* Reset the designation status of G0..G3.  */
2244   for (i = 0; i < 4; i++)
2245     if (status->designation[i] != spec->initial_designation[i]
2246         && spec->initial_designation[i])
2247       {
2248         MCharset *charset = spec->initial_designation[i];
2249         
2250         ISO2022_ENCODE_DESIGNATION (i, charset, spec, status);
2251       }
2252
2253   *dstp = dst;
2254   return 0;
2255
2256  memory_shortage:
2257   *dstp = dst;
2258   return -1;
2259 }
2260
2261
2262 static int
2263 encode_coding_iso_2022 (MText *mt, int from, int to,
2264                        unsigned char *destination, int dst_bytes,
2265                        MConverter *converter)
2266 {
2267   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
2268   MCodingSystem *coding = internal->coding;
2269   unsigned char *src, *src_end;
2270   unsigned char *dst = destination;
2271   unsigned char *dst_end = dst + dst_bytes;
2272   int nchars = 0;
2273   unsigned char *dst_base;
2274   struct iso_2022_spec *spec = (struct iso_2022_spec *) coding->extra_spec;
2275   int full_support = spec->flags & MCODING_ISO_FULL_SUPPORT;
2276   struct iso_2022_status *status
2277     = (struct iso_2022_status *) &(converter->status);
2278   MCharset *primary, *charset0, *charset1;
2279   int next_primary_change;
2280   int ncharsets = coding->ncharsets;
2281   MCharset **charsets = coding->charsets;
2282   MCharset *cns_charsets[15];
2283   int ascii_compatible = coding->ascii_compatible;
2284   MCharset *non_standard_charset = NULL;
2285   int non_standard_charset_bytes = 0;
2286   int non_standard_bytes = 0;
2287   unsigned char *non_standard_begin = NULL;
2288   enum MTextFormat format = mt->format;
2289
2290   SET_SRC (mt, format, from, to);
2291
2292   if (spec->flags & MCODING_ISO_EUC_TW_SHIFT)
2293     {
2294       int i;
2295
2296       memset (cns_charsets, 0, sizeof (cns_charsets));
2297       for (i = 0; i < ncharsets; i++)
2298         if (charsets[i]->dimension == 2)
2299           {
2300             int final = charsets[i]->final_byte;
2301
2302             if (final >= 'G' && final <= 'M')
2303               cns_charsets[final - 'G'] = charsets[i];
2304             else if (final < 0)
2305               cns_charsets[14] = charsets[i];
2306           }
2307     }
2308
2309   next_primary_change = from;
2310   primary = NULL;
2311   charset0 = status->designation[status->invocation[0]];
2312   charset1 = (status->invocation[1] < 0 ? NULL
2313               : status->designation[status->invocation[1]]);
2314
2315   while (1)
2316     {
2317       int bytes, c;
2318
2319       dst_base = dst;
2320       ONE_MORE_CHAR (c, bytes, format);
2321
2322       if (c < 128 && ascii_compatible)
2323         {
2324           if (status->utf8_shifting)
2325             ISO2022_ENCODE_UTF8_SHIFT_END ();
2326           CHECK_DST (1);
2327           *dst++ = c;
2328         }
2329       else if (c <= 32 || c == 127)
2330         {
2331           if (status->utf8_shifting)
2332             ISO2022_ENCODE_UTF8_SHIFT_END ();
2333           if (spec->flags & MCODING_ISO_RESET_AT_CNTL
2334               || (c == '\n' && spec->flags & MCODING_ISO_RESET_AT_EOL))
2335             {
2336               if (iso_2022_reset_invocation_designation (spec, status,
2337                                                          &dst, dst_end) < 0)
2338                 goto insufficient_destination;
2339               charset0 = status->designation[status->invocation[0]];
2340               charset1 = (status->invocation[1] < 0 ? NULL
2341                           : status->designation[status->invocation[1]]);
2342             }
2343           CHECK_DST (1);
2344           *dst++ = c;
2345         }
2346       else
2347         {
2348           unsigned code = MCHAR_INVALID_CODE;
2349           MCharset *charset = NULL;
2350           int gr_mask;
2351           int pos = from + nchars;
2352
2353           if (pos >= next_primary_change)
2354             {
2355               MSymbol primary_charset
2356                 = (MSymbol) mtext_get_prop (mt, pos, Mcharset);
2357               primary = MCHARSET (primary_charset);
2358               if (primary && primary != mcharset__binary)
2359                 {
2360                   if (primary->final_byte <= 0)
2361                     primary = NULL;
2362                   else if (! full_support)
2363                     {
2364                       int i;
2365
2366                       for (i = 0; i < ncharsets; i++)
2367                         if (primary == charsets[i])
2368                           break;
2369                       if (i == ncharsets)
2370                         primary = NULL;
2371                     }
2372                 }
2373
2374               mtext_prop_range (mt, Mcharset, pos,
2375                                 NULL, &next_primary_change, 0);
2376             }
2377
2378           if (primary && primary != mcharset__binary)
2379             {
2380               code = ENCODE_CHAR (primary, c);
2381               if (code != MCHAR_INVALID_CODE)
2382                 charset = primary;
2383             }
2384           if (! charset)
2385             {
2386               if (c <= 32 || c == 127)
2387                 {
2388                   code = c;
2389                   charset = mcharset__ascii;
2390                 }
2391               else 
2392                 {
2393                   int i;
2394
2395                   for (i = 0; i < ncharsets; i++)
2396                     {
2397                       charset = charsets[i];
2398                       code = ENCODE_CHAR (charset, c);
2399                       if (code != MCHAR_INVALID_CODE)
2400                         break;
2401                     }
2402                   if (i == ncharsets)
2403                     {
2404                       if (spec->flags & MCODING_ISO_FULL_SUPPORT)
2405                         {
2406                           for (i = 0; i < mcharset__iso_2022_table.used; i++)
2407                             {
2408                               charset = mcharset__iso_2022_table.charsets[i];
2409                               code = ENCODE_CHAR (charset, c);
2410                               if (code != MCHAR_INVALID_CODE)
2411                                 break;
2412                             }
2413                           if (i == mcharset__iso_2022_table.used)
2414                             {
2415                               if (spec->flags & MCODING_ISO_DESIGNATION_CTEXT_EXT)
2416                                 goto unsupported_char;
2417                               converter->result = MCONVERSION_RESULT_INVALID_CHAR;
2418                               goto finish;
2419                             }
2420                         }
2421                       else
2422                         goto unsupported_char;
2423                     }
2424                 }
2425             }
2426
2427           if (charset
2428               && (charset->final_byte >= 0
2429                   || spec->flags & MCODING_ISO_EUC_TW_SHIFT))
2430             {
2431               if (code >= 0x80 && code < 0xA0)
2432                 goto unsupported_char;
2433               code &= 0x7F7F7F7F;
2434               if (status->utf8_shifting)
2435                 ISO2022_ENCODE_UTF8_SHIFT_END ();
2436               if (charset == charset0)
2437                 gr_mask = 0;
2438               else if (charset == charset1)
2439                 gr_mask = 0x80;
2440               else
2441                 {
2442                   unsigned char *p = NULL;
2443
2444                   if (spec->flags & MCODING_ISO_EUC_TW_SHIFT)
2445                     {
2446                       int i;
2447
2448                       if (cns_charsets[0] == charset)
2449                         {
2450                           CHECK_DST (2);
2451                         }
2452                       else
2453                         {
2454                           for (i = 1; i < 15; i++)
2455                             if (cns_charsets[i] == charset)
2456                               break;
2457                           CHECK_DST (4);
2458                           *dst++ = ISO_CODE_SS2;
2459                           *dst++ = 0xA1 + i;
2460                         }
2461                       status->single_shifting = 1;
2462                       p = dst;
2463                     }
2464                   else
2465                     {
2466                       if (iso_2022_designate_invoke_charset
2467                           (coding, charset, spec, status, &dst, dst_end) < 0)
2468                         goto insufficient_destination;
2469                       charset0 = status->designation[status->invocation[0]];
2470                       charset1 = (status->invocation[1] < 0 ? NULL
2471                                   : status->designation[status->invocation[1]]);
2472                     }
2473                   if (status->single_shifting)
2474                     gr_mask
2475                       = (spec->flags & MCODING_ISO_EIGHT_BIT) ? 0x80 : 0;
2476                   else if (charset == charset0)
2477                     gr_mask = 0;
2478                   else
2479                     gr_mask = 0x80;
2480                 }
2481               if (charset->dimension == 1)
2482                 {
2483                   CHECK_DST (1);
2484                   *dst++ = code | gr_mask;
2485                 }
2486               else if (charset->dimension == 2)
2487                 {
2488                   CHECK_DST (2);
2489                   *dst++ = (code >> 8) | gr_mask;
2490                   *dst++ = (code & 0xFF) | gr_mask;
2491                 }
2492               else
2493                 {
2494                   CHECK_DST (3);
2495                   *dst++ = (code >> 16) | gr_mask;
2496                   *dst++ = ((code >> 8) & 0xFF) | gr_mask;
2497                   *dst++ = (code & 0xFF) | gr_mask;
2498                 }
2499               status->single_shifting = 0;
2500             }
2501           else if (charset && spec->flags & MCODING_ISO_DESIGNATION_CTEXT_EXT)
2502             {
2503               if (charset != non_standard_charset)
2504                 {
2505                   char *name = (find_ctext_non_standard_name
2506                                 (charset, &non_standard_charset_bytes));
2507
2508                   if (name)
2509                     {
2510                       int len = strlen (name);
2511                       
2512                       ISO2022_ENCODE_NON_STANDARD (name, len);
2513                       non_standard_charset = charset;
2514                     }
2515                   else
2516                     non_standard_charset = NULL;
2517                 }
2518
2519               if (non_standard_charset)
2520                 {
2521                   if (dst + non_standard_charset_bytes > dst_end)
2522                     goto insufficient_destination;
2523                   non_standard_bytes += non_standard_charset_bytes;
2524                   non_standard_begin[4] = (non_standard_bytes / 128) | 0x80;
2525                   non_standard_begin[5] = (non_standard_bytes % 128) | 0x80;
2526                   if (non_standard_charset_bytes == 1)
2527                     *dst++ = code;
2528                   else if (non_standard_charset_bytes == 2)
2529                     *dst++ = code >> 8, *dst++ = code & 0xFF;
2530                   else if (non_standard_charset_bytes == 3)
2531                     *dst++ = code >> 16, *dst++ = (code >> 8) & 0xFF,
2532                       *dst++ = code & 0xFF;
2533                   else          /* i.e non_standard_charset_bytes == 3 */
2534                     *dst++ = code >> 24, *dst++ = (code >> 16) & 0xFF,
2535                       *dst++ = (code >> 8) & 0xFF, *dst++ = code & 0xFF;
2536                 }
2537               else
2538                 {
2539                   int len = CHAR_BYTES (c);
2540
2541                   if (c >= 0x110000)
2542                     goto unsupported_char;
2543                   if (! status->utf8_shifting)
2544                     ISO2022_ENCODE_UTF8_SHIFT_START (len);
2545                   else
2546                     CHECK_DST (len);
2547                   CHAR_STRING (c, dst);
2548                 }
2549             }
2550           else
2551             goto unsupported_char;
2552         }
2553       src += bytes;
2554       nchars++;
2555       continue;
2556
2557     unsupported_char:
2558       {
2559         int len;
2560
2561         if (iso_2022_designate_invoke_charset (coding, mcharset__ascii,
2562                                                spec, status,
2563                                                &dst, dst_end) < 0)
2564           goto insufficient_destination;
2565         if (! converter->lenient)
2566           break;
2567         len = encode_unsupporeted_char (c, dst, dst_end, mt, from + nchars);
2568         if (len == 0)
2569           goto insufficient_destination;
2570         dst += len;
2571         src += bytes;
2572         nchars++;
2573       }
2574     }
2575   /* We reach here because of an unsupported char.  */
2576   converter->result = MCONVERSION_RESULT_INVALID_CHAR;
2577   goto finish;
2578
2579  insufficient_destination:
2580   dst = dst_base;
2581   converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
2582
2583  finish:
2584   if (converter->result == MCONVERSION_RESULT_SUCCESS
2585       && converter->last_block)
2586     {
2587       if (status->utf8_shifting)
2588         {
2589           ISO2022_ENCODE_UTF8_SHIFT_END ();
2590           dst_base = dst;
2591         }
2592       if (spec->flags & MCODING_ISO_RESET_AT_EOL
2593           && charset0 != spec->initial_designation[0])
2594         {
2595           if (iso_2022_reset_invocation_designation (spec, status,
2596                                                      &dst, dst_end) < 0)
2597             goto insufficient_destination;
2598         }
2599     }
2600   converter->nchars += nchars;
2601   converter->nbytes += dst - destination;
2602   return (converter->result == MCONVERSION_RESULT_INVALID_CHAR ? -1 : 0);
2603 }
2604
2605 \f
2606 /* Staffs for coding-systems of type MCODING_TYPE_MISC.  */
2607
2608 /* For SJIS handling... */
2609
2610 #define SJIS_TO_JIS(s1, s2)                             \
2611   (s2 >= 0x9F                                           \
2612    ? (((s1 * 2 - (s1 >= 0xE0 ? 0x160 : 0xE0)) << 8)     \
2613       | (s2 - 0x7E))                                    \
2614    : (((s1 * 2 - ((s1 >= 0xE0) ? 0x161 : 0xE1)) << 8)   \
2615       | (s2 - ((s2 >= 0x7F) ? 0x20 : 0x1F))))
2616
2617 #define JIS_TO_SJIS(c1, c2)                             \
2618   ((c1 & 1)                                             \
2619    ? (((c1 / 2 + ((c1 < 0x5F) ? 0x71 : 0xB1)) << 8)     \
2620       | (c2 + ((c2 >= 0x60) ? 0x20 : 0x1F)))            \
2621    : (((c1 / 2 + ((c1 < 0x5F) ? 0x70 : 0xB0)) << 8)     \
2622       | (c2 + 0x7E)))
2623
2624
2625 static int
2626 reset_coding_sjis (MConverter *converter)
2627 {
2628   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
2629   MCodingSystem *coding = internal->coding;
2630
2631   if (! coding->ready)
2632     {
2633       MSymbol kanji_sym = msymbol ("jisx0208.1983");
2634       MCharset *kanji = MCHARSET (kanji_sym);
2635       MSymbol kana_sym = msymbol ("jisx0201-kana");
2636       MCharset *kana = MCHARSET (kana_sym);
2637
2638       if (! kanji_sym || ! kana_sym)
2639         return -1;
2640       coding->ncharsets = 3;
2641       coding->charsets[1] = kanji;
2642       coding->charsets[2] = kana;
2643     }
2644   coding->ready = 1;
2645   return 0;
2646 }
2647
2648 static int
2649 decode_coding_sjis (unsigned char *source, int src_bytes, MText *mt,
2650                     MConverter *converter)
2651 {
2652   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
2653   MCodingSystem *coding = internal->coding;
2654   unsigned char *src = internal->carryover;
2655   unsigned char *src_stop = src + internal->carryover_bytes;
2656   unsigned char *src_end = source + src_bytes;
2657   unsigned char *src_base;
2658   unsigned char *dst = mt->data + mt->nbytes;
2659   unsigned char *dst_end = mt->data + mt->allocated - MAX_UTF8_CHAR_BYTES;
2660   int nchars = 0;
2661   int last_nchars = 0;
2662   int at_most = converter->at_most > 0 ? converter->at_most : -1;
2663
2664   MCharset *charset_roman = coding->charsets[0];
2665   MCharset *charset_kanji = coding->charsets[1];
2666   MCharset *charset_kana = coding->charsets[2];
2667   MCharset *charset = mcharset__ascii;
2668   int error = 0;
2669
2670   while (1)
2671     {
2672       MCharset *this_charset;
2673       int c, c1, c2;
2674
2675       ONE_MORE_BASE_BYTE (c1);
2676
2677       c2 = -1;
2678       if (c1 < 0x80)
2679         {
2680           this_charset = ((c1 <= 0x20 || c1 == 0x7F)
2681                           ? mcharset__ascii
2682                           : charset_roman);
2683         }
2684       else if ((c1 >= 0x81 && c1 <= 0x9F) || (c1 >= 0xE0 && c1 <= 0xEF))
2685         {
2686           ONE_MORE_BYTE (c2);
2687           if ((c2 >= 0x40 && c2 <= 0x7F) || (c2 >= 80 && c2 <= 0xFC))
2688             {
2689               this_charset = charset_kanji;
2690               c1 = SJIS_TO_JIS (c1, c2);
2691             }
2692           else
2693             goto invalid_byte;
2694         }
2695       else if (c1 >= 0xA1 && c1 <= 0xDF)
2696         {
2697           this_charset = charset_kana;
2698           c1 &= 0x7F;
2699         }
2700       else
2701         goto invalid_byte;
2702
2703       c = DECODE_CHAR (this_charset, c1);
2704       if (c >= 0)
2705         goto emit_char;
2706
2707     invalid_byte:
2708       if (! converter->lenient)
2709         break;
2710       REWIND_SRC_TO_BASE ();
2711       c = *src++;
2712       this_charset = mcharset__binary;
2713
2714     emit_char:
2715       if (this_charset != mcharset__ascii
2716           && this_charset != charset)
2717         {
2718           TAKEIN_CHARS (mt, nchars - last_nchars, 
2719                         dst - (mt->data + mt->nbytes), charset);
2720           charset = this_charset;
2721           last_nchars = nchars;
2722         }
2723       EMIT_CHAR (c);
2724     }
2725   /* We reach here because of an invalid byte.  */
2726   error = 1;
2727
2728  source_end:
2729   TAKEIN_CHARS (mt, nchars - last_nchars,
2730                 dst - (mt->data + mt->nbytes), charset);
2731   return finish_decoding (mt, converter, nchars,
2732                           source, src_end, src_base, error);
2733 }
2734
2735 static int
2736 encode_coding_sjis (MText *mt, int from, int to,
2737                     unsigned char *destination, int dst_bytes,
2738                     MConverter *converter)
2739 {
2740   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
2741   MCodingSystem *coding = internal->coding;
2742   unsigned char *src, *src_end;
2743   unsigned char *dst = destination;
2744   unsigned char *dst_end = dst + dst_bytes;
2745   int nchars = 0;
2746   MCharset *charset_roman = coding->charsets[0];
2747   MCharset *charset_kanji = coding->charsets[1];
2748   MCharset *charset_kana = coding->charsets[2];
2749   enum MTextFormat format = mt->format;
2750
2751   SET_SRC (mt, format, from, to);
2752
2753   while (1)
2754     {
2755       int c, bytes, len;
2756       unsigned code;
2757
2758       ONE_MORE_CHAR (c, bytes, format);
2759
2760       if (c <= 0x20 || c == 0x7F)
2761         {
2762           CHECK_DST (1);
2763           *dst++ = c;
2764         }
2765       else
2766         {
2767           if ((code = ENCODE_CHAR (charset_roman, c)) != MCHAR_INVALID_CODE)
2768             {
2769               CHECK_DST (1);
2770               *dst++ = c;
2771             }
2772           else if ((code = ENCODE_CHAR (charset_kanji, c))
2773                    != MCHAR_INVALID_CODE)
2774             {
2775               int c1 = code >> 8, c2 = code & 0xFF;
2776               code = JIS_TO_SJIS (c1, c2);
2777               CHECK_DST (2);
2778               *dst++ = code >> 8;
2779               *dst++ = code & 0xFF;
2780             }
2781           else if ((code = ENCODE_CHAR (charset_kana, c))
2782                    != MCHAR_INVALID_CODE)
2783             {
2784               CHECK_DST (1);
2785               *dst++ = code | 0x80;
2786             }
2787           else
2788             {
2789               if (! converter->lenient)
2790                 break;
2791               len = encode_unsupporeted_char (c, dst, dst_end,
2792                                               mt, from + nchars);
2793               if (len == 0)
2794                 goto insufficient_destination;
2795               dst += len;
2796             }
2797         }
2798       src += bytes;
2799       nchars++;
2800     }
2801   /* We reach here because of an unsupported char.  */
2802   converter->result = MCONVERSION_RESULT_INVALID_CHAR;
2803   goto finish;
2804
2805  insufficient_destination:
2806   converter->result = MCONVERSION_RESULT_INSUFFICIENT_DST;
2807
2808  finish:
2809   converter->nchars += nchars;
2810   converter->nbytes += dst - destination;
2811   return (converter->result == MCONVERSION_RESULT_INVALID_CHAR ? -1 : 0);
2812 }
2813
2814
2815 static MCodingSystem *
2816 find_coding (MSymbol name)
2817 {
2818   MCodingSystem *coding = (MCodingSystem *) msymbol_get (name, Mcoding);
2819
2820   if (! coding)
2821     {
2822       MPlist *param = mplist_get (coding_definition_list, name);
2823
2824       if (! param)
2825         return NULL;
2826       param = mplist__from_plist (param);
2827       mconv_define_coding (MSYMBOL_NAME (name), param, NULL, NULL, NULL, NULL);
2828       coding = (MCodingSystem *) msymbol_get (name, Mcoding);
2829       M17N_OBJECT_UNREF (param);
2830     }
2831   return coding;
2832 }
2833
2834 #define BINDING_NONE 0
2835 #define BINDING_BUFFER 1
2836 #define BINDING_STREAM 2
2837
2838 #define CONVERT_WORKSIZE 0x10000
2839
2840 \f
2841 /* Internal API */
2842
2843 int
2844 mcoding__init (void)
2845 {
2846   int i;
2847   MPlist *param, *charsets, *pl;
2848
2849   MLIST_INIT1 (&coding_list, codings, 128);
2850   coding_definition_list = mplist ();
2851
2852   /* ISO-2022 specific initialize routine.  */
2853   for (i = 0; i < 0x20; i++)
2854     iso_2022_code_class[i] = ISO_control_0;
2855   for (i = 0x21; i < 0x7F; i++)
2856     iso_2022_code_class[i] = ISO_graphic_plane_0;
2857   for (i = 0x80; i < 0xA0; i++)
2858     iso_2022_code_class[i] = ISO_control_1;
2859   for (i = 0xA1; i < 0xFF; i++)
2860     iso_2022_code_class[i] = ISO_graphic_plane_1;
2861   iso_2022_code_class[0x20] = iso_2022_code_class[0x7F] = ISO_0x20_or_0x7F;
2862   iso_2022_code_class[0xA0] = iso_2022_code_class[0xFF] = ISO_0xA0_or_0xFF;
2863   iso_2022_code_class[0x0E] = ISO_shift_out;
2864   iso_2022_code_class[0x0F] = ISO_shift_in;
2865   iso_2022_code_class[0x19] = ISO_single_shift_2_7;
2866   iso_2022_code_class[0x1B] = ISO_escape;
2867   iso_2022_code_class[0x8E] = ISO_single_shift_2;
2868   iso_2022_code_class[0x8F] = ISO_single_shift_3;
2869   iso_2022_code_class[0x9B] = ISO_control_sequence_introducer;
2870
2871   Mcoding = msymbol ("coding");
2872
2873   Mutf = msymbol ("utf");
2874   Miso_2022 = msymbol ("iso-2022");
2875
2876   Mreset_at_eol = msymbol ("reset-at-eol");
2877   Mreset_at_cntl = msymbol ("reset-at-cntl");
2878   Meight_bit = msymbol ("eight-bit");
2879   Mlong_form = msymbol ("long-form");
2880   Mdesignation_g0 = msymbol ("designation-g0");
2881   Mdesignation_g1 = msymbol ("designation-g1");
2882   Mdesignation_ctext = msymbol ("designation-ctext");
2883   Mdesignation_ctext_ext = msymbol ("designation-ctext-ext");
2884   Mlocking_shift = msymbol ("locking-shift");
2885   Msingle_shift = msymbol ("single-shift");
2886   Msingle_shift_7 = msymbol ("single-shift-7");
2887   Meuc_tw_shift = msymbol ("euc-tw-shift");
2888   Miso_6429 = msymbol ("iso-6429");
2889   Mrevision_number = msymbol ("revision-number");
2890   Mfull_support = msymbol ("full-support");
2891   Mmaybe = msymbol ("maybe");
2892
2893   Mtype = msymbol ("type");
2894   Mcharsets = msymbol_as_managing_key ("charsets");
2895   Mflags = msymbol_as_managing_key ("flags");
2896   Mdesignation = msymbol_as_managing_key ("designation");
2897   Minvocation = msymbol_as_managing_key ("invocation");
2898   Mcode_unit = msymbol ("code-unit");
2899   Mbom = msymbol ("bom");
2900   Mlittle_endian = msymbol ("little-endian");
2901
2902   param = mplist ();
2903   charsets = mplist ();
2904   pl = param;
2905   /* Setup predefined codings.  */
2906   mplist_set (charsets, Msymbol, Mcharset_ascii);
2907   pl = mplist_add (pl, Mtype, Mcharset);
2908   pl = mplist_add (pl, Mcharsets, charsets);
2909   Mcoding_us_ascii = mconv_define_coding ("us-ascii", param,
2910                                           NULL, NULL, NULL, NULL);
2911
2912   {
2913     MSymbol alias = msymbol ("ANSI_X3.4-1968");
2914     MCodingSystem *coding
2915       = (MCodingSystem *) msymbol_get (Mcoding_us_ascii, Mcoding);
2916
2917     msymbol_put (alias, Mcoding, coding);
2918     alias = msymbol__canonicalize (alias);
2919     msymbol_put (alias, Mcoding, coding);
2920   }
2921
2922   mplist_set (charsets, Msymbol, Mcharset_iso_8859_1);
2923   Mcoding_iso_8859_1 = mconv_define_coding ("iso-8859-1", param,
2924                                             NULL, NULL, NULL, NULL);
2925
2926   mplist_set (charsets, Msymbol, Mcharset_m17n);
2927   mplist_put (param, Mtype, Mutf);
2928   mplist_put (param, Mcode_unit, (void *) 8);
2929   Mcoding_utf_8_full = mconv_define_coding ("utf-8-full", param,
2930                                             NULL, NULL, NULL, NULL);
2931
2932   mplist_set (charsets, Msymbol, Mcharset_unicode);
2933   Mcoding_utf_8 = mconv_define_coding ("utf-8", param,
2934                                        NULL, NULL, NULL, NULL);
2935
2936   mplist_put (param, Mcode_unit, (void *) 16);
2937   mplist_put (param, Mbom, Mmaybe);
2938 #ifndef WORDS_BIGENDIAN
2939   mplist_put (param, Mlittle_endian, Mt);
2940 #endif
2941   Mcoding_utf_16 = mconv_define_coding ("utf-16", param,
2942                                         NULL, NULL, NULL, NULL);
2943
2944   mplist_put (param, Mcode_unit, (void *) 32);
2945   Mcoding_utf_32 = mconv_define_coding ("utf-32", param,
2946                                         NULL, NULL, NULL, NULL);
2947
2948   mplist_put (param, Mcode_unit, (void *) 16);
2949   mplist_put (param, Mbom, Mnil);
2950   mplist_put (param, Mlittle_endian, Mnil);
2951   Mcoding_utf_16be = mconv_define_coding ("utf-16be", param,
2952                                           NULL, NULL, NULL, NULL);
2953
2954   mplist_put (param, Mcode_unit, (void *) 32);
2955   Mcoding_utf_32be = mconv_define_coding ("utf-32be", param,
2956                                           NULL, NULL, NULL, NULL);
2957
2958   mplist_put (param, Mcode_unit, (void *) 16);
2959   mplist_put (param, Mlittle_endian, Mt);
2960   Mcoding_utf_16le = mconv_define_coding ("utf-16le", param,
2961                                           NULL, NULL, NULL, NULL);
2962
2963   mplist_put (param, Mcode_unit, (void *) 32);
2964   Mcoding_utf_32le = mconv_define_coding ("utf-32le", param,
2965                                           NULL, NULL, NULL, NULL);
2966
2967   mplist_put (param, Mtype, Mnil);
2968   mplist_set (charsets, Msymbol, Mcharset_ascii);
2969   Mcoding_sjis = mconv_define_coding ("sjis", param,
2970                                       reset_coding_sjis,
2971                                       decode_coding_sjis,
2972                                       encode_coding_sjis, NULL);
2973
2974   M17N_OBJECT_UNREF (charsets);
2975   M17N_OBJECT_UNREF (param);
2976
2977   return 0;
2978 }
2979
2980 void
2981 mcoding__fini (void)
2982 {
2983   int i;
2984   MPlist *plist;
2985
2986   for (i = 0; i < coding_list.used; i++)
2987     {
2988       MCodingSystem *coding = coding_list.codings[i];
2989
2990       if (coding->extra_info)
2991         free (coding->extra_info);
2992       if (coding->extra_spec)
2993         free (coding->extra_spec);
2994       free (coding);
2995     }
2996   MLIST_FREE1 (&coding_list, codings);
2997   MPLIST_DO (plist, coding_definition_list)
2998     M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2999   M17N_OBJECT_UNREF (coding_definition_list);
3000 }
3001
3002 void
3003 mconv__define_coding_from_charset (MSymbol sym)
3004 {
3005   MPlist *param = mplist (), *charsets = mplist ();
3006
3007   mplist_set (charsets, Msymbol, sym);
3008   mplist_add (param, Mtype, Mcharset);
3009   mplist_add (param, Mcharsets, charsets);
3010   mconv_define_coding (msymbol_name (sym), param, NULL, NULL, NULL, NULL);
3011   M17N_OBJECT_UNREF (charsets);
3012   M17N_OBJECT_UNREF (param);
3013 }
3014
3015 void
3016 mconv__register_charset_coding (MSymbol sym)
3017 {
3018   if (! mplist_find_by_key (coding_definition_list, sym))
3019     {
3020       MPlist *param = mplist (), *charsets = mplist ();
3021
3022       mplist_set (charsets, Msymbol, sym);
3023       mplist_add (param, Msymbol, Mtype);
3024       mplist_add (param, Msymbol, Mcharset);
3025       mplist_add (param, Msymbol, Mcharsets);
3026       mplist_add (param, Mplist, charsets);
3027       mplist_put (coding_definition_list, sym, param);
3028       M17N_OBJECT_UNREF (charsets);
3029     }
3030 }
3031
3032
3033 int
3034 mcoding__load_from_database ()
3035 {
3036   MDatabase *mdb = mdatabase_find (msymbol ("coding-list"), Mnil, Mnil, Mnil);
3037   MPlist *def_list, *plist;
3038   MPlist *definitions = coding_definition_list;
3039   int mdebug_mask = MDEBUG_CODING;
3040
3041   if (! mdb)
3042     return 0;
3043   MDEBUG_PUSH_TIME ();
3044   def_list = (MPlist *) mdatabase_load (mdb);
3045   MDEBUG_PRINT_TIME ("CODING", (stderr, " to load the data."));
3046   MDEBUG_POP_TIME ();
3047   if (! def_list)
3048     return -1;
3049
3050   MDEBUG_PUSH_TIME ();
3051   MPLIST_DO (plist, def_list)
3052     {
3053       MPlist *pl;
3054       MSymbol name;
3055
3056       if (! MPLIST_PLIST_P (plist))
3057         MERROR (MERROR_CHARSET, -1);
3058       pl = MPLIST_PLIST (plist);
3059       if (! MPLIST_SYMBOL_P (pl))
3060         MERROR (MERROR_CHARSET, -1);
3061       name = MPLIST_SYMBOL (pl);
3062       pl = MPLIST_NEXT (pl);
3063       definitions = mplist_add (definitions, name, pl);
3064       M17N_OBJECT_REF (pl);
3065     }
3066
3067   M17N_OBJECT_UNREF (def_list);
3068   MDEBUG_PRINT_TIME ("CODING", (stderr, " to parse the loaded data."));
3069   MDEBUG_POP_TIME ();
3070   return 0;
3071 }
3072
3073 /*** @} */
3074 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
3075 \f
3076 /* External API */
3077
3078 /*** @addtogroup m17nConv */
3079 /*** @{ */
3080 /*=*/
3081
3082 /***en @name Variables: Symbols representing a coding system */
3083 /***ja @name ÊÑ¿ô: ÄêµÁºÑ¤ß¥³¡¼¥É·Ï¤ò»ØÄꤹ¤ë¤¿¤á¤Î¥·¥ó¥Ü¥ë */
3084 /*** @{ */
3085 /*=*/
3086
3087 /***en
3088     @brief Symbol for the coding system US-ASCII
3089
3090     The symbol #Mcoding_us_ascii has name <tt>"us-ascii"</tt> and
3091     represents a coding system for the CES US-ASCII.  */
3092
3093 /***ja
3094     @brief MIME charset "US-ASCII" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë
3095
3096     ¥·¥ó¥Ü¥ë @c Mcoding_us_ascii ¤Ï <tt>"us-ascii"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Á¡¢
3097     MIME charset <tt>"US-ASCII"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»ØÄꤹ¤ë¤¿¤á
3098     ¤Ë»È¤ï¤ì¤ë¡£
3099      */
3100 MSymbol Mcoding_us_ascii;
3101 /*=*/
3102
3103 /***en
3104     @brief Symbol for the coding system ISO-8859-1
3105
3106     The symbol #Mcoding_iso_8859_1 has name <tt>"iso-8859-1"</tt> and
3107     represents a coding system for the CES ISO-8859-1.  */
3108
3109 /***ja
3110     @brief MIME charset "ISO-8859-1" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë
3111
3112     ¥·¥ó¥Ü¥ë @c Mcoding_iso_8859_1 ¤Ï <tt>"iso-8859-1"</tt> ¤È¤¤¤¦Ì¾Á°
3113     ¤ò»ý¤Á¡¢MIME charset <tt>"ISO-8859-1"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»Ø
3114     Äꤹ¤ë¤¿¤á¤Ë»È¤ï¤ì¤ë¡£ */
3115
3116 MSymbol Mcoding_iso_8859_1;
3117 /*=*/
3118
3119 /***en
3120     @brief Symbol for the coding system UTF-8
3121
3122     The symbol #Mcoding_utf_8 has name <tt>"utf-8"</tt> and represents
3123     a coding system for the CES UTF-8.  */
3124
3125 /***ja
3126     @brief RFC 2279 ¤Î "UTF-8" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë¡ÊUnicode ÍÑ¡Ë
3127
3128     ¥·¥ó¥Ü¥ë @c Mcoding_utf_8 ¤Ï <tt>"utf-8"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Á¡¢
3129     RFC 2279 ¤ÇÄêµÁ¤µ¤ì¤ë<tt>"UTF-8"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»ØÄꤹ¤ë
3130     ¤¿¤á¤Ë»È¤ï¤ì¤ë¡£¤³¤Î¥³¡¼¥É·Ï¤Ï Unicode ¤ÎÁ´¤Æ¤Îʸ»ú¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£
3131      */
3132
3133 MSymbol Mcoding_utf_8;
3134 /*=*/
3135
3136 /***en
3137     @brief UTF-8-FULL
3138
3139
3140     The symbol #Mcoding_utf_8_full has name <tt>"utf-8-full"</tt> and
3141     represents a coding system that is a extension of UTF-8.  This
3142     coding system uses the same encoding algorithm as UTF-8 but is not
3143     limited to the Unicode characters.  It can encode all characters
3144     supported by the m17n library.  */
3145
3146 /***ja
3147     @brief RFC 2279 ¤Î "UTF-8" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë¡ÊÁ´Ê¸»úÍÑ¡Ë
3148
3149     ¥·¥ó¥Ü¥ë @c Mcoding_utf_8_full ¤Ï <tt>"utf-8-full"</tt> ¤È¤¤¤¦Ì¾Á°
3150     ¤ò»ý¤Á¡¢RFC 2279 ¤ÇÄêµÁ¤µ¤ì¤ë<tt>"UTF-8"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò
3151     »ØÄꤹ¤ë¤¿¤á¤Ë»È¤ï¤ì¤ë¡£¤³¤Î¥³¡¼¥É·Ï¤Ï m17n ¥é¥¤¥Ö¥é¥ê¤¬°·¤¦Á´¤Æ¤Î
3152     Ê¸»ú¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£  */
3153
3154 MSymbol Mcoding_utf_8_full;
3155 /*=*/
3156
3157 /***en
3158     @brief UTF-16
3159
3160     The symbol #Mcoding_utf_16 has name <tt>"utf-16"</tt> and
3161     represents a coding system for the CES UTF-16 (RFC 2279).  */
3162 /***ja
3163     @brief RFC 2781 ¤Î "UTF-16" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë
3164
3165     ¥·¥ó¥Ü¥ë @c Mcoding_utf_16 ¤Ï <tt>"utf-16"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Á¡¢
3166     RFC 2279 ¤ÇÄêµÁ¤µ¤ì¤ë<tt>"UTF-16"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»ØÄꤹ
3167     ¤ë¤¿¤á¤Ë»È¤ï¤ì¤ë¡£¤³¤Î¥³¡¼¥É·Ï¤Ï Unicode ¤ÎÁ´¤Æ¤Îʸ»ú¤ò¥µ¥Ý¡¼¥È¤¹
3168     ¤ë¡£ */
3169
3170 MSymbol Mcoding_utf_16;
3171 /*=*/
3172
3173 /***en
3174     @brief UTF-16BE
3175
3176     The symbol #Mcoding_utf_16be has name <tt>"utf-16be"</tt> and
3177     represents a coding system for the CES UTF-16BE (RFC 2279).  */
3178
3179 MSymbol Mcoding_utf_16be;
3180 /*=*/
3181
3182 /***en
3183     @brief UTF-16LE
3184
3185     The symbol #Mcoding_utf_16le has name <tt>"utf-16le"</tt> and
3186     represents a coding system for the CES UTF-16LE (RFC 2279).  */
3187
3188 MSymbol Mcoding_utf_16le;
3189 /*=*/
3190
3191 /***en
3192     @brief UTF-32
3193
3194     The symbol #Mcoding_utf_32 has name <tt>"utf-32"</tt> and
3195     represents a coding system for the CES UTF-32 (RFC 2279).  */
3196
3197 MSymbol Mcoding_utf_32;
3198 /*=*/
3199
3200 /***en
3201     @brief UTF-32be
3202
3203     The symbol #Mcoding_utf_32be has name <tt>"utf-32be"</tt> and
3204     represents a coding system for the CES UTF-32BE (RFC 2279).  */
3205
3206 MSymbol Mcoding_utf_32be;
3207 /*=*/
3208
3209 /***en
3210     @brief UTF-32LE
3211
3212     The symbol #Mcoding_utf_32le has name <tt>"utf-32le"</tt> and
3213     represents a coding system for the CES UTF-32LE (RFC 2279).  */
3214 MSymbol Mcoding_utf_32le;
3215 /*=*/
3216
3217 /***en
3218     @brief SJIS
3219
3220     The symbol #Mcoding_sjis has name <tt>"sjis"</tt> and represents a coding
3221     system for the CES Shift-JIS.  */ 
3222
3223 MSymbol Mcoding_sjis;
3224 /*** @} */ 
3225 /*=*/
3226
3227 /***en
3228     @name Variables: Parameter keys for mconv_define_coding ().  */
3229 /*** @{ */
3230 /*=*/
3231
3232 /***en
3233     Parameter key for mconv_define_coding () (which see). */ 
3234 MSymbol Mtype;
3235 /*=*/
3236
3237 MSymbol Mcharsets;
3238 MSymbol Mflags;
3239 MSymbol Mdesignation;
3240 MSymbol Minvocation;
3241 MSymbol Mcode_unit;
3242 MSymbol Mbom;
3243 MSymbol Mlittle_endian;
3244 /*** @} */
3245 /*=*/
3246
3247 /***en
3248     @name Variables: Symbols representing coding system type.  */
3249 /*** @{ */
3250 /*=*/
3251
3252 /***en
3253     Symbol that can be a value of the #Mtype parameter of a coding
3254     system used in an argument to the mconv_define_coding () function
3255     (which see).  */
3256  
3257 MSymbol Mutf;
3258 /*=*/
3259 MSymbol Miso_2022;
3260 /*=*/
3261 /*** @} */
3262 /*=*/
3263
3264 /***en
3265     @name Variables: Symbols appearing in the value of #Mfrag parameter.  */
3266 /*** @{ */
3267 /*=*/
3268
3269 /***en
3270     Symbol that can be a value of the #Mflags parameter of a coding
3271     system used in an argument to the mconv_define_coding () function
3272     (which see).  */
3273 MSymbol Mreset_at_eol;
3274 /*=*/
3275 MSymbol Mreset_at_cntl;
3276 MSymbol Meight_bit;
3277 MSymbol Mlong_form;
3278 MSymbol Mdesignation_g0;
3279 MSymbol Mdesignation_g1;
3280 MSymbol Mdesignation_ctext;
3281 MSymbol Mdesignation_ctext_ext;
3282 MSymbol Mlocking_shift;
3283 MSymbol Msingle_shift;
3284 MSymbol Msingle_shift_7;
3285 MSymbol Meuc_tw_shift;
3286 MSymbol Miso_6429;
3287 MSymbol Mrevision_number;
3288 MSymbol Mfull_support;
3289 /*** @} */
3290 /*=*/
3291
3292 /***en
3293     @name Variables: etc
3294
3295     Remaining variables.  */
3296 /***ja @name ÊÑ¿ô: ¤½¤Î¾ */
3297 /*** @{ */
3298 /*=*/
3299 /***en
3300     @brief Symbol whose name is "maybe".
3301
3302     The variable #Mmaybe is a symbol of name <tt>"maybe"</tt>.  It is
3303     used a value of #Mbom parameter of the function
3304     mconv_define_coding () (which see).  */
3305
3306 MSymbol Mmaybe;
3307 /*=*/
3308
3309 /***en
3310     @brief The symbol @c Mcoding
3311
3312     Any decoded M-text has a text property whose key is the predefined
3313     symbol @c Mcoding.  The name of @c Mcoding is
3314     <tt>"coding"</tt>.  */
3315
3316 /***ja
3317     @brief ¥·¥ó¥Ü¥ë @c Mcoding
3318
3319     ¥Ç¥³¡¼¥É¤µ¤ì¤¿ M-text ¤Ï¡¢¥­¡¼¤¬ @c Mcoding ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×
3320     ¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£¥·¥ó¥Ü¥ë @c Mcoding ¤Ï <tt>"coding"</tt> ¤È¤¤¤¦Ì¾
3321     Á°¤Ç¤¢¤é¤«¤¸¤áÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£  */
3322
3323 MSymbol Mcoding;
3324 /*=*/
3325 /*** @} */ 
3326 /*=*/
3327
3328 /***en
3329     @brief Define a coding system
3330
3331     The mconv_define_coding () function defines a new coding system
3332     and makes it accessive via a symbol whose name is $NAME.  $PLIST
3333     specifies parameters of the charset as below:
3334
3335     <ul>
3336
3337     <li> Key is @c Mtype, value is a symbol
3338
3339     The value specifies the type of the coding system.  It must be
3340     #Mcharset, #Mutf, #Miso_2022, or #Mnil.
3341
3342     If the type is #Mcharset, $EXTRA_INFO is ignored.
3343
3344     If the type is #Miso_2022, $EXTRA_INFO must be a pointer to
3345     #MCodingInfoISO2022.
3346
3347     If the type is #Mutf, $EXTRA_INFO must be a pointer to
3348     #MCodingInfoUTF.
3349
3350     If the type is #Mnil, the argument $RESETTER, $DECODER, and
3351     $ENCODER must be supplied.  $EXTRA_INFO is ignored.  Otherwise,
3352     they can be @c NULL and the m17n library provides proper defaults.
3353
3354     <li> Key is #Mcharsets, value is a plist
3355
3356     The value specifies a list charsets supported by the coding
3357     system.  The keys of the plist must be #Msymbol, and the values
3358     must be symbols representing charsets.
3359
3360     <li> Key is #Mflags, value is a plist
3361
3362     If the type is #Miso_2022, the values specifies flags to control
3363     the ISO 2022 interpreter.  The keys of the plist must e @c
3364     Msymbol, and values must be one of the following.
3365
3366     <ul>
3367
3368     <li> #Mreset_at_eol
3369
3370     If this flag exits, designation and invocation status is reset to
3371     the initial state at the end of line.
3372
3373     <li> #Mreset_at_cntl
3374
3375     If this flag exists, designation and invocation status is reset to
3376     the initial state at a control character.
3377
3378     <li> #Meight_bit
3379
3380     If this flag exists, the graphic plane right is used.
3381
3382     <li> #Mlong_form
3383
3384     If this flag exists, the over-long escape sequences (ESC '$' '('
3385     <final_byte>) are used for designating the charsets JISX0208.1978,
3386     GB2312, and JISX0208.
3387
3388     <li> #Mdesignation_g0
3389
3390     If this flag and #Mfull_support exists, designates charsets not
3391     listed in the charset list to the graphic register G0.
3392
3393     <li> #Mdesignation_g1
3394
3395     If this flag and #Mfull_support exists, designates charsets not
3396     listed in the charset list to the graphic register G1.
3397
3398     <li> #Mdesignation_ctext
3399
3400     If this flag and #Mfull_support exists, designates charsets not
3401     listed in the charset list to a graphic register G0 or G1 based on
3402     the criteria of the Compound Text.
3403
3404     <li> #Mdesignation_ctext_ext
3405
3406     If this flag and #Mfull_support exists, designates charsets not
3407     listed in the charset list to a graphic register G0 or G1, or use
3408     extended segment for such charsets based on the criteria of the
3409     Compound Text.
3410
3411     <li> #Mlocking_shift
3412
3413     If this flag exists, use locking shift.
3414
3415     <li> #Msingle_shift
3416
3417     If this flag exists, use single shift.
3418
3419     <li> #Msingle_shift_7
3420
3421     If this flag exists, use 7-bit single shift code (0x19).
3422
3423     <li> #Meuc_tw_shift;
3424
3425     If this flag exists, use a special shifting according to EUC-TW.
3426
3427     <li> #Miso_6429
3428
3429     This flag is currently ignored.
3430
3431     <li> #Mrevision_number
3432
3433     If this flag exists, use a revision number escape sequence to
3434     designate a charset that has a revision number.
3435
3436     <li> #Mfull_support
3437
3438     If this flag exists, support all charsets registered in the
3439     International Registry.
3440
3441     </ul>
3442
3443     <li> Key is #Mdesignation, value is a plist
3444
3445     If the type is #Miso_2022, the value specifies how to designate
3446     each supported characters.  The keys of the plist must be @c
3447     Minteger, and the values must be numbers indicating a graphic
3448     registers.  The Nth element value is for the Nth charset of the
3449     charset list.  The value 0..3 means that it is assumed that a
3450     charset is already designated to the graphic register 0..3.  The
3451     negative value G (-4..-1) means that a charset is not designated
3452     to any register at first, and if necessary, is designated to the
3453     (G+4) graphic register.
3454
3455     <li> Key is #Minvocation, value is a plist
3456
3457     If the type is #Miso_2022, the value specifies how to invocate
3458     each graphic registers.  The plist length must be one or two.  The
3459     keys of the plist must be #Minteger, and the values must be
3460     numbers indicating a graphic register.  The value of the first
3461     element specifies which graphic register is invocated to the
3462     graphic plane left.  If the length is one, no graphic register is
3463     invocated to the graphic plane right.  Otherwise, the value of the
3464     second element specifies which graphic register is invocated to
3465     the graphic plane right.
3466
3467     <li> Key is #Mcode_unit, value is an integer
3468
3469     If the type is #Mutf, the value specifies the bit length of a
3470     code-unit.  It must be 8, 16, or 32.
3471
3472     <li> Key is #Mbom, value is a symbol
3473
3474     If the type is #Mutf and the code-unit bit length is 16 or 32,
3475     it specifies whether or not to use BOM (Byte Order Mark).  If the
3476     value is #Mnil (default), BOM is not used, else if the value is
3477     #Mmaybe, the existence of BOM is detected at decoding time, else
3478     BOM is used.
3479
3480     <li> Key is #Mlittle_endian, value is a symbol
3481
3482     If the type is #Mutf and the code-unit bit length is 16 or 32,
3483     it specifies whether or not the encoding is little endian.  If the
3484     value is #Mnil (default), it is big endian, else it is little
3485     endian.
3486
3487     </ul>
3488
3489     $RESETTER is a pointer to a function that resets a converter for
3490     the coding system to the initial status.  The pointed function is
3491     called with one argument, a pointer to a converter object.
3492
3493     $DECODER is a pointer to a function that decodes a byte sequence
3494     according to the coding system.  The pointed function is called
3495     with four arguments:
3496
3497         @li A pointer to the byte sequence to decode.
3498         @li The number of bytes to decode.
3499         @li A pointer to an M-text to which the decoded characters are appended.
3500         @li A pointer to a converter object.
3501
3502     $DECODER must return 0 if it succeeds.  Otherwise it must return -1.
3503
3504     $ENCODER is a pointer to a function that encodes an M-text
3505     according to the coding system.  The pointed function is called
3506     with six arguments:
3507
3508         @li A pointer to the M-text to encode.
3509         @li The starting position of the encoding.
3510         @li The ending position of the encoding.
3511         @li A pointer to a memory area where the produced bytes are stored.
3512         @li The size of the memory area.
3513         @li A pointer to a converter object.
3514
3515     $ENCODER must return 0 if it succeeds.  Otherwise it must return -1.
3516
3517     $EXTRA_INFO is a pointer to a data structure that contains extra
3518     information about the coding system.  The type of the data
3519     structure depends on $TYPE.
3520
3521     @return  
3522
3523     If the operation was successful, mconv_define_coding () returns a
3524     symbol whose name is $NAME.  If an error is detected, it returns
3525     #Mnil and assigns an error code to the external variable @c
3526     merror_code.  */
3527
3528 /***ja
3529     @brief ¥³¡¼¥É·Ï¤ÎÄêµÁ
3530
3531     ´Ø¿ô mconv_define_coding () ¤Ï¡¢¿·¤·¤¤¥³¡¼¥É·Ï¤òÄêµÁ¤·¡¢¤½¤ì¤ò 
3532     $NAME ¤È¤¤¤¦Ì¾Á°¤Î¥·¥ó¥Ü¥ë·Ðͳ¤Ç¥¢¥¯¥»¥¹¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¡£
3533
3534     $TYPE ¤Ï Îóµó·¿ #MCodingType ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ê¡¢¥³¡¼¥É·Ï¤Î¹½Â¤¤ò
3535     »ØÄꤹ¤ë¡£
3536
3537     $CHARSET_NAMES ¤Ï¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¥»¥Ã¥È¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤ÎÇÛÎó¤Ç¤¢¤ê¡¢
3538     $NCHARSETS ¤Ï¤½¤ÎÍ×ÁÇ¿ô¤Ç¤¢¤ë¡£
3539
3540     $TYPE ¤¬ #MCODING_TYPE_MISC ¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$RESETTER, $DECODER,
3541     $ENCODER ¤òÍ¿¤¨¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤ì°Ê³°¤Î¾ì¹ç¤Ë¤Ï¤³¤ì¤é¤Ï @c
3542     NULL ¤Ç¹½¤ï¤Ê¤¤¡£¤½¤ÎºÝ¤Ë¤Ï m17n ¥é¥¤¥Ö¥é¥ê¤¬Å¬Àڤʥǥե©¥ë¥ÈÃͤò
3543     Í¿¤¨¤ë¡£
3544
3545     $RESETTER ¤Ï¤³¤Î¥³¡¼¥É·ÏÍѤΥ³¥ó¥Ð¡¼¥¿¤ò½é´ü¾õÂ֤˥ꥻ¥Ã¥È¤¹¤ë´Ø¿ô
3546     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï¥³¥ó¥Ð¡¼¥¿¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤È
3547     ¤¤¤¦£±°ú¿ô¤ò¤È¤ë¡£
3548
3549     $DECODER ¤Ï¥Ð¥¤¥ÈÎó¤ò¤³¤Î¥³¡¼¥É·Ï¤Ë½¾¤Ã¤Æ¥Ç¥³¡¼¥É¤¹¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤
3550     ¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï°Ê²¼¤Î4°ú¿ô¤ò¤È¤ë¡£
3551
3552         @li ¥Ð¥¤¥ÈÎó¤Ø¤Î¥Ý¥¤¥ó¥¿
3553         @li ¥Ç¥³¡¼¥É¤¹¤Ù¤­¥Ð¥¤¥È¿ô
3554         @li ¥Ç¥³¡¼¥É·ë²Ì¤Îʸ»ú¤òÉղ乤ë M-text ¤Ø¤Î¥Ý¥¤¥ó¥¿
3555         @li ¥³¥ó¥Ð¡¼¥¿¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿
3556
3557     $DECODER ¤ÏÀ®¸ù¤·¤¿¤È¤­¤Ë¤Ï0¤ò¡¢¼ºÇÔ¤·¤¿¤È¤­¤Ë¤Ï-1¤òÊÖ¤µ¤Ê¤¯¤Æ¤Ï¤Ê
3558     ¤é¤Ê¤¤¡£
3559
3560     $ENCODER ¤Ï M-text ¤ò¤³¤Î¥³¡¼¥É·Ï¤Ë½¾¤Ã¤Æ¥¨¥ó¥³¡¼¥É¤¹
3561     ¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï°Ê²¼¤Î6°ú¿ô¤ò¤È¤ë¡£
3562
3563         @li M-text ¤Ø¤Î¥Ý¥¤¥ó¥¿
3564         @li M-text ¤Î¥¨¥ó¥³¡¼¥É³«»Ï°ÌÃÖ
3565         @li M-text ¤Î¥¨¥ó¥³¡¼¥É½ªÎ»°ÌÃÖ
3566         @li À¸À®¤·¤¿¥Ð¥¤¥È¤òÊÝ»ý¤¹¤ë¥á¥â¥êÎΰè¤Ø¤Î¥Ý¥¤¥ó¥¿
3567         @li ¥á¥â¥êÎΰè¤Î¥µ¥¤¥º
3568         @li ¥³¥ó¥Ð¡¼¥¿¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿
3569
3570     $ENCODER ¤ÏÀ®¸ù¤·¤¿¤È¤­¤Ë¤Ï0¤ò¡¢¼ºÇÔ¤·¤¿¤È¤­¤Ë¤Ï-1¤òÊÖ¤µ¤Ê¤¯¤Æ¤Ï¤Ê
3571     ¤é¤Ê¤¤¡£
3572
3573     $EXTRA_INFO ¤Ï¥³¡¼¥Ç¥£¥°¥·¥¹¥Æ¥à¤Ë´Ø¤¹¤ëÄɲþðÊó¤ò´Þ¤à¥Ç¡¼¥¿¹½Â¤¤Ø
3574     ¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î¥Ç¡¼¥¿¹½Â¤¤Î¥¿¥¤¥×¤Ï $TYPE ¤Ë°Í¸¤¹¤ë¡£
3575
3576     $TYPE ¤¬ #MCODING_TYPE_ISO_2022 ¤Ç¤¢¤ì¤Ð¡¢$EXTRA_INFO ¤Ï @c
3577     MCodingInfoISO2022 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3578
3579     $TYPE ¤¬ #MCODING_TYPE_UTF ¤Ç¤¢¤ì¤Ð¡¢$EXTRA_INFO ¤Ï @c
3580     MCodingInfoUTF ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3581
3582     $TYPE ¤¬ #MCODING_TYPE_CHARSET, #MCODING_TYPE_MISC ¤Î¤É¤ì¤«¤Ç
3583     ¤¢¤ì¤Ð¡¢$EXTRA_INFO ¤Ï̵»ë¤µ¤ì¤ë¡£
3584
3585     @return  
3586
3587     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mconv_define_coding () ¤Ï $NAME ¤È¤¤¤¦Ì¾Á°¤Î¥·
3588     ¥ó¥Ü¥ë¤òÊÖ¤¹¡£¤³¤Î¥·¥ó¥Ü¥ë¤Ï¡¢¥­¡¼¤¬ $Mcoding ¤Ç¡¢ºî¤é¤ì¤¿¥³¡¼¥É·Ï
3589     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£ ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì
3590     ¤¿¾ì¹ç¤Ï Mnil ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3591       */
3592
3593 /***
3594     @errors
3595     @c MERROR_CODING  */
3596
3597 MSymbol
3598 mconv_define_coding (char *name, MPlist *plist,
3599                      int (*resetter) (MConverter *),
3600                      int (*decoder) (unsigned char *, int, MText *,
3601                                      MConverter *),
3602                      int (*encoder) (MText *, int, int,
3603                                      unsigned char *, int,
3604                                      MConverter *),
3605                      void *extra_info)
3606 {
3607   MSymbol sym = msymbol (name);
3608   int i;
3609   MCodingSystem *coding;
3610   MPlist *pl;
3611
3612   MSTRUCT_MALLOC (coding, MERROR_CODING);
3613   coding->name = sym;
3614   if ((coding->type = (MSymbol) mplist_get (plist, Mtype)) == Mnil)
3615     coding->type = Mcharset;
3616   pl = (MPlist *) mplist_get (plist, Mcharsets);
3617   if (! pl)
3618     MERROR (MERROR_CODING, Mnil);
3619   coding->ncharsets = mplist_length (pl);
3620   if (coding->ncharsets > NUM_SUPPORTED_CHARSETS)
3621     coding->ncharsets = NUM_SUPPORTED_CHARSETS;
3622   for (i = 0; i < coding->ncharsets; i++, pl = MPLIST_NEXT (pl))
3623     {
3624       MSymbol charset_name;
3625
3626       if (MPLIST_KEY (pl) != Msymbol)
3627         MERROR (MERROR_CODING, Mnil);
3628       charset_name = MPLIST_SYMBOL (pl);
3629       if (! (coding->charsets[i] = MCHARSET (charset_name)))
3630         MERROR (MERROR_CODING, Mnil);
3631     }
3632
3633   coding->resetter = resetter;
3634   coding->decoder = decoder;
3635   coding->encoder = encoder;
3636   coding->ascii_compatible = 0;
3637   coding->extra_info = extra_info;
3638   coding->extra_spec = NULL;
3639   coding->ready = 0;
3640
3641   if (coding->type == Mcharset)
3642     {
3643       if (! coding->resetter)
3644         coding->resetter = reset_coding_charset;
3645       if (! coding->decoder)
3646         coding->decoder = decode_coding_charset;
3647       if (! coding->encoder)
3648         coding->encoder = encode_coding_charset;
3649     }
3650   else if (coding->type == Mutf)
3651     {
3652       MCodingInfoUTF *info = malloc (sizeof (MCodingInfoUTF));
3653       MSymbol val;
3654
3655       if (! coding->resetter)
3656         coding->resetter = reset_coding_utf;
3657
3658       info->code_unit_bits = (int) mplist_get (plist, Mcode_unit);
3659       if (info->code_unit_bits == 8)
3660         {
3661           if (! coding->decoder)
3662             coding->decoder = decode_coding_utf_8;
3663           if (! coding->encoder)
3664             coding->encoder = encode_coding_utf_8;
3665         }
3666       else if (info->code_unit_bits == 16)
3667         {
3668           if (! coding->decoder)
3669             coding->decoder = decode_coding_utf_16;
3670           if (! coding->encoder)
3671             coding->encoder = encode_coding_utf_16;
3672         }
3673       else if (info->code_unit_bits == 32)
3674         {
3675           if (! coding->decoder)
3676             coding->decoder = decode_coding_utf_32;
3677           if (! coding->encoder)
3678             coding->encoder = encode_coding_utf_32;
3679         }
3680       else
3681         MERROR (MERROR_CODING, Mnil);
3682       val = (MSymbol) mplist_get (plist, Mbom);
3683       if (val == Mnil)
3684         info->bom = 1;
3685       else if (val == Mmaybe)
3686         info->bom = 0;
3687       else
3688         info->bom = 2;
3689
3690       info->endian = (mplist_get (plist, Mlittle_endian) ? 1 : 0);
3691       coding->extra_info = info;
3692     }
3693   else if (coding->type == Miso_2022)
3694     {
3695       MCodingInfoISO2022 *info = malloc (sizeof (MCodingInfoISO2022));
3696
3697       if (! coding->resetter)
3698         coding->resetter = reset_coding_iso_2022;
3699       if (! coding->decoder)
3700         coding->decoder = decode_coding_iso_2022;
3701       if (! coding->encoder)
3702         coding->encoder = encode_coding_iso_2022;
3703
3704       info->initial_invocation[0] = 0;
3705       info->initial_invocation[1] = -1;
3706       pl = (MPlist *) mplist_get (plist, Minvocation);
3707       if (pl)
3708         {
3709           if (MPLIST_KEY (pl) != Minteger)
3710             MERROR (MERROR_CODING, Mnil);
3711           info->initial_invocation[0] = MPLIST_INTEGER (pl);
3712           if (! MPLIST_TAIL_P (pl))
3713             {
3714               pl = MPLIST_NEXT (pl);
3715               if (MPLIST_KEY (pl) != Minteger)
3716                 MERROR (MERROR_CODING, Mnil);
3717               info->initial_invocation[1] = MPLIST_INTEGER (pl);
3718             }
3719         }
3720       memset (info->designations, 0, sizeof (info->designations));
3721       for (i = 0, pl = (MPlist *) mplist_get (plist, Mdesignation);
3722            i < 32 && pl && MPLIST_KEY (pl) == Minteger;
3723            i++, pl = MPLIST_NEXT (pl))
3724         info->designations[i] = MPLIST_INTEGER (pl);
3725
3726       info->flags = 0;
3727       MPLIST_DO (pl, (MPlist *) mplist_get (plist, Mflags))
3728         {
3729           MSymbol val;
3730
3731           if (MPLIST_KEY (pl) != Msymbol)
3732             MERROR (MERROR_CODING, Mnil);
3733           val = MPLIST_SYMBOL (pl);
3734           if (val == Mreset_at_eol)
3735             info->flags |= MCODING_ISO_RESET_AT_EOL;
3736           else if (val == Mreset_at_cntl)
3737             info->flags |= MCODING_ISO_RESET_AT_CNTL;
3738           else if (val == Meight_bit)
3739             info->flags |= MCODING_ISO_EIGHT_BIT;
3740           else if (val == Mlong_form)
3741             info->flags |= MCODING_ISO_LOCKING_SHIFT;
3742           else if (val == Mdesignation_g0)
3743             info->flags |= MCODING_ISO_DESIGNATION_G0;
3744           else if (val == Mdesignation_g1)
3745             info->flags |= MCODING_ISO_DESIGNATION_G1;
3746           else if (val == Mdesignation_ctext)
3747             info->flags |= MCODING_ISO_DESIGNATION_CTEXT;
3748           else if (val == Mdesignation_ctext_ext)
3749             info->flags |= MCODING_ISO_DESIGNATION_CTEXT_EXT;
3750           else if (val == Mlocking_shift)
3751             info->flags |= MCODING_ISO_LOCKING_SHIFT;
3752           else if (val == Msingle_shift)
3753             info->flags |= MCODING_ISO_SINGLE_SHIFT;
3754           else if (val == Msingle_shift_7)
3755             info->flags |= MCODING_ISO_SINGLE_SHIFT_7;
3756           else if (val == Meuc_tw_shift)
3757             info->flags |= MCODING_ISO_EUC_TW_SHIFT;
3758           else if (val == Miso_6429)
3759             info->flags |= MCODING_ISO_ISO6429;
3760           else if (val == Mrevision_number)
3761             info->flags |= MCODING_ISO_REVISION_NUMBER;
3762           else if (val == Mfull_support)
3763             info->flags |= MCODING_ISO_FULL_SUPPORT;
3764         }
3765
3766       coding->extra_info = info;
3767     }
3768   else
3769     {
3770       if (! coding->decoder || ! coding->encoder)
3771         MERROR (MERROR_CODING, Mnil);
3772       if (! coding->resetter)
3773         coding->ready = 1;
3774     }
3775
3776   msymbol_put (sym, Mcoding, coding);
3777   msymbol_put (msymbol__canonicalize (sym), Mcoding, coding);
3778   plist = (MPlist *) mplist_get (plist, Maliases);
3779   if (plist)
3780     {
3781       MPLIST_DO (pl, plist)
3782         {
3783           MSymbol alias;
3784
3785           if (MPLIST_KEY (pl) != Msymbol)
3786             continue;
3787           alias = MPLIST_SYMBOL (pl);
3788           msymbol_put (alias, Mcoding, coding);
3789           msymbol_put (msymbol__canonicalize (alias), Mcoding, coding);
3790         }
3791     }
3792
3793   MLIST_APPEND1 (&coding_list, codings, coding, MERROR_CODING);
3794
3795   return sym;
3796 }
3797
3798 /*=*/
3799
3800 /***en
3801     @brief Resolve coding system name.
3802
3803     The mconv_resolve_coding () function returns $SYMBOL if it
3804     represents a coding system.  Otherwise, canonicalize $SYMBOL as to
3805     a coding system name, and if the canonicalized name represents a
3806     coding system, return it.  Otherwise, return Mnil.  */
3807
3808
3809 MSymbol
3810 mconv_resolve_coding (MSymbol symbol)
3811 {
3812   MCodingSystem *coding = find_coding (symbol);
3813
3814   if (! coding)
3815     {
3816       symbol = msymbol__canonicalize (symbol);
3817       coding = find_coding (symbol);
3818     }
3819   return (coding ? coding->name : Mnil);
3820 }
3821
3822 /*=*/
3823
3824
3825 /***en
3826     @brief List symbols representing a coding system.
3827
3828     The mconv_list_codings () function makes an array of symbols
3829     representing a coding system, stores the pointer to the array in a
3830     place pointed to by $SYMBOLS, and returns the length of the array.  */
3831
3832 int
3833 mconv_list_codings (MSymbol **symbols)
3834 {
3835   int i = coding_list.used + mplist_length (coding_definition_list);
3836   int j;
3837   MPlist *plist;
3838
3839   MTABLE_MALLOC ((*symbols), i, MERROR_CODING);
3840   i = 0;
3841   MPLIST_DO (plist, coding_definition_list)
3842     (*symbols)[i++] = MPLIST_KEY (plist);
3843   for (j = 0; j < coding_list.used; j++)
3844     if (! mplist_find_by_key (coding_definition_list, 
3845                               coding_list.codings[j]->name))
3846       (*symbols)[i++] = coding_list.codings[j]->name;
3847   return i;
3848 }
3849
3850 /*=*/
3851
3852 /***en
3853     @brief Create a code converter bound to a buffer.
3854
3855     The mconv_buffer_converter () function creates a pointer to a code
3856     converter for coding system $CODING.  The code converter is bound
3857     to buffer area of $N bytes pointed to by $BUF.  Subsequent
3858     decodings and encodings are done to/from this buffer area.
3859
3860     $CODING can be #Mnil.  In this case, a coding system associated
3861     with the current locale (LC_CTYPE) is used.
3862
3863     @return
3864     If the operation was successful, mconv_buffer_converter () returns
3865     the created code converter.  Otherwise it returns @c NULL and
3866     assigns an error code to the external variable #merror_code.  */
3867
3868 /***ja
3869     @brief ¥Ð¥Ã¥Õ¥¡¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤òºî¤ë
3870
3871     ´Ø¿ô mconv_buffer_converter () ¤Ï¡¢¥³¡¼¥É·Ï $CODING ÍѤΥ³¡¼¥É¥³¥ó
3872     ¥Ð¡¼¥¿¤òºî¤ë¡£¤³¤Î¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ï¡¢$BUF ¤Ç¼¨¤µ¤ì¤ëÂ礭¤µ $N ¥Ð
3873     ¥¤¥È¤Î¥Ð¥Ã¥Õ¥¡Îΰè¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤ë¡£¤³¤ì°Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó
3874     ¥¨¥ó¥³¡¼¥É¤Ï¡¢¤³¤Î¥Ð¥Ã¥Õ¥¡Îΰè¤ËÂФ·¤Æ¹Ô¤Ê¤ï¤ì¤ë¡£
3875
3876     $CODING ¤Ï #Mnil ¤Ç¤¢¤Ã¤Æ¤â¤è¤¤¡£¤³¤Î¾ì¹ç¤Ï¸½ºß¤Î¥í¥±¡¼¥ë 
3877     (LC_CTYPE) ¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥³¡¼¥É·Ï¤¬»È¤ï¤ì¤ë¡£
3878
3879     @return
3880     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð mconv_buffer_converter () ¤Ï ºî¤é¤ì¤¿¥³¡¼¥É¥³
3881     ¥ó¥Ð¡¼¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
3882     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3883
3884     @latexonly \IPAlabel{mconverter} @endlatexonly  */
3885
3886 /***
3887     @errors
3888     @c MERROR_SYMBOL, @c MERROR_CODING
3889
3890     @seealso 
3891     mconv_stream_converter ()  */
3892
3893 MConverter *
3894 mconv_buffer_converter (MSymbol name, unsigned char *buf, int n)
3895 {
3896   MCodingSystem *coding;
3897   MConverter *converter;
3898   MConverterStatus *internal;
3899
3900   if (name == Mnil)
3901     name = mlocale_get_prop (mlocale__ctype, Mcoding);
3902   coding = find_coding (name);
3903   if (! coding)
3904     MERROR (MERROR_CODING, NULL);
3905   MSTRUCT_CALLOC (converter, MERROR_CODING);
3906   MSTRUCT_CALLOC (internal, MERROR_CODING);
3907   converter->internal_info = internal;
3908   internal->coding = coding;
3909   if (coding->resetter
3910       && (*coding->resetter) (converter) < 0)
3911     {
3912       free (internal);
3913       free (converter);
3914       MERROR (MERROR_CODING, NULL);
3915     }
3916
3917   internal->unread = mtext ();
3918   internal->work_mt = mtext ();
3919   mtext__enlarge (internal->work_mt, MAX_UTF8_CHAR_BYTES);
3920   internal->buf = buf;
3921   internal->used = 0;
3922   internal->bufsize = n;
3923   internal->binding = BINDING_BUFFER;
3924
3925   return converter;
3926 }
3927
3928 /*=*/
3929
3930 /***en
3931     @brief Create a code converter bound to a stream.
3932
3933     The mconv_stream_converter () function create a pointer to a code
3934     converter for coding system $CODING.  The code converter is bound
3935     to stream $FP.  Subsequent decodings and encodings are done
3936     to/from this stream.
3937
3938     $CODING can be #Mnil.  In this case, a coding system associated
3939     with the current locale (LC_CTYPE) is used.
3940
3941     @return If the operation was successful, mconv_stream_converter ()
3942     returns the created code converter.  Otherwise it returns @c NULL
3943     and assigns an error code to the external variable @c
3944     merror_code.  */
3945
3946 /***ja
3947     @brief ¥¹¥È¥ê¡¼¥à¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤òºî¤ë
3948
3949     ´Ø¿ô mconv_stream_converter () ¤Ï¡¢¥³¡¼¥É·Ï $CODING ÍѤΥ³¡¼¥É¥³¥ó
3950     ¥Ð¡¼¥¿¤òºî¤ë¡£¤³¤Î¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ï¡¢¥¹¥È¥ê¡¼¥à $FP ¤Ë·ë¤ÓÉÕ¤±¤é
3951     ¤ì¤ë¡£¤³¤ì°Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó¥¨¥ó¥³¡¼¥É¤Ï¡¢¤³¤Î¥¹¥È¥ê¡¼¥à¤ËÂФ·¤Æ
3952     ¹Ô¤Ê¤ï¤ì¤ë¡£
3953
3954     $CODING ¤Ï #Mnil ¤Ç¤¢¤Ã¤Æ¤â¤è¤¤¡£¤³¤Î¾ì¹ç¤Ï¸½ºß¤Î¥í¥±¡¼¥ë 
3955     (LC_CTYPE) ¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥³¡¼¥É·Ï¤¬»È¤ï¤ì¤ë¡£
3956
3957     @return
3958     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_stream_converter () ¤Ïºî¤é¤ì¤¿¥³¡¼¥É¥³
3959     ¥ó¥Ð¡¼¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
3960     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3961
3962     @latexonly \IPAlabel{mconverter} @endlatexonly  */
3963
3964 /***
3965     @errors
3966     @c MERROR_SYMBOL, @c MERROR_CODING
3967
3968     @seealso
3969     mconv_buffer_converter ()  */
3970
3971 MConverter *
3972 mconv_stream_converter (MSymbol name, FILE *fp)
3973 {
3974   MCodingSystem *coding;
3975   MConverter *converter;
3976   MConverterStatus *internal;
3977
3978   if (name == Mnil)
3979     name = mlocale_get_prop (mlocale__ctype, Mcoding);
3980   coding = find_coding (name);
3981   if (! coding)
3982     MERROR (MERROR_CODING, NULL);
3983   MSTRUCT_CALLOC (converter, MERROR_CODING);
3984   MSTRUCT_CALLOC (internal, MERROR_CODING);
3985   converter->internal_info = internal;
3986   internal->coding = coding;
3987   if (coding->resetter
3988       && (*coding->resetter) (converter) < 0)
3989     {
3990       free (internal);
3991       free (converter);
3992       MERROR (MERROR_CODING, NULL);
3993     }
3994
3995   if (fseek (fp, 0, SEEK_CUR) < 0)
3996     {
3997       if (errno == EBADF)
3998         {
3999           free (internal);
4000           free (converter);
4001           return NULL;
4002         }
4003       internal->seekable = 0;
4004     }
4005   else
4006     internal->seekable = 1;
4007   internal->unread = mtext ();
4008   internal->work_mt = mtext ();
4009   mtext__enlarge (internal->work_mt, MAX_UTF8_CHAR_BYTES);
4010   internal->fp = fp;
4011   internal->binding = BINDING_STREAM;
4012
4013   return converter;
4014 }
4015
4016 /*=*/
4017
4018 /***en
4019     @brief Reset a code converter.
4020
4021     The mconv_reset_converter () function resets code converter
4022     $CONVERTER to the initial state.
4023
4024     @return
4025     If $CONVERTER->coding has its own reseter function,
4026     mconv_reset_converter () returns the result of that function
4027     applied to $CONVERTER.  Otherwise it returns 0.  */
4028
4029 /***ja
4030     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò¥ê¥»¥Ã¥È¤¹¤ë
4031
4032     ´Ø¿ô mconv_reset_converter () ¤Ï¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤ò½é´ü
4033     ¾õÂÖ¤ËÌ᤹¡£
4034
4035     @return
4036     ¤â¤· $CONVERTER->coding ¤Ë¥ê¥»¥Ã¥ÈÍѤδؿô¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤Ê¤é¤Ð¡¢
4037     mconv_reset_converter () ¤Ï¤½¤Î´Ø¿ô¤Ë $CONVERTER ¤òŬÍѤ·¤¿·ë²Ì¤ò
4038     ÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð0¤òÊÖ¤¹¡£  */
4039
4040 int
4041 mconv_reset_converter (MConverter *converter)
4042 {
4043   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4044
4045   converter->nchars = converter->nbytes = 0;
4046   converter->result = MCONVERSION_RESULT_SUCCESS;
4047   internal->carryover_bytes = 0;
4048   mtext_reset (internal->unread);
4049   if (internal->coding->resetter)
4050     return (*internal->coding->resetter) (converter);
4051   return 0;
4052 }
4053
4054 /*=*/
4055
4056 /***en
4057     @brief Free a code converter.
4058
4059     The mconv_free_converter () function frees the code converter
4060     $CONVERTER.  */
4061
4062 /***ja
4063     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò²òÊü¤¹¤ë
4064
4065     ´Ø¿ô mconv_free_converter () ¤Ï¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤ò²òÊü
4066     ¤¹¤ë¡£  */
4067
4068 void
4069 mconv_free_converter (MConverter *converter)
4070 {
4071   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4072
4073   M17N_OBJECT_UNREF (internal->work_mt);
4074   M17N_OBJECT_UNREF (internal->unread);
4075   free (internal);
4076   free (converter);
4077 }
4078
4079 /*=*/
4080
4081 /***en
4082     @brief Bind a buffer to a code converter.
4083
4084     The mconv_rebind_buffer () function binds buffer area of $N bytes
4085     pointed to by $BUF to code converter $CONVERTER.  Subsequent
4086     decodings and encodings are done to/from this newly bound buffer
4087     area.
4088
4089     @return
4090     This function always returns $CONVERTER.  */
4091
4092 /***ja
4093     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ë¥Ð¥Ã¥Õ¥¡Îΰè¤ò·ë¤ÓÉÕ¤±¤ë
4094
4095     ´Ø¿ô mconv_rebind_buffer () ¤Ï¡¢$BUF ¤Ë¤è¤Ã¤Æ»Ø¤µ¤ì¤¿Â礭¤µ $N ¥Ð
4096     ¥¤¥È¤Î¥Ð¥Ã¥Õ¥¡Îΰè¤ò¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë·ë¤ÓÉÕ¤±¤ë¡£¤³¤ì
4097     °Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó¥¨¥ó¥³¡¼¥É¤Ï¡¢¤³¤Î¿·¤¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥Ð¥Ã¥Õ¥¡
4098     Îΰè¤ËÂФ·¤Æ¹Ô¤Ê¤ï¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¡£
4099
4100     @return
4101     ¤³¤Î´Ø¿ô¤Ï¾ï¤Ë $CONVERTER ¤òÊÖ¤¹¡£
4102
4103     @latexonly \IPAlabel{mconv_rebind_buffer} @endlatexonly  */
4104
4105 /***
4106     @seealso
4107     mconv_rebind_stream () */
4108
4109 MConverter *
4110 mconv_rebind_buffer (MConverter *converter, unsigned char *buf, int n)
4111 {
4112   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4113
4114   internal->buf = buf;
4115   internal->used = 0;
4116   internal->bufsize = n;
4117   internal->binding = BINDING_BUFFER;
4118   return converter;
4119 }
4120
4121 /*=*/
4122
4123 /***en
4124     @brief Bind a stream to a code converter.
4125
4126     The mconv_rebind_stream () function binds stream $FP to code
4127     converter $CONVERTER.  Following decodings and encodings are done
4128     to/from this newly bound stream.
4129
4130     @return
4131     This function always returns $CONVERTER.  */
4132
4133 /***ja
4134     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ë¥¹¥È¥ê¡¼¥à¤ò·ë¤ÓÉÕ¤±¤ë
4135
4136     ´Ø¿ô mconv_rebind_stream () ¤Ï¡¢¥¹¥È¥ê¡¼¥à $FP ¤ò¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ 
4137     $CONVERTER ¤Ë·ë¤ÓÉÕ¤±¤ë¡£¤³¤ì°Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó¥¨¥ó¥³¡¼¥É¤Ï¡¢
4138     ¤³¤Î¿·¤¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥¹¥È¥ê¡¼¥à¤ËÂФ·¤Æ¹Ô¤Ê¤ï¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¡£
4139
4140     @return
4141     ¤³¤Î´Ø¿ô¤Ï¾ï¤Ë $CONVERTER ¤òÊÖ¤¹¡£
4142
4143     @latexonly \IPAlabel{mconv_rebind_stream} @endlatexonly  */
4144
4145 /***
4146     @seealso
4147     mconv_rebind_buffer () */
4148
4149 MConverter *
4150 mconv_rebind_stream (MConverter *converter, FILE *fp)
4151 {
4152   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4153
4154   if (fseek (fp, 0, SEEK_CUR) < 0)
4155     {
4156       if (errno == EBADF)
4157         return NULL;
4158       internal->seekable = 0;
4159     }
4160   else
4161     internal->seekable = 1;
4162   internal->fp = fp;
4163   internal->binding = BINDING_STREAM;
4164   return converter;
4165 }
4166
4167 /*=*/
4168
4169 /***en
4170     @brief Decode a byte sequence into an M-text.
4171
4172     The mconv_decode () function decodes a byte sequence and appends
4173     the result at the end of M-text $MT.  The source byte sequence is
4174     taken from currently bound the buffer area or the stream.
4175
4176     @return
4177     If the operation was successful, mconv_decode () returns updated
4178     $MT.  Otherwise it returns @c NULL and assigns an error code to
4179     the external variable #merror_code.  */
4180
4181 /***ja
4182     @brief ¥Ð¥¤¥ÈÎó¤ò M-text ¤Ë¥Ç¥³¡¼¥É¤¹¤ë
4183
4184     ´Ø¿ô mconv_decode () ¤Ï¡¢¥Ð¥¤¥ÈÎó¤ò¥Ç¥³¡¼¥É¤·¤Æ¤½¤Î·ë²Ì¤ò M-text
4185     $MT ¤ÎËöÈø¤ËÄɲ乤롣¥Ç¥³¡¼¥É¸µ¤Î¥Ð¥¤¥ÈÎó¤Ï¡¢¸½ºß·ë¤ÓÉÕ¤±¤é¤ì¤Æ¤¤¤ë
4186     ¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤«¤é¼è¤é¤ì¤ë¡£
4187
4188     @return
4189     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_decode () ¤Ï¹¹¿·¤µ¤ì¤¿ $MT ¤òÊÖ¤¹¡£¤½
4190     ¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
4191     ÀßÄꤹ¤ë¡£  */
4192
4193 /***
4194     @errors
4195     @c MERROR_IO, @c MERROR_CODING
4196
4197     @seealso
4198     mconv_rebind_buffer (), mconv_rebind_stream (),
4199     mconv_encode (), mconv_encode_range (),
4200     mconv_decode_buffer (), mconv_decode_stream ()  */
4201
4202 MText *
4203 mconv_decode (MConverter *converter, MText *mt)
4204 {
4205   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4206   int at_most = converter->at_most > 0 ? converter->at_most : -1;
4207   int n;
4208
4209   M_CHECK_READONLY (mt, NULL);
4210
4211   if (! mt->data)
4212     mtext__enlarge (mt, MAX_UTF8_CHAR_BYTES);
4213
4214   converter->nchars = converter->nbytes = 0;
4215   converter->result = MCONVERSION_RESULT_SUCCESS;
4216
4217   n = mtext_nchars (internal->unread);
4218   if (n > 0)
4219     {
4220       int limit = n;
4221       int i;
4222
4223       if (at_most > 0 && at_most < limit)
4224         limit = at_most;
4225
4226       for (i = 0, n -= 1; i < limit; i++, converter->nchars++, n--)
4227         mtext_cat_char (mt, mtext_ref_char (internal->unread, n));
4228       mtext_del (internal->unread, n + 1, internal->unread->nchars);
4229       if (at_most > 0)
4230         {
4231           if (at_most == limit)
4232             return mt;
4233           converter->at_most -= converter->nchars;
4234         }
4235     }
4236
4237   if (internal->binding == BINDING_BUFFER)
4238     {
4239       (*internal->coding->decoder) (internal->buf + internal->used,
4240                                     internal->bufsize - internal->used,
4241                                     mt, converter);
4242       internal->used += converter->nbytes;
4243     }  
4244   else if (internal->binding == BINDING_STREAM)
4245     {
4246       unsigned char work[CONVERT_WORKSIZE];
4247       int last_block = converter->last_block;
4248       int use_fread = at_most < 0 && internal->seekable;
4249
4250       converter->last_block = 0;
4251       while (1)
4252         {
4253           int nbytes, prev_nbytes;
4254
4255           if (feof (internal->fp))
4256             nbytes = 0;
4257           else if (use_fread)
4258             nbytes = fread (work, sizeof (unsigned char), CONVERT_WORKSIZE,
4259                             internal->fp);
4260           else
4261             {
4262               int c = getc (internal->fp);
4263
4264               if (c != EOF)
4265                 work[0] = c, nbytes = 1;
4266               else
4267                 nbytes = 0;
4268             }
4269
4270           if (ferror (internal->fp))
4271             {
4272               converter->result = MCONVERSION_RESULT_IO_ERROR;
4273               break;
4274             }
4275
4276           if (nbytes == 0)
4277             converter->last_block = last_block;
4278           prev_nbytes = converter->nbytes;
4279           (*internal->coding->decoder) (work, nbytes, mt, converter);
4280           if (converter->nbytes - prev_nbytes < nbytes)
4281             {
4282               if (use_fread)
4283                 fseek (internal->fp, converter->nbytes - prev_nbytes - nbytes,
4284                        SEEK_CUR);
4285               else
4286                 ungetc (work[0], internal->fp);
4287               break;
4288             }
4289           if (nbytes == 0
4290               || (converter->at_most > 0
4291                   && converter->nchars == converter->at_most))
4292             break;
4293         }
4294       converter->last_block = last_block;
4295     }
4296   else                          /* internal->binding == BINDING_NONE */
4297     MERROR (MERROR_CODING, NULL);
4298
4299   converter->at_most = at_most;
4300   return ((converter->result == MCONVERSION_RESULT_SUCCESS
4301            || converter->result == MCONVERSION_RESULT_INSUFFICIENT_SRC)
4302           ? mt : NULL);
4303 }
4304
4305 /*=*/
4306
4307 /***en
4308     @brief Decode a buffer area based on a coding system.
4309
4310     The mconv_decode_buffer () function decodes $N bytes of buffer
4311     area pointed to by $BUF based on the coding system $NAME.  A
4312     temporary code converter for decoding is automatically created
4313     and freed.
4314
4315     @return
4316     If the operation was successful, mconv_decode_buffer () returns
4317     the resulting M-text.  Otherwise it returns NULL and assigns an
4318     error code to the external variable #merror_code.  */
4319
4320 /***ja
4321     @brief ¥³¡¼¥É·Ï¤Ë´ð¤Å¤¤¤Æ¥Ð¥Ã¥Õ¥¡Îΰè¤ò¥Ç¥³¡¼¥É¤¹¤ë
4322
4323     ´Ø¿ô mconv_decode_buffer () ¤Ï¡¢$BUF ¤Ë¤è¤Ã¤Æ»Ø¤µ¤ì¤¿ $N ¥Ð¥¤¥È¤Î
4324     ¥Ð¥Ã¥Õ¥¡Îΰè¤ò¡¢¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤¤Æ¥Ç¥³¡¼¥É¤¹¤ë¡£¥Ç¥³¡¼¥É¤Ë
4325     É¬Íפʥ³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4326
4327     @return
4328     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_decode_buffer () ¤ÏÆÀ¤é¤ì¤¿ M-text ¤ò
4329     ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
4330     ¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
4331
4332 /***
4333     @errors
4334     @c MERROR_IO, @c MERROR_CODING
4335
4336     @seealso
4337     mconv_decode (), mconv_decode_stream ()  */
4338
4339 MText *
4340 mconv_decode_buffer (MSymbol name, unsigned char *buf, int n)
4341 {
4342   MConverter *converter = mconv_buffer_converter (name, buf, n);
4343   MText *mt;
4344
4345   if (! converter)
4346     return NULL;
4347   mt = mtext ();
4348   if (! mconv_decode (converter, mt))
4349     {
4350       M17N_OBJECT_UNREF (mt);
4351       mt = NULL;
4352     }
4353   mconv_free_converter (converter);
4354   return mt;
4355 }
4356
4357 /*=*/
4358
4359 /***en
4360     @brief Decode a stream input based on a coding system.
4361
4362     The mconv_decode_stream () function decodes the entire byte
4363     sequence read in from stream $FP based on the coding system $NAME.
4364     A code converter for decoding is automatically created and freed.
4365
4366     @return
4367     If the operation was successful, mconv_decode_stream () returns
4368     the resulting M-text.  Otherwise it returns NULL and assigns an
4369     error code to the external variable #merror_code.  */
4370
4371 /***ja
4372     @brief ¥³¡¼¥É·Ï¤Ë´ð¤Å¤¤¤Æ¥¹¥È¥ê¡¼¥àÆþÎϤò¥Ç¥³¡¼¥É¤¹¤ë
4373
4374     ´Ø¿ô mconv_decode_stream () ¤Ï¡¢¥¹¥È¥ê¡¼¥à $FP ¤«¤éÆɤ߹þ¤Þ¤ì¤ë¥Ð
4375     ¥¤¥ÈÎóÁ´ÂΤò¡¢¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤¤Æ¥Ç¥³¡¼¥É¤¹¤ë¡£¥Ç¥³¡¼¥É¤Ëɬ
4376     Íפʥ³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4377
4378     @return
4379     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_decode_stream () ¤ÏÆÀ¤é¤ì¤¿ M-text ¤òÊÖ
4380     ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
4381     ¥É¤òÀßÄꤹ¤ë¡£  */
4382
4383 /***
4384     @errors
4385     @c MERROR_IO, @c MERROR_CODING
4386
4387     @seealso
4388     mconv_decode (), mconv_decode_buffer ()  */
4389
4390 MText *
4391 mconv_decode_stream (MSymbol name, FILE *fp)
4392 {
4393   MConverter *converter = mconv_stream_converter (name, fp);
4394   MText *mt;
4395
4396   if (! converter)
4397     return NULL;
4398   mt = mtext ();
4399   if (! mconv_decode (converter, mt))
4400     {
4401       M17N_OBJECT_UNREF (mt);
4402       mt = NULL;
4403     }
4404   mconv_free_converter (converter);
4405   return mt;
4406 }
4407
4408 /*=*/
4409
4410 /***en @brief Encode an M-text into a byte sequence.
4411
4412     The mconv_encode () function encodes M-text $MT and writes the
4413     resulting byte sequence into the buffer area or the stream that is
4414     currently bound to code converter $CONVERTER.
4415
4416     @return
4417     If the operation was successful, mconv_encode () returns the
4418     number of written bytes.  Otherwise it returns -1 and assigns an
4419     error code to the external variable #merror_code.  */
4420
4421 /***ja
4422     @brief M-text ¤ò¥Ð¥¤¥ÈÎó¤Ë¥¨¥ó¥³¡¼¥É¤¹¤ë
4423
4424     ´Ø¿ô mconv_encode () ¤Ï¡¢M-text $MT ¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼
4425     ¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼
4426     ¥à¤Ë½ñ¤­¹þ¤à¡£
4427
4428     @return
4429     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È¿ô¤òÊÖ¤¹¡£
4430     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄê
4431     ¤¹¤ë¡£  */
4432
4433 /***
4434     @errors
4435     @c MERROR_IO, @c MERROR_CODING
4436
4437     @seealso
4438     mconv_rebind_buffer (), mconv_rebind_stream(),
4439     mconv_decode (), mconv_encode_range ()  */
4440
4441 int
4442 mconv_encode (MConverter *converter, MText *mt)
4443 {
4444   return mconv_encode_range (converter, mt, 0, mtext_nchars (mt));
4445 }
4446
4447 /*=*/
4448
4449 /***en
4450     @brief Encode a part of an M-text
4451
4452     The mconv_encode_range () function encodes the text between $FROM
4453     (inclusive) and $TO (exclusive) in M-text $MT and writes the
4454     resulting byte sequence into the buffer area or the stream that is
4455     currently bound to code converter $CONVERTER.
4456
4457     @return
4458     If the operation was successful, mconv_encode_range () returns the
4459     number of written bytes. Otherwise it returns -1 and assigns an
4460     error code to the external variable #merror_code.  */
4461
4462 /***ja
4463     @brief M-text ¤Î°ìÉô¤ò¤ò¥Ð¥¤¥ÈÎó¤Ë¥¨¥ó¥³¡¼¥É¤¹¤ë
4464
4465     ´Ø¿ô mconv_encode_range () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤à¡Ë¤«¤é 
4466     $TO ¡Ê´Þ¤Þ¤Ê¤¤¡Ë¤Þ¤Ç¤ÎÈϰϤΥƥ­¥¹¥È¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼
4467     ¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼
4468     ¥à¤Ë½ñ¤­¹þ¤à¡£
4469
4470     @return
4471     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode_range () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È¿ô
4472     ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
4473     ¥É¤òÀßÄꤹ¤ë¡£  */
4474
4475 /***
4476     @errors
4477     @c MERROR_RANGE, @c MERROR_IO, @c MERROR_CODING
4478
4479     @seealso
4480     mconv_rebind_buffer (), mconv_rebind_stream(),
4481     mconv_decode (), mconv_encode ()  */
4482
4483 int
4484 mconv_encode_range (MConverter *converter, MText *mt, int from, int to)
4485 {
4486   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4487
4488   M_CHECK_POS_X (mt, from, -1);
4489   M_CHECK_POS_X (mt, to, -1);
4490   if (to < from)
4491     to = from;
4492
4493   if (converter->at_most > 0 && from + converter->at_most < to)
4494     to = from + converter->at_most;
4495
4496   converter->nchars = converter->nbytes = 0;
4497   converter->result = MCONVERSION_RESULT_SUCCESS;
4498
4499   mtext_put_prop (mt, from, to, Mcoding, internal->coding->name);
4500   if (internal->binding == BINDING_BUFFER)
4501     {
4502       (*internal->coding->encoder) (mt, from, to,
4503                                     internal->buf + internal->used,
4504                                     internal->bufsize - internal->used,
4505                                     converter);
4506       internal->used += converter->nbytes;
4507     }
4508   else if (internal->binding == BINDING_STREAM)
4509     {
4510       unsigned char work[CONVERT_WORKSIZE];
4511
4512       while (from < to)
4513         {
4514           int written = 0;
4515           int prev_nbytes = converter->nbytes;
4516           int this_nbytes;
4517
4518           (*internal->coding->encoder) (mt, from, to, work,
4519                                         CONVERT_WORKSIZE, converter);
4520           this_nbytes = converter->nbytes - prev_nbytes;
4521           while (written < this_nbytes)
4522             {
4523               int wrtn = fwrite (work + written, sizeof (unsigned char),
4524                                  this_nbytes - written, internal->fp);
4525
4526               if (ferror (internal->fp))
4527                 break;
4528               written += wrtn;
4529             }
4530           if (written < this_nbytes)
4531             {
4532               converter->result = MCONVERSION_RESULT_IO_ERROR;
4533               break;
4534             }
4535           from += converter->nchars;
4536         }
4537     }
4538   else                          /* fail safe */
4539     MERROR (MERROR_CODING, -1);
4540
4541   return ((converter->result == MCONVERSION_RESULT_SUCCESS
4542            || converter->result == MCONVERSION_RESULT_INSUFFICIENT_DST)
4543           ? converter->nbytes : -1);
4544 }
4545
4546 /*=*/
4547
4548 /***en
4549     @brief Encode an M-text into a buffer area.
4550
4551     The mconv_encode_buffer () function encodes M-text $MT based on
4552     coding system $NAME and writes the resulting byte sequence into the
4553     buffer area pointed to by $BUF.  At most $N bytes are written.  A
4554     temporary code converter for encoding is automatically created
4555     and freed.
4556
4557     @return
4558     If the operation was successful, mconv_encode_buffer () returns
4559     the number of written bytes.  Otherwise it returns -1 and assigns
4560     an error code to the external variable #merror_code.  */
4561
4562 /***ja
4563     @brief M-text ¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¥Ð¥Ã¥Õ¥¡Îΰè¤Ë½ñ¤­¹þ¤à
4564
4565     ´Ø¿ô mconv_encode_buffer () ¤ÏM-text $MT ¤ò¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤
4566     ¤Æ¥¨¥ó¥³¡¼¥É¤·¡¢ÆÀ¤é¤ì¤¿¥Ð¥¤¥ÈÎó¤ò $BUF ¤Î»Ø¤¹¥Ð¥Ã¥Õ¥¡Îΰè¤Ë½ñ¤­¹þ
4567     ¤à¡£$N ¤Ï½ñ¤­¹þ¤àºÇÂç¥Ð¥¤¥È¿ô¤Ç¤¢¤ë¡£¥¨¥ó¥³¡¼¥É¤ËɬÍפʥ³¡¼¥É¥³¥ó
4568     ¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4569
4570     @return
4571     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode_buffer () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È
4572     ¿ô¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð-1¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
4573     ¥É¤òÀßÄꤹ¤ë¡£  */
4574
4575 /***
4576     @errors
4577     @c MERROR_IO, @c MERROR_CODING
4578
4579     @seealso
4580     mconv_encode (), mconv_encode_stream ()  */
4581
4582 int
4583 mconv_encode_buffer (MSymbol name, MText *mt, unsigned char *buf, int n)
4584 {
4585   MConverter *converter = mconv_buffer_converter (name, buf, n);
4586   int ret;
4587
4588   if (! converter)
4589     return -1;
4590   ret = mconv_encode (converter, mt);
4591   mconv_free_converter (converter);
4592   return ret;
4593 }
4594
4595 /*=*/
4596
4597 /***en
4598     @brief Encode an M-text to write to a stream.
4599
4600     The mconv_encode_stream () function encodes M-text $MT based on
4601     coding system $NAME and writes the resulting byte sequence to
4602     stream $FP.  A temporary code converter for encoding is
4603     automatically created and freed.
4604
4605     @return
4606     If the operation was successful, mconv_encode_stream () returns
4607     the number of written bytes.  Otherwise it returns -1 and assigns
4608     an error code to the external variable #merror_code.  */
4609
4610 /***ja
4611     @brief M-text ¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¥¹¥È¥ê¡¼¥à¤Ë½ñ¤­¹þ¤à
4612
4613     ´Ø¿ô mconv_encode_stream () ¤ÏM-text $MT ¤ò¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤
4614     ¤Æ¥¨¥ó¥³¡¼¥É¤·¡¢ÆÀ¤é¤ì¤¿¥Ð¥¤¥ÈÎó¤ò¥¹¥È¥ê¡¼¥à $FP ¤Ë½ñ¤­½Ð¤¹¡£¥¨¥ó
4615     ¥³¡¼¥É¤ËɬÍפʥ³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4616
4617     @return
4618     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode_stream () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È¿ô
4619     ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð-1¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É
4620     ¤òÀßÄꤹ¤ë¡£  */
4621
4622 /***
4623     @errors
4624     @c MERROR_IO, @c MERROR_CODING
4625
4626     @seealso
4627     mconv_encode (), mconv_encode_buffer (), mconv_encode_file ()  */
4628
4629 int
4630 mconv_encode_stream (MSymbol name, MText *mt, FILE *fp)
4631 {
4632   MConverter *converter = mconv_stream_converter (name, fp);
4633   int ret;
4634
4635   if (! converter)
4636     return -1;
4637   ret = mconv_encode (converter, mt);
4638   mconv_free_converter (converter);
4639   return ret;
4640 }
4641
4642 /*=*/
4643
4644 /***en
4645     @brief Read a character via a code converter.
4646
4647     The mconv_getc () function reads one character from the buffer
4648     area or the stream that is currently bound to code converter
4649     $CONVERTER.  The decoder of $CONVERTER is used to decode the byte
4650     sequence.  The internal status of $CONVERTER is updated
4651     appropriately.
4652
4653     @return
4654     If the operation was successful, mconv_getc () returns the
4655     character read in.  If the input source reaches EOF, it returns @c
4656     EOF without changing the external variable #merror_code.  If an
4657     error is detected, it returns @c EOF and assigns an error code to
4658     #merror_code.  */
4659
4660 /***ja
4661     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿·Ðͳ¤Ç1ʸ»úÆɤà
4662
4663     ´Ø¿ô mconv_getc () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±
4664     ¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤«¤é1ʸ»ú¤òÆɤ߹þ¤à¡£¥Ð¥¤
4665     ¥ÈÎó¤Î¥Ç¥³¡¼¥É¤Ë¤Ï $CONVERTER ¤Î¥Ç¥³¡¼¥À¤¬ÍѤ¤¤é¤ì¤ë¡£$CONVERTER 
4666     ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4667
4668     @return
4669     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_getc () ¤ÏÆɤ߹þ¤Þ¤ì¤¿Ê¸»ú¤òÊÖ¤¹¡£ÆþÎϸ»¤¬ 
4670     EOF ¤Ë㤷¤¿¾ì¹ç¤Ï¡¢³°ÉôÊÑ¿ô #merror_code ¤òÊѤ¨¤º¤Ë @c EOF ¤òÊÖ¤¹¡£
4671     ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c EOF ¤òÊÖ¤·¡¢#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É
4672     ¤òÀßÄꤹ¤ë¡£  */
4673
4674 /***
4675     @errors
4676     @c MERROR_CODING
4677
4678     @seealso
4679     mconv_ungetc (), mconv_putc (), mconv_gets ()  */
4680
4681 int
4682 mconv_getc (MConverter *converter)
4683 {
4684   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4685   int at_most = converter->at_most;
4686
4687   mtext_reset (internal->work_mt);
4688   converter->at_most = 1;
4689   mconv_decode (converter, internal->work_mt);
4690   converter->at_most = at_most;
4691   return (converter->nchars == 1
4692           ? STRING_CHAR (internal->work_mt->data)
4693           : EOF);
4694 }
4695
4696 /*=*/
4697
4698 /***en
4699     @brief Push a character back to a code converter.
4700
4701     The mconv_ungetc () function pushes character $C back to code
4702     converter $CONVERTER.  Any number of characters can be pushed
4703     back.  The lastly pushed back character is firstly read by the
4704     subsequent mconv_getc () call.  The characters pushed back are
4705     registered only in $CONVERTER; they are not written to the input
4706     source.  The internal status of $CONVERTER is updated
4707     appropriately.
4708
4709     @return
4710     If the operation was successful, mconv_ungetc () returns $C.
4711     Otherwise it returns @c EOF and assigns an error code to the
4712     external variable #merror_code.  */
4713
4714 /***ja
4715     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ë1ʸ»úÌ᤹
4716
4717     ´Ø¿ô mconv_ungetc () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ëʸ»ú $C ¤ò
4718     ²¡¤·Ì᤹¡£²¡¤·Ì᤻¤ëʸ»ú¿ô¤ËÀ©¸Â¤Ï¤Ê¤¤¡£¤³¤Î¸å¤Ë mconv_getc () ¤ò
4719     ¸Æ¤Ó½Ð¤¹¤È¡¢ºÇ¸å¤ËÌᤵ¤ì¤¿Ê¸»ú¤¬ºÇ½é¤ËÆɤޤì¤ë¡£²¡¤·Ìᤵ¤ì¤¿Ê¸»ú¤Ï 
4720     $CONVERTER ¤ÎÆâÉô¤ËÃߤ¨¤é¤ì¤ë¤À¤±¤Ç¤¢¤ê¡¢¼ÂºÝ¤ËÆþÎϸ»¤Ë½ñ¤­¹þ¤Þ¤ì
4721     ¤ë¤ï¤±¤Ç¤Ï¤Ê¤¤¡£$CONVERTER ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4722
4723     @return
4724     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_ungetc () ¤Ï $C ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c
4725     EOF ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
4726
4727 /***
4728     @errors
4729     @c MERROR_CODING, @c MERROR_CHAR
4730
4731     @seealso
4732     mconv_getc (), mconv_putc (), mconv_gets ()  */
4733
4734 int
4735 mconv_ungetc (MConverter *converter, int c)
4736 {
4737   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4738
4739   M_CHECK_CHAR (c, EOF);
4740
4741   converter->result = MCONVERSION_RESULT_SUCCESS;
4742   mtext_cat_char (internal->unread, c);
4743   return c;
4744 }
4745
4746 /*=*/
4747
4748 /***en
4749     @brief Write a character via a code converter.
4750
4751     The mconv_putc () function writes character $C to the buffer area
4752     or the stream that is currently bound to code converter
4753     $CONVERTER.  The encoder of $CONVERTER is used to encode the
4754     character.  The number of bytes actually written is set to the @c
4755     nbytes member of $CONVERTER.  The internal status of $CONVERTER
4756     is updated appropriately.
4757
4758     @return
4759     If the operation was successful, mconv_putc () returns $C.
4760     If an error is detected, it returns @c EOF and assigns
4761     an error code to the external variable #merror_code.  */
4762
4763 /***ja
4764     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò·Ðͳ¤Ç1ʸ»ú½ñ¤¯
4765
4766     ´Ø¿ô mconv_putc () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±
4767     ¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤Ëʸ»ú $C ¤ò½ñ¤­½Ð¤¹¡£Ê¸»ú
4768     ¤Î¥¨¥ó¥³¡¼¥É¤Ë¤Ï $CONVERTER ¤Î¥¨¥ó¥³¡¼¥À¤¬ÍѤ¤¤é¤ì¤ë¡£¼ÂºÝ¤Ë½ñ¤­½Ð
4769     ¤µ¤ì¤¿¥Ð¥¤¥È¿ô¤Ï¡¢$CONVERTER ¤Î ¥á¥ó¥Ð¡¼ @c nbytes ¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£
4770     $CONVERTER ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4771
4772     @return
4773     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_putc () ¤Ï $C ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç
4774     ¤Ï @c EOF ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
4775
4776 /***
4777     @errors
4778     @c MERROR_CODING, @c MERROR_IO, @c MERROR_CHAR
4779
4780     @seealso
4781     mconv_getc (), mconv_ungetc (), mconv_gets ()  */
4782
4783 int
4784 mconv_putc (MConverter *converter, int c)
4785 {
4786   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4787
4788   M_CHECK_CHAR (c, EOF);
4789   mtext_reset (internal->work_mt);
4790   mtext_cat_char (internal->work_mt, c);
4791   if (mconv_encode_range (converter, internal->work_mt, 0, 1) < 0)
4792     return EOF;
4793   return c;
4794 }
4795
4796 /*=*/
4797
4798 /***en
4799     @brief Read a line using a code converter.
4800
4801     The mconv_gets () function reads one line from the buffer area or
4802     the stream that is currently bound to code converter $CONVERTER.
4803     The decoder of $CONVERTER is used for decoding.  The decoded
4804     character sequence is appended at the end of M-text $MT.  The
4805     final newline character in the original byte sequence is not
4806     appended.  The internal status of $CONVERTER is updated
4807     appropriately.
4808
4809     @return
4810     If the operation was successful, mconv_gets () returns the
4811     modified $MT.  If it encounters EOF without reading a single
4812     character, it returns $MT without changing it.  If an error is
4813     detected, it returns @c NULL and assigns an error code to @c
4814     merror_code.  */
4815
4816 /***ja
4817     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò»È¤Ã¤Æ1¹ÔÆɤà
4818
4819     ´Ø¿ô mconv_gets () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±
4820     ¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤«¤é1¹Ô¤òÆɤ߹þ¤à¡£¥Ð¥¤¥È
4821     Îó¤Î¥Ç¥³¡¼¥É¤Ë¤Ï $CONVERTER ¤Î¥Ç¥³¡¼¥À¤¬ÍѤ¤¤é¤ì¤ë¡£¥Ç¥³¡¼¥É¤µ¤ì¤¿
4822     Ê¸»úÎó¤Ï M-text $MT ¤ÎËöÈø¤ËÄɲ䵤ì¤ë¡£¸µ¤Î¥Ð¥¤¥ÈÎó¤Î½ªÃ¼²þ¹Ôʸ»ú
4823     ¤ÏÄɲ䵤ì¤Ê¤¤¡£$CONVERTER ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4824
4825     @return
4826     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_gets () ¤ÏÊѹ¹¤µ¤ì¤¿ $MT ¤òÊÖ¤¹¡£¤â¤·1ʸ»ú
4827     ¤âÆɤޤº¤Ë EOF ¤ËÅö¤¿¤Ã¤¿¾ì¹ç¤Ï¡¢$MT ¤òÊѹ¹¤»¤º¤Ë¤½¤Î¤Þ¤ÞÊÖ¤¹¡£¥¨
4828     ¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
4829     ÀßÄꤹ¤ë¡£  */
4830
4831 /***
4832     @errors
4833     @c MERROR_CODING
4834
4835     @seealso
4836     mconv_getc (), mconv_ungetc (), mconv_putc ()  */
4837
4838 MText *
4839 mconv_gets (MConverter *converter, MText *mt)
4840 {
4841   int c;
4842
4843   M_CHECK_READONLY (mt, NULL);
4844   while (1)
4845     {
4846       c = mconv_getc (converter);
4847       if (c == EOF || c == '\n')
4848         break;
4849       mtext_cat_char (mt, c);
4850     }
4851   if (c == EOF && converter->result != MCONVERSION_RESULT_SUCCESS)
4852     /* mconv_getc () sets merror_code */
4853     return NULL;
4854   return mt;
4855 }
4856
4857 /*=*/
4858
4859 /*** @} */
4860
4861 /*
4862   Local Variables:
4863   coding: euc-japan
4864   End:
4865 */