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