*** 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 sets; CCS) ¤Îʸ
43     »úÉä¹ç²½Êý¼° (character encoding scheme; CES) ¤ò @e ¥³¡¼¥É·Ï ¤È¸Æ
44     ¤Ö¥ª¥Ö¥¸¥§¥¯¥È¤Çɽ¸½¤¹¤ë¡£m17n ¥é¥¤¥Ö¥é¥ê¤¬¥µ¥Ý¡¼¥È¤¹¤ëCES ¤Ï¡¢
45     UTF-8, UTF-16, ISO-2022, DIRECT-CHARSET, ¤½¤Î¾¡¢¤ËÂçÊ̤µ¤ì¤ë¡£¥¢
46     ¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤¬Æȼ«¤Ë¥³¡¼¥É·Ï¤òÄɲ乤뤳¤È¤â²Äǽ¤Ç¤¢¤ë¡£
47
48     ¥³¡¼¥É¥Ý¥¤¥ó¥È¤«¤éʸ»ú¥³¡¼¥É¤Ø¤ÎÊÑ´¹¤ò @e ¥¨¥ó¥³¡¼¥É ¤È¸Æ¤Ó¡¢Ê¸»ú
49     ¥³¡¼¥É¤«¤é¥³¡¼¥É¥Ý¥¤¥ó¥È¤Ø¤ÎÊÑ´¹¤ò @e ¥Ç¥³¡¼¥É ¤È¸Æ¤Ö¡£
50
51     ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¡¢»ØÄꤵ¤ì¤¿¥³¡¼¥É·Ï¤Ç¥Ð¥¤¥ÈÎó¤ò¥Ç¥³¡¼
52     ¥É¤¹¤ë¤³¤È¤Ç M-text ¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£¤Þ¤¿µÕ¤Ë¡¢»ØÄꤵ¤ì¤¿¥³¡¼¥É
53     ·Ï¤Ç M-text ¤ò¥¨¥ó¥³¡¼¥É¤·¤¹¤ë¤³¤È¤Ç¥Ð¥¤¥ÈÎó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¡£  */
54
55 /*=*/
56
57 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
58 /*** @addtogroup m17nInternal
59      @{ */
60
61 #include <config.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <ctype.h>
65 #include <string.h>
66 #include <sys/types.h>
67 #include <unistd.h>
68 #include <errno.h>
69
70 #include "m17n.h"
71 #include "m17n-misc.h"
72 #include "internal.h"
73 #include "plist.h"
74 #include "character.h"
75 #include "charset.h"
76 #include "coding.h"
77 #include "mtext.h"
78 #include "symbol.h"
79 #include "mlocale.h"
80
81 #define NUM_SUPPORTED_CHARSETS 32
82
83 /** Structure for coding system object.  */
84
85 typedef struct
86 {
87   /** Name of the coding system.  */
88   MSymbol name;
89
90   /** Type of the coding system.  */
91   MSymbol type;
92
93   /* Number of supported charsets.  */
94   int ncharsets;
95
96   /** Array of supported charsets.  */
97   MCharset *charsets[NUM_SUPPORTED_CHARSETS];
98
99   /** If non-NULL, function to call at the time of creating and
100       reseting a converter.  */
101   int (*resetter) (MConverter *converter);
102
103   int (*decoder) (unsigned char *str, int str_bytes, MText *mt,
104                   MConverter *converter);
105
106   int (*encoder) (MText *mt, int from, int to,
107                   unsigned char *str, int str_bytes,
108                   MConverter *converter);
109
110   /** If non-zero, the coding system decode/encode ASCII characters as
111       is.  */
112   int ascii_compatible;
113
114   /** Pointer to extra information given when the coding system is
115       defined.  The meaning depends on <type>.  */
116   void *extra_info;
117
118   /** Pointer to information referred on conversion.  The meaning
119       depends on <type>.  The value NULL means that the coding system
120       is not yet setup.  */
121   void *extra_spec;
122
123   int ready;
124 } MCodingSystem;
125
126 struct MCodingList
127 {
128   int size, inc, used;
129   MCodingSystem **codings;
130 };
131
132 static struct MCodingList coding_list;
133
134 static MPlist *coding_definition_list;
135
136 typedef struct {
137   /**en
138      Pointer to a structure of a coding system.  */
139   /**ja
140      ¥³¡¼¥É·Ï¤òɽ¤ï¤¹¥Ç¡¼¥¿¹½Â¤¤Ø¤Î¥Ý¥¤¥ó¥¿ */
141   MCodingSystem *coding;
142
143   /**en
144      Buffer for carryover bytes generated while decoding. */
145   /**ja
146      ¥Ç¥³¡¼¥ÉÃæ¤Î¥­¥ã¥ê¥£¥ª¡¼¥Ð¡¼¥Ð¥¤¥ÈÍѥХåե¡ */
147   unsigned char carryover[256];
148
149   /**en
150      Number of carryover bytes. */
151   /**ja
152      ¥­¥ã¥ê¥£¥ª¡¼¥Ð¡¼¥Ð¥¤¥È¿ô */
153   int carryover_bytes;
154
155   /**en
156      Beginning of the byte sequence bound to this converter. */
157   /**ja
158      ¤³¤Î¥³¥ó¥Ð¡¼¥¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥Ð¥¤¥ÈÎó¤ÎÀèƬ°ÌÃÖ */
159   unsigned char *buf;
160
161   /**en
162      Size of buf. */
163   /**ja
164      buf ¤ÎÂ礭¤µ */
165   int bufsize;
166
167   /**en
168      Number of bytes already consumed in buf. */
169   /**ja
170      buf Æâ¤Ç¤¹¤Ç¤Ë¾ÃÈñ¤µ¤ì¤¿¥Ð¥¤¥È¿ô */
171   int used;
172
173   /**en
174      Stream bound to this converter. */
175   /**ja
176      ¤³¤Î¥³¥ó¥Ð¡¼¥¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥¹¥È¥ê¡¼¥à */
177   FILE *fp;
178
179   /**en
180      Which of above two is in use. */
181   /**ja
182      ¾åµ­2¼Ô¤Î¤¤¤º¤ì¤¬»È¤ï¤ì¤Æ¤¤¤ë¤« */
183   int binding;
184
185   /**en
186      Buffer for unget. */
187   /**ja
188      Unget ÍѥХåե¡ */
189   MText *unread;
190
191   /*en
192     Working area. */
193   /*ja
194     ºî¶ÈÎΰè */
195   MText *work_mt;
196
197   int seekable;
198 } MConverterStatus;
199
200
201 \f
202 /* Local macros and functions.  */
203
204 /** At first, set SRC_BASE to SRC.  Then check if we have already
205     produced AT_MOST chars.  If so, set SRC_END to SRC, and jump to
206     source_end.  Otherwise, get one more byte C from SRC.  In that
207     case, if SRC == SRC_END, jump to the label source_end.  */
208
209 #define ONE_MORE_BASE_BYTE(c)           \
210   do {                                  \
211     src_base = src;                     \
212     if (nchars == at_most)              \
213       {                                 \
214         src_end = src;                  \
215         goto source_end;                \
216       }                                 \
217     if (src == src_stop)                \
218       {                                 \
219         if (src == src_end)             \
220           goto source_end;              \
221         src_base = src = source;        \
222         if (src == src_end)             \
223           goto source_end;              \
224         src_stop = src_end;             \
225       }                                 \
226     (c) = *src++;                       \
227   } while (0)
228
229
230 /** Get one more byte C from SRC.  If SRC == SRC_END, jump to the
231    label source_end.  */
232
233 #define ONE_MORE_BYTE(c)        \
234   do {                          \
235     if (src == src_stop)        \
236       {                         \
237         if (src == src_end)     \
238           goto source_end;      \
239         src = source;           \
240         if (src == src_end)     \
241           goto source_end;      \
242         src_stop = src_end;     \
243       }                         \
244     (c) = *src++;               \
245   } while (0)
246
247
248 #define REWIND_SRC_TO_BASE()                                            \
249   do {                                                                  \
250     if (src_base < source || src_base >= src_end)                       \
251       src_stop = internal->carryover + internal->carryover_bytes;       \
252     src = src_base;                                                     \
253   } while (0)
254
255
256 /** Push back byte C to SRC.  */
257
258 #define UNGET_ONE_BYTE(c)               \
259   do {                                  \
260     if (src > source)                   \
261       src--;                            \
262     else                                \
263       {                                 \
264         internal->carryover[0] = c;     \
265         internal->carryover_bytes = 1;  \
266         src = internal->carryover;      \
267         src_stop = src + 1;             \
268       }                                 \
269   } while  (0);
270
271
272 /** Store multibyte representation of character C at DST and increment
273     DST to the next of the produced bytes.  DST must be a pointer to
274     data area of M-text MT.  If the produced bytes are going to exceed
275     DST_END, enlarge the data area of MT.  */
276
277 #define EMIT_CHAR(c)                                            \
278   do {                                                          \
279     int bytes = CHAR_BYTES (c);                                 \
280     int len;                                                    \
281                                                                 \
282     if (dst + bytes + 1 > dst_end)                              \
283       {                                                         \
284         len = dst - mt->data;                                   \
285         bytes = mt->allocated + bytes + (src_stop - src);       \
286         mtext__enlarge (mt, bytes);                             \
287         dst = mt->data + len;                                   \
288         dst_end = mt->data + mt->allocated;                     \
289       }                                                         \
290     dst += CHAR_STRING (c, dst);                                \
291     nchars++;                                                   \
292   } while (0)
293
294
295 /* Check if there is enough room to produce LEN bytes at DST.  If not,
296    go to the label insufficient_destination.  */
297
298 #define CHECK_DST(len)                  \
299   do {                                  \
300     if (dst + (len) > dst_end)          \
301       goto insufficient_destination;    \
302   } while (0)
303
304
305 /** Take NUM_CHARS characters (NUM_BYTES bytes) already stored at
306     (MT->data + MT->nbytes) into MT, and put charset property on
307     them with CHARSET->name.  */
308
309 #define TAKEIN_CHARS(mt, num_chars, num_bytes, charset)                 \
310   do {                                                                  \
311     int chars = (num_chars);                                            \
312                                                                         \
313     if (chars > 0)                                                      \
314       {                                                                 \
315         mtext__takein ((mt), chars, (num_bytes));                       \
316         if (charset)                                                    \
317           mtext_put_prop ((mt), (mt)->nchars - chars, (mt)->nchars,     \
318                           Mcharset, (void *) ((charset)->name));        \
319       }                                                                 \
320   } while (0)
321
322
323 #define SET_SRC(mt, format, from, to)                                   \
324   do {                                                                  \
325     if (format <= MTEXT_FORMAT_UTF_8)                                   \
326       {                                                                 \
327         src = mt->data + POS_CHAR_TO_BYTE (mt, from);                   \
328         src_end = mt->data + POS_CHAR_TO_BYTE (mt, to);                 \
329       }                                                                 \
330     else if (format <= MTEXT_FORMAT_UTF_16BE)                           \
331       {                                                                 \
332         src                                                             \
333           = mt->data + (sizeof (short)) * POS_CHAR_TO_BYTE (mt, from);  \
334         src_end                                                         \
335           = mt->data + (sizeof (short)) * POS_CHAR_TO_BYTE (mt, to);    \
336       }                                                                 \
337     else                                                                \
338       {                                                                 \
339         src = mt->data + (sizeof (int)) * from;                         \
340         src_end = mt->data + (sizeof (int)) * to;                       \
341       }                                                                 \
342   } while (0)
343
344
345 #define ONE_MORE_CHAR(c, bytes, format)                         \
346   do {                                                          \
347     if (src == src_end)                                         \
348       goto finish;                                              \
349     if (format <= MTEXT_FORMAT_UTF_8)                           \
350       c = STRING_CHAR_AND_BYTES (src, bytes);                   \
351     else if (format <= MTEXT_FORMAT_UTF_16BE)                   \
352       {                                                         \
353         c = mtext_ref_char (mt, from++);                        \
354         bytes = (sizeof (short)) * CHAR_UNITS_UTF16 (c);        \
355       }                                                         \
356     else                                                        \
357       {                                                         \
358         c = ((unsigned *) (mt->data))[from++];                  \
359         bytes = sizeof (int);                                   \
360       }                                                         \
361   } while (0)
362
363
364 static int
365 encode_unsupporeted_char (int c, unsigned char *dst, unsigned char *dst_end,
366                           MText *mt, int pos)
367 {
368   int len;
369   char *format;
370
371   len = c < 0x10000 ? 8 : 10;
372   if (dst + len > dst_end)
373     return 0;
374
375   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         free (coding->extra_spec);
2993       free (coding);
2994     }
2995   MLIST_FREE1 (&coding_list, codings);
2996   MPLIST_DO (plist, coding_definition_list)
2997     M17N_OBJECT_UNREF (MPLIST_VAL (plist));
2998   M17N_OBJECT_UNREF (coding_definition_list);
2999 }
3000
3001 void
3002 mconv__define_coding_from_charset (MSymbol sym)
3003 {
3004   MPlist *param = mplist (), *charsets = mplist ();
3005
3006   mplist_set (charsets, Msymbol, sym);
3007   mplist_add (param, Mtype, Mcharset);
3008   mplist_add (param, Mcharsets, charsets);
3009   mconv_define_coding (msymbol_name (sym), param, NULL, NULL, NULL, NULL);
3010   M17N_OBJECT_UNREF (charsets);
3011   M17N_OBJECT_UNREF (param);
3012 }
3013
3014 void
3015 mconv__register_charset_coding (MSymbol sym)
3016 {
3017   if (! mplist_find_by_key (coding_definition_list, sym))
3018     {
3019       MPlist *param = mplist (), *charsets = mplist ();
3020
3021       mplist_set (charsets, Msymbol, sym);
3022       mplist_add (param, Msymbol, Mtype);
3023       mplist_add (param, Msymbol, Mcharset);
3024       mplist_add (param, Msymbol, Mcharsets);
3025       mplist_add (param, Mplist, charsets);
3026       mplist_put (coding_definition_list, sym, param);
3027       M17N_OBJECT_UNREF (charsets);
3028     }
3029 }
3030
3031
3032 int
3033 mcoding__load_from_database ()
3034 {
3035   MDatabase *mdb = mdatabase_find (msymbol ("coding-list"), Mnil, Mnil, Mnil);
3036   MPlist *def_list, *plist;
3037   MPlist *definitions = coding_definition_list;
3038   int mdebug_mask = MDEBUG_CODING;
3039
3040   if (! mdb)
3041     return 0;
3042   MDEBUG_PUSH_TIME ();
3043   def_list = (MPlist *) mdatabase_load (mdb);
3044   MDEBUG_PRINT_TIME ("CODING", (stderr, " to load the data."));
3045   MDEBUG_POP_TIME ();
3046   if (! def_list)
3047     return -1;
3048
3049   MDEBUG_PUSH_TIME ();
3050   MPLIST_DO (plist, def_list)
3051     {
3052       MPlist *pl;
3053       MSymbol name;
3054
3055       if (! MPLIST_PLIST_P (plist))
3056         MERROR (MERROR_CHARSET, -1);
3057       pl = MPLIST_PLIST (plist);
3058       if (! MPLIST_SYMBOL_P (pl))
3059         MERROR (MERROR_CHARSET, -1);
3060       name = MPLIST_SYMBOL (pl);
3061       pl = MPLIST_NEXT (pl);
3062       definitions = mplist_add (definitions, name, pl);
3063       M17N_OBJECT_REF (pl);
3064     }
3065
3066   M17N_OBJECT_UNREF (def_list);
3067   MDEBUG_PRINT_TIME ("CODING", (stderr, " to parse the loaded data."));
3068   MDEBUG_POP_TIME ();
3069   return 0;
3070 }
3071
3072 /*** @} */
3073 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
3074 \f
3075 /* External API */
3076
3077 /*** @addtogroup m17nConv */
3078 /*** @{ */
3079 /*=*/
3080
3081 /***en @name Variables: Symbols representing a coding system */
3082 /***ja @name ÊÑ¿ô: ÄêµÁºÑ¤ß¥³¡¼¥É·Ï¤ò»ØÄꤹ¤ë¤¿¤á¤Î¥·¥ó¥Ü¥ë */
3083 /*** @{ */
3084 /*=*/
3085
3086 /***en
3087     @brief Symbol for the coding system US-ASCII
3088
3089     The symbol #Mcoding_us_ascii has name <tt>"us-ascii"</tt> and
3090     represents a coding system for the CES US-ASCII.  */
3091
3092 /***ja
3093     @brief MIME charset "US-ASCII" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë
3094
3095     ¥·¥ó¥Ü¥ë @c Mcoding_us_ascii ¤Ï <tt>"us-ascii"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Á¡¢
3096     MIME charset <tt>"US-ASCII"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»ØÄꤹ¤ë¤¿¤á
3097     ¤Ë»È¤ï¤ì¤ë¡£
3098      */
3099 MSymbol Mcoding_us_ascii;
3100 /*=*/
3101
3102 /***en
3103     @brief Symbol for the coding system ISO-8859-1
3104
3105     The symbol #Mcoding_iso_8859_1 has name <tt>"iso-8859-1"</tt> and
3106     represents a coding system for the CES ISO-8859-1.  */
3107
3108 /***ja
3109     @brief MIME charset "ISO-8859-1" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë
3110
3111     ¥·¥ó¥Ü¥ë @c Mcoding_iso_8859_1 ¤Ï <tt>"iso-8859-1"</tt> ¤È¤¤¤¦Ì¾Á°
3112     ¤ò»ý¤Á¡¢MIME charset <tt>"ISO-8859-1"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»Ø
3113     Äꤹ¤ë¤¿¤á¤Ë»È¤ï¤ì¤ë¡£ */
3114
3115 MSymbol Mcoding_iso_8859_1;
3116 /*=*/
3117
3118 /***en
3119     @brief Symbol for the coding system UTF-8
3120
3121     The symbol #Mcoding_utf_8 has name <tt>"utf-8"</tt> and represents
3122     a coding system for the CES UTF-8.  */
3123
3124 /***ja
3125     @brief RFC 2279 ¤Î "UTF-8" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë¡ÊUnicode ÍÑ¡Ë
3126
3127     ¥·¥ó¥Ü¥ë @c Mcoding_utf_8 ¤Ï <tt>"utf-8"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Á¡¢
3128     RFC 2279 ¤ÇÄêµÁ¤µ¤ì¤ë<tt>"UTF-8"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»ØÄꤹ¤ë
3129     ¤¿¤á¤Ë»È¤ï¤ì¤ë¡£¤³¤Î¥³¡¼¥É·Ï¤Ï Unicode ¤ÎÁ´¤Æ¤Îʸ»ú¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£
3130      */
3131
3132 MSymbol Mcoding_utf_8;
3133 /*=*/
3134
3135 /***en
3136     @brief UTF-8-FULL
3137
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 RFC 2279 ¤Î "UTF-8" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë¡ÊÁ´Ê¸»úÍÑ¡Ë
3147
3148     ¥·¥ó¥Ü¥ë @c Mcoding_utf_8_full ¤Ï <tt>"utf-8-full"</tt> ¤È¤¤¤¦Ì¾Á°
3149     ¤ò»ý¤Á¡¢RFC 2279 ¤ÇÄêµÁ¤µ¤ì¤ë<tt>"UTF-8"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò
3150     »ØÄꤹ¤ë¤¿¤á¤Ë»È¤ï¤ì¤ë¡£¤³¤Î¥³¡¼¥É·Ï¤Ï m17n ¥é¥¤¥Ö¥é¥ê¤¬°·¤¦Á´¤Æ¤Î
3151     Ê¸»ú¤ò¥µ¥Ý¡¼¥È¤¹¤ë¡£  */
3152
3153 MSymbol Mcoding_utf_8_full;
3154 /*=*/
3155
3156 /***en
3157     @brief UTF-16
3158
3159     The symbol #Mcoding_utf_16 has name <tt>"utf-16"</tt> and
3160     represents a coding system for the CES UTF-16 (RFC 2279).  */
3161 /***ja
3162     @brief RFC 2781 ¤Î "UTF-16" ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤Î¥·¥ó¥Ü¥ë
3163
3164     ¥·¥ó¥Ü¥ë @c Mcoding_utf_16 ¤Ï <tt>"utf-16"</tt> ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Á¡¢
3165     RFC 2279 ¤ÇÄêµÁ¤µ¤ì¤ë<tt>"UTF-16"</tt> ¤ËÂбþ¤¹¤ë¥³¡¼¥É·Ï¤ò»ØÄꤹ
3166     ¤ë¤¿¤á¤Ë»È¤ï¤ì¤ë¡£¤³¤Î¥³¡¼¥É·Ï¤Ï Unicode ¤ÎÁ´¤Æ¤Îʸ»ú¤ò¥µ¥Ý¡¼¥È¤¹
3167     ¤ë¡£ */
3168
3169 MSymbol Mcoding_utf_16;
3170 /*=*/
3171
3172 /***en
3173     @brief UTF-16BE
3174
3175     The symbol #Mcoding_utf_16be has name <tt>"utf-16be"</tt> and
3176     represents a coding system for the CES UTF-16BE (RFC 2279).  */
3177
3178 MSymbol Mcoding_utf_16be;
3179 /*=*/
3180
3181 /***en
3182     @brief UTF-16LE
3183
3184     The symbol #Mcoding_utf_16le has name <tt>"utf-16le"</tt> and
3185     represents a coding system for the CES UTF-16LE (RFC 2279).  */
3186
3187 MSymbol Mcoding_utf_16le;
3188 /*=*/
3189
3190 /***en
3191     @brief UTF-32
3192
3193     The symbol #Mcoding_utf_32 has name <tt>"utf-32"</tt> and
3194     represents a coding system for the CES UTF-32 (RFC 2279).  */
3195
3196 MSymbol Mcoding_utf_32;
3197 /*=*/
3198
3199 /***en
3200     @brief UTF-32be
3201
3202     The symbol #Mcoding_utf_32be has name <tt>"utf-32be"</tt> and
3203     represents a coding system for the CES UTF-32BE (RFC 2279).  */
3204
3205 MSymbol Mcoding_utf_32be;
3206 /*=*/
3207
3208 /***en
3209     @brief UTF-32LE
3210
3211     The symbol #Mcoding_utf_32le has name <tt>"utf-32le"</tt> and
3212     represents a coding system for the CES UTF-32LE (RFC 2279).  */
3213 MSymbol Mcoding_utf_32le;
3214 /*=*/
3215
3216 /***en
3217     @brief SJIS
3218
3219     The symbol #Mcoding_sjis has name <tt>"sjis"</tt> and represents a coding
3220     system for the CES Shift-JIS.  */ 
3221
3222 MSymbol Mcoding_sjis;
3223 /*** @} */ 
3224 /*=*/
3225
3226 /***en
3227     @name Variables: Parameter keys for mconv_define_coding ().  */
3228 /*** @{ */
3229 /*=*/
3230
3231 /***en
3232     Parameter key for mconv_define_coding () (which see). */ 
3233 MSymbol Mtype;
3234 /*=*/
3235
3236 MSymbol Mcharsets;
3237 MSymbol Mflags;
3238 MSymbol Mdesignation;
3239 MSymbol Minvocation;
3240 MSymbol Mcode_unit;
3241 MSymbol Mbom;
3242 MSymbol Mlittle_endian;
3243 /*** @} */
3244 /*=*/
3245
3246 /***en
3247     @name Variables: Symbols representing coding system type.  */
3248 /*** @{ */
3249 /*=*/
3250
3251 /***en
3252     Symbol that can be a value of the #Mtype parameter of a coding
3253     system used in an argument to the mconv_define_coding () function
3254     (which see).  */
3255  
3256 MSymbol Mutf;
3257 /*=*/
3258 MSymbol Miso_2022;
3259 /*=*/
3260 /*** @} */
3261 /*=*/
3262
3263 /***en
3264     @name Variables: Symbols appearing in the value of #Mfrag parameter.  */
3265 /*** @{ */
3266 /*=*/
3267
3268 /***en
3269     Symbol that can be a value of the #Mflags parameter of a coding
3270     system used in an argument to the mconv_define_coding () function
3271     (which see).  */
3272 MSymbol Mreset_at_eol;
3273 /*=*/
3274 MSymbol Mreset_at_cntl;
3275 MSymbol Meight_bit;
3276 MSymbol Mlong_form;
3277 MSymbol Mdesignation_g0;
3278 MSymbol Mdesignation_g1;
3279 MSymbol Mdesignation_ctext;
3280 MSymbol Mdesignation_ctext_ext;
3281 MSymbol Mlocking_shift;
3282 MSymbol Msingle_shift;
3283 MSymbol Msingle_shift_7;
3284 MSymbol Meuc_tw_shift;
3285 MSymbol Miso_6429;
3286 MSymbol Mrevision_number;
3287 MSymbol Mfull_support;
3288 /*** @} */
3289 /*=*/
3290
3291 /***en
3292     @name Variables: etc
3293
3294     Remaining variables.  */
3295 /***ja @name ÊÑ¿ô: ¤½¤Î¾ */
3296 /*** @{ */
3297 /*=*/
3298 /***en
3299     @brief Symbol whose name is "maybe".
3300
3301     The variable #Mmaybe is a symbol of name <tt>"maybe"</tt>.  It is
3302     used a value of #Mbom parameter of the function
3303     mconv_define_coding () (which see).  */
3304
3305 MSymbol Mmaybe;
3306 /*=*/
3307
3308 /***en
3309     @brief The symbol @c Mcoding
3310
3311     Any decoded M-text has a text property whose key is the predefined
3312     symbol @c Mcoding.  The name of @c Mcoding is
3313     <tt>"coding"</tt>.  */
3314
3315 /***ja
3316     @brief ¥·¥ó¥Ü¥ë @c Mcoding
3317
3318     ¥Ç¥³¡¼¥É¤µ¤ì¤¿ M-text ¤Ï¡¢¥­¡¼¤¬ @c Mcoding ¤Ç¤¢¤ë¤è¤¦¤Ê¥Æ¥­¥¹¥È¥×
3319     ¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£¥·¥ó¥Ü¥ë @c Mcoding ¤Ï <tt>"coding"</tt> ¤È¤¤¤¦Ì¾
3320     Á°¤Ç¤¢¤é¤«¤¸¤áÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£  */
3321
3322 MSymbol Mcoding;
3323 /*=*/
3324 /*** @} */ 
3325 /*=*/
3326
3327 /***en
3328     @brief Define a coding system
3329
3330     The mconv_define_coding () function defines a new coding system
3331     and makes it accessive via a symbol whose name is $NAME.  $PLIST
3332     specifies parameters of the charset as below:
3333
3334     <ul>
3335
3336     <li> Key is @c Mtype, value is a symbol
3337
3338     The value specifies the type of the coding system.  It must be
3339     #Mcharset, #Mutf, #Miso_2022, or #Mnil.
3340
3341     If the type is #Mcharset, $EXTRA_INFO is ignored.
3342
3343     If the type is #Miso_2022, $EXTRA_INFO must be a pointer to
3344     #MCodingInfoISO2022.
3345
3346     If the type is #Mutf, $EXTRA_INFO must be a pointer to
3347     #MCodingInfoUTF.
3348
3349     If the type is #Mnil, the argument $RESETTER, $DECODER, and
3350     $ENCODER must be supplied.  $EXTRA_INFO is ignored.  Otherwise,
3351     they can be @c NULL and the m17n library provides proper defaults.
3352
3353     <li> Key is #Mcharsets, value is a plist
3354
3355     The value specifies a list charsets supported by the coding
3356     system.  The keys of the plist must be #Msymbol, and the values
3357     must be symbols representing charsets.
3358
3359     <li> Key is #Mflags, value is a plist
3360
3361     If the type is #Miso_2022, the values specifies flags to control
3362     the ISO 2022 interpreter.  The keys of the plist must e @c
3363     Msymbol, and values must be one of the following.
3364
3365     <ul>
3366
3367     <li> #Mreset_at_eol
3368
3369     If this flag exits, designation and invocation status is reset to
3370     the initial state at the end of line.
3371
3372     <li> #Mreset_at_cntl
3373
3374     If this flag exists, designation and invocation status is reset to
3375     the initial state at a control character.
3376
3377     <li> #Meight_bit
3378
3379     If this flag exists, the graphic plane right is used.
3380
3381     <li> #Mlong_form
3382
3383     If this flag exists, the over-long escape sequences (ESC '$' '('
3384     <final_byte>) are used for designating the charsets JISX0208.1978,
3385     GB2312, and JISX0208.
3386
3387     <li> #Mdesignation_g0
3388
3389     If this flag and #Mfull_support exists, designates charsets not
3390     listed in the charset list to the graphic register G0.
3391
3392     <li> #Mdesignation_g1
3393
3394     If this flag and #Mfull_support exists, designates charsets not
3395     listed in the charset list to the graphic register G1.
3396
3397     <li> #Mdesignation_ctext
3398
3399     If this flag and #Mfull_support exists, designates charsets not
3400     listed in the charset list to a graphic register G0 or G1 based on
3401     the criteria of the Compound Text.
3402
3403     <li> #Mdesignation_ctext_ext
3404
3405     If this flag and #Mfull_support exists, designates charsets not
3406     listed in the charset list to a graphic register G0 or G1, or use
3407     extended segment for such charsets based on the criteria of the
3408     Compound Text.
3409
3410     <li> #Mlocking_shift
3411
3412     If this flag exists, use locking shift.
3413
3414     <li> #Msingle_shift
3415
3416     If this flag exists, use single shift.
3417
3418     <li> #Msingle_shift_7
3419
3420     If this flag exists, use 7-bit single shift code (0x19).
3421
3422     <li> #Meuc_tw_shift;
3423
3424     If this flag exists, use a special shifting according to EUC-TW.
3425
3426     <li> #Miso_6429
3427
3428     This flag is currently ignored.
3429
3430     <li> #Mrevision_number
3431
3432     If this flag exists, use a revision number escape sequence to
3433     designate a charset that has a revision number.
3434
3435     <li> #Mfull_support
3436
3437     If this flag exists, support all charsets registered in the
3438     International Registry.
3439
3440     </ul>
3441
3442     <li> Key is #Mdesignation, value is a plist
3443
3444     If the type is #Miso_2022, the value specifies how to designate
3445     each supported characters.  The keys of the plist must be @c
3446     Minteger, and the values must be numbers indicating a graphic
3447     registers.  The Nth element value is for the Nth charset of the
3448     charset list.  The value 0..3 means that it is assumed that a
3449     charset is already designated to the graphic register 0..3.  The
3450     negative value G (-4..-1) means that a charset is not designated
3451     to any register at first, and if necessary, is designated to the
3452     (G+4) graphic register.
3453
3454     <li> Key is #Minvocation, value is a plist
3455
3456     If the type is #Miso_2022, the value specifies how to invocate
3457     each graphic registers.  The plist length must be one or two.  The
3458     keys of the plist must be #Minteger, and the values must be
3459     numbers indicating a graphic register.  The value of the first
3460     element specifies which graphic register is invocated to the
3461     graphic plane left.  If the length is one, no graphic register is
3462     invocated to the graphic plane right.  Otherwise, the value of the
3463     second element specifies which graphic register is invocated to
3464     the graphic plane right.
3465
3466     <li> Key is #Mcode_unit, value is an integer
3467
3468     If the type is #Mutf, the value specifies the bit length of a
3469     code-unit.  It must be 8, 16, or 32.
3470
3471     <li> Key is #Mbom, value is a symbol
3472
3473     If the type is #Mutf and the code-unit bit length is 16 or 32,
3474     it specifies whether or not to use BOM (Byte Order Mark).  If the
3475     value is #Mnil (default), BOM is not used, else if the value is
3476     #Mmaybe, the existence of BOM is detected at decoding time, else
3477     BOM is used.
3478
3479     <li> Key is #Mlittle_endian, value is a symbol
3480
3481     If the type is #Mutf and the code-unit bit length is 16 or 32,
3482     it specifies whether or not the encoding is little endian.  If the
3483     value is #Mnil (default), it is big endian, else it is little
3484     endian.
3485
3486     </ul>
3487
3488     $RESETTER is a pointer to a function that resets a converter for
3489     the coding system to the initial status.  The pointed function is
3490     called with one argument, a pointer to a converter object.
3491
3492     $DECODER is a pointer to a function that decodes a byte sequence
3493     according to the coding system.  The pointed function is called
3494     with four arguments:
3495
3496         @li A pointer to the byte sequence to decode.
3497         @li The number of bytes to decode.
3498         @li A pointer to an M-text to which the decoded characters are appended.
3499         @li A pointer to a converter object.
3500
3501     $DECODER must return 0 if it succeeds.  Otherwise it must return -1.
3502
3503     $ENCODER is a pointer to a function that encodes an M-text
3504     according to the coding system.  The pointed function is called
3505     with six arguments:
3506
3507         @li A pointer to the M-text to encode.
3508         @li The starting position of the encoding.
3509         @li The ending position of the encoding.
3510         @li A pointer to a memory area where the produced bytes are stored.
3511         @li The size of the memory area.
3512         @li A pointer to a converter object.
3513
3514     $ENCODER must return 0 if it succeeds.  Otherwise it must return -1.
3515
3516     $EXTRA_INFO is a pointer to a data structure that contains extra
3517     information about the coding system.  The type of the data
3518     structure depends on $TYPE.
3519
3520     @return  
3521
3522     If the operation was successful, mconv_define_coding () returns a
3523     symbol whose name is $NAME.  If an error is detected, it returns
3524     #Mnil and assigns an error code to the external variable @c
3525     merror_code.  */
3526
3527 /***ja
3528     @brief ¥³¡¼¥É·Ï¤ÎÄêµÁ
3529
3530     ´Ø¿ô mconv_define_coding () ¤Ï¡¢¿·¤·¤¤¥³¡¼¥É·Ï¤òÄêµÁ¤·¡¢¤½¤ì¤ò 
3531     $NAME ¤È¤¤¤¦Ì¾Á°¤Î¥·¥ó¥Ü¥ë·Ðͳ¤Ç¥¢¥¯¥»¥¹¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¡£
3532
3533     $TYPE ¤Ï Îóµó·¿ #MCodingType ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤ê¡¢¥³¡¼¥É·Ï¤Î¹½Â¤¤ò
3534     »ØÄꤹ¤ë¡£
3535
3536     $CHARSET_NAMES ¤Ï¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¥»¥Ã¥È¤òɽ¤ï¤¹¥·¥ó¥Ü¥ë¤ÎÇÛÎó¤Ç¤¢¤ê¡¢
3537     $NCHARSETS ¤Ï¤½¤ÎÍ×ÁÇ¿ô¤Ç¤¢¤ë¡£
3538
3539     $TYPE ¤¬ #MCODING_TYPE_MISC ¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$RESETTER, $DECODER,
3540     $ENCODER ¤òÍ¿¤¨¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤ì°Ê³°¤Î¾ì¹ç¤Ë¤Ï¤³¤ì¤é¤Ï @c
3541     NULL ¤Ç¹½¤ï¤Ê¤¤¡£¤½¤ÎºÝ¤Ë¤Ï m17n ¥é¥¤¥Ö¥é¥ê¤¬Å¬Àڤʥǥե©¥ë¥ÈÃͤò
3542     Í¿¤¨¤ë¡£
3543
3544     $RESETTER ¤Ï¤³¤Î¥³¡¼¥É·ÏÍѤΥ³¥ó¥Ð¡¼¥¿¤ò½é´ü¾õÂ֤˥ꥻ¥Ã¥È¤¹¤ë´Ø¿ô
3545     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï¥³¥ó¥Ð¡¼¥¿¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤È
3546     ¤¤¤¦£±°ú¿ô¤ò¤È¤ë¡£
3547
3548     $DECODER ¤Ï¥Ð¥¤¥ÈÎó¤ò¤³¤Î¥³¡¼¥É·Ï¤Ë½¾¤Ã¤Æ¥Ç¥³¡¼¥É¤¹¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤
3549     ¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï°Ê²¼¤Î4°ú¿ô¤ò¤È¤ë¡£
3550
3551         @li ¥Ð¥¤¥ÈÎó¤Ø¤Î¥Ý¥¤¥ó¥¿
3552         @li ¥Ç¥³¡¼¥É¤¹¤Ù¤­¥Ð¥¤¥È¿ô
3553         @li ¥Ç¥³¡¼¥É·ë²Ì¤Îʸ»ú¤òÉղ乤ë M-text ¤Ø¤Î¥Ý¥¤¥ó¥¿
3554         @li ¥³¥ó¥Ð¡¼¥¿¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿
3555
3556     $DECODER ¤ÏÀ®¸ù¤·¤¿¤È¤­¤Ë¤Ï0¤ò¡¢¼ºÇÔ¤·¤¿¤È¤­¤Ë¤Ï-1¤òÊÖ¤µ¤Ê¤¯¤Æ¤Ï¤Ê
3557     ¤é¤Ê¤¤¡£
3558
3559     $ENCODER ¤Ï M-text ¤ò¤³¤Î¥³¡¼¥É·Ï¤Ë½¾¤Ã¤Æ¥¨¥ó¥³¡¼¥É¤¹
3560     ¤ë´Ø¿ô¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î´Ø¿ô¤Ï°Ê²¼¤Î6°ú¿ô¤ò¤È¤ë¡£
3561
3562         @li M-text ¤Ø¤Î¥Ý¥¤¥ó¥¿
3563         @li M-text ¤Î¥¨¥ó¥³¡¼¥É³«»Ï°ÌÃÖ
3564         @li M-text ¤Î¥¨¥ó¥³¡¼¥É½ªÎ»°ÌÃÖ
3565         @li À¸À®¤·¤¿¥Ð¥¤¥È¤òÊÝ»ý¤¹¤ë¥á¥â¥êÎΰè¤Ø¤Î¥Ý¥¤¥ó¥¿
3566         @li ¥á¥â¥êÎΰè¤Î¥µ¥¤¥º
3567         @li ¥³¥ó¥Ð¡¼¥¿¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿
3568
3569     $ENCODER ¤ÏÀ®¸ù¤·¤¿¤È¤­¤Ë¤Ï0¤ò¡¢¼ºÇÔ¤·¤¿¤È¤­¤Ë¤Ï-1¤òÊÖ¤µ¤Ê¤¯¤Æ¤Ï¤Ê
3570     ¤é¤Ê¤¤¡£
3571
3572     $EXTRA_INFO ¤Ï¥³¡¼¥Ç¥£¥°¥·¥¹¥Æ¥à¤Ë´Ø¤¹¤ëÄɲþðÊó¤ò´Þ¤à¥Ç¡¼¥¿¹½Â¤¤Ø
3573     ¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¤³¤Î¥Ç¡¼¥¿¹½Â¤¤Î¥¿¥¤¥×¤Ï $TYPE ¤Ë°Í¸¤¹¤ë¡£
3574
3575     $TYPE ¤¬ #MCODING_TYPE_ISO_2022 ¤Ç¤¢¤ì¤Ð¡¢$EXTRA_INFO ¤Ï @c
3576     MCodingInfoISO2022 ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3577
3578     $TYPE ¤¬ #MCODING_TYPE_UTF ¤Ç¤¢¤ì¤Ð¡¢$EXTRA_INFO ¤Ï @c
3579     MCodingInfoUTF ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
3580
3581     $TYPE ¤¬ #MCODING_TYPE_CHARSET, #MCODING_TYPE_MISC ¤Î¤É¤ì¤«¤Ç
3582     ¤¢¤ì¤Ð¡¢$EXTRA_INFO ¤Ï̵»ë¤µ¤ì¤ë¡£
3583
3584     @return  
3585
3586     ½èÍý¤ËÀ®¸ù¤¹¤ì¤Ð mconv_define_coding () ¤Ï $NAME ¤È¤¤¤¦Ì¾Á°¤Î¥·
3587     ¥ó¥Ü¥ë¤òÊÖ¤¹¡£¤³¤Î¥·¥ó¥Ü¥ë¤Ï¡¢¥­¡¼¤¬ $Mcoding ¤Ç¡¢ºî¤é¤ì¤¿¥³¡¼¥É·Ï
3588     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÃͤȤ¹¤ë¥·¥ó¥Ü¥ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¡£ ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì
3589     ¤¿¾ì¹ç¤Ï Mnil ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3590       */
3591
3592 /***
3593     @errors
3594     @c MERROR_CODING  */
3595
3596 MSymbol
3597 mconv_define_coding (char *name, MPlist *plist,
3598                      int (*resetter) (MConverter *),
3599                      int (*decoder) (unsigned char *, int, MText *,
3600                                      MConverter *),
3601                      int (*encoder) (MText *, int, int,
3602                                      unsigned char *, int,
3603                                      MConverter *),
3604                      void *extra_info)
3605 {
3606   MSymbol sym = msymbol (name);
3607   int i;
3608   MCodingSystem *coding;
3609   MPlist *pl;
3610
3611   MSTRUCT_MALLOC (coding, MERROR_CODING);
3612   coding->name = sym;
3613   if ((coding->type = (MSymbol) mplist_get (plist, Mtype)) == Mnil)
3614     coding->type = Mcharset;
3615   pl = (MPlist *) mplist_get (plist, Mcharsets);
3616   if (! pl)
3617     MERROR (MERROR_CODING, Mnil);
3618   coding->ncharsets = mplist_length (pl);
3619   if (coding->ncharsets > NUM_SUPPORTED_CHARSETS)
3620     coding->ncharsets = NUM_SUPPORTED_CHARSETS;
3621   for (i = 0; i < coding->ncharsets; i++, pl = MPLIST_NEXT (pl))
3622     {
3623       MSymbol charset_name;
3624
3625       if (MPLIST_KEY (pl) != Msymbol)
3626         MERROR (MERROR_CODING, Mnil);
3627       charset_name = MPLIST_SYMBOL (pl);
3628       if (! (coding->charsets[i] = MCHARSET (charset_name)))
3629         MERROR (MERROR_CODING, Mnil);
3630     }
3631
3632   coding->resetter = resetter;
3633   coding->decoder = decoder;
3634   coding->encoder = encoder;
3635   coding->ascii_compatible = 0;
3636   coding->extra_info = extra_info;
3637   coding->extra_spec = NULL;
3638   coding->ready = 0;
3639
3640   if (coding->type == Mcharset)
3641     {
3642       if (! coding->resetter)
3643         coding->resetter = reset_coding_charset;
3644       if (! coding->decoder)
3645         coding->decoder = decode_coding_charset;
3646       if (! coding->encoder)
3647         coding->encoder = encode_coding_charset;
3648     }
3649   else if (coding->type == Mutf)
3650     {
3651       MCodingInfoUTF *info = malloc (sizeof (MCodingInfoUTF));
3652       MSymbol val;
3653
3654       if (! coding->resetter)
3655         coding->resetter = reset_coding_utf;
3656
3657       info->code_unit_bits = (int) mplist_get (plist, Mcode_unit);
3658       if (info->code_unit_bits == 8)
3659         {
3660           if (! coding->decoder)
3661             coding->decoder = decode_coding_utf_8;
3662           if (! coding->encoder)
3663             coding->encoder = encode_coding_utf_8;
3664         }
3665       else if (info->code_unit_bits == 16)
3666         {
3667           if (! coding->decoder)
3668             coding->decoder = decode_coding_utf_16;
3669           if (! coding->encoder)
3670             coding->encoder = encode_coding_utf_16;
3671         }
3672       else if (info->code_unit_bits == 32)
3673         {
3674           if (! coding->decoder)
3675             coding->decoder = decode_coding_utf_32;
3676           if (! coding->encoder)
3677             coding->encoder = encode_coding_utf_32;
3678         }
3679       else
3680         MERROR (MERROR_CODING, Mnil);
3681       val = (MSymbol) mplist_get (plist, Mbom);
3682       if (val == Mnil)
3683         info->bom = 1;
3684       else if (val == Mmaybe)
3685         info->bom = 0;
3686       else
3687         info->bom = 2;
3688
3689       info->endian = (mplist_get (plist, Mlittle_endian) ? 1 : 0);
3690       coding->extra_info = info;
3691     }
3692   else if (coding->type == Miso_2022)
3693     {
3694       MCodingInfoISO2022 *info = malloc (sizeof (MCodingInfoISO2022));
3695
3696       if (! coding->resetter)
3697         coding->resetter = reset_coding_iso_2022;
3698       if (! coding->decoder)
3699         coding->decoder = decode_coding_iso_2022;
3700       if (! coding->encoder)
3701         coding->encoder = encode_coding_iso_2022;
3702
3703       info->initial_invocation[0] = 0;
3704       info->initial_invocation[1] = -1;
3705       pl = (MPlist *) mplist_get (plist, Minvocation);
3706       if (pl)
3707         {
3708           if (MPLIST_KEY (pl) != Minteger)
3709             MERROR (MERROR_CODING, Mnil);
3710           info->initial_invocation[0] = MPLIST_INTEGER (pl);
3711           if (! MPLIST_TAIL_P (pl))
3712             {
3713               pl = MPLIST_NEXT (pl);
3714               if (MPLIST_KEY (pl) != Minteger)
3715                 MERROR (MERROR_CODING, Mnil);
3716               info->initial_invocation[1] = MPLIST_INTEGER (pl);
3717             }
3718         }
3719       memset (info->designations, 0, sizeof (info->designations));
3720       for (i = 0, pl = (MPlist *) mplist_get (plist, Mdesignation);
3721            i < 32 && pl && MPLIST_KEY (pl) == Minteger;
3722            i++, pl = MPLIST_NEXT (pl))
3723         info->designations[i] = MPLIST_INTEGER (pl);
3724
3725       info->flags = 0;
3726       MPLIST_DO (pl, (MPlist *) mplist_get (plist, Mflags))
3727         {
3728           MSymbol val;
3729
3730           if (MPLIST_KEY (pl) != Msymbol)
3731             MERROR (MERROR_CODING, Mnil);
3732           val = MPLIST_SYMBOL (pl);
3733           if (val == Mreset_at_eol)
3734             info->flags |= MCODING_ISO_RESET_AT_EOL;
3735           else if (val == Mreset_at_cntl)
3736             info->flags |= MCODING_ISO_RESET_AT_CNTL;
3737           else if (val == Meight_bit)
3738             info->flags |= MCODING_ISO_EIGHT_BIT;
3739           else if (val == Mlong_form)
3740             info->flags |= MCODING_ISO_LOCKING_SHIFT;
3741           else if (val == Mdesignation_g0)
3742             info->flags |= MCODING_ISO_DESIGNATION_G0;
3743           else if (val == Mdesignation_g1)
3744             info->flags |= MCODING_ISO_DESIGNATION_G1;
3745           else if (val == Mdesignation_ctext)
3746             info->flags |= MCODING_ISO_DESIGNATION_CTEXT;
3747           else if (val == Mdesignation_ctext_ext)
3748             info->flags |= MCODING_ISO_DESIGNATION_CTEXT_EXT;
3749           else if (val == Mlocking_shift)
3750             info->flags |= MCODING_ISO_LOCKING_SHIFT;
3751           else if (val == Msingle_shift)
3752             info->flags |= MCODING_ISO_SINGLE_SHIFT;
3753           else if (val == Msingle_shift_7)
3754             info->flags |= MCODING_ISO_SINGLE_SHIFT_7;
3755           else if (val == Meuc_tw_shift)
3756             info->flags |= MCODING_ISO_EUC_TW_SHIFT;
3757           else if (val == Miso_6429)
3758             info->flags |= MCODING_ISO_ISO6429;
3759           else if (val == Mrevision_number)
3760             info->flags |= MCODING_ISO_REVISION_NUMBER;
3761           else if (val == Mfull_support)
3762             info->flags |= MCODING_ISO_FULL_SUPPORT;
3763         }
3764
3765       coding->extra_info = info;
3766     }
3767   else
3768     {
3769       if (! coding->decoder || ! coding->encoder)
3770         MERROR (MERROR_CODING, Mnil);
3771       if (! coding->resetter)
3772         coding->ready = 1;
3773     }
3774
3775   msymbol_put (sym, Mcoding, coding);
3776   msymbol_put (msymbol__canonicalize (sym), Mcoding, coding);
3777   plist = (MPlist *) mplist_get (plist, Maliases);
3778   if (plist)
3779     {
3780       MPLIST_DO (pl, plist)
3781         {
3782           MSymbol alias;
3783
3784           if (MPLIST_KEY (pl) != Msymbol)
3785             continue;
3786           alias = MPLIST_SYMBOL (pl);
3787           msymbol_put (alias, Mcoding, coding);
3788           msymbol_put (msymbol__canonicalize (alias), Mcoding, coding);
3789         }
3790     }
3791
3792   MLIST_APPEND1 (&coding_list, codings, coding, MERROR_CODING);
3793
3794   return sym;
3795 }
3796
3797 /*=*/
3798
3799 /***en
3800     @brief Resolve coding system name.
3801
3802     The mconv_resolve_coding () function returns $SYMBOL if it
3803     represents a coding system.  Otherwise, canonicalize $SYMBOL as to
3804     a coding system name, and if the canonicalized name represents a
3805     coding system, return it.  Otherwise, return Mnil.  */
3806
3807
3808 MSymbol
3809 mconv_resolve_coding (MSymbol symbol)
3810 {
3811   MCodingSystem *coding = find_coding (symbol);
3812
3813   if (! coding)
3814     {
3815       symbol = msymbol__canonicalize (symbol);
3816       coding = find_coding (symbol);
3817     }
3818   return (coding ? coding->name : Mnil);
3819 }
3820
3821 /*=*/
3822
3823
3824 /***en
3825     @brief List symbols representing a coding system.
3826
3827     The mconv_list_codings () function makes an array of symbols
3828     representing a coding system, stores the pointer to the array in a
3829     place pointed to by $SYMBOLS, and returns the length of the array.  */
3830
3831 int
3832 mconv_list_codings (MSymbol **symbols)
3833 {
3834   int i = coding_list.used + mplist_length (coding_definition_list);
3835   int j;
3836   MPlist *plist;
3837
3838   MTABLE_MALLOC ((*symbols), i, MERROR_CODING);
3839   i = 0;
3840   MPLIST_DO (plist, coding_definition_list)
3841     (*symbols)[i++] = MPLIST_KEY (plist);
3842   for (j = 0; j < coding_list.used; j++)
3843     if (! mplist_find_by_key (coding_definition_list, 
3844                               coding_list.codings[j]->name))
3845       (*symbols)[i++] = coding_list.codings[j]->name;
3846   return i;
3847 }
3848
3849 /*=*/
3850
3851 /***en
3852     @brief Create a code converter bound to a buffer.
3853
3854     The mconv_buffer_converter () function creates a pointer to a code
3855     converter for coding system $CODING.  The code converter is bound
3856     to buffer area of $N bytes pointed to by $BUF.  Subsequent
3857     decodings and encodings are done to/from this buffer area.
3858
3859     $CODING can be #Mnil.  In this case, a coding system associated
3860     with the current locale (LC_CTYPE) is used.
3861
3862     @return
3863     If the operation was successful, mconv_buffer_converter () returns
3864     the created code converter.  Otherwise it returns @c NULL and
3865     assigns an error code to the external variable #merror_code.  */
3866
3867 /***ja
3868     @brief ¥Ð¥Ã¥Õ¥¡¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤òºî¤ë
3869
3870     ´Ø¿ô mconv_buffer_converter () ¤Ï¡¢¥³¡¼¥É·Ï $CODING ÍѤΥ³¡¼¥É¥³¥ó
3871     ¥Ð¡¼¥¿¤òºî¤ë¡£¤³¤Î¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ï¡¢$BUF ¤Ç¼¨¤µ¤ì¤ëÂ礭¤µ $N ¥Ð
3872     ¥¤¥È¤Î¥Ð¥Ã¥Õ¥¡Îΰè¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤ë¡£¤³¤ì°Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó
3873     ¥¨¥ó¥³¡¼¥É¤Ï¡¢¤³¤Î¥Ð¥Ã¥Õ¥¡Îΰè¤ËÂФ·¤Æ¹Ô¤Ê¤ï¤ì¤ë¡£
3874
3875     $CODING ¤Ï #Mnil ¤Ç¤¢¤Ã¤Æ¤â¤è¤¤¡£¤³¤Î¾ì¹ç¤Ï¸½ºß¤Î¥í¥±¡¼¥ë 
3876     (LC_CTYPE) ¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥³¡¼¥É·Ï¤¬»È¤ï¤ì¤ë¡£
3877
3878     @return
3879     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð mconv_buffer_converter () ¤Ï ºî¤é¤ì¤¿¥³¡¼¥É¥³
3880     ¥ó¥Ð¡¼¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
3881     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3882
3883     @latexonly \IPAlabel{mconverter} @endlatexonly  */
3884
3885 /***
3886     @errors
3887     @c MERROR_SYMBOL, @c MERROR_CODING
3888
3889     @seealso 
3890     mconv_stream_converter ()  */
3891
3892 MConverter *
3893 mconv_buffer_converter (MSymbol name, unsigned char *buf, int n)
3894 {
3895   MCodingSystem *coding;
3896   MConverter *converter;
3897   MConverterStatus *internal;
3898
3899   if (name == Mnil)
3900     name = mlocale_get_prop (mlocale__ctype, Mcoding);
3901   coding = find_coding (name);
3902   if (! coding)
3903     MERROR (MERROR_CODING, NULL);
3904   MSTRUCT_CALLOC (converter, MERROR_CODING);
3905   MSTRUCT_CALLOC (internal, MERROR_CODING);
3906   converter->internal_info = internal;
3907   internal->coding = coding;
3908   if (coding->resetter
3909       && (*coding->resetter) (converter) < 0)
3910     {
3911       free (internal);
3912       free (converter);
3913       MERROR (MERROR_CODING, NULL);
3914     }
3915
3916   internal->unread = mtext ();
3917   internal->work_mt = mtext ();
3918   mtext__enlarge (internal->work_mt, MAX_UTF8_CHAR_BYTES);
3919   internal->buf = buf;
3920   internal->used = 0;
3921   internal->bufsize = n;
3922   internal->binding = BINDING_BUFFER;
3923
3924   return converter;
3925 }
3926
3927 /*=*/
3928
3929 /***en
3930     @brief Create a code converter bound to a stream.
3931
3932     The mconv_stream_converter () function create a pointer to a code
3933     converter for coding system $CODING.  The code converter is bound
3934     to stream $FP.  Subsequent decodings and encodings are done
3935     to/from this stream.
3936
3937     $CODING can be #Mnil.  In this case, a coding system associated
3938     with the current locale (LC_CTYPE) is used.
3939
3940     @return If the operation was successful, mconv_stream_converter ()
3941     returns the created code converter.  Otherwise it returns @c NULL
3942     and assigns an error code to the external variable @c
3943     merror_code.  */
3944
3945 /***ja
3946     @brief ¥¹¥È¥ê¡¼¥à¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤òºî¤ë
3947
3948     ´Ø¿ô mconv_stream_converter () ¤Ï¡¢¥³¡¼¥É·Ï $CODING ÍѤΥ³¡¼¥É¥³¥ó
3949     ¥Ð¡¼¥¿¤òºî¤ë¡£¤³¤Î¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ï¡¢¥¹¥È¥ê¡¼¥à $FP ¤Ë·ë¤ÓÉÕ¤±¤é
3950     ¤ì¤ë¡£¤³¤ì°Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó¥¨¥ó¥³¡¼¥É¤Ï¡¢¤³¤Î¥¹¥È¥ê¡¼¥à¤ËÂФ·¤Æ
3951     ¹Ô¤Ê¤ï¤ì¤ë¡£
3952
3953     $CODING ¤Ï #Mnil ¤Ç¤¢¤Ã¤Æ¤â¤è¤¤¡£¤³¤Î¾ì¹ç¤Ï¸½ºß¤Î¥í¥±¡¼¥ë 
3954     (LC_CTYPE) ¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥³¡¼¥É·Ï¤¬»È¤ï¤ì¤ë¡£
3955
3956     @return
3957     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_stream_converter () ¤Ïºî¤é¤ì¤¿¥³¡¼¥É¥³
3958     ¥ó¥Ð¡¼¥¿¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code 
3959     ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£
3960
3961     @latexonly \IPAlabel{mconverter} @endlatexonly  */
3962
3963 /***
3964     @errors
3965     @c MERROR_SYMBOL, @c MERROR_CODING
3966
3967     @seealso
3968     mconv_buffer_converter ()  */
3969
3970 MConverter *
3971 mconv_stream_converter (MSymbol name, FILE *fp)
3972 {
3973   MCodingSystem *coding;
3974   MConverter *converter;
3975   MConverterStatus *internal;
3976
3977   if (name == Mnil)
3978     name = mlocale_get_prop (mlocale__ctype, Mcoding);
3979   coding = find_coding (name);
3980   if (! coding)
3981     MERROR (MERROR_CODING, NULL);
3982   MSTRUCT_CALLOC (converter, MERROR_CODING);
3983   MSTRUCT_CALLOC (internal, MERROR_CODING);
3984   converter->internal_info = internal;
3985   internal->coding = coding;
3986   if (coding->resetter
3987       && (*coding->resetter) (converter) < 0)
3988     {
3989       free (internal);
3990       free (converter);
3991       MERROR (MERROR_CODING, NULL);
3992     }
3993
3994   if (fseek (fp, 0, SEEK_CUR) < 0)
3995     {
3996       if (errno == EBADF)
3997         {
3998           free (internal);
3999           free (converter);
4000           return NULL;
4001         }
4002       internal->seekable = 0;
4003     }
4004   else
4005     internal->seekable = 1;
4006   internal->unread = mtext ();
4007   internal->work_mt = mtext ();
4008   mtext__enlarge (internal->work_mt, MAX_UTF8_CHAR_BYTES);
4009   internal->fp = fp;
4010   internal->binding = BINDING_STREAM;
4011
4012   return converter;
4013 }
4014
4015 /*=*/
4016
4017 /***en
4018     @brief Reset a code converter.
4019
4020     The mconv_reset_converter () function resets code converter
4021     $CONVERTER to the initial state.
4022
4023     @return
4024     If $CONVERTER->coding has its own reseter function,
4025     mconv_reset_converter () returns the result of that function
4026     applied to $CONVERTER.  Otherwise it returns 0.  */
4027
4028 /***ja
4029     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò¥ê¥»¥Ã¥È¤¹¤ë
4030
4031     ´Ø¿ô mconv_reset_converter () ¤Ï¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤ò½é´ü
4032     ¾õÂÖ¤ËÌ᤹¡£
4033
4034     @return
4035     ¤â¤· $CONVERTER->coding ¤Ë¥ê¥»¥Ã¥ÈÍѤδؿô¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤Ê¤é¤Ð¡¢
4036     mconv_reset_converter () ¤Ï¤½¤Î´Ø¿ô¤Ë $CONVERTER ¤òŬÍѤ·¤¿·ë²Ì¤ò
4037     ÊÖ¤·¡¢¤½¤¦¤Ç¤Ê¤±¤ì¤Ð0¤òÊÖ¤¹¡£  */
4038
4039 int
4040 mconv_reset_converter (MConverter *converter)
4041 {
4042   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4043
4044   converter->nchars = converter->nbytes = 0;
4045   converter->result = MCONVERSION_RESULT_SUCCESS;
4046   internal->carryover_bytes = 0;
4047   mtext_reset (internal->unread);
4048   if (internal->coding->resetter)
4049     return (*internal->coding->resetter) (converter);
4050   return 0;
4051 }
4052
4053 /*=*/
4054
4055 /***en
4056     @brief Free a code converter.
4057
4058     The mconv_free_converter () function frees the code converter
4059     $CONVERTER.  */
4060
4061 /***ja
4062     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò²òÊü¤¹¤ë
4063
4064     ´Ø¿ô mconv_free_converter () ¤Ï¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤ò²òÊü
4065     ¤¹¤ë¡£  */
4066
4067 void
4068 mconv_free_converter (MConverter *converter)
4069 {
4070   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4071
4072   M17N_OBJECT_UNREF (internal->work_mt);
4073   M17N_OBJECT_UNREF (internal->unread);
4074   free (internal);
4075   free (converter);
4076 }
4077
4078 /*=*/
4079
4080 /***en
4081     @brief Bind a buffer to a code converter.
4082
4083     The mconv_rebind_buffer () function binds buffer area of $N bytes
4084     pointed to by $BUF to code converter $CONVERTER.  Subsequent
4085     decodings and encodings are done to/from this newly bound buffer
4086     area.
4087
4088     @return
4089     This function always returns $CONVERTER.  */
4090
4091 /***ja
4092     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ë¥Ð¥Ã¥Õ¥¡Îΰè¤ò·ë¤ÓÉÕ¤±¤ë
4093
4094     ´Ø¿ô mconv_rebind_buffer () ¤Ï¡¢$BUF ¤Ë¤è¤Ã¤Æ»Ø¤µ¤ì¤¿Â礭¤µ $N ¥Ð
4095     ¥¤¥È¤Î¥Ð¥Ã¥Õ¥¡Îΰè¤ò¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë·ë¤ÓÉÕ¤±¤ë¡£¤³¤ì
4096     °Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó¥¨¥ó¥³¡¼¥É¤Ï¡¢¤³¤Î¿·¤¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥Ð¥Ã¥Õ¥¡
4097     Îΰè¤ËÂФ·¤Æ¹Ô¤Ê¤ï¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¡£
4098
4099     @return
4100     ¤³¤Î´Ø¿ô¤Ï¾ï¤Ë $CONVERTER ¤òÊÖ¤¹¡£
4101
4102     @latexonly \IPAlabel{mconv_rebind_buffer} @endlatexonly  */
4103
4104 /***
4105     @seealso
4106     mconv_rebind_stream () */
4107
4108 MConverter *
4109 mconv_rebind_buffer (MConverter *converter, unsigned char *buf, int n)
4110 {
4111   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4112
4113   internal->buf = buf;
4114   internal->used = 0;
4115   internal->bufsize = n;
4116   internal->binding = BINDING_BUFFER;
4117   return converter;
4118 }
4119
4120 /*=*/
4121
4122 /***en
4123     @brief Bind a stream to a code converter.
4124
4125     The mconv_rebind_stream () function binds stream $FP to code
4126     converter $CONVERTER.  Following decodings and encodings are done
4127     to/from this newly bound stream.
4128
4129     @return
4130     This function always returns $CONVERTER.  */
4131
4132 /***ja
4133     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ë¥¹¥È¥ê¡¼¥à¤ò·ë¤ÓÉÕ¤±¤ë
4134
4135     ´Ø¿ô mconv_rebind_stream () ¤Ï¡¢¥¹¥È¥ê¡¼¥à $FP ¤ò¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ 
4136     $CONVERTER ¤Ë·ë¤ÓÉÕ¤±¤ë¡£¤³¤ì°Ê¹ß¤Î¥Ç¥³¡¼¥É¤ª¤è¤Ó¥¨¥ó¥³¡¼¥É¤Ï¡¢
4137     ¤³¤Î¿·¤¿¤Ë·ë¤ÓÉÕ¤±¤é¤ì¤¿¥¹¥È¥ê¡¼¥à¤ËÂФ·¤Æ¹Ô¤Ê¤ï¤ì¤ë¤è¤¦¤Ë¤Ê¤ë¡£
4138
4139     @return
4140     ¤³¤Î´Ø¿ô¤Ï¾ï¤Ë $CONVERTER ¤òÊÖ¤¹¡£
4141
4142     @latexonly \IPAlabel{mconv_rebind_stream} @endlatexonly  */
4143
4144 /***
4145     @seealso
4146     mconv_rebind_buffer () */
4147
4148 MConverter *
4149 mconv_rebind_stream (MConverter *converter, FILE *fp)
4150 {
4151   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4152
4153   if (fseek (fp, 0, SEEK_CUR) < 0)
4154     {
4155       if (errno == EBADF)
4156         return NULL;
4157       internal->seekable = 0;
4158     }
4159   else
4160     internal->seekable = 1;
4161   internal->fp = fp;
4162   internal->binding = BINDING_STREAM;
4163   return converter;
4164 }
4165
4166 /*=*/
4167
4168 /***en
4169     @brief Decode a byte sequence into an M-text.
4170
4171     The mconv_decode () function decodes a byte sequence and appends
4172     the result at the end of M-text $MT.  The source byte sequence is
4173     taken from currently bound the buffer area or the stream.
4174
4175     @return
4176     If the operation was successful, mconv_decode () returns updated
4177     $MT.  Otherwise it returns @c NULL and assigns an error code to
4178     the external variable #merror_code.  */
4179
4180 /***ja
4181     @brief ¥Ð¥¤¥ÈÎó¤ò M-text ¤Ë¥Ç¥³¡¼¥É¤¹¤ë
4182
4183     ´Ø¿ô mconv_decode () ¤Ï¡¢¥Ð¥¤¥ÈÎó¤ò¥Ç¥³¡¼¥É¤·¤Æ¤½¤Î·ë²Ì¤ò M-text
4184     $MT ¤ÎËöÈø¤ËÄɲ乤롣¥Ç¥³¡¼¥É¸µ¤Î¥Ð¥¤¥ÈÎó¤Ï¡¢¸½ºß·ë¤ÓÉÕ¤±¤é¤ì¤Æ¤¤¤ë
4185     ¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤«¤é¼è¤é¤ì¤ë¡£
4186
4187     @return
4188     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_decode () ¤Ï¹¹¿·¤µ¤ì¤¿ $MT ¤òÊÖ¤¹¡£¤½
4189     ¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
4190     ÀßÄꤹ¤ë¡£  */
4191
4192 /***
4193     @errors
4194     @c MERROR_IO, @c MERROR_CODING
4195
4196     @seealso
4197     mconv_rebind_buffer (), mconv_rebind_stream (),
4198     mconv_encode (), mconv_encode_range (),
4199     mconv_decode_buffer (), mconv_decode_stream ()  */
4200
4201 MText *
4202 mconv_decode (MConverter *converter, MText *mt)
4203 {
4204   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4205   int at_most = converter->at_most > 0 ? converter->at_most : -1;
4206   int n;
4207
4208   M_CHECK_READONLY (mt, NULL);
4209
4210   if (! mt->data)
4211     mtext__enlarge (mt, MAX_UTF8_CHAR_BYTES);
4212
4213   converter->nchars = converter->nbytes = 0;
4214   converter->result = MCONVERSION_RESULT_SUCCESS;
4215
4216   n = mtext_nchars (internal->unread);
4217   if (n > 0)
4218     {
4219       int limit = n;
4220       int i;
4221
4222       if (at_most > 0 && at_most < limit)
4223         limit = at_most;
4224
4225       for (i = 0, n -= 1; i < limit; i++, converter->nchars++, n--)
4226         mtext_cat_char (mt, mtext_ref_char (internal->unread, n));
4227       mtext_del (internal->unread, n + 1, internal->unread->nchars);
4228       if (at_most > 0)
4229         {
4230           if (at_most == limit)
4231             return mt;
4232           converter->at_most -= converter->nchars;
4233         }
4234     }
4235
4236   if (internal->binding == BINDING_BUFFER)
4237     {
4238       (*internal->coding->decoder) (internal->buf + internal->used,
4239                                     internal->bufsize - internal->used,
4240                                     mt, converter);
4241       internal->used += converter->nbytes;
4242     }  
4243   else if (internal->binding == BINDING_STREAM)
4244     {
4245       unsigned char work[CONVERT_WORKSIZE];
4246       int last_block = converter->last_block;
4247       int use_fread = at_most < 0 && internal->seekable;
4248
4249       converter->last_block = 0;
4250       while (1)
4251         {
4252           int nbytes, prev_nbytes;
4253
4254           if (feof (internal->fp))
4255             nbytes = 0;
4256           else if (use_fread)
4257             nbytes = fread (work, sizeof (unsigned char), CONVERT_WORKSIZE,
4258                             internal->fp);
4259           else
4260             {
4261               int c = getc (internal->fp);
4262
4263               if (c != EOF)
4264                 work[0] = c, nbytes = 1;
4265               else
4266                 nbytes = 0;
4267             }
4268
4269           if (ferror (internal->fp))
4270             {
4271               converter->result = MCONVERSION_RESULT_IO_ERROR;
4272               break;
4273             }
4274
4275           if (nbytes == 0)
4276             converter->last_block = last_block;
4277           prev_nbytes = converter->nbytes;
4278           (*internal->coding->decoder) (work, nbytes, mt, converter);
4279           if (converter->nbytes - prev_nbytes < nbytes)
4280             {
4281               if (use_fread)
4282                 fseek (internal->fp, converter->nbytes - prev_nbytes - nbytes,
4283                        SEEK_CUR);
4284               else
4285                 ungetc (work[0], internal->fp);
4286               break;
4287             }
4288           if (nbytes == 0
4289               || (converter->at_most > 0
4290                   && converter->nchars == converter->at_most))
4291             break;
4292         }
4293       converter->last_block = last_block;
4294     }
4295   else                          /* internal->binding == BINDING_NONE */
4296     MERROR (MERROR_CODING, NULL);
4297
4298   converter->at_most = at_most;
4299   return ((converter->result == MCONVERSION_RESULT_SUCCESS
4300            || converter->result == MCONVERSION_RESULT_INSUFFICIENT_SRC)
4301           ? mt : NULL);
4302 }
4303
4304 /*=*/
4305
4306 /***en
4307     @brief Decode a buffer area based on a coding system.
4308
4309     The mconv_decode_buffer () function decodes $N bytes of buffer
4310     area pointed to by $BUF based on the coding system $NAME.  A
4311     temporary code converter for decoding is automatically created
4312     and freed.
4313
4314     @return
4315     If the operation was successful, mconv_decode_buffer () returns
4316     the resulting M-text.  Otherwise it returns NULL and assigns an
4317     error code to the external variable #merror_code.  */
4318
4319 /***ja
4320     @brief ¥³¡¼¥É·Ï¤Ë´ð¤Å¤¤¤Æ¥Ð¥Ã¥Õ¥¡Îΰè¤ò¥Ç¥³¡¼¥É¤¹¤ë
4321
4322     ´Ø¿ô mconv_decode_buffer () ¤Ï¡¢$BUF ¤Ë¤è¤Ã¤Æ»Ø¤µ¤ì¤¿ $N ¥Ð¥¤¥È¤Î
4323     ¥Ð¥Ã¥Õ¥¡Îΰè¤ò¡¢¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤¤Æ¥Ç¥³¡¼¥É¤¹¤ë¡£¥Ç¥³¡¼¥É¤Ë
4324     É¬Íפʥ³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4325
4326     @return
4327     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_decode_buffer () ¤ÏÆÀ¤é¤ì¤¿ M-text ¤ò
4328     ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼
4329     ¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
4330
4331 /***
4332     @errors
4333     @c MERROR_IO, @c MERROR_CODING
4334
4335     @seealso
4336     mconv_decode (), mconv_decode_stream ()  */
4337
4338 MText *
4339 mconv_decode_buffer (MSymbol name, unsigned char *buf, int n)
4340 {
4341   MConverter *converter = mconv_buffer_converter (name, buf, n);
4342   MText *mt;
4343
4344   if (! converter)
4345     return NULL;
4346   mt = mtext ();
4347   if (! mconv_decode (converter, mt))
4348     {
4349       M17N_OBJECT_UNREF (mt);
4350       mt = NULL;
4351     }
4352   mconv_free_converter (converter);
4353   return mt;
4354 }
4355
4356 /*=*/
4357
4358 /***en
4359     @brief Decode a stream input based on a coding system.
4360
4361     The mconv_decode_stream () function decodes the entire byte
4362     sequence read in from stream $FP based on the coding system $NAME.
4363     A code converter for decoding is automatically created and freed.
4364
4365     @return
4366     If the operation was successful, mconv_decode_stream () returns
4367     the resulting M-text.  Otherwise it returns NULL and assigns an
4368     error code to the external variable #merror_code.  */
4369
4370 /***ja
4371     @brief ¥³¡¼¥É·Ï¤Ë´ð¤Å¤¤¤Æ¥¹¥È¥ê¡¼¥àÆþÎϤò¥Ç¥³¡¼¥É¤¹¤ë
4372
4373     ´Ø¿ô mconv_decode_stream () ¤Ï¡¢¥¹¥È¥ê¡¼¥à $FP ¤«¤éÆɤ߹þ¤Þ¤ì¤ë¥Ð
4374     ¥¤¥ÈÎóÁ´ÂΤò¡¢¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤¤Æ¥Ç¥³¡¼¥É¤¹¤ë¡£¥Ç¥³¡¼¥É¤Ëɬ
4375     Íפʥ³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4376
4377     @return
4378     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_decode_stream () ¤ÏÆÀ¤é¤ì¤¿ M-text ¤òÊÖ
4379     ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c NULL ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
4380     ¥É¤òÀßÄꤹ¤ë¡£  */
4381
4382 /***
4383     @errors
4384     @c MERROR_IO, @c MERROR_CODING
4385
4386     @seealso
4387     mconv_decode (), mconv_decode_buffer ()  */
4388
4389 MText *
4390 mconv_decode_stream (MSymbol name, FILE *fp)
4391 {
4392   MConverter *converter = mconv_stream_converter (name, fp);
4393   MText *mt;
4394
4395   if (! converter)
4396     return NULL;
4397   mt = mtext ();
4398   if (! mconv_decode (converter, mt))
4399     {
4400       M17N_OBJECT_UNREF (mt);
4401       mt = NULL;
4402     }
4403   mconv_free_converter (converter);
4404   return mt;
4405 }
4406
4407 /*=*/
4408
4409 /***en @brief Encode an M-text into a byte sequence.
4410
4411     The mconv_encode () function encodes M-text $MT and writes the
4412     resulting byte sequence into the buffer area or the stream that is
4413     currently bound to code converter $CONVERTER.
4414
4415     @return
4416     If the operation was successful, mconv_encode () returns the
4417     number of written bytes.  Otherwise it returns -1 and assigns an
4418     error code to the external variable #merror_code.  */
4419
4420 /***ja
4421     @brief M-text ¤ò¥Ð¥¤¥ÈÎó¤Ë¥¨¥ó¥³¡¼¥É¤¹¤ë
4422
4423     ´Ø¿ô mconv_encode () ¤Ï¡¢M-text $MT ¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼
4424     ¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼
4425     ¥à¤Ë½ñ¤­¹þ¤à¡£
4426
4427     @return
4428     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È¿ô¤òÊÖ¤¹¡£
4429     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄê
4430     ¤¹¤ë¡£  */
4431
4432 /***
4433     @errors
4434     @c MERROR_IO, @c MERROR_CODING
4435
4436     @seealso
4437     mconv_rebind_buffer (), mconv_rebind_stream(),
4438     mconv_decode (), mconv_encode_range ()  */
4439
4440 int
4441 mconv_encode (MConverter *converter, MText *mt)
4442 {
4443   return mconv_encode_range (converter, mt, 0, mtext_nchars (mt));
4444 }
4445
4446 /*=*/
4447
4448 /***en
4449     @brief Encode a part of an M-text
4450
4451     The mconv_encode_range () function encodes the text between $FROM
4452     (inclusive) and $TO (exclusive) in M-text $MT and writes the
4453     resulting byte sequence into the buffer area or the stream that is
4454     currently bound to code converter $CONVERTER.
4455
4456     @return
4457     If the operation was successful, mconv_encode_range () returns the
4458     number of written bytes. Otherwise it returns -1 and assigns an
4459     error code to the external variable #merror_code.  */
4460
4461 /***ja
4462     @brief M-text ¤Î°ìÉô¤ò¤ò¥Ð¥¤¥ÈÎó¤Ë¥¨¥ó¥³¡¼¥É¤¹¤ë
4463
4464     ´Ø¿ô mconv_encode_range () ¤Ï¡¢M-text $MT ¤Î $FROM ¡Ê´Þ¤à¡Ë¤«¤é 
4465     $TO ¡Ê´Þ¤Þ¤Ê¤¤¡Ë¤Þ¤Ç¤ÎÈϰϤΥƥ­¥¹¥È¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼
4466     ¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼
4467     ¥à¤Ë½ñ¤­¹þ¤à¡£
4468
4469     @return
4470     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode_range () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È¿ô
4471     ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
4472     ¥É¤òÀßÄꤹ¤ë¡£  */
4473
4474 /***
4475     @errors
4476     @c MERROR_RANGE, @c MERROR_IO, @c MERROR_CODING
4477
4478     @seealso
4479     mconv_rebind_buffer (), mconv_rebind_stream(),
4480     mconv_decode (), mconv_encode ()  */
4481
4482 int
4483 mconv_encode_range (MConverter *converter, MText *mt, int from, int to)
4484 {
4485   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4486
4487   M_CHECK_POS_X (mt, from, -1);
4488   M_CHECK_POS_X (mt, to, -1);
4489   if (to < from)
4490     to = from;
4491
4492   if (converter->at_most > 0 && from + converter->at_most < to)
4493     to = from + converter->at_most;
4494
4495   converter->nchars = converter->nbytes = 0;
4496   converter->result = MCONVERSION_RESULT_SUCCESS;
4497
4498   if (internal->binding == BINDING_BUFFER)
4499     {
4500       (*internal->coding->encoder) (mt, from, to,
4501                                     internal->buf + internal->used,
4502                                     internal->bufsize - internal->used,
4503                                     converter);
4504       internal->used += converter->nbytes;
4505     }
4506   else if (internal->binding == BINDING_STREAM)
4507     {
4508       unsigned char work[CONVERT_WORKSIZE];
4509
4510       while (from < to)
4511         {
4512           int written = 0;
4513           int prev_nbytes = converter->nbytes;
4514           int this_nbytes;
4515
4516           (*internal->coding->encoder) (mt, from, to, work,
4517                                         CONVERT_WORKSIZE, converter);
4518           this_nbytes = converter->nbytes - prev_nbytes;
4519           while (written < this_nbytes)
4520             {
4521               int wrtn = fwrite (work + written, sizeof (unsigned char),
4522                                  this_nbytes - written, internal->fp);
4523
4524               if (ferror (internal->fp))
4525                 break;
4526               written += wrtn;
4527             }
4528           if (written < this_nbytes)
4529             {
4530               converter->result = MCONVERSION_RESULT_IO_ERROR;
4531               break;
4532             }
4533           from += converter->nchars;
4534         }
4535     }
4536   else                          /* fail safe */
4537     MERROR (MERROR_CODING, -1);
4538
4539   return ((converter->result == MCONVERSION_RESULT_SUCCESS
4540            || converter->result == MCONVERSION_RESULT_INSUFFICIENT_DST)
4541           ? converter->nbytes : -1);
4542 }
4543
4544 /*=*/
4545
4546 /***en
4547     @brief Encode an M-text into a buffer area.
4548
4549     The mconv_encode_buffer () function encodes M-text $MT based on
4550     coding system $NAME and writes the resulting byte sequence into the
4551     buffer area pointed to by $BUF.  At most $N bytes are written.  A
4552     temporary code converter for encoding is automatically created
4553     and freed.
4554
4555     @return
4556     If the operation was successful, mconv_encode_buffer () returns
4557     the number of written bytes.  Otherwise it returns -1 and assigns
4558     an error code to the external variable #merror_code.  */
4559
4560 /***ja
4561     @brief M-text ¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¥Ð¥Ã¥Õ¥¡Îΰè¤Ë½ñ¤­¹þ¤à
4562
4563     ´Ø¿ô mconv_encode_buffer () ¤ÏM-text $MT ¤ò¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤
4564     ¤Æ¥¨¥ó¥³¡¼¥É¤·¡¢ÆÀ¤é¤ì¤¿¥Ð¥¤¥ÈÎó¤ò $BUF ¤Î»Ø¤¹¥Ð¥Ã¥Õ¥¡Îΰè¤Ë½ñ¤­¹þ
4565     ¤à¡£$N ¤Ï½ñ¤­¹þ¤àºÇÂç¥Ð¥¤¥È¿ô¤Ç¤¢¤ë¡£¥¨¥ó¥³¡¼¥É¤ËɬÍפʥ³¡¼¥É¥³¥ó
4566     ¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4567
4568     @return
4569     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode_buffer () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È
4570     ¿ô¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð-1¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼
4571     ¥É¤òÀßÄꤹ¤ë¡£  */
4572
4573 /***
4574     @errors
4575     @c MERROR_IO, @c MERROR_CODING
4576
4577     @seealso
4578     mconv_encode (), mconv_encode_stream ()  */
4579
4580 int
4581 mconv_encode_buffer (MSymbol name, MText *mt, unsigned char *buf, int n)
4582 {
4583   MConverter *converter = mconv_buffer_converter (name, buf, n);
4584   int ret;
4585
4586   if (! converter)
4587     return -1;
4588   ret = mconv_encode (converter, mt);
4589   mconv_free_converter (converter);
4590   return ret;
4591 }
4592
4593 /*=*/
4594
4595 /***en
4596     @brief Encode an M-text to write to a stream.
4597
4598     The mconv_encode_stream () function encodes M-text $MT based on
4599     coding system $NAME and writes the resulting byte sequence to
4600     stream $FP.  A temporary code converter for encoding is
4601     automatically created and freed.
4602
4603     @return
4604     If the operation was successful, mconv_encode_stream () returns
4605     the number of written bytes.  Otherwise it returns -1 and assigns
4606     an error code to the external variable #merror_code.  */
4607
4608 /***ja
4609     @brief M-text ¤ò¥¨¥ó¥³¡¼¥É¤·¤Æ¥¹¥È¥ê¡¼¥à¤Ë½ñ¤­¹þ¤à
4610
4611     ´Ø¿ô mconv_encode_stream () ¤ÏM-text $MT ¤ò¥³¡¼¥É·Ï $NAME ¤Ë´ð¤Å¤¤
4612     ¤Æ¥¨¥ó¥³¡¼¥É¤·¡¢ÆÀ¤é¤ì¤¿¥Ð¥¤¥ÈÎó¤ò¥¹¥È¥ê¡¼¥à $FP ¤Ë½ñ¤­½Ð¤¹¡£¥¨¥ó
4613     ¥³¡¼¥É¤ËɬÍפʥ³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ÎºîÀ®¤È²òÊü¤Ï¼«Æ°Åª¤Ë¹Ô¤Ê¤ï¤ì¤ë¡£
4614
4615     @return
4616     ¤â¤·½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_encode_stream () ¤Ï½ñ¤­¹þ¤Þ¤ì¤¿¥Ð¥¤¥È¿ô
4617     ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð-1¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É
4618     ¤òÀßÄꤹ¤ë¡£  */
4619
4620 /***
4621     @errors
4622     @c MERROR_IO, @c MERROR_CODING
4623
4624     @seealso
4625     mconv_encode (), mconv_encode_buffer (), mconv_encode_file ()  */
4626
4627 int
4628 mconv_encode_stream (MSymbol name, MText *mt, FILE *fp)
4629 {
4630   MConverter *converter = mconv_stream_converter (name, fp);
4631   int ret;
4632
4633   if (! converter)
4634     return -1;
4635   ret = mconv_encode (converter, mt);
4636   mconv_free_converter (converter);
4637   return ret;
4638 }
4639
4640 /*=*/
4641
4642 /***en
4643     @brief Read a character via a code converter.
4644
4645     The mconv_getc () function reads one character from the buffer
4646     area or the stream that is currently bound to code converter
4647     $CONVERTER.  The decoder of $CONVERTER is used to decode the byte
4648     sequence.  The internal status of $CONVERTER is updated
4649     appropriately.
4650
4651     @return
4652     If the operation was successful, mconv_getc () returns the
4653     character read in.  If the input source reaches EOF, it returns @c
4654     EOF without changing the external variable #merror_code.  If an
4655     error is detected, it returns @c EOF and assigns an error code to
4656     #merror_code.  */
4657
4658 /***ja
4659     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿·Ðͳ¤Ç1ʸ»úÆɤà
4660
4661     ´Ø¿ô mconv_getc () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±
4662     ¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤«¤é1ʸ»ú¤òÆɤ߹þ¤à¡£¥Ð¥¤
4663     ¥ÈÎó¤Î¥Ç¥³¡¼¥É¤Ë¤Ï $CONVERTER ¤Î¥Ç¥³¡¼¥À¤¬ÍѤ¤¤é¤ì¤ë¡£$CONVERTER 
4664     ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4665
4666     @return
4667     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_getc () ¤ÏÆɤ߹þ¤Þ¤ì¤¿Ê¸»ú¤òÊÖ¤¹¡£ÆþÎϸ»¤¬ 
4668     EOF ¤Ë㤷¤¿¾ì¹ç¤Ï¡¢³°ÉôÊÑ¿ô #merror_code ¤òÊѤ¨¤º¤Ë @c EOF ¤òÊÖ¤¹¡£
4669     ¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c EOF ¤òÊÖ¤·¡¢#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É
4670     ¤òÀßÄꤹ¤ë¡£  */
4671
4672 /***
4673     @errors
4674     @c MERROR_CODING
4675
4676     @seealso
4677     mconv_ungetc (), mconv_putc (), mconv_gets ()  */
4678
4679 int
4680 mconv_getc (MConverter *converter)
4681 {
4682   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4683   int at_most = converter->at_most;
4684
4685   mtext_reset (internal->work_mt);
4686   converter->at_most = 1;
4687   mconv_decode (converter, internal->work_mt);
4688   converter->at_most = at_most;
4689   return (converter->nchars == 1
4690           ? STRING_CHAR (internal->work_mt->data)
4691           : EOF);
4692 }
4693
4694 /*=*/
4695
4696 /***en
4697     @brief Push a character back to a code converter.
4698
4699     The mconv_ungetc () function pushes character $C back to code
4700     converter $CONVERTER.  Any number of characters can be pushed
4701     back.  The lastly pushed back character is firstly read by the
4702     subsequent mconv_getc () call.  The characters pushed back are
4703     registered only in $CONVERTER; they are not written to the input
4704     source.  The internal status of $CONVERTER is updated
4705     appropriately.
4706
4707     @return
4708     If the operation was successful, mconv_ungetc () returns $C.
4709     Otherwise it returns @c EOF and assigns an error code to the
4710     external variable #merror_code.  */
4711
4712 /***ja
4713     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤Ë1ʸ»úÌ᤹
4714
4715     ´Ø¿ô mconv_ungetc () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ëʸ»ú $C ¤ò
4716     ²¡¤·Ì᤹¡£²¡¤·Ì᤻¤ëʸ»ú¿ô¤ËÀ©¸Â¤Ï¤Ê¤¤¡£¤³¤Î¸å¤Ë mconv_getc () ¤ò
4717     ¸Æ¤Ó½Ð¤¹¤È¡¢ºÇ¸å¤ËÌᤵ¤ì¤¿Ê¸»ú¤¬ºÇ½é¤ËÆɤޤì¤ë¡£²¡¤·Ìᤵ¤ì¤¿Ê¸»ú¤Ï 
4718     $CONVERTER ¤ÎÆâÉô¤ËÃߤ¨¤é¤ì¤ë¤À¤±¤Ç¤¢¤ê¡¢¼ÂºÝ¤ËÆþÎϸ»¤Ë½ñ¤­¹þ¤Þ¤ì
4719     ¤ë¤ï¤±¤Ç¤Ï¤Ê¤¤¡£$CONVERTER ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4720
4721     @return
4722     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_ungetc () ¤Ï $C ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð @c
4723     EOF ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
4724
4725 /***
4726     @errors
4727     @c MERROR_CODING, @c MERROR_CHAR
4728
4729     @seealso
4730     mconv_getc (), mconv_putc (), mconv_gets ()  */
4731
4732 int
4733 mconv_ungetc (MConverter *converter, int c)
4734 {
4735   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4736
4737   M_CHECK_CHAR (c, EOF);
4738
4739   converter->result = MCONVERSION_RESULT_SUCCESS;
4740   mtext_cat_char (internal->unread, c);
4741   return c;
4742 }
4743
4744 /*=*/
4745
4746 /***en
4747     @brief Write a character via a code converter.
4748
4749     The mconv_putc () function writes character $C to the buffer area
4750     or the stream that is currently bound to code converter
4751     $CONVERTER.  The encoder of $CONVERTER is used to encode the
4752     character.  The number of bytes actually written is set to the @c
4753     nbytes member of $CONVERTER.  The internal status of $CONVERTER
4754     is updated appropriately.
4755
4756     @return
4757     If the operation was successful, mconv_putc () returns $C.
4758     If an error is detected, it returns @c EOF and assigns
4759     an error code to the external variable #merror_code.  */
4760
4761 /***ja
4762     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò·Ðͳ¤Ç1ʸ»ú½ñ¤¯
4763
4764     ´Ø¿ô mconv_putc () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±
4765     ¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤Ëʸ»ú $C ¤ò½ñ¤­½Ð¤¹¡£Ê¸»ú
4766     ¤Î¥¨¥ó¥³¡¼¥É¤Ë¤Ï $CONVERTER ¤Î¥¨¥ó¥³¡¼¥À¤¬ÍѤ¤¤é¤ì¤ë¡£¼ÂºÝ¤Ë½ñ¤­½Ð
4767     ¤µ¤ì¤¿¥Ð¥¤¥È¿ô¤Ï¡¢$CONVERTER ¤Î ¥á¥ó¥Ð¡¼ @c nbytes ¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£
4768     $CONVERTER ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4769
4770     @return
4771     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_putc () ¤Ï $C ¤òÊÖ¤¹¡£¥¨¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç
4772     ¤Ï @c EOF ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
4773
4774 /***
4775     @errors
4776     @c MERROR_CODING, @c MERROR_IO, @c MERROR_CHAR
4777
4778     @seealso
4779     mconv_getc (), mconv_ungetc (), mconv_gets ()  */
4780
4781 int
4782 mconv_putc (MConverter *converter, int c)
4783 {
4784   MConverterStatus *internal = (MConverterStatus *) converter->internal_info;
4785
4786   M_CHECK_CHAR (c, EOF);
4787   mtext_reset (internal->work_mt);
4788   mtext_cat_char (internal->work_mt, c);
4789   if (mconv_encode_range (converter, internal->work_mt, 0, 1) < 0)
4790     return EOF;
4791   return c;
4792 }
4793
4794 /*=*/
4795
4796 /***en
4797     @brief Read a line using a code converter.
4798
4799     The mconv_gets () function reads one line from the buffer area or
4800     the stream that is currently bound to code converter $CONVERTER.
4801     The decoder of $CONVERTER is used for decoding.  The decoded
4802     character sequence is appended at the end of M-text $MT.  The
4803     final newline character in the original byte sequence is not
4804     appended.  The internal status of $CONVERTER is updated
4805     appropriately.
4806
4807     @return
4808     If the operation was successful, mconv_gets () returns the
4809     modified $MT.  If it encounters EOF without reading a single
4810     character, it returns $MT without changing it.  If an error is
4811     detected, it returns @c NULL and assigns an error code to @c
4812     merror_code.  */
4813
4814 /***ja
4815     @brief ¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿¤ò»È¤Ã¤Æ1¹ÔÆɤà
4816
4817     ´Ø¿ô mconv_gets () ¤Ï¡¢¥³¡¼¥É¥³¥ó¥Ð¡¼¥¿ $CONVERTER ¤Ë¸½ºß·ë¤ÓÉÕ¤±
4818     ¤é¤ì¤Æ¤¤¤ë¥Ð¥Ã¥Õ¥¡Îΰ褢¤ë¤¤¤Ï¥¹¥È¥ê¡¼¥à¤«¤é1¹Ô¤òÆɤ߹þ¤à¡£¥Ð¥¤¥È
4819     Îó¤Î¥Ç¥³¡¼¥É¤Ë¤Ï $CONVERTER ¤Î¥Ç¥³¡¼¥À¤¬ÍѤ¤¤é¤ì¤ë¡£¥Ç¥³¡¼¥É¤µ¤ì¤¿
4820     Ê¸»úÎó¤Ï M-text $MT ¤ÎËöÈø¤ËÄɲ䵤ì¤ë¡£¸µ¤Î¥Ð¥¤¥ÈÎó¤Î½ªÃ¼²þ¹Ôʸ»ú
4821     ¤ÏÄɲ䵤ì¤Ê¤¤¡£$CONVERTER ¤ÎÆâÉô¾õÂÖ¤ÏɬÍפ˱þ¤¸¤Æ¹¹¿·¤µ¤ì¤ë¡£
4822
4823     @return
4824     ½èÍý¤¬À®¸ù¤¹¤ì¤Ð¡¢mconv_gets () ¤ÏÊѹ¹¤µ¤ì¤¿ $MT ¤òÊÖ¤¹¡£¤â¤·1ʸ»ú
4825     ¤âÆɤޤº¤Ë EOF ¤ËÅö¤¿¤Ã¤¿¾ì¹ç¤Ï¡¢$MT ¤òÊѹ¹¤»¤º¤Ë¤½¤Î¤Þ¤ÞÊÖ¤¹¡£¥¨
4826     ¥é¡¼¤¬¸¡½Ð¤µ¤ì¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤·¡¢#merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
4827     ÀßÄꤹ¤ë¡£  */
4828
4829 /***
4830     @errors
4831     @c MERROR_CODING
4832
4833     @seealso
4834     mconv_getc (), mconv_ungetc (), mconv_putc ()  */
4835
4836 MText *
4837 mconv_gets (MConverter *converter, MText *mt)
4838 {
4839   int c;
4840
4841   M_CHECK_READONLY (mt, NULL);
4842   while (1)
4843     {
4844       c = mconv_getc (converter);
4845       if (c == EOF || c == '\n')
4846         break;
4847       mtext_cat_char (mt, c);
4848     }
4849   if (c == EOF && converter->result != MCONVERSION_RESULT_SUCCESS)
4850     /* mconv_getc () sets merror_code */
4851     return NULL;
4852   return mt;
4853 }
4854
4855 /*=*/
4856
4857 /*** @} */
4858
4859 /*
4860   Local Variables:
4861   coding: euc-japan
4862   End:
4863 */