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