038ec5b1d50c4f3786772d8a3ba73bcc66a67509
[chise/xemacs-chise.git.1] / src / mule-charset.c
1 /* Functions to handle multilingual characters.
2    Copyright (C) 1992, 1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1999,2000,2001,2002,2003 MORIOKA Tomohiko
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 /* Rewritten by Ben Wing <ben@xemacs.org>. */
24
25 /* Rewritten by MORIOKA Tomohiko <tomo@m17n.org> for XEmacs UTF-2000. */
26
27 #include <config.h>
28 #ifdef UTF2000
29 #include <limits.h>
30 #endif
31 #include "lisp.h"
32
33 #include "buffer.h"
34 #include "chartab.h"
35 #include "elhash.h"
36 #include "lstream.h"
37 #include "device.h"
38 #include "faces.h"
39 #include "mule-ccl.h"
40
41 /* The various pre-defined charsets. */
42
43 Lisp_Object Vcharset_ascii;
44 Lisp_Object Vcharset_control_1;
45 Lisp_Object Vcharset_latin_iso8859_1;
46 Lisp_Object Vcharset_latin_iso8859_2;
47 Lisp_Object Vcharset_latin_iso8859_3;
48 Lisp_Object Vcharset_latin_iso8859_4;
49 Lisp_Object Vcharset_thai_tis620;
50 Lisp_Object Vcharset_greek_iso8859_7;
51 Lisp_Object Vcharset_arabic_iso8859_6;
52 Lisp_Object Vcharset_hebrew_iso8859_8;
53 Lisp_Object Vcharset_katakana_jisx0201;
54 Lisp_Object Vcharset_latin_jisx0201;
55 Lisp_Object Vcharset_cyrillic_iso8859_5;
56 Lisp_Object Vcharset_latin_iso8859_9;
57 Lisp_Object Vcharset_japanese_jisx0208_1978;
58 Lisp_Object Vcharset_chinese_gb2312;
59 Lisp_Object Vcharset_chinese_gb12345;
60 Lisp_Object Vcharset_japanese_jisx0208;
61 Lisp_Object Vcharset_japanese_jisx0208_1990;
62 Lisp_Object Vcharset_korean_ksc5601;
63 Lisp_Object Vcharset_japanese_jisx0212;
64 Lisp_Object Vcharset_chinese_cns11643_1;
65 Lisp_Object Vcharset_chinese_cns11643_2;
66 #ifdef UTF2000
67 Lisp_Object Vcharset_ucs;
68 Lisp_Object Vcharset_ucs_bmp;
69 Lisp_Object Vcharset_ucs_smp;
70 Lisp_Object Vcharset_ucs_sip;
71 Lisp_Object Vcharset_latin_viscii;
72 Lisp_Object Vcharset_latin_tcvn5712;
73 Lisp_Object Vcharset_latin_viscii_lower;
74 Lisp_Object Vcharset_latin_viscii_upper;
75 Lisp_Object Vcharset_jis_x0208;
76 Lisp_Object Vcharset_chinese_big5;
77 Lisp_Object Vcharset_ethiopic_ucs;
78 #endif
79 Lisp_Object Vcharset_chinese_big5_1;
80 Lisp_Object Vcharset_chinese_big5_2;
81
82 #ifdef ENABLE_COMPOSITE_CHARS
83 Lisp_Object Vcharset_composite;
84
85 /* Hash tables for composite chars.  One maps string representing
86    composed chars to their equivalent chars; one goes the
87    other way. */
88 Lisp_Object Vcomposite_char_char2string_hash_table;
89 Lisp_Object Vcomposite_char_string2char_hash_table;
90
91 static int composite_char_row_next;
92 static int composite_char_col_next;
93
94 #endif /* ENABLE_COMPOSITE_CHARS */
95
96 struct charset_lookup *chlook;
97
98 static const struct lrecord_description charset_lookup_description_1[] = {
99   { XD_LISP_OBJECT_ARRAY, offsetof (struct charset_lookup, charset_by_leading_byte),
100 #ifdef UTF2000
101     NUM_LEADING_BYTES+4*128
102 #else
103     128+4*128*2 
104 #endif
105   }, { XD_END }
106 };
107
108 static const struct struct_description charset_lookup_description = {
109   sizeof (struct charset_lookup),
110   charset_lookup_description_1
111 };
112
113 #ifndef UTF2000
114 /* Table of number of bytes in the string representation of a character
115    indexed by the first byte of that representation.
116
117    rep_bytes_by_first_byte(c) is more efficient than the equivalent
118    canonical computation:
119
120    XCHARSET_REP_BYTES (CHARSET_BY_LEADING_BYTE (c)) */
121
122 const Bytecount rep_bytes_by_first_byte[0xA0] =
123 { /* 0x00 - 0x7f are for straight ASCII */
124   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
125   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
126   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
127   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
128   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
129   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
130   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
131   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
132   /* 0x80 - 0x8f are for Dimension-1 official charsets */
133 #ifdef CHAR_IS_UCS4
134   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
135 #else
136   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
137 #endif
138   /* 0x90 - 0x9d are for Dimension-2 official charsets */
139   /* 0x9e is for Dimension-1 private charsets */
140   /* 0x9f is for Dimension-2 private charsets */
141   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4
142 };
143 #endif
144
145 #ifdef UTF2000
146
147 int decoding_table_check_elements (Lisp_Object v, int dim, int ccs_len);
148 int
149 decoding_table_check_elements (Lisp_Object v, int dim, int ccs_len)
150 {
151   int i;
152
153   if (XVECTOR_LENGTH (v) > ccs_len)
154     return -1;
155
156   for (i = 0; i < XVECTOR_LENGTH (v); i++)
157     {
158       Lisp_Object c = XVECTOR_DATA(v)[i];
159
160       if (!NILP (c) && !CHARP (c))
161         {
162           if (VECTORP (c))
163             {
164               int ret = decoding_table_check_elements (c, dim - 1, ccs_len);
165               if (ret)
166                 return ret;
167             }
168           else
169             return -2;
170         }
171     }
172   return 0;
173 }
174
175 Lisp_Object
176 put_char_ccs_code_point (Lisp_Object character,
177                          Lisp_Object ccs, Lisp_Object value)
178 {
179   if (!EQ (XCHARSET_NAME (ccs), Qmap_ucs)
180       || !INTP (value)
181       || (XCHAR (character) != XINT (value)))
182     {
183       Lisp_Object v = XCHARSET_DECODING_TABLE (ccs);
184       int code_point;
185
186       if (CONSP (value))
187         { /* obsolete representation: value must be a list of bytes */
188           Lisp_Object ret = Fcar (value);
189           Lisp_Object rest;
190
191           if (!INTP (ret))
192             signal_simple_error ("Invalid value for coded-charset", value);
193           code_point = XINT (ret);
194           if (XCHARSET_GRAPHIC (ccs) == 1)
195             code_point &= 0x7F;
196           rest = Fcdr (value);
197           while (!NILP (rest))
198             {
199               int j;
200
201               if (!CONSP (rest))
202                 signal_simple_error ("Invalid value for coded-charset",
203                                      value);
204               ret = Fcar (rest);
205               if (!INTP (ret))
206                 signal_simple_error ("Invalid value for coded-charset",
207                                      value);
208               j = XINT (ret);
209               if (XCHARSET_GRAPHIC (ccs) == 1)
210                 j &= 0x7F;
211               code_point = (code_point << 8) | j;
212               rest = Fcdr (rest);
213             }
214           value = make_int (code_point);
215         }
216       else if (INTP (value))
217         {
218           code_point = XINT (value);
219           if (XCHARSET_GRAPHIC (ccs) == 1)
220             {
221               code_point &= 0x7F7F7F7F;
222               value = make_int (code_point);
223             }
224         }
225       else
226         signal_simple_error ("Invalid value for coded-charset", value);
227
228       if (VECTORP (v))
229         {
230           Lisp_Object cpos = Fget_char_attribute (character, ccs, Qnil);
231           if (INTP (cpos))
232             {
233               decoding_table_remove_char (ccs, XINT (cpos));
234             }
235         }
236       decoding_table_put_char (ccs, code_point, character);
237     }
238   return value;
239 }
240
241 Lisp_Object
242 remove_char_ccs (Lisp_Object character, Lisp_Object ccs)
243 {
244   Lisp_Object decoding_table = XCHARSET_DECODING_TABLE (ccs);
245   Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
246
247   if (VECTORP (decoding_table))
248     {
249       Lisp_Object cpos = Fget_char_attribute (character, ccs, Qnil);
250
251       if (!NILP (cpos))
252         {
253           decoding_table_remove_char (ccs, XINT (cpos));
254         }
255     }
256   if (CHAR_TABLEP (encoding_table))
257     {
258       put_char_id_table (XCHAR_TABLE(encoding_table), character, Qunbound);
259     }
260   return Qt;
261 }
262
263 #endif
264
265 #ifndef UTF2000
266 int leading_code_private_11;
267 #endif
268
269 Lisp_Object Qcharsetp;
270
271 /* Qdoc_string, Qdimension, Qchars defined in general.c */
272 Lisp_Object Qregistry, Qfinal, Qgraphic;
273 Lisp_Object Qdirection;
274 Lisp_Object Qreverse_direction_charset;
275 Lisp_Object Qleading_byte;
276 Lisp_Object Qshort_name, Qlong_name;
277 #ifdef UTF2000
278 Lisp_Object Qmin_code, Qmax_code, Qcode_offset;
279 Lisp_Object Qmother, Qconversion, Q94x60, Q94x94x60, Qbig5_1, Qbig5_2;
280 #endif
281
282 Lisp_Object Qascii,
283   Qcontrol_1,
284   Qlatin_iso8859_1,
285   Qlatin_iso8859_2,
286   Qlatin_iso8859_3,
287   Qlatin_iso8859_4,
288   Qthai_tis620,
289   Qgreek_iso8859_7,
290   Qarabic_iso8859_6,
291   Qhebrew_iso8859_8,
292   Qkatakana_jisx0201,
293   Qlatin_jisx0201,
294   Qcyrillic_iso8859_5,
295   Qlatin_iso8859_9,
296   Qjapanese_jisx0208_1978,
297   Qchinese_gb2312,
298   Qchinese_gb12345,
299   Qjapanese_jisx0208,
300   Qkorean_ksc5601,
301   Qjapanese_jisx0212,
302   Qchinese_cns11643_1,
303   Qchinese_cns11643_2,
304 #ifdef UTF2000
305   Qmap_ucs, Qucs,
306   Qucs_bmp,
307   Qucs_smp,
308   Qucs_sip,
309   Qlatin_viscii,
310   Qlatin_tcvn5712,
311   Qlatin_viscii_lower,
312   Qlatin_viscii_upper,
313   Qvietnamese_viscii_lower,
314   Qvietnamese_viscii_upper,
315   Qmap_jis_x0208,
316   Qmap_jis_x0208_1990,
317   Qchinese_big5,
318   Qethiopic_ucs,
319 #endif
320   Qchinese_big5_1,
321   Qchinese_big5_2,
322   Qcomposite;
323
324 Lisp_Object Ql2r, Qr2l;
325
326 Lisp_Object Vcharset_hash_table;
327
328 /* Composite characters are characters constructed by overstriking two
329    or more regular characters.
330
331    1) The old Mule implementation involves storing composite characters
332       in a buffer as a tag followed by all of the actual characters
333       used to make up the composite character.  I think this is a bad
334       idea; it greatly complicates code that wants to handle strings
335       one character at a time because it has to deal with the possibility
336       of great big ungainly characters.  It's much more reasonable to
337       simply store an index into a table of composite characters.
338
339    2) The current implementation only allows for 16,384 separate
340       composite characters over the lifetime of the XEmacs process.
341       This could become a potential problem if the user
342       edited lots of different files that use composite characters.
343       Due to FSF bogosity, increasing the number of allowable
344       composite characters under Mule would decrease the number
345       of possible faces that can exist.  Mule already has shrunk
346       this to 2048, and further shrinkage would become uncomfortable.
347       No such problems exist in XEmacs.
348
349       Composite characters could be represented as 0x80 C1 C2 C3,
350       where each C[1-3] is in the range 0xA0 - 0xFF.  This allows
351       for slightly under 2^20 (one million) composite characters
352       over the XEmacs process lifetime, and you only need to
353       increase the size of a Mule character from 19 to 21 bits.
354       Or you could use 0x80 C1 C2 C3 C4, allowing for about
355       85 million (slightly over 2^26) composite characters. */
356
357 \f
358 /************************************************************************/
359 /*                       Basic Emchar functions                         */
360 /************************************************************************/
361
362 /* Convert a non-ASCII Mule character C into a one-character Mule-encoded
363    string in STR.  Returns the number of bytes stored.
364    Do not call this directly.  Use the macro set_charptr_emchar() instead.
365  */
366
367 Bytecount
368 non_ascii_set_charptr_emchar (Bufbyte *str, Emchar c)
369 {
370   Bufbyte *p;
371 #ifndef UTF2000
372   Charset_ID lb;
373   int c1, c2;
374   Lisp_Object charset;
375 #endif
376
377   p = str;
378 #ifdef UTF2000
379   if ( c <= 0x7f )
380     {
381       *p++ = c;
382     }
383   else if ( c <= 0x7ff )
384     {
385       *p++ = (c >> 6) | 0xc0;
386       *p++ = (c & 0x3f) | 0x80;
387     }
388   else if ( c <= 0xffff )
389     {
390       *p++ =  (c >> 12) | 0xe0;
391       *p++ = ((c >>  6) & 0x3f) | 0x80;
392       *p++ =  (c        & 0x3f) | 0x80;
393     }
394   else if ( c <= 0x1fffff )
395     {
396       *p++ =  (c >> 18) | 0xf0;
397       *p++ = ((c >> 12) & 0x3f) | 0x80;
398       *p++ = ((c >>  6) & 0x3f) | 0x80;
399       *p++ =  (c        & 0x3f) | 0x80;
400     }
401   else if ( c <= 0x3ffffff )
402     {
403       *p++ =  (c >> 24) | 0xf8;
404       *p++ = ((c >> 18) & 0x3f) | 0x80;
405       *p++ = ((c >> 12) & 0x3f) | 0x80;
406       *p++ = ((c >>  6) & 0x3f) | 0x80;
407       *p++ =  (c        & 0x3f) | 0x80;
408     }
409   else
410     {
411       *p++ =  (c >> 30) | 0xfc;
412       *p++ = ((c >> 24) & 0x3f) | 0x80;
413       *p++ = ((c >> 18) & 0x3f) | 0x80;
414       *p++ = ((c >> 12) & 0x3f) | 0x80;
415       *p++ = ((c >>  6) & 0x3f) | 0x80;
416       *p++ =  (c        & 0x3f) | 0x80;
417     }
418 #else
419   BREAKUP_CHAR (c, charset, c1, c2);
420   lb = CHAR_LEADING_BYTE (c);
421   if (LEADING_BYTE_PRIVATE_P (lb))
422     *p++ = PRIVATE_LEADING_BYTE_PREFIX (lb);
423   *p++ = lb;
424   if (EQ (charset, Vcharset_control_1))
425     c1 += 0x20;
426   *p++ = c1 | 0x80;
427   if (c2)
428     *p++ = c2 | 0x80;
429 #endif
430   return (p - str);
431 }
432
433 /* Return the first character from a Mule-encoded string in STR,
434    assuming it's non-ASCII.  Do not call this directly.
435    Use the macro charptr_emchar() instead. */
436
437 Emchar
438 non_ascii_charptr_emchar (const Bufbyte *str)
439 {
440 #ifdef UTF2000
441   Bufbyte b;
442   Emchar ch;
443   int len;
444
445   b = *str++;
446   if ( b >= 0xfc )
447     {
448       ch = (b & 0x01);
449       len = 5;
450     }
451   else if ( b >= 0xf8 )
452     {
453       ch = b & 0x03;
454       len = 4;
455     }
456   else if ( b >= 0xf0 )
457     {
458       ch = b & 0x07;
459       len = 3;
460     }
461   else if ( b >= 0xe0 )
462     {
463       ch = b & 0x0f;
464       len = 2;
465     }
466   else if ( b >= 0xc0 )
467     {
468       ch = b & 0x1f;
469       len = 1;
470     }
471   else
472     {
473       ch = b;
474       len = 0;
475     }
476   for( ; len > 0; len-- )
477     {
478       b = *str++;
479       ch = ( ch << 6 ) | ( b & 0x3f );
480     }
481   return ch;
482 #else
483   Bufbyte i0 = *str, i1, i2 = 0;
484   Lisp_Object charset;
485
486   if (i0 == LEADING_BYTE_CONTROL_1)
487     return (Emchar) (*++str - 0x20);
488
489   if (LEADING_BYTE_PREFIX_P (i0))
490     i0 = *++str;
491
492   i1 = *++str & 0x7F;
493
494   charset = CHARSET_BY_LEADING_BYTE (i0);
495   if (XCHARSET_DIMENSION (charset) == 2)
496     i2 = *++str & 0x7F;
497
498   return MAKE_CHAR (charset, i1, i2);
499 #endif
500 }
501
502 /* Return whether CH is a valid Emchar, assuming it's non-ASCII.
503    Do not call this directly.  Use the macro valid_char_p() instead. */
504
505 #ifndef UTF2000
506 int
507 non_ascii_valid_char_p (Emchar ch)
508 {
509   int f1, f2, f3;
510
511   /* Must have only lowest 19 bits set */
512   if (ch & ~0x7FFFF)
513     return 0;
514
515   f1 = CHAR_FIELD1 (ch);
516   f2 = CHAR_FIELD2 (ch);
517   f3 = CHAR_FIELD3 (ch);
518
519   if (f1 == 0)
520     {
521       Lisp_Object charset;
522
523       if (f2 < MIN_CHAR_FIELD2_OFFICIAL ||
524           (f2 > MAX_CHAR_FIELD2_OFFICIAL && f2 < MIN_CHAR_FIELD2_PRIVATE) ||
525            f2 > MAX_CHAR_FIELD2_PRIVATE)
526         return 0;
527       if (f3 < 0x20)
528         return 0;
529
530       if (f3 != 0x20 && f3 != 0x7F && !(f2 >= MIN_CHAR_FIELD2_PRIVATE &&
531                                         f2 <= MAX_CHAR_FIELD2_PRIVATE))
532         return 1;
533
534       /*
535          NOTE: This takes advantage of the fact that
536          FIELD2_TO_OFFICIAL_LEADING_BYTE and
537          FIELD2_TO_PRIVATE_LEADING_BYTE are the same.
538          */
539       charset = CHARSET_BY_LEADING_BYTE (f2 + FIELD2_TO_OFFICIAL_LEADING_BYTE);
540       if (EQ (charset, Qnil))
541         return 0;
542       return (XCHARSET_CHARS (charset) == 96);
543     }
544   else
545     {
546       Lisp_Object charset;
547
548       if (f1 < MIN_CHAR_FIELD1_OFFICIAL ||
549           (f1 > MAX_CHAR_FIELD1_OFFICIAL && f1 < MIN_CHAR_FIELD1_PRIVATE) ||
550           f1 > MAX_CHAR_FIELD1_PRIVATE)
551         return 0;
552       if (f2 < 0x20 || f3 < 0x20)
553         return 0;
554
555 #ifdef ENABLE_COMPOSITE_CHARS
556       if (f1 + FIELD1_TO_OFFICIAL_LEADING_BYTE == LEADING_BYTE_COMPOSITE)
557         {
558           if (UNBOUNDP (Fgethash (make_int (ch),
559                                   Vcomposite_char_char2string_hash_table,
560                                   Qunbound)))
561             return 0;
562           return 1;
563         }
564 #endif /* ENABLE_COMPOSITE_CHARS */
565
566       if (f2 != 0x20 && f2 != 0x7F && f3 != 0x20 && f3 != 0x7F
567           && !(f1 >= MIN_CHAR_FIELD1_PRIVATE && f1 <= MAX_CHAR_FIELD1_PRIVATE))
568         return 1;
569
570       if (f1 <= MAX_CHAR_FIELD1_OFFICIAL)
571         charset =
572           CHARSET_BY_LEADING_BYTE (f1 + FIELD1_TO_OFFICIAL_LEADING_BYTE);
573       else
574         charset =
575           CHARSET_BY_LEADING_BYTE (f1 + FIELD1_TO_PRIVATE_LEADING_BYTE);
576
577       if (EQ (charset, Qnil))
578         return 0;
579       return (XCHARSET_CHARS (charset) == 96);
580     }
581 }
582 #endif
583
584 \f
585 /************************************************************************/
586 /*                       Basic string functions                         */
587 /************************************************************************/
588
589 /* Copy the character pointed to by SRC into DST.  Do not call this
590    directly.  Use the macro charptr_copy_char() instead.
591    Return the number of bytes copied.  */
592
593 Bytecount
594 non_ascii_charptr_copy_char (const Bufbyte *src, Bufbyte *dst)
595 {
596   unsigned int bytes = REP_BYTES_BY_FIRST_BYTE (*src);
597   unsigned int i;
598   for (i = bytes; i; i--, dst++, src++)
599     *dst = *src;
600   return bytes;
601 }
602
603 \f
604 /************************************************************************/
605 /*                        streams of Emchars                            */
606 /************************************************************************/
607
608 /* Treat a stream as a stream of Emchar's rather than a stream of bytes.
609    The functions below are not meant to be called directly; use
610    the macros in insdel.h. */
611
612 Emchar
613 Lstream_get_emchar_1 (Lstream *stream, int ch)
614 {
615   Bufbyte str[MAX_EMCHAR_LEN];
616   Bufbyte *strptr = str;
617   unsigned int bytes;
618
619   str[0] = (Bufbyte) ch;
620
621   for (bytes = REP_BYTES_BY_FIRST_BYTE (ch) - 1; bytes; bytes--)
622     {
623       int c = Lstream_getc (stream);
624       bufpos_checking_assert (c >= 0);
625       *++strptr = (Bufbyte) c;
626     }
627   return charptr_emchar (str);
628 }
629
630 int
631 Lstream_fput_emchar (Lstream *stream, Emchar ch)
632 {
633   Bufbyte str[MAX_EMCHAR_LEN];
634   Bytecount len = set_charptr_emchar (str, ch);
635   return Lstream_write (stream, str, len);
636 }
637
638 void
639 Lstream_funget_emchar (Lstream *stream, Emchar ch)
640 {
641   Bufbyte str[MAX_EMCHAR_LEN];
642   Bytecount len = set_charptr_emchar (str, ch);
643   Lstream_unread (stream, str, len);
644 }
645
646 \f
647 /************************************************************************/
648 /*                            charset object                            */
649 /************************************************************************/
650
651 static Lisp_Object
652 mark_charset (Lisp_Object obj)
653 {
654   Lisp_Charset *cs = XCHARSET (obj);
655
656   mark_object (cs->short_name);
657   mark_object (cs->long_name);
658   mark_object (cs->doc_string);
659   mark_object (cs->registry);
660   mark_object (cs->ccl_program);
661 #ifdef UTF2000
662   mark_object (cs->decoding_table);
663   mark_object (cs->mother);
664 #endif
665   return cs->name;
666 }
667
668 static void
669 print_charset (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
670 {
671   Lisp_Charset *cs = XCHARSET (obj);
672   char buf[200];
673
674   if (print_readably)
675     error ("printing unreadable object #<charset %s 0x%x>",
676            string_data (XSYMBOL (CHARSET_NAME (cs))->name),
677            cs->header.uid);
678
679   write_c_string ("#<charset ", printcharfun);
680   print_internal (CHARSET_NAME (cs), printcharfun, 0);
681   write_c_string (" ", printcharfun);
682   print_internal (CHARSET_SHORT_NAME (cs), printcharfun, 1);
683   write_c_string (" ", printcharfun);
684   print_internal (CHARSET_LONG_NAME (cs), printcharfun, 1);
685   write_c_string (" ", printcharfun);
686   print_internal (CHARSET_DOC_STRING (cs), printcharfun, 1);
687   sprintf (buf, " %d^%d %s cols=%d g%d final='%c' reg=",
688            CHARSET_CHARS (cs),
689            CHARSET_DIMENSION (cs),
690            CHARSET_DIRECTION (cs) == CHARSET_LEFT_TO_RIGHT ? "l2r" : "r2l",
691            CHARSET_COLUMNS (cs),
692            CHARSET_GRAPHIC (cs),
693            CHARSET_FINAL (cs));
694   write_c_string (buf, printcharfun);
695   print_internal (CHARSET_REGISTRY (cs), printcharfun, 0);
696   sprintf (buf, " 0x%x>", cs->header.uid);
697   write_c_string (buf, printcharfun);
698 }
699
700 static const struct lrecord_description charset_description[] = {
701   { XD_LISP_OBJECT, offsetof (Lisp_Charset, name) },
702   { XD_LISP_OBJECT, offsetof (Lisp_Charset, doc_string) },
703   { XD_LISP_OBJECT, offsetof (Lisp_Charset, registry) },
704   { XD_LISP_OBJECT, offsetof (Lisp_Charset, short_name) },
705   { XD_LISP_OBJECT, offsetof (Lisp_Charset, long_name) },
706   { XD_LISP_OBJECT, offsetof (Lisp_Charset, reverse_direction_charset) },
707   { XD_LISP_OBJECT, offsetof (Lisp_Charset, ccl_program) },
708 #ifdef UTF2000
709   { XD_LISP_OBJECT, offsetof (Lisp_Charset, decoding_table) },
710   { XD_LISP_OBJECT, offsetof (Lisp_Charset, mother) },
711 #endif
712   { XD_END }
713 };
714
715 DEFINE_LRECORD_IMPLEMENTATION ("charset", charset,
716                                mark_charset, print_charset, 0, 0, 0,
717                                charset_description,
718                                Lisp_Charset);
719
720 /* Make a new charset. */
721 /* #### SJT Should generic properties be allowed? */
722 static Lisp_Object
723 make_charset (Charset_ID id, Lisp_Object name,
724               unsigned short chars, unsigned char dimension,
725               unsigned char columns, unsigned char graphic,
726               Bufbyte final, unsigned char direction, Lisp_Object short_name,
727               Lisp_Object long_name, Lisp_Object doc,
728               Lisp_Object reg,
729               Lisp_Object decoding_table,
730               Emchar min_code, Emchar max_code,
731               Emchar code_offset, unsigned char byte_offset,
732               Lisp_Object mother, unsigned char conversion)
733 {
734   Lisp_Object obj;
735   Lisp_Charset *cs = alloc_lcrecord_type (Lisp_Charset, &lrecord_charset);
736
737   zero_lcrecord (cs);
738
739   XSETCHARSET (obj, cs);
740
741   CHARSET_ID            (cs) = id;
742   CHARSET_NAME          (cs) = name;
743   CHARSET_SHORT_NAME    (cs) = short_name;
744   CHARSET_LONG_NAME     (cs) = long_name;
745   CHARSET_CHARS         (cs) = chars;
746   CHARSET_DIMENSION     (cs) = dimension;
747   CHARSET_DIRECTION     (cs) = direction;
748   CHARSET_COLUMNS       (cs) = columns;
749   CHARSET_GRAPHIC       (cs) = graphic;
750   CHARSET_FINAL         (cs) = final;
751   CHARSET_DOC_STRING    (cs) = doc;
752   CHARSET_REGISTRY      (cs) = reg;
753   CHARSET_CCL_PROGRAM   (cs) = Qnil;
754   CHARSET_REVERSE_DIRECTION_CHARSET (cs) = Qnil;
755 #ifdef UTF2000
756   CHARSET_DECODING_TABLE(cs) = Qunbound;
757   CHARSET_MIN_CODE      (cs) = min_code;
758   CHARSET_MAX_CODE      (cs) = max_code;
759   CHARSET_CODE_OFFSET   (cs) = code_offset;
760   CHARSET_BYTE_OFFSET   (cs) = byte_offset;
761   CHARSET_MOTHER        (cs) = mother;
762   CHARSET_CONVERSION    (cs) = conversion;
763 #endif
764
765 #ifndef UTF2000
766   if (id == LEADING_BYTE_ASCII)
767     CHARSET_REP_BYTES (cs) = 1;
768   else if (id < 0xA0)
769     CHARSET_REP_BYTES (cs) = CHARSET_DIMENSION (cs) + 1;
770   else
771     CHARSET_REP_BYTES (cs) = CHARSET_DIMENSION (cs) + 2;
772 #endif
773
774   if (final)
775     {
776       /* some charsets do not have final characters.  This includes
777          ASCII, Control-1, Composite, and the two faux private
778          charsets. */
779       unsigned char iso2022_type
780         = (dimension == 1 ? 0 : 2) + (chars == 94 ? 0 : 1);
781 #if UTF2000
782       if (code_offset == 0)
783         {
784           assert (NILP (chlook->charset_by_attributes[iso2022_type][final]));
785           chlook->charset_by_attributes[iso2022_type][final] = obj;
786         }
787 #else
788       assert (NILP
789               (chlook->charset_by_attributes[iso2022_type][final][direction]));
790       chlook->charset_by_attributes[iso2022_type][final][direction] = obj;
791 #endif
792     }
793
794   assert (NILP (chlook->charset_by_leading_byte[id - MIN_LEADING_BYTE]));
795   chlook->charset_by_leading_byte[id - MIN_LEADING_BYTE] = obj;
796
797   /* Some charsets are "faux" and don't have names or really exist at
798      all except in the leading-byte table. */
799   if (!NILP (name))
800     Fputhash (name, obj, Vcharset_hash_table);
801   return obj;
802 }
803
804 static int
805 get_unallocated_leading_byte (int dimension)
806 {
807   Charset_ID lb;
808
809 #ifdef UTF2000
810   if (chlook->next_allocated_leading_byte > MAX_LEADING_BYTE_PRIVATE)
811     lb = 0;
812   else
813     lb = chlook->next_allocated_leading_byte++;
814 #else
815   if (dimension == 1)
816     {
817       if (chlook->next_allocated_1_byte_leading_byte > MAX_LEADING_BYTE_PRIVATE_1)
818         lb = 0;
819       else
820         lb = chlook->next_allocated_1_byte_leading_byte++;
821     }
822   else
823     {
824       if (chlook->next_allocated_2_byte_leading_byte > MAX_LEADING_BYTE_PRIVATE_2)
825         lb = 0;
826       else
827         lb = chlook->next_allocated_2_byte_leading_byte++;
828     }
829 #endif
830
831   if (!lb)
832     signal_simple_error
833       ("No more character sets free for this dimension",
834        make_int (dimension));
835
836   return lb;
837 }
838
839 #ifdef UTF2000
840 /* Number of Big5 characters which have the same code in 1st byte.  */
841
842 #define BIG5_SAME_ROW (0xFF - 0xA1 + 0x7F - 0x40)
843
844 Emchar
845 decode_defined_char (Lisp_Object ccs, int code_point)
846 {
847   int dim = XCHARSET_DIMENSION (ccs);
848   Lisp_Object decoding_table = XCHARSET_DECODING_TABLE (ccs);
849   Emchar char_id = -1;
850   Lisp_Object mother;
851
852   while (dim > 0)
853     {
854       dim--;
855       decoding_table
856         = get_ccs_octet_table (decoding_table, ccs,
857                                (code_point >> (dim * 8)) & 255);
858     }
859   if (CHARP (decoding_table))
860     return XCHAR (decoding_table);
861 #ifdef HAVE_CHISE_CLIENT
862   if (EQ (decoding_table, Qunloaded))
863     {
864       char_id = load_char_decoding_entry_maybe (ccs, code_point);
865     }
866 #endif
867   if (char_id >= 0)
868     return char_id;
869   else if ( CHARSETP (mother = XCHARSET_MOTHER (ccs)) )
870     {
871       if ( XCHARSET_CONVERSION (ccs) == CONVERSION_IDENTICAL )
872         {
873           if ( EQ (mother, Vcharset_ucs) )
874             return DECODE_CHAR (mother, code_point);
875           else
876             return decode_defined_char (mother, code_point);
877         }
878       else if ( XCHARSET_CONVERSION (ccs) == CONVERSION_BIG5_1 )
879         {
880           unsigned int I
881             = (((code_point >> 8) & 0x7F) - 33) * 94
882             + (( code_point       & 0x7F) - 33);
883           unsigned char b1 = I / (0xFF - 0xA1 + 0x7F - 0x40) + 0xA1;
884           unsigned char b2 = I % (0xFF - 0xA1 + 0x7F - 0x40);
885
886           b2 += b2 < 0x3F ? 0x40 : 0x62;
887           return decode_defined_char (mother, (b1 << 8) | b2);
888         }
889       else if ( XCHARSET_CONVERSION (ccs) == CONVERSION_BIG5_2 )
890         {
891           unsigned int I
892             = (((code_point >> 8) & 0x7F) - 33) * 94
893             + (( code_point       & 0x7F) - 33)
894             + BIG5_SAME_ROW * (0xC9 - 0xA1);
895           unsigned char b1 = I / (0xFF - 0xA1 + 0x7F - 0x40) + 0xA1;
896           unsigned char b2 = I % (0xFF - 0xA1 + 0x7F - 0x40);
897
898           b2 += b2 < 0x3F ? 0x40 : 0x62;
899           return decode_defined_char (mother, (b1 << 8) | b2);
900         }
901     }
902   return -1;
903 }
904
905 Emchar
906 decode_builtin_char (Lisp_Object charset, int code_point)
907 {
908   Lisp_Object mother = XCHARSET_MOTHER (charset);
909   int final;
910
911   if ( XCHARSET_MAX_CODE (charset) > 0 )
912     {
913       if ( CHARSETP (mother) )
914         {
915           int code = code_point;
916
917           if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x60 )
918             {
919               int row = code_point >> 8;
920               int cell = code_point & 255;        
921
922               if (row < 16 + 32)
923                 return -1;
924               else if (row < 16 + 32 + 30)
925                 code = (row - (16 + 32)) * 94 + cell - 33;
926               else if (row < 18 + 32 + 30)
927                 return -1;
928               else if (row < 18 + 32 + 60)
929                 code = (row - (18 + 32)) * 94 + cell - 33;
930             }
931           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x94x60 )
932             {
933               int plane = code_point >> 16;
934               int row = (code_point >> 8) & 255;
935               int cell = code_point & 255;        
936
937               if (row < 16 + 32)
938                 return -1;
939               else if (row < 16 + 32 + 30)
940                 code
941                   = (plane - 33) * 94 * 60
942                   + (row - (16 + 32)) * 94
943                   + cell - 33;
944               else if (row < 18 + 32 + 30)
945                 return -1;
946               else if (row < 18 + 32 + 60)
947                 code
948                   = (plane - 33) * 94 * 60
949                   + (row - (18 + 32)) * 94
950                   + cell - 33;
951             }
952           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_BIG5_1 )
953             {
954               unsigned int I
955                 = (((code_point >> 8) & 0x7F) - 33) * 94
956                 + (( code_point       & 0x7F) - 33);
957               unsigned char b1 = I / (0xFF - 0xA1 + 0x7F - 0x40) + 0xA1;
958               unsigned char b2 = I % (0xFF - 0xA1 + 0x7F - 0x40);
959
960               b2 += b2 < 0x3F ? 0x40 : 0x62;
961               code = (b1 << 8) | b2;
962             }
963           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_BIG5_2 )
964             {
965               unsigned int I
966                 = (((code_point >> 8) & 0x7F) - 33) * 94
967                 + (( code_point       & 0x7F) - 33)
968                 + BIG5_SAME_ROW * (0xC9 - 0xA1);
969               unsigned char b1 = I / (0xFF - 0xA1 + 0x7F - 0x40) + 0xA1;
970               unsigned char b2 = I % (0xFF - 0xA1 + 0x7F - 0x40);
971
972               b2 += b2 < 0x3F ? 0x40 : 0x62;
973               code = (b1 << 8) | b2;
974             }
975           return
976             decode_builtin_char (mother, code + XCHARSET_CODE_OFFSET(charset));
977         }
978       else
979         {
980           Emchar cid
981             = (XCHARSET_DIMENSION (charset) == 1
982                ?
983                code_point - XCHARSET_BYTE_OFFSET (charset)
984                :
985                ((code_point >> 8) - XCHARSET_BYTE_OFFSET (charset))
986                * XCHARSET_CHARS (charset)
987                + (code_point & 0xFF) - XCHARSET_BYTE_OFFSET (charset))
988             + XCHARSET_CODE_OFFSET (charset);
989           if ((cid < XCHARSET_MIN_CODE (charset))
990               || (XCHARSET_MAX_CODE (charset) < cid))
991             return -1;
992           return cid;
993         }
994     }
995   else if ((final = XCHARSET_FINAL (charset)) >= '0')
996     {
997       if (XCHARSET_DIMENSION (charset) == 1)
998         {
999           switch (XCHARSET_CHARS (charset))
1000             {
1001             case 94:
1002               return MIN_CHAR_94
1003                 + (final - '0') * 94 + ((code_point & 0x7F) - 33);
1004             case 96:
1005               return MIN_CHAR_96
1006                 + (final - '0') * 96 + ((code_point & 0x7F) - 32);
1007             default:
1008               abort ();
1009               return -1;
1010             }
1011         }
1012       else
1013         {
1014           switch (XCHARSET_CHARS (charset))
1015             {
1016             case 94:
1017               return MIN_CHAR_94x94
1018                 + (final - '0') * 94 * 94
1019                 + (((code_point >> 8) & 0x7F) - 33) * 94
1020                 + ((code_point & 0x7F) - 33);
1021             case 96:
1022               return MIN_CHAR_96x96
1023                 + (final - '0') * 96 * 96
1024                 + (((code_point >> 8) & 0x7F) - 32) * 96
1025                 + ((code_point & 0x7F) - 32);
1026             default:
1027               abort ();
1028               return -1;
1029             }
1030         }
1031     }
1032   else
1033     return -1;
1034 }
1035
1036 int
1037 charset_code_point (Lisp_Object charset, Emchar ch, int defined_only)
1038 {
1039   Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (charset);
1040   Lisp_Object ret;
1041
1042   if ( CHAR_TABLEP (encoding_table)
1043        && INTP (ret = get_char_id_table (XCHAR_TABLE(encoding_table),
1044                                          ch)) )
1045     return XINT (ret);
1046   else
1047     {
1048       Lisp_Object mother = XCHARSET_MOTHER (charset);
1049       int min = XCHARSET_MIN_CODE (charset);
1050       int max = XCHARSET_MAX_CODE (charset);
1051       int code = -1;
1052
1053       if ( CHARSETP (mother) )
1054         {
1055           if (XCHARSET_FINAL (charset) >= '0')
1056             code = charset_code_point (mother, ch, 1);
1057           else
1058             code = charset_code_point (mother, ch, defined_only);
1059         }
1060       else if (defined_only)
1061         return -1;
1062       else if ( ((max == 0) && CHARSETP (mother)
1063                  && (XCHARSET_FINAL (charset) == 0))
1064                 || ((min <= ch) && (ch <= max)) )
1065         code = ch;
1066       if ( ((max == 0) && CHARSETP (mother) && (code >= 0))
1067            || ((min <= code) && (code <= max)) )
1068         {
1069           int d = code - XCHARSET_CODE_OFFSET (charset);
1070
1071           if ( XCHARSET_CONVERSION (charset) == CONVERSION_IDENTICAL )
1072             return d;
1073           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94 )
1074             return d + 33;
1075           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_96 )
1076             return d + 32;
1077           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x60 )
1078             {
1079               int row  = d / 94;
1080               int cell = d % 94 + 33;
1081
1082               if (row < 30)
1083                 row += 16 + 32;
1084               else
1085                 row += 18 + 32;
1086               return (row << 8) | cell;
1087             }
1088           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_BIG5_1 )
1089             {
1090               int B1 = d >> 8, B2 = d & 0xFF;
1091               unsigned int I
1092                 = (B1 - 0xA1) * BIG5_SAME_ROW + B2
1093                 - (B2 < 0x7F ? 0x40 : 0x62);
1094
1095               if (B1 < 0xC9)
1096                 {
1097                   return ((I / 94 + 33) << 8) | (I % 94 + 33);
1098                 }
1099             }
1100           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_BIG5_2 )
1101             {
1102               int B1 = d >> 8, B2 = d & 0xFF;
1103               unsigned int I
1104                 = (B1 - 0xA1) * BIG5_SAME_ROW + B2
1105                 - (B2 < 0x7F ? 0x40 : 0x62);
1106
1107               if (B1 >= 0xC9)
1108                 {
1109                   I -= (BIG5_SAME_ROW) * (0xC9 - 0xA1);
1110                   return ((I / 94 + 33) << 8) | (I % 94 + 33);
1111                 }
1112             }
1113           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x94 )
1114             return ((d / 94 + 33) << 8) | (d % 94 + 33);
1115           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_96x96 )
1116             return ((d / 96 + 32) << 8) | (d % 96 + 32);
1117           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x94x60 )
1118             {
1119               int plane =  d / (94 * 60) + 33;
1120               int row   = (d % (94 * 60)) / 94;
1121               int cell  =  d %  94 + 33;
1122
1123               if (row < 30)
1124                 row += 16 + 32;
1125               else
1126                 row += 18 + 32;
1127               return (plane << 16) | (row << 8) | cell;
1128             }
1129           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x94x94 )
1130             return
1131               (   (d / (94 * 94) + 33) << 16)
1132               |  ((d / 94 % 94   + 33) <<  8)
1133               |   (d % 94        + 33);
1134           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_96x96x96 )
1135             return
1136               (   (d / (96 * 96) + 32) << 16)
1137               |  ((d / 96 % 96   + 32) <<  8)
1138               |   (d % 96        + 32);
1139           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_94x94x94x94 )
1140             return
1141               (  (d / (94 * 94 * 94) + 33) << 24)
1142               | ((d / (94 * 94) % 94 + 33) << 16)
1143               | ((d / 94 % 94        + 33) <<  8)
1144               |  (d % 94             + 33);
1145           else if ( XCHARSET_CONVERSION (charset) == CONVERSION_96x96x96x96 )
1146             return
1147               (  (d / (96 * 96 * 96) + 32) << 24)
1148               | ((d / (96 * 96) % 96 + 32) << 16)
1149               | ((d / 96 % 96        + 32) <<  8)
1150               |  (d % 96             + 32);
1151           else
1152             {
1153               printf ("Unknown CCS-conversion %d is specified!",
1154                       XCHARSET_CONVERSION (charset));
1155               exit (-1);
1156             }
1157         }
1158       else if ( ( XCHARSET_FINAL (charset) >= '0' ) &&
1159                 ( XCHARSET_MIN_CODE (charset) == 0 )
1160                /*
1161                 (XCHARSET_CODE_OFFSET (charset) == 0) ||
1162                 (XCHARSET_CODE_OFFSET (charset)
1163                  == XCHARSET_MIN_CODE (charset))
1164                */ )
1165         {
1166           int d;
1167
1168           if (XCHARSET_DIMENSION (charset) == 1)
1169             {
1170               if (XCHARSET_CHARS (charset) == 94)
1171                 {
1172                   if (((d = ch - (MIN_CHAR_94
1173                                   + (XCHARSET_FINAL (charset) - '0') * 94))
1174                        >= 0)
1175                       && (d < 94))
1176                     return d + 33;
1177                 }
1178               else if (XCHARSET_CHARS (charset) == 96)
1179                 {
1180                   if (((d = ch - (MIN_CHAR_96
1181                                   + (XCHARSET_FINAL (charset) - '0') * 96))
1182                        >= 0)
1183                       && (d < 96))
1184                     return d + 32;
1185                 }
1186               else
1187                 return -1;
1188             }
1189           else if (XCHARSET_DIMENSION (charset) == 2)
1190             {
1191               if (XCHARSET_CHARS (charset) == 94)
1192                 {
1193                   if (((d = ch - (MIN_CHAR_94x94
1194                                   +
1195                                   (XCHARSET_FINAL (charset) - '0') * 94 * 94))
1196                        >= 0)
1197                       && (d < 94 * 94))
1198                     return (((d / 94) + 33) << 8) | (d % 94 + 33);
1199                 }
1200               else if (XCHARSET_CHARS (charset) == 96)
1201                 {
1202                   if (((d = ch - (MIN_CHAR_96x96
1203                                   +
1204                                   (XCHARSET_FINAL (charset) - '0') * 96 * 96))
1205                        >= 0)
1206                       && (d < 96 * 96))
1207                     return (((d / 96) + 32) << 8) | (d % 96 + 32);
1208                 }
1209               else
1210                 return -1;
1211             }
1212         }
1213     }
1214   return -1;
1215 }
1216
1217 int
1218 encode_builtin_char_1 (Emchar c, Lisp_Object* charset)
1219 {
1220   if (c <= MAX_CHAR_BASIC_LATIN)
1221     {
1222       *charset = Vcharset_ascii;
1223       return c;
1224     }
1225   else if (c < 0xA0)
1226     {
1227       *charset = Vcharset_control_1;
1228       return c & 0x7F;
1229     }
1230   else if (c <= 0xff)
1231     {
1232       *charset = Vcharset_latin_iso8859_1;
1233       return c & 0x7F;
1234     }
1235   /*
1236   else if ((MIN_CHAR_HEBREW <= c) && (c <= MAX_CHAR_HEBREW))
1237     {
1238       *charset = Vcharset_hebrew_iso8859_8;
1239       return c - MIN_CHAR_HEBREW + 0x20;
1240     }
1241   */
1242   else if ((MIN_CHAR_THAI <= c) && (c <= MAX_CHAR_THAI))
1243     {
1244       *charset = Vcharset_thai_tis620;
1245       return c - MIN_CHAR_THAI + 0x20;
1246     }
1247   /*
1248   else if ((MIN_CHAR_HALFWIDTH_KATAKANA <= c)
1249            && (c <= MAX_CHAR_HALFWIDTH_KATAKANA))
1250     {
1251       return list2 (Vcharset_katakana_jisx0201,
1252                     make_int (c - MIN_CHAR_HALFWIDTH_KATAKANA + 33));
1253     }
1254   */
1255   else if (c <= MAX_CHAR_BMP)
1256     {
1257       *charset = Vcharset_ucs_bmp;
1258       return c;
1259     }
1260   else if (c <= MAX_CHAR_SMP)
1261     {
1262       *charset = Vcharset_ucs_smp;
1263       return c - MIN_CHAR_SMP;
1264     }
1265   else if (c <= MAX_CHAR_SIP)
1266     {
1267       *charset = Vcharset_ucs_sip;
1268       return c - MIN_CHAR_SIP;
1269     }
1270   else if (c < MIN_CHAR_94)
1271     {
1272       *charset = Vcharset_ucs;
1273       return c;
1274     }
1275   else if (c <= MAX_CHAR_94)
1276     {
1277       *charset = CHARSET_BY_ATTRIBUTES (94, 1,
1278                                         ((c - MIN_CHAR_94) / 94) + '0',
1279                                         CHARSET_LEFT_TO_RIGHT);
1280       if (!NILP (*charset))
1281         return ((c - MIN_CHAR_94) % 94) + 33;
1282       else
1283         {
1284           *charset = Vcharset_ucs;
1285           return c;
1286         }
1287     }
1288   else if (c <= MAX_CHAR_96)
1289     {
1290       *charset = CHARSET_BY_ATTRIBUTES (96, 1,
1291                                         ((c - MIN_CHAR_96) / 96) + '0',
1292                                         CHARSET_LEFT_TO_RIGHT);
1293       if (!NILP (*charset))
1294         return ((c - MIN_CHAR_96) % 96) + 32;
1295       else
1296         {
1297           *charset = Vcharset_ucs;
1298           return c;
1299         }
1300     }
1301   else if (c <= MAX_CHAR_94x94)
1302     {
1303       *charset
1304         = CHARSET_BY_ATTRIBUTES (94, 2,
1305                                  ((c - MIN_CHAR_94x94) / (94 * 94)) + '0',
1306                                  CHARSET_LEFT_TO_RIGHT);
1307       if (!NILP (*charset))
1308         return (((((c - MIN_CHAR_94x94) / 94) % 94) + 33) << 8)
1309           | (((c - MIN_CHAR_94x94) % 94) + 33);
1310       else
1311         {
1312           *charset = Vcharset_ucs;
1313           return c;
1314         }
1315     }
1316   else if (c <= MAX_CHAR_96x96)
1317     {
1318       *charset
1319         = CHARSET_BY_ATTRIBUTES (96, 2,
1320                                  ((c - MIN_CHAR_96x96) / (96 * 96)) + '0',
1321                                  CHARSET_LEFT_TO_RIGHT);
1322       if (!NILP (*charset))
1323         return ((((c - MIN_CHAR_96x96) / 96) % 96) + 32) << 8
1324           | (((c - MIN_CHAR_96x96) % 96) + 32);
1325       else
1326         {
1327           *charset = Vcharset_ucs;
1328           return c;
1329         }
1330     }
1331   else
1332     {
1333       *charset = Vcharset_ucs;
1334       return c;
1335     }
1336 }
1337
1338 Lisp_Object Vdefault_coded_charset_priority_list;
1339 #endif
1340
1341 \f
1342 /************************************************************************/
1343 /*                      Basic charset Lisp functions                    */
1344 /************************************************************************/
1345
1346 DEFUN ("charsetp", Fcharsetp, 1, 1, 0, /*
1347 Return non-nil if OBJECT is a charset.
1348 */
1349        (object))
1350 {
1351   return CHARSETP (object) ? Qt : Qnil;
1352 }
1353
1354 DEFUN ("find-charset", Ffind_charset, 1, 1, 0, /*
1355 Retrieve the charset of the given name.
1356 If CHARSET-OR-NAME is a charset object, it is simply returned.
1357 Otherwise, CHARSET-OR-NAME should be a symbol.  If there is no such charset,
1358 nil is returned.  Otherwise the associated charset object is returned.
1359 */
1360        (charset_or_name))
1361 {
1362   if (CHARSETP (charset_or_name))
1363     return charset_or_name;
1364
1365   CHECK_SYMBOL (charset_or_name);
1366   return Fgethash (charset_or_name, Vcharset_hash_table, Qnil);
1367 }
1368
1369 DEFUN ("get-charset", Fget_charset, 1, 1, 0, /*
1370 Retrieve the charset of the given name.
1371 Same as `find-charset' except an error is signalled if there is no such
1372 charset instead of returning nil.
1373 */
1374        (name))
1375 {
1376   Lisp_Object charset = Ffind_charset (name);
1377
1378   if (NILP (charset))
1379     signal_simple_error ("No such charset", name);
1380   return charset;
1381 }
1382
1383 /* We store the charsets in hash tables with the names as the key and the
1384    actual charset object as the value.  Occasionally we need to use them
1385    in a list format.  These routines provide us with that. */
1386 struct charset_list_closure
1387 {
1388   Lisp_Object *charset_list;
1389 };
1390
1391 static int
1392 add_charset_to_list_mapper (Lisp_Object key, Lisp_Object value,
1393                             void *charset_list_closure)
1394 {
1395   /* This function can GC */
1396   struct charset_list_closure *chcl =
1397     (struct charset_list_closure*) charset_list_closure;
1398   Lisp_Object *charset_list = chcl->charset_list;
1399
1400   *charset_list = Fcons (key /* XCHARSET_NAME (value) */, *charset_list);
1401   return 0;
1402 }
1403
1404 DEFUN ("charset-list", Fcharset_list, 0, 0, 0, /*
1405 Return a list of the names of all defined charsets.
1406 */
1407        ())
1408 {
1409   Lisp_Object charset_list = Qnil;
1410   struct gcpro gcpro1;
1411   struct charset_list_closure charset_list_closure;
1412
1413   GCPRO1 (charset_list);
1414   charset_list_closure.charset_list = &charset_list;
1415   elisp_maphash (add_charset_to_list_mapper, Vcharset_hash_table,
1416                  &charset_list_closure);
1417   UNGCPRO;
1418
1419   return charset_list;
1420 }
1421
1422 DEFUN ("charset-name", Fcharset_name, 1, 1, 0, /*
1423 Return the name of charset CHARSET.
1424 */
1425        (charset))
1426 {
1427   return XCHARSET_NAME (Fget_charset (charset));
1428 }
1429
1430 /* #### SJT Should generic properties be allowed? */
1431 DEFUN ("make-charset", Fmake_charset, 3, 3, 0, /*
1432 Define a new character set.
1433 This function is for use with Mule support.
1434 NAME is a symbol, the name by which the character set is normally referred.
1435 DOC-STRING is a string describing the character set.
1436 PROPS is a property list, describing the specific nature of the
1437 character set.  Recognized properties are:
1438
1439 'short-name     Short version of the charset name (ex: Latin-1)
1440 'long-name      Long version of the charset name (ex: ISO8859-1 (Latin-1))
1441 'registry       A regular expression matching the font registry field for
1442                 this character set.
1443 'dimension      Number of octets used to index a character in this charset.
1444                 Either 1 or 2.  Defaults to 1.
1445                 If UTF-2000 feature is enabled, 3 or 4 are also available.
1446 'columns        Number of columns used to display a character in this charset.
1447                 Only used in TTY mode. (Under X, the actual width of a
1448                 character can be derived from the font used to display the
1449                 characters.) If unspecified, defaults to the dimension
1450                 (this is almost always the correct value).
1451 'chars          Number of characters in each dimension (94 or 96).
1452                 Defaults to 94.  Note that if the dimension is 2, the
1453                 character set thus described is 94x94 or 96x96.
1454                 If UTF-2000 feature is enabled, 128 or 256 are also available.
1455 'final          Final byte of ISO 2022 escape sequence.  Must be
1456                 supplied.  Each combination of (DIMENSION, CHARS) defines a
1457                 separate namespace for final bytes.  Note that ISO
1458                 2022 restricts the final byte to the range
1459                 0x30 - 0x7E if dimension == 1, and 0x30 - 0x5F if
1460                 dimension == 2.  Note also that final bytes in the range
1461                 0x30 - 0x3F are reserved for user-defined (not official)
1462                 character sets.
1463 'graphic        0 (use left half of font on output) or 1 (use right half
1464                 of font on output).  Defaults to 0.  For example, for
1465                 a font whose registry is ISO8859-1, the left half
1466                 (octets 0x20 - 0x7F) is the `ascii' character set, while
1467                 the right half (octets 0xA0 - 0xFF) is the `latin-1'
1468                 character set.  With 'graphic set to 0, the octets
1469                 will have their high bit cleared; with it set to 1,
1470                 the octets will have their high bit set.
1471 'direction      'l2r (left-to-right) or 'r2l (right-to-left).
1472                 Defaults to 'l2r.
1473 'ccl-program    A compiled CCL program used to convert a character in
1474                 this charset into an index into the font.  This is in
1475                 addition to the 'graphic property.  The CCL program
1476                 is passed the octets of the character, with the high
1477                 bit cleared and set depending upon whether the value
1478                 of the 'graphic property is 0 or 1.
1479 'mother         [UTF-2000 only] Base coded-charset.
1480 'code-min       [UTF-2000 only] Minimum code-point of a base coded-charset.
1481 'code-max       [UTF-2000 only] Maximum code-point of a base coded-charset.
1482 'code-offset    [UTF-2000 only] Offset for a code-point of a base
1483                 coded-charset.
1484 'conversion     [UTF-2000 only] Conversion for a code-point of a base
1485                 coded-charset (94x60, 94x94x60, big5-1 or big5-2).
1486 */
1487        (name, doc_string, props))
1488 {
1489   int id, dimension = 1, chars = 94, graphic = 0, final = 0, columns = -1;
1490   int direction = CHARSET_LEFT_TO_RIGHT;
1491   Lisp_Object registry = Qnil;
1492   Lisp_Object charset;
1493   Lisp_Object ccl_program = Qnil;
1494   Lisp_Object short_name = Qnil, long_name = Qnil;
1495   Lisp_Object mother = Qnil;
1496   int min_code = 0, max_code = 0, code_offset = 0;
1497   int byte_offset = -1;
1498   int conversion = 0;
1499
1500   CHECK_SYMBOL (name);
1501   if (!NILP (doc_string))
1502     CHECK_STRING (doc_string);
1503
1504   charset = Ffind_charset (name);
1505   if (!NILP (charset))
1506     signal_simple_error ("Cannot redefine existing charset", name);
1507
1508   {
1509     EXTERNAL_PROPERTY_LIST_LOOP_3 (keyword, value, props)
1510       {
1511         if (EQ (keyword, Qshort_name))
1512           {
1513             CHECK_STRING (value);
1514             short_name = value;
1515           }
1516
1517         else if (EQ (keyword, Qlong_name))
1518           {
1519             CHECK_STRING (value);
1520             long_name = value;
1521           }
1522
1523         else if (EQ (keyword, Qdimension))
1524           {
1525             CHECK_INT (value);
1526             dimension = XINT (value);
1527             if (dimension < 1 ||
1528 #ifdef UTF2000
1529                 dimension > 4
1530 #else
1531                 dimension > 2
1532 #endif
1533                 )
1534               signal_simple_error ("Invalid value for 'dimension", value);
1535           }
1536
1537         else if (EQ (keyword, Qchars))
1538           {
1539             CHECK_INT (value);
1540             chars = XINT (value);
1541             if (chars != 94 && chars != 96
1542 #ifdef UTF2000
1543                 && chars != 128 && chars != 256
1544 #endif
1545                 )
1546               signal_simple_error ("Invalid value for 'chars", value);
1547           }
1548
1549         else if (EQ (keyword, Qcolumns))
1550           {
1551             CHECK_INT (value);
1552             columns = XINT (value);
1553             if (columns != 1 && columns != 2)
1554               signal_simple_error ("Invalid value for 'columns", value);
1555           }
1556
1557         else if (EQ (keyword, Qgraphic))
1558           {
1559             CHECK_INT (value);
1560             graphic = XINT (value);
1561             if (graphic < 0 ||
1562 #ifdef UTF2000
1563                 graphic > 2
1564 #else
1565                 graphic > 1
1566 #endif
1567                 )
1568               signal_simple_error ("Invalid value for 'graphic", value);
1569           }
1570
1571         else if (EQ (keyword, Qregistry))
1572           {
1573             CHECK_STRING (value);
1574             registry = value;
1575           }
1576
1577         else if (EQ (keyword, Qdirection))
1578           {
1579             if (EQ (value, Ql2r))
1580               direction = CHARSET_LEFT_TO_RIGHT;
1581             else if (EQ (value, Qr2l))
1582               direction = CHARSET_RIGHT_TO_LEFT;
1583             else
1584               signal_simple_error ("Invalid value for 'direction", value);
1585           }
1586
1587         else if (EQ (keyword, Qfinal))
1588           {
1589             CHECK_CHAR_COERCE_INT (value);
1590             final = XCHAR (value);
1591             if (final < '0' || final > '~')
1592               signal_simple_error ("Invalid value for 'final", value);
1593           }
1594
1595 #ifdef UTF2000
1596         else if (EQ (keyword, Qmother))
1597           {
1598             mother = Fget_charset (value);
1599           }
1600
1601         else if (EQ (keyword, Qmin_code))
1602           {
1603             CHECK_INT (value);
1604             min_code = XUINT (value);
1605           }
1606
1607         else if (EQ (keyword, Qmax_code))
1608           {
1609             CHECK_INT (value);
1610             max_code = XUINT (value);
1611           }
1612
1613         else if (EQ (keyword, Qcode_offset))
1614           {
1615             CHECK_INT (value);
1616             code_offset = XUINT (value);
1617           }
1618
1619         else if (EQ (keyword, Qconversion))
1620           {
1621             if (EQ (value, Q94x60))
1622               conversion = CONVERSION_94x60;
1623             else if (EQ (value, Q94x94x60))
1624               conversion = CONVERSION_94x94x60;
1625             else if (EQ (value, Qbig5_1))
1626               conversion = CONVERSION_BIG5_1;
1627             else if (EQ (value, Qbig5_2))
1628               conversion = CONVERSION_BIG5_2;
1629             else
1630               signal_simple_error ("Unrecognized conversion", value);
1631           }
1632
1633 #endif
1634         else if (EQ (keyword, Qccl_program))
1635           {
1636             struct ccl_program test_ccl;
1637
1638             if (setup_ccl_program (&test_ccl, value) < 0)
1639               signal_simple_error ("Invalid value for 'ccl-program", value);
1640             ccl_program = value;
1641           }
1642
1643         else
1644           signal_simple_error ("Unrecognized property", keyword);
1645       }
1646   }
1647
1648 #ifndef UTF2000
1649   if (!final)
1650     error ("'final must be specified");
1651 #endif
1652   if (dimension == 2 && final > 0x5F)
1653     signal_simple_error
1654       ("Final must be in the range 0x30 - 0x5F for dimension == 2",
1655        make_char (final));
1656
1657   if (!NILP (CHARSET_BY_ATTRIBUTES (chars, dimension, final,
1658                                     CHARSET_LEFT_TO_RIGHT)) ||
1659       !NILP (CHARSET_BY_ATTRIBUTES (chars, dimension, final,
1660                                     CHARSET_RIGHT_TO_LEFT)))
1661     error
1662       ("Character set already defined for this DIMENSION/CHARS/FINAL combo");
1663
1664   id = get_unallocated_leading_byte (dimension);
1665
1666   if (NILP (doc_string))
1667     doc_string = build_string ("");
1668
1669   if (NILP (registry))
1670     registry = build_string ("");
1671
1672   if (NILP (short_name))
1673     XSETSTRING (short_name, XSYMBOL (name)->name);
1674
1675   if (NILP (long_name))
1676     long_name = doc_string;
1677
1678   if (columns == -1)
1679     columns = dimension;
1680
1681   if (byte_offset < 0)
1682     {
1683       if (chars == 94)
1684         byte_offset = 33;
1685       else if (chars == 96)
1686         byte_offset = 32;
1687       else
1688         byte_offset = 0;
1689     }
1690
1691   charset = make_charset (id, name, chars, dimension, columns, graphic,
1692                           final, direction, short_name, long_name,
1693                           doc_string, registry,
1694                           Qnil, min_code, max_code, code_offset, byte_offset,
1695                           mother, conversion);
1696   if (!NILP (ccl_program))
1697     XCHARSET_CCL_PROGRAM (charset) = ccl_program;
1698   return charset;
1699 }
1700
1701 DEFUN ("make-reverse-direction-charset", Fmake_reverse_direction_charset,
1702        2, 2, 0, /*
1703 Make a charset equivalent to CHARSET but which goes in the opposite direction.
1704 NEW-NAME is the name of the new charset.  Return the new charset.
1705 */
1706        (charset, new_name))
1707 {
1708   Lisp_Object new_charset = Qnil;
1709   int id, chars, dimension, columns, graphic, final;
1710   int direction;
1711   Lisp_Object registry, doc_string, short_name, long_name;
1712   Lisp_Charset *cs;
1713
1714   charset = Fget_charset (charset);
1715   if (!NILP (XCHARSET_REVERSE_DIRECTION_CHARSET (charset)))
1716     signal_simple_error ("Charset already has reverse-direction charset",
1717                          charset);
1718
1719   CHECK_SYMBOL (new_name);
1720   if (!NILP (Ffind_charset (new_name)))
1721     signal_simple_error ("Cannot redefine existing charset", new_name);
1722
1723   cs = XCHARSET (charset);
1724
1725   chars     = CHARSET_CHARS     (cs);
1726   dimension = CHARSET_DIMENSION (cs);
1727   columns   = CHARSET_COLUMNS   (cs);
1728   id = get_unallocated_leading_byte (dimension);
1729
1730   graphic = CHARSET_GRAPHIC (cs);
1731   final = CHARSET_FINAL (cs);
1732   direction = CHARSET_RIGHT_TO_LEFT;
1733   if (CHARSET_DIRECTION (cs) == CHARSET_RIGHT_TO_LEFT)
1734     direction = CHARSET_LEFT_TO_RIGHT;
1735   doc_string = CHARSET_DOC_STRING (cs);
1736   short_name = CHARSET_SHORT_NAME (cs);
1737   long_name = CHARSET_LONG_NAME (cs);
1738   registry = CHARSET_REGISTRY (cs);
1739
1740   new_charset = make_charset (id, new_name, chars, dimension, columns,
1741                               graphic, final, direction, short_name, long_name,
1742                               doc_string, registry,
1743 #ifdef UTF2000
1744                               CHARSET_DECODING_TABLE(cs),
1745                               CHARSET_MIN_CODE(cs),
1746                               CHARSET_MAX_CODE(cs),
1747                               CHARSET_CODE_OFFSET(cs),
1748                               CHARSET_BYTE_OFFSET(cs),
1749                               CHARSET_MOTHER(cs),
1750                               CHARSET_CONVERSION (cs)
1751 #else
1752                               Qnil, 0, 0, 0, 0, Qnil, 0
1753 #endif
1754 );
1755
1756   CHARSET_REVERSE_DIRECTION_CHARSET (cs) = new_charset;
1757   XCHARSET_REVERSE_DIRECTION_CHARSET (new_charset) = charset;
1758
1759   return new_charset;
1760 }
1761
1762 DEFUN ("define-charset-alias", Fdefine_charset_alias, 2, 2, 0, /*
1763 Define symbol ALIAS as an alias for CHARSET.
1764 */
1765        (alias, charset))
1766 {
1767   CHECK_SYMBOL (alias);
1768   charset = Fget_charset (charset);
1769   return Fputhash (alias, charset, Vcharset_hash_table);
1770 }
1771
1772 /* #### Reverse direction charsets not yet implemented.  */
1773 #if 0
1774 DEFUN ("charset-reverse-direction-charset", Fcharset_reverse_direction_charset,
1775        1, 1, 0, /*
1776 Return the reverse-direction charset parallel to CHARSET, if any.
1777 This is the charset with the same properties (in particular, the same
1778 dimension, number of characters per dimension, and final byte) as
1779 CHARSET but whose characters are displayed in the opposite direction.
1780 */
1781        (charset))
1782 {
1783   charset = Fget_charset (charset);
1784   return XCHARSET_REVERSE_DIRECTION_CHARSET (charset);
1785 }
1786 #endif
1787
1788 DEFUN ("charset-from-attributes", Fcharset_from_attributes, 3, 4, 0, /*
1789 Return a charset with the given DIMENSION, CHARS, FINAL, and DIRECTION.
1790 If DIRECTION is omitted, both directions will be checked (left-to-right
1791 will be returned if character sets exist for both directions).
1792 */
1793        (dimension, chars, final, direction))
1794 {
1795   int dm, ch, fi, di = -1;
1796   Lisp_Object obj = Qnil;
1797
1798   CHECK_INT (dimension);
1799   dm = XINT (dimension);
1800   if (dm < 1 || dm > 2)
1801     signal_simple_error ("Invalid value for DIMENSION", dimension);
1802
1803   CHECK_INT (chars);
1804   ch = XINT (chars);
1805   if (ch != 94 && ch != 96)
1806     signal_simple_error ("Invalid value for CHARS", chars);
1807
1808   CHECK_CHAR_COERCE_INT (final);
1809   fi = XCHAR (final);
1810   if (fi < '0' || fi > '~')
1811     signal_simple_error ("Invalid value for FINAL", final);
1812
1813   if (EQ (direction, Ql2r))
1814     di = CHARSET_LEFT_TO_RIGHT;
1815   else if (EQ (direction, Qr2l))
1816     di = CHARSET_RIGHT_TO_LEFT;
1817   else if (!NILP (direction))
1818     signal_simple_error ("Invalid value for DIRECTION", direction);
1819
1820   if (dm == 2 && fi > 0x5F)
1821     signal_simple_error
1822       ("Final must be in the range 0x30 - 0x5F for dimension == 2", final);
1823
1824     if (di == -1)
1825     {
1826       obj = CHARSET_BY_ATTRIBUTES (ch, dm, fi, CHARSET_LEFT_TO_RIGHT);
1827       if (NILP (obj))
1828         obj = CHARSET_BY_ATTRIBUTES (ch, dm, fi, CHARSET_RIGHT_TO_LEFT);
1829     }
1830   else
1831     obj = CHARSET_BY_ATTRIBUTES (ch, dm, fi, di);
1832
1833   if (CHARSETP (obj))
1834     return XCHARSET_NAME (obj);
1835   return obj;
1836 }
1837
1838 DEFUN ("charset-short-name", Fcharset_short_name, 1, 1, 0, /*
1839 Return short name of CHARSET.
1840 */
1841        (charset))
1842 {
1843   return XCHARSET_SHORT_NAME (Fget_charset (charset));
1844 }
1845
1846 DEFUN ("charset-long-name", Fcharset_long_name, 1, 1, 0, /*
1847 Return long name of CHARSET.
1848 */
1849        (charset))
1850 {
1851   return XCHARSET_LONG_NAME (Fget_charset (charset));
1852 }
1853
1854 DEFUN ("charset-description", Fcharset_description, 1, 1, 0, /*
1855 Return description of CHARSET.
1856 */
1857        (charset))
1858 {
1859   return XCHARSET_DOC_STRING (Fget_charset (charset));
1860 }
1861
1862 DEFUN ("charset-dimension", Fcharset_dimension, 1, 1, 0, /*
1863 Return dimension of CHARSET.
1864 */
1865        (charset))
1866 {
1867   return make_int (XCHARSET_DIMENSION (Fget_charset (charset)));
1868 }
1869
1870 DEFUN ("charset-property", Fcharset_property, 2, 2, 0, /*
1871 Return property PROP of CHARSET, a charset object or symbol naming a charset.
1872 Recognized properties are those listed in `make-charset', as well as
1873 'name and 'doc-string.
1874 */
1875        (charset, prop))
1876 {
1877   Lisp_Charset *cs;
1878
1879   charset = Fget_charset (charset);
1880   cs = XCHARSET (charset);
1881
1882   CHECK_SYMBOL (prop);
1883   if (EQ (prop, Qname))        return CHARSET_NAME (cs);
1884   if (EQ (prop, Qshort_name))  return CHARSET_SHORT_NAME (cs);
1885   if (EQ (prop, Qlong_name))   return CHARSET_LONG_NAME (cs);
1886   if (EQ (prop, Qdoc_string))  return CHARSET_DOC_STRING (cs);
1887   if (EQ (prop, Qdimension))   return make_int (CHARSET_DIMENSION (cs));
1888   if (EQ (prop, Qcolumns))     return make_int (CHARSET_COLUMNS (cs));
1889   if (EQ (prop, Qgraphic))     return make_int (CHARSET_GRAPHIC (cs));
1890   if (EQ (prop, Qfinal))       return CHARSET_FINAL (cs) == 0 ?
1891                                  Qnil : make_char (CHARSET_FINAL (cs));
1892   if (EQ (prop, Qchars))       return make_int (CHARSET_CHARS (cs));
1893   if (EQ (prop, Qregistry))    return CHARSET_REGISTRY (cs);
1894   if (EQ (prop, Qccl_program)) return CHARSET_CCL_PROGRAM (cs);
1895   if (EQ (prop, Qdirection))
1896     return CHARSET_DIRECTION (cs) == CHARSET_LEFT_TO_RIGHT ? Ql2r : Qr2l;
1897   if (EQ (prop, Qreverse_direction_charset))
1898     {
1899       Lisp_Object obj = CHARSET_REVERSE_DIRECTION_CHARSET (cs);
1900       /* #### Is this translation OK?  If so, error checking sufficient? */
1901       return CHARSETP (obj) ? XCHARSET_NAME (obj) : obj;
1902     }
1903 #ifdef UTF2000
1904   if (EQ (prop, Qmother))
1905     return CHARSET_MOTHER (cs);
1906   if (EQ (prop, Qmin_code))
1907     return make_int (CHARSET_MIN_CODE (cs));
1908   if (EQ (prop, Qmax_code))
1909     return make_int (CHARSET_MAX_CODE (cs));
1910 #endif
1911   signal_simple_error ("Unrecognized charset property name", prop);
1912   return Qnil; /* not reached */
1913 }
1914
1915 DEFUN ("charset-id", Fcharset_id, 1, 1, 0, /*
1916 Return charset identification number of CHARSET.
1917 */
1918         (charset))
1919 {
1920   return make_int(XCHARSET_LEADING_BYTE (Fget_charset (charset)));
1921 }
1922
1923 /* #### We need to figure out which properties we really want to
1924    allow to be set. */
1925
1926 DEFUN ("set-charset-ccl-program", Fset_charset_ccl_program, 2, 2, 0, /*
1927 Set the 'ccl-program property of CHARSET to CCL-PROGRAM.
1928 */
1929        (charset, ccl_program))
1930 {
1931   struct ccl_program test_ccl;
1932
1933   charset = Fget_charset (charset);
1934   if (setup_ccl_program (&test_ccl, ccl_program) < 0)
1935     signal_simple_error ("Invalid ccl-program", ccl_program);
1936   XCHARSET_CCL_PROGRAM (charset) = ccl_program;
1937   return Qnil;
1938 }
1939
1940 static void
1941 invalidate_charset_font_caches (Lisp_Object charset)
1942 {
1943   /* Invalidate font cache entries for charset on all devices. */
1944   Lisp_Object devcons, concons, hash_table;
1945   DEVICE_LOOP_NO_BREAK (devcons, concons)
1946     {
1947       struct device *d = XDEVICE (XCAR (devcons));
1948       hash_table = Fgethash (charset, d->charset_font_cache, Qunbound);
1949       if (!UNBOUNDP (hash_table))
1950         Fclrhash (hash_table);
1951     }
1952 }
1953
1954 DEFUN ("set-charset-registry", Fset_charset_registry, 2, 2, 0, /*
1955 Set the 'registry property of CHARSET to REGISTRY.
1956 */
1957        (charset, registry))
1958 {
1959   charset = Fget_charset (charset);
1960   CHECK_STRING (registry);
1961   XCHARSET_REGISTRY (charset) = registry;
1962   invalidate_charset_font_caches (charset);
1963   face_property_was_changed (Vdefault_face, Qfont, Qglobal);
1964   return Qnil;
1965 }
1966
1967 #ifdef UTF2000
1968 DEFUN ("charset-mapping-table", Fcharset_mapping_table, 1, 1, 0, /*
1969 Return mapping-table of CHARSET.
1970 */
1971        (charset))
1972 {
1973   return XCHARSET_DECODING_TABLE (Fget_charset (charset));
1974 }
1975
1976 DEFUN ("set-charset-mapping-table", Fset_charset_mapping_table, 2, 2, 0, /*
1977 Set mapping-table of CHARSET to TABLE.
1978 */
1979        (charset, table))
1980 {
1981   struct Lisp_Charset *cs;
1982   int i;
1983   int byte_offset;
1984
1985   charset = Fget_charset (charset);
1986   cs = XCHARSET (charset);
1987
1988   if (NILP (table))
1989     {
1990       CHARSET_DECODING_TABLE(cs) = Qnil;
1991       return table;
1992     }
1993   else if (VECTORP (table))
1994     {
1995       int ccs_len = CHARSET_BYTE_SIZE (cs);
1996       int ret = decoding_table_check_elements (table,
1997                                                CHARSET_DIMENSION (cs),
1998                                                ccs_len);
1999       if (ret)
2000         {
2001           if (ret == -1)
2002             signal_simple_error ("Too big table", table);
2003           else if (ret == -2)
2004             signal_simple_error ("Invalid element is found", table);
2005           else
2006             signal_simple_error ("Something wrong", table);
2007         }
2008       CHARSET_DECODING_TABLE(cs) = Qnil;
2009     }
2010   else
2011     signal_error (Qwrong_type_argument,
2012                   list2 (build_translated_string ("vector-or-nil-p"),
2013                          table));
2014
2015   byte_offset = CHARSET_BYTE_OFFSET (cs);
2016   switch (CHARSET_DIMENSION (cs))
2017     {
2018     case 1:
2019       for (i = 0; i < XVECTOR_LENGTH (table); i++)
2020         {
2021           Lisp_Object c = XVECTOR_DATA(table)[i];
2022
2023           if (CHARP (c))
2024             Fput_char_attribute (c, XCHARSET_NAME (charset),
2025                                  make_int (i + byte_offset));
2026         }
2027       break;
2028     case 2:
2029       for (i = 0; i < XVECTOR_LENGTH (table); i++)
2030         {
2031           Lisp_Object v = XVECTOR_DATA(table)[i];
2032
2033           if (VECTORP (v))
2034             {
2035               int j;
2036
2037               for (j = 0; j < XVECTOR_LENGTH (v); j++)
2038                 {
2039                   Lisp_Object c = XVECTOR_DATA(v)[j];
2040
2041                   if (CHARP (c))
2042                     Fput_char_attribute
2043                       (c, XCHARSET_NAME (charset),
2044                        make_int ( ( (i + byte_offset) << 8 )
2045                                   | (j + byte_offset)
2046                                   ) );
2047                 }
2048             }
2049           else if (CHARP (v))
2050             Fput_char_attribute (v, XCHARSET_NAME (charset),
2051                                  make_int (i + byte_offset));
2052         }
2053       break;
2054     }
2055   return table;
2056 }
2057
2058 #ifdef HAVE_CHISE_CLIENT
2059 DEFUN ("save-charset-mapping-table", Fsave_charset_mapping_table, 1, 1, 0, /*
2060 Save mapping-table of CHARSET.
2061 */
2062        (charset))
2063 {
2064   struct Lisp_Charset *cs;
2065   int byte_min, byte_max;
2066   Lisp_Object db;
2067   Lisp_Object db_file;
2068
2069   charset = Fget_charset (charset);
2070   cs = XCHARSET (charset);
2071
2072   db_file = char_attribute_system_db_file (CHARSET_NAME (cs),
2073                                            Qsystem_char_id, 1);
2074   db = Fopen_database (db_file, Qnil, Qnil, build_string ("w+"), Qnil);
2075
2076   byte_min = CHARSET_BYTE_OFFSET (cs);
2077   byte_max = byte_min + CHARSET_BYTE_SIZE (cs);
2078   switch (CHARSET_DIMENSION (cs))
2079     {
2080     case 1:
2081       {
2082         Lisp_Object table_c = XCHARSET_DECODING_TABLE (charset);
2083         int cell;
2084
2085         for (cell = byte_min; cell < byte_max; cell++)
2086           {
2087             Lisp_Object c = get_ccs_octet_table (table_c, charset, cell);
2088
2089             if (CHARP (c))
2090               Fput_database (Fprin1_to_string (make_int (cell), Qnil),
2091                              Fprin1_to_string (c, Qnil),
2092                              db, Qt);
2093           }
2094       }
2095       break;
2096     case 2:
2097       {
2098         Lisp_Object table_r = XCHARSET_DECODING_TABLE (charset);
2099         int row;
2100
2101         for (row = byte_min; row < byte_max; row++)
2102           {
2103             Lisp_Object table_c = get_ccs_octet_table (table_r, charset, row);
2104             int cell;
2105
2106             for (cell = byte_min; cell < byte_max; cell++)
2107               {
2108                 Lisp_Object c = get_ccs_octet_table (table_c, charset, cell);
2109
2110                 if (CHARP (c))
2111                   Fput_database (Fprin1_to_string (make_int ((row << 8)
2112                                                              | cell),
2113                                                    Qnil),
2114                                  Fprin1_to_string (c, Qnil),
2115                                  db, Qt);
2116               }
2117           }
2118       }
2119       break;
2120     case 3:
2121       {
2122         Lisp_Object table_p = XCHARSET_DECODING_TABLE (charset);
2123         int plane;
2124
2125         for (plane = byte_min; plane < byte_max; plane++)
2126           {
2127             Lisp_Object table_r
2128               = get_ccs_octet_table (table_p, charset, plane);
2129             int row;
2130
2131             for (row = byte_min; row < byte_max; row++)
2132               {
2133                 Lisp_Object table_c
2134                   = get_ccs_octet_table (table_r, charset, row);
2135                 int cell;
2136
2137                 for (cell = byte_min; cell < byte_max; cell++)
2138                   {
2139                     Lisp_Object c = get_ccs_octet_table (table_c, charset,
2140                                                          cell);
2141
2142                     if (CHARP (c))
2143                       Fput_database (Fprin1_to_string (make_int ((plane << 16)
2144                                                                  | (row <<  8)
2145                                                                  | cell),
2146                                                        Qnil),
2147                                      Fprin1_to_string (c, Qnil),
2148                                      db, Qt);
2149                   }
2150               }
2151           }
2152       }
2153       break;
2154     default:
2155       {
2156         Lisp_Object table_g = XCHARSET_DECODING_TABLE (charset);
2157         int group;
2158
2159         for (group = byte_min; group < byte_max; group++)
2160           {
2161             Lisp_Object table_p
2162               = get_ccs_octet_table (table_g, charset, group);
2163             int plane;
2164
2165             for (plane = byte_min; plane < byte_max; plane++)
2166               {
2167                 Lisp_Object table_r
2168                   = get_ccs_octet_table (table_p, charset, plane);
2169                 int row;
2170
2171                 for (row = byte_min; row < byte_max; row++)
2172                   {
2173                     Lisp_Object table_c
2174                       = get_ccs_octet_table (table_r, charset, row);
2175                     int cell;
2176
2177                     for (cell = byte_min; cell < byte_max; cell++)
2178                       {
2179                         Lisp_Object c
2180                           = get_ccs_octet_table (table_c, charset, cell);
2181
2182                         if (CHARP (c))
2183                           Fput_database (Fprin1_to_string
2184                                          (make_int ((  group << 24)
2185                                                     | (plane << 16)
2186                                                     | (row   <<  8)
2187                                                     |  cell),
2188                                           Qnil),
2189                                          Fprin1_to_string (c, Qnil),
2190                                          db, Qt);
2191                       }
2192                   }
2193               }
2194           }
2195       }
2196     }
2197   return Fclose_database (db);
2198 }
2199
2200 DEFUN ("reset-charset-mapping-table", Freset_charset_mapping_table, 1, 1, 0, /*
2201 Reset mapping-table of CCS with database file.
2202 */
2203        (ccs))
2204 {
2205   Lisp_Object db_file;
2206
2207   ccs = Fget_charset (ccs);
2208   db_file = char_attribute_system_db_file (XCHARSET_NAME(ccs),
2209                                            Qsystem_char_id, 0);
2210
2211   if (!NILP (Ffile_exists_p (db_file)))
2212     {
2213       XCHARSET_DECODING_TABLE(ccs) = Qunloaded;
2214       return Qt;
2215     }
2216   return Qnil;
2217 }
2218
2219 Emchar
2220 load_char_decoding_entry_maybe (Lisp_Object ccs, int code_point)
2221 {
2222   Lisp_Object db;
2223   Lisp_Object db_file
2224     = char_attribute_system_db_file (XCHARSET_NAME(ccs), Qsystem_char_id,
2225                                      0);
2226
2227   db = Fopen_database (db_file, Qnil, Qnil, build_string ("r"), Qnil);
2228   if (!NILP (db))
2229     {
2230       Lisp_Object ret
2231         = Fget_database (Fprin1_to_string (make_int (code_point), Qnil),
2232                          db, Qnil);
2233       if (!NILP (ret))
2234         {
2235           ret = Fread (ret);
2236           if (CHARP (ret))
2237             {
2238               decoding_table_put_char (ccs, code_point, ret);
2239               Fclose_database (db);
2240               return XCHAR (ret);
2241             }
2242         }
2243       decoding_table_put_char (ccs, code_point, Qnil);
2244       Fclose_database (db);
2245     }
2246   return -1;
2247 }
2248 #endif /* HAVE_CHISE_CLIENT */
2249 #endif /* UTF2000 */
2250
2251 \f
2252 /************************************************************************/
2253 /*              Lisp primitives for working with characters             */
2254 /************************************************************************/
2255
2256 #ifdef UTF2000
2257 DEFUN ("decode-char", Fdecode_char, 2, 3, 0, /*
2258 Make a character from CHARSET and code-point CODE.
2259 If DEFINED_ONLY is non-nil, builtin character is not returned.
2260 If corresponding character is not found, nil is returned.
2261 */
2262        (charset, code, defined_only))
2263 {
2264   int c;
2265
2266   charset = Fget_charset (charset);
2267   CHECK_INT (code);
2268   c = XINT (code);
2269   if (XCHARSET_GRAPHIC (charset) == 1)
2270     c &= 0x7F7F7F7F;
2271   if (NILP (defined_only))
2272     c = DECODE_CHAR (charset, c);
2273   else
2274     c = decode_defined_char (charset, c);
2275   return c >= 0 ? make_char (c) : Qnil;
2276 }
2277
2278 DEFUN ("decode-builtin-char", Fdecode_builtin_char, 2, 2, 0, /*
2279 Make a builtin character from CHARSET and code-point CODE.
2280 */
2281        (charset, code))
2282 {
2283   int c;
2284
2285   charset = Fget_charset (charset);
2286   CHECK_INT (code);
2287   if (EQ (charset, Vcharset_latin_viscii))
2288     {
2289       Lisp_Object chr = Fdecode_char (charset, code, Qnil);
2290       Lisp_Object ret;
2291
2292       if (!NILP (chr))
2293         {
2294           if (!NILP
2295               (ret = Fget_char_attribute (chr,
2296                                           Vcharset_latin_viscii_lower,
2297                                           Qnil)))
2298             {
2299               charset = Vcharset_latin_viscii_lower;
2300               code = ret;
2301             }
2302           else if (!NILP
2303                    (ret = Fget_char_attribute (chr,
2304                                                Vcharset_latin_viscii_upper,
2305                                                Qnil)))
2306             {
2307               charset = Vcharset_latin_viscii_upper;
2308               code = ret;
2309             }
2310         }
2311     }
2312   c = XINT (code);
2313 #if 0
2314   if (XCHARSET_GRAPHIC (charset) == 1)
2315     c &= 0x7F7F7F7F;
2316 #endif
2317   c = decode_builtin_char (charset, c);
2318   return c >= 0 ? make_char (c) : Fdecode_char (charset, code, Qnil);
2319 }
2320 #endif
2321
2322 DEFUN ("make-char", Fmake_char, 2, 3, 0, /*
2323 Make a character from CHARSET and octets ARG1 and ARG2.
2324 ARG2 is required only for characters from two-dimensional charsets.
2325 For example, (make-char 'latin-iso8859-2 185) will return the Latin 2
2326 character s with caron.
2327 */
2328        (charset, arg1, arg2))
2329 {
2330   Lisp_Charset *cs;
2331   int a1, a2;
2332   int lowlim, highlim;
2333
2334   charset = Fget_charset (charset);
2335   cs = XCHARSET (charset);
2336
2337   if      (EQ (charset, Vcharset_ascii))     lowlim =  0, highlim = 127;
2338   else if (EQ (charset, Vcharset_control_1)) lowlim =  0, highlim =  31;
2339 #ifdef UTF2000
2340   else if (CHARSET_CHARS (cs) == 256)        lowlim =  0, highlim = 255;
2341 #endif
2342   else if (CHARSET_CHARS (cs) == 94)         lowlim = 33, highlim = 126;
2343   else  /* CHARSET_CHARS (cs) == 96) */      lowlim = 32, highlim = 127;
2344
2345   CHECK_INT (arg1);
2346   /* It is useful (and safe, according to Olivier Galibert) to strip
2347      the 8th bit off ARG1 and ARG2 because it allows programmers to
2348      write (make-char 'latin-iso8859-2 CODE) where code is the actual
2349      Latin 2 code of the character.  */
2350 #ifdef UTF2000
2351   a1 = XINT (arg1);
2352   if (highlim < 128)
2353     a1 &= 0x7f;
2354 #else
2355   a1 = XINT (arg1);
2356 #endif
2357   if (a1 < lowlim || a1 > highlim)
2358     args_out_of_range_3 (arg1, make_int (lowlim), make_int (highlim));
2359
2360   if (CHARSET_DIMENSION (cs) == 1)
2361     {
2362       if (!NILP (arg2))
2363         signal_simple_error
2364           ("Charset is of dimension one; second octet must be nil", arg2);
2365       return make_char (MAKE_CHAR (charset, a1, 0));
2366     }
2367
2368   CHECK_INT (arg2);
2369 #ifdef UTF2000
2370   a2 = XINT (arg2);
2371   if (highlim < 128)
2372     a2 &= 0x7f;
2373 #else
2374   a2 = XINT (arg2) & 0x7f;
2375 #endif
2376   if (a2 < lowlim || a2 > highlim)
2377     args_out_of_range_3 (arg2, make_int (lowlim), make_int (highlim));
2378
2379   return make_char (MAKE_CHAR (charset, a1, a2));
2380 }
2381
2382 DEFUN ("char-charset", Fchar_charset, 1, 1, 0, /*
2383 Return the character set of CHARACTER.
2384 */
2385        (character))
2386 {
2387   CHECK_CHAR_COERCE_INT (character);
2388
2389   return XCHARSET_NAME (CHAR_CHARSET (XCHAR (character)));
2390 }
2391
2392 DEFUN ("char-octet", Fchar_octet, 1, 2, 0, /*
2393 Return the octet numbered N (should be 0 or 1) of CHARACTER.
2394 N defaults to 0 if omitted.
2395 */
2396        (character, n))
2397 {
2398   Lisp_Object charset;
2399   int octet0, octet1;
2400
2401   CHECK_CHAR_COERCE_INT (character);
2402
2403   BREAKUP_CHAR (XCHAR (character), charset, octet0, octet1);
2404
2405   if (NILP (n) || EQ (n, Qzero))
2406     return make_int (octet0);
2407   else if (EQ (n, make_int (1)))
2408     return make_int (octet1);
2409   else
2410     signal_simple_error ("Octet number must be 0 or 1", n);
2411 }
2412
2413 #ifdef UTF2000
2414 DEFUN ("encode-char", Fencode_char, 2, 3, 0, /*
2415 Return code-point of CHARACTER in specified CHARSET.
2416 */
2417        (character, charset, defined_only))
2418 {
2419   int code_point;
2420
2421   CHECK_CHAR_COERCE_INT (character);
2422   charset = Fget_charset (charset);
2423   code_point = charset_code_point (charset, XCHAR (character),
2424                                    !NILP (defined_only));
2425   if (code_point >= 0)
2426     return make_int (code_point);
2427   else
2428     return Qnil;
2429 }
2430 #endif
2431
2432 DEFUN ("split-char", Fsplit_char, 1, 1, 0, /*
2433 Return list of charset and one or two position-codes of CHARACTER.
2434 */
2435        (character))
2436 {
2437   /* This function can GC */
2438   struct gcpro gcpro1, gcpro2;
2439   Lisp_Object charset = Qnil;
2440   Lisp_Object rc = Qnil;
2441 #ifdef UTF2000
2442   int code_point;
2443   int dimension;
2444 #else
2445   int c1, c2;
2446 #endif
2447
2448   GCPRO2 (charset, rc);
2449   CHECK_CHAR_COERCE_INT (character);
2450
2451 #ifdef UTF2000
2452   code_point = ENCODE_CHAR (XCHAR (character), charset);
2453   dimension = XCHARSET_DIMENSION (charset);
2454   while (dimension > 0)
2455     {
2456       rc = Fcons (make_int (code_point & 255), rc);
2457       code_point >>= 8;
2458       dimension--;
2459     }
2460   rc = Fcons (XCHARSET_NAME (charset), rc);
2461 #else
2462   BREAKUP_CHAR (XCHAR (character), charset, c1, c2);
2463
2464   if (XCHARSET_DIMENSION (Fget_charset (charset)) == 2)
2465     {
2466       rc = list3 (XCHARSET_NAME (charset), make_int (c1), make_int (c2));
2467     }
2468   else
2469     {
2470       rc = list2 (XCHARSET_NAME (charset), make_int (c1));
2471     }
2472 #endif
2473   UNGCPRO;
2474
2475   return rc;
2476 }
2477
2478 \f
2479 #ifdef ENABLE_COMPOSITE_CHARS
2480 /************************************************************************/
2481 /*                     composite character functions                    */
2482 /************************************************************************/
2483
2484 Emchar
2485 lookup_composite_char (Bufbyte *str, int len)
2486 {
2487   Lisp_Object lispstr = make_string (str, len);
2488   Lisp_Object ch = Fgethash (lispstr,
2489                              Vcomposite_char_string2char_hash_table,
2490                              Qunbound);
2491   Emchar emch;
2492
2493   if (UNBOUNDP (ch))
2494     {
2495       if (composite_char_row_next >= 128)
2496         signal_simple_error ("No more composite chars available", lispstr);
2497       emch = MAKE_CHAR (Vcharset_composite, composite_char_row_next,
2498                         composite_char_col_next);
2499       Fputhash (make_char (emch), lispstr,
2500                 Vcomposite_char_char2string_hash_table);
2501       Fputhash (lispstr, make_char (emch),
2502                 Vcomposite_char_string2char_hash_table);
2503       composite_char_col_next++;
2504       if (composite_char_col_next >= 128)
2505         {
2506           composite_char_col_next = 32;
2507           composite_char_row_next++;
2508         }
2509     }
2510   else
2511     emch = XCHAR (ch);
2512   return emch;
2513 }
2514
2515 Lisp_Object
2516 composite_char_string (Emchar ch)
2517 {
2518   Lisp_Object str = Fgethash (make_char (ch),
2519                               Vcomposite_char_char2string_hash_table,
2520                               Qunbound);
2521   assert (!UNBOUNDP (str));
2522   return str;
2523 }
2524
2525 xxDEFUN ("make-composite-char", Fmake_composite_char, 1, 1, 0, /*
2526 Convert a string into a single composite character.
2527 The character is the result of overstriking all the characters in
2528 the string.
2529 */
2530        (string))
2531 {
2532   CHECK_STRING (string);
2533   return make_char (lookup_composite_char (XSTRING_DATA (string),
2534                                            XSTRING_LENGTH (string)));
2535 }
2536
2537 xxDEFUN ("composite-char-string", Fcomposite_char_string, 1, 1, 0, /*
2538 Return a string of the characters comprising a composite character.
2539 */
2540        (ch))
2541 {
2542   Emchar emch;
2543
2544   CHECK_CHAR (ch);
2545   emch = XCHAR (ch);
2546   if (CHAR_LEADING_BYTE (emch) != LEADING_BYTE_COMPOSITE)
2547     signal_simple_error ("Must be composite char", ch);
2548   return composite_char_string (emch);
2549 }
2550 #endif /* ENABLE_COMPOSITE_CHARS */
2551
2552 \f
2553 /************************************************************************/
2554 /*                            initialization                            */
2555 /************************************************************************/
2556
2557 void
2558 syms_of_mule_charset (void)
2559 {
2560   INIT_LRECORD_IMPLEMENTATION (charset);
2561
2562   DEFSUBR (Fcharsetp);
2563   DEFSUBR (Ffind_charset);
2564   DEFSUBR (Fget_charset);
2565   DEFSUBR (Fcharset_list);
2566   DEFSUBR (Fcharset_name);
2567   DEFSUBR (Fmake_charset);
2568   DEFSUBR (Fmake_reverse_direction_charset);
2569   /*  DEFSUBR (Freverse_direction_charset); */
2570   DEFSUBR (Fdefine_charset_alias);
2571   DEFSUBR (Fcharset_from_attributes);
2572   DEFSUBR (Fcharset_short_name);
2573   DEFSUBR (Fcharset_long_name);
2574   DEFSUBR (Fcharset_description);
2575   DEFSUBR (Fcharset_dimension);
2576   DEFSUBR (Fcharset_property);
2577   DEFSUBR (Fcharset_id);
2578   DEFSUBR (Fset_charset_ccl_program);
2579   DEFSUBR (Fset_charset_registry);
2580 #ifdef UTF2000
2581   DEFSUBR (Fcharset_mapping_table);
2582   DEFSUBR (Fset_charset_mapping_table);
2583 #ifdef HAVE_CHISE_CLIENT
2584   DEFSUBR (Fsave_charset_mapping_table);
2585   DEFSUBR (Freset_charset_mapping_table);
2586 #endif
2587
2588   DEFSUBR (Fdecode_char);
2589   DEFSUBR (Fdecode_builtin_char);
2590   DEFSUBR (Fencode_char);
2591 #endif
2592   DEFSUBR (Fmake_char);
2593   DEFSUBR (Fchar_charset);
2594   DEFSUBR (Fchar_octet);
2595   DEFSUBR (Fsplit_char);
2596
2597 #ifdef ENABLE_COMPOSITE_CHARS
2598   DEFSUBR (Fmake_composite_char);
2599   DEFSUBR (Fcomposite_char_string);
2600 #endif
2601
2602   defsymbol (&Qcharsetp, "charsetp");
2603   defsymbol (&Qregistry, "registry");
2604   defsymbol (&Qfinal, "final");
2605   defsymbol (&Qgraphic, "graphic");
2606   defsymbol (&Qdirection, "direction");
2607   defsymbol (&Qreverse_direction_charset, "reverse-direction-charset");
2608   defsymbol (&Qshort_name, "short-name");
2609   defsymbol (&Qlong_name, "long-name");
2610 #ifdef UTF2000
2611   defsymbol (&Qmother, "mother");
2612   defsymbol (&Qmin_code, "min-code");
2613   defsymbol (&Qmax_code, "max-code");
2614   defsymbol (&Qcode_offset, "code-offset");
2615   defsymbol (&Qconversion, "conversion");
2616   defsymbol (&Q94x60, "94x60");
2617   defsymbol (&Q94x94x60, "94x94x60");
2618   defsymbol (&Qbig5_1, "big5-1");
2619   defsymbol (&Qbig5_2, "big5-2");
2620 #endif
2621
2622   defsymbol (&Ql2r, "l2r");
2623   defsymbol (&Qr2l, "r2l");
2624
2625   /* Charsets, compatible with FSF 20.3
2626      Naming convention is Script-Charset[-Edition] */
2627   defsymbol (&Qascii,                   "ascii");
2628   defsymbol (&Qcontrol_1,               "control-1");
2629   defsymbol (&Qlatin_iso8859_1,         "latin-iso8859-1");
2630   defsymbol (&Qlatin_iso8859_2,         "latin-iso8859-2");
2631   defsymbol (&Qlatin_iso8859_3,         "latin-iso8859-3");
2632   defsymbol (&Qlatin_iso8859_4,         "latin-iso8859-4");
2633   defsymbol (&Qthai_tis620,             "thai-tis620");
2634   defsymbol (&Qgreek_iso8859_7,         "greek-iso8859-7");
2635   defsymbol (&Qarabic_iso8859_6,        "arabic-iso8859-6");
2636   defsymbol (&Qhebrew_iso8859_8,        "hebrew-iso8859-8");
2637   defsymbol (&Qkatakana_jisx0201,       "katakana-jisx0201");
2638   defsymbol (&Qlatin_jisx0201,          "latin-jisx0201");
2639   defsymbol (&Qcyrillic_iso8859_5,      "cyrillic-iso8859-5");
2640   defsymbol (&Qlatin_iso8859_9,         "latin-iso8859-9");
2641   defsymbol (&Qjapanese_jisx0208_1978,  "japanese-jisx0208-1978");
2642   defsymbol (&Qchinese_gb2312,          "chinese-gb2312");
2643   defsymbol (&Qchinese_gb12345,         "chinese-gb12345");
2644   defsymbol (&Qjapanese_jisx0208,       "japanese-jisx0208");
2645   defsymbol (&Qkorean_ksc5601,          "korean-ksc5601");
2646   defsymbol (&Qjapanese_jisx0212,       "japanese-jisx0212");
2647   defsymbol (&Qchinese_cns11643_1,      "chinese-cns11643-1");
2648   defsymbol (&Qchinese_cns11643_2,      "chinese-cns11643-2");
2649 #ifdef UTF2000
2650   defsymbol (&Qmap_ucs,                 "=ucs");
2651   defsymbol (&Qucs,                     "ucs");
2652   defsymbol (&Qucs_bmp,                 "ucs-bmp");
2653   defsymbol (&Qucs_smp,                 "ucs-smp");
2654   defsymbol (&Qucs_sip,                 "ucs-sip");
2655   defsymbol (&Qlatin_viscii,            "latin-viscii");
2656   defsymbol (&Qlatin_tcvn5712,          "latin-tcvn5712");
2657   defsymbol (&Qlatin_viscii_lower,      "latin-viscii-lower");
2658   defsymbol (&Qlatin_viscii_upper,      "latin-viscii-upper");
2659   defsymbol (&Qvietnamese_viscii_lower, "vietnamese-viscii-lower");
2660   defsymbol (&Qvietnamese_viscii_upper, "vietnamese-viscii-upper");
2661   defsymbol (&Qmap_jis_x0208,           "=jis-x0208");
2662   defsymbol (&Qmap_jis_x0208_1990,      "=jis-x0208-1990");
2663   defsymbol (&Qchinese_big5,            "chinese-big5");
2664   defsymbol (&Qethiopic_ucs,            "ethiopic-ucs");
2665 #endif
2666   defsymbol (&Qchinese_big5_1,          "chinese-big5-1");
2667   defsymbol (&Qchinese_big5_2,          "chinese-big5-2");
2668
2669   defsymbol (&Qcomposite,               "composite");
2670 }
2671
2672 void
2673 vars_of_mule_charset (void)
2674 {
2675   int i, j;
2676 #ifndef UTF2000
2677   int k;
2678 #endif
2679
2680   chlook = xnew_and_zero (struct charset_lookup); /* zero for Purify. */
2681   dump_add_root_struct_ptr (&chlook, &charset_lookup_description);
2682
2683   /* Table of charsets indexed by leading byte. */
2684   for (i = 0; i < countof (chlook->charset_by_leading_byte); i++)
2685     chlook->charset_by_leading_byte[i] = Qnil;
2686
2687 #ifdef UTF2000
2688   /* Table of charsets indexed by type/final-byte. */
2689   for (i = 0; i < countof (chlook->charset_by_attributes); i++)
2690     for (j = 0; j < countof (chlook->charset_by_attributes[0]); j++)
2691       chlook->charset_by_attributes[i][j] = Qnil;
2692 #else
2693   /* Table of charsets indexed by type/final-byte/direction. */
2694   for (i = 0; i < countof (chlook->charset_by_attributes); i++)
2695     for (j = 0; j < countof (chlook->charset_by_attributes[0]); j++)
2696       for (k = 0; k < countof (chlook->charset_by_attributes[0][0]); k++)
2697         chlook->charset_by_attributes[i][j][k] = Qnil;
2698 #endif
2699
2700 #ifdef UTF2000
2701   chlook->next_allocated_leading_byte = MIN_LEADING_BYTE_PRIVATE;
2702 #else
2703   chlook->next_allocated_1_byte_leading_byte = MIN_LEADING_BYTE_PRIVATE_1;
2704   chlook->next_allocated_2_byte_leading_byte = MIN_LEADING_BYTE_PRIVATE_2;
2705 #endif
2706
2707 #ifndef UTF2000
2708   leading_code_private_11 = PRE_LEADING_BYTE_PRIVATE_1;
2709   DEFVAR_INT ("leading-code-private-11", &leading_code_private_11 /*
2710 Leading-code of private TYPE9N charset of column-width 1.
2711 */ );
2712   leading_code_private_11 = PRE_LEADING_BYTE_PRIVATE_1;
2713 #endif
2714
2715 #ifdef UTF2000
2716   Vdefault_coded_charset_priority_list = Qnil;
2717   DEFVAR_LISP ("default-coded-charset-priority-list",
2718                &Vdefault_coded_charset_priority_list /*
2719 Default order of preferred coded-character-sets.
2720 */ );
2721 #endif
2722 }
2723
2724 void
2725 complex_vars_of_mule_charset (void)
2726 {
2727   staticpro (&Vcharset_hash_table);
2728   Vcharset_hash_table =
2729     make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
2730
2731   /* Predefined character sets.  We store them into variables for
2732      ease of access. */
2733
2734 #ifdef UTF2000
2735   staticpro (&Vcharset_ucs);
2736   Vcharset_ucs =
2737     make_charset (LEADING_BYTE_UCS, Qmap_ucs, 256, 4,
2738                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
2739                   build_string ("UCS"),
2740                   build_string ("UCS"),
2741                   build_string ("ISO/IEC 10646"),
2742                   build_string (""),
2743                   Qnil, 0, 0x7FFFFFFF, 0, 0, Qnil, CONVERSION_IDENTICAL);
2744   staticpro (&Vcharset_ucs_bmp);
2745   Vcharset_ucs_bmp =
2746     make_charset (LEADING_BYTE_UCS_BMP, Qucs_bmp, 256, 2,
2747                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
2748                   build_string ("BMP"),
2749                   build_string ("UCS-BMP"),
2750                   build_string ("ISO/IEC 10646 Group 0 Plane 0 (BMP)"),
2751                   build_string
2752                   ("\\(ISO10646.*-[01]\\|UCS00-0\\|UNICODE[23]?-0\\)"),
2753                   Qnil, 0, 0xFFFF, 0, 0, Qnil, CONVERSION_IDENTICAL);
2754   staticpro (&Vcharset_ucs_smp);
2755   Vcharset_ucs_smp =
2756     make_charset (LEADING_BYTE_UCS_SMP, Qucs_smp, 256, 2,
2757                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
2758                   build_string ("SMP"),
2759                   build_string ("UCS-SMP"),
2760                   build_string ("ISO/IEC 10646 Group 0 Plane 1 (SMP)"),
2761                   build_string ("UCS00-1"),
2762                   Qnil, MIN_CHAR_SMP, MAX_CHAR_SMP,
2763                   MIN_CHAR_SMP, 0, Qnil, CONVERSION_IDENTICAL);
2764   staticpro (&Vcharset_ucs_sip);
2765   Vcharset_ucs_sip =
2766     make_charset (LEADING_BYTE_UCS_SIP, Qucs_sip, 256, 2,
2767                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
2768                   build_string ("SIP"),
2769                   build_string ("UCS-SIP"),
2770                   build_string ("ISO/IEC 10646 Group 0 Plane 2 (SIP)"),
2771                   build_string ("\\(ISO10646.*-2\\|UCS00-2\\)"),
2772                   Qnil, MIN_CHAR_SIP, MAX_CHAR_SIP,
2773                   MIN_CHAR_SIP, 0, Qnil, CONVERSION_IDENTICAL);
2774 #else
2775 # define MIN_CHAR_THAI 0
2776 # define MAX_CHAR_THAI 0
2777   /* # define MIN_CHAR_HEBREW 0 */
2778   /* # define MAX_CHAR_HEBREW 0 */
2779 # define MIN_CHAR_HALFWIDTH_KATAKANA 0
2780 # define MAX_CHAR_HALFWIDTH_KATAKANA 0
2781 #endif
2782   staticpro (&Vcharset_ascii);
2783   Vcharset_ascii =
2784     make_charset (LEADING_BYTE_ASCII, Qascii, 94, 1,
2785                   1, 0, 'B', CHARSET_LEFT_TO_RIGHT,
2786                   build_string ("ASCII"),
2787                   build_string ("ASCII)"),
2788                   build_string ("ASCII (ISO646 IRV)"),
2789                   build_string ("\\(iso8859-[0-9]*\\|-ascii\\)"),
2790                   Qnil, 0, 0x7F, 0, 0, Qnil, CONVERSION_IDENTICAL);
2791   staticpro (&Vcharset_control_1);
2792   Vcharset_control_1 =
2793     make_charset (LEADING_BYTE_CONTROL_1, Qcontrol_1, 94, 1,
2794                   1, 1, 0, CHARSET_LEFT_TO_RIGHT,
2795                   build_string ("C1"),
2796                   build_string ("Control characters"),
2797                   build_string ("Control characters 128-191"),
2798                   build_string (""),
2799                   Qnil, 0x80, 0x9F, 0x80, 0, Qnil, CONVERSION_IDENTICAL);
2800   staticpro (&Vcharset_latin_iso8859_1);
2801   Vcharset_latin_iso8859_1 =
2802     make_charset (LEADING_BYTE_LATIN_ISO8859_1, Qlatin_iso8859_1, 96, 1,
2803                   1, 1, 'A', CHARSET_LEFT_TO_RIGHT,
2804                   build_string ("Latin-1"),
2805                   build_string ("ISO8859-1 (Latin-1)"),
2806                   build_string ("ISO8859-1 (Latin-1)"),
2807                   build_string ("iso8859-1"),
2808                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2809   staticpro (&Vcharset_latin_iso8859_2);
2810   Vcharset_latin_iso8859_2 =
2811     make_charset (LEADING_BYTE_LATIN_ISO8859_2, Qlatin_iso8859_2, 96, 1,
2812                   1, 1, 'B', CHARSET_LEFT_TO_RIGHT,
2813                   build_string ("Latin-2"),
2814                   build_string ("ISO8859-2 (Latin-2)"),
2815                   build_string ("ISO8859-2 (Latin-2)"),
2816                   build_string ("iso8859-2"),
2817                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2818   staticpro (&Vcharset_latin_iso8859_3);
2819   Vcharset_latin_iso8859_3 =
2820     make_charset (LEADING_BYTE_LATIN_ISO8859_3, Qlatin_iso8859_3, 96, 1,
2821                   1, 1, 'C', CHARSET_LEFT_TO_RIGHT,
2822                   build_string ("Latin-3"),
2823                   build_string ("ISO8859-3 (Latin-3)"),
2824                   build_string ("ISO8859-3 (Latin-3)"),
2825                   build_string ("iso8859-3"),
2826                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2827   staticpro (&Vcharset_latin_iso8859_4);
2828   Vcharset_latin_iso8859_4 =
2829     make_charset (LEADING_BYTE_LATIN_ISO8859_4, Qlatin_iso8859_4, 96, 1,
2830                   1, 1, 'D', CHARSET_LEFT_TO_RIGHT,
2831                   build_string ("Latin-4"),
2832                   build_string ("ISO8859-4 (Latin-4)"),
2833                   build_string ("ISO8859-4 (Latin-4)"),
2834                   build_string ("iso8859-4"),
2835                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2836   staticpro (&Vcharset_thai_tis620);
2837   Vcharset_thai_tis620 =
2838     make_charset (LEADING_BYTE_THAI_TIS620, Qthai_tis620, 96, 1,
2839                   1, 1, 'T', CHARSET_LEFT_TO_RIGHT,
2840                   build_string ("TIS620"),
2841                   build_string ("TIS620 (Thai)"),
2842                   build_string ("TIS620.2529 (Thai)"),
2843                   build_string ("tis620"),
2844                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2845   staticpro (&Vcharset_greek_iso8859_7);
2846   Vcharset_greek_iso8859_7 =
2847     make_charset (LEADING_BYTE_GREEK_ISO8859_7, Qgreek_iso8859_7, 96, 1,
2848                   1, 1, 'F', CHARSET_LEFT_TO_RIGHT,
2849                   build_string ("ISO8859-7"),
2850                   build_string ("ISO8859-7 (Greek)"),
2851                   build_string ("ISO8859-7 (Greek)"),
2852                   build_string ("iso8859-7"),
2853                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2854   staticpro (&Vcharset_arabic_iso8859_6);
2855   Vcharset_arabic_iso8859_6 =
2856     make_charset (LEADING_BYTE_ARABIC_ISO8859_6, Qarabic_iso8859_6, 96, 1,
2857                   1, 1, 'G', CHARSET_RIGHT_TO_LEFT,
2858                   build_string ("ISO8859-6"),
2859                   build_string ("ISO8859-6 (Arabic)"),
2860                   build_string ("ISO8859-6 (Arabic)"),
2861                   build_string ("iso8859-6"),
2862                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2863   staticpro (&Vcharset_hebrew_iso8859_8);
2864   Vcharset_hebrew_iso8859_8 =
2865     make_charset (LEADING_BYTE_HEBREW_ISO8859_8, Qhebrew_iso8859_8, 96, 1,
2866                   1, 1, 'H', CHARSET_RIGHT_TO_LEFT,
2867                   build_string ("ISO8859-8"),
2868                   build_string ("ISO8859-8 (Hebrew)"),
2869                   build_string ("ISO8859-8 (Hebrew)"),
2870                   build_string ("iso8859-8"),
2871                   Qnil,
2872                   0 /* MIN_CHAR_HEBREW */,
2873                   0 /* MAX_CHAR_HEBREW */, 0, 32,
2874                   Qnil, CONVERSION_IDENTICAL);
2875   staticpro (&Vcharset_katakana_jisx0201);
2876   Vcharset_katakana_jisx0201 =
2877     make_charset (LEADING_BYTE_KATAKANA_JISX0201, Qkatakana_jisx0201, 94, 1,
2878                   1, 1, 'I', CHARSET_LEFT_TO_RIGHT,
2879                   build_string ("JISX0201 Kana"),
2880                   build_string ("JISX0201.1976 (Japanese Kana)"),
2881                   build_string ("JISX0201.1976 Japanese Kana"),
2882                   build_string ("jisx0201\\.1976"),
2883                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
2884   staticpro (&Vcharset_latin_jisx0201);
2885   Vcharset_latin_jisx0201 =
2886     make_charset (LEADING_BYTE_LATIN_JISX0201, Qlatin_jisx0201, 94, 1,
2887                   1, 0, 'J', CHARSET_LEFT_TO_RIGHT,
2888                   build_string ("JISX0201 Roman"),
2889                   build_string ("JISX0201.1976 (Japanese Roman)"),
2890                   build_string ("JISX0201.1976 Japanese Roman"),
2891                   build_string ("jisx0201\\.1976"),
2892                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
2893   staticpro (&Vcharset_cyrillic_iso8859_5);
2894   Vcharset_cyrillic_iso8859_5 =
2895     make_charset (LEADING_BYTE_CYRILLIC_ISO8859_5, Qcyrillic_iso8859_5, 96, 1,
2896                   1, 1, 'L', CHARSET_LEFT_TO_RIGHT,
2897                   build_string ("ISO8859-5"),
2898                   build_string ("ISO8859-5 (Cyrillic)"),
2899                   build_string ("ISO8859-5 (Cyrillic)"),
2900                   build_string ("iso8859-5"),
2901                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2902   staticpro (&Vcharset_latin_iso8859_9);
2903   Vcharset_latin_iso8859_9 =
2904     make_charset (LEADING_BYTE_LATIN_ISO8859_9, Qlatin_iso8859_9, 96, 1,
2905                   1, 1, 'M', CHARSET_LEFT_TO_RIGHT,
2906                   build_string ("Latin-5"),
2907                   build_string ("ISO8859-9 (Latin-5)"),
2908                   build_string ("ISO8859-9 (Latin-5)"),
2909                   build_string ("iso8859-9"),
2910                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
2911 #ifdef UTF2000
2912   staticpro (&Vcharset_jis_x0208);
2913   Vcharset_jis_x0208 =
2914     make_charset (LEADING_BYTE_JIS_X0208,
2915                   Qmap_jis_x0208, 94, 2,
2916                   2, 0, 'B', CHARSET_LEFT_TO_RIGHT,
2917                   build_string ("JIS X0208"),
2918                   build_string ("JIS X0208 Common"),
2919                   build_string ("JIS X0208 Common part"),
2920                   build_string ("jisx0208\\.1990"),
2921                   Qnil,
2922                   MIN_CHAR_JIS_X0208_1990,
2923                   MAX_CHAR_JIS_X0208_1990, MIN_CHAR_JIS_X0208_1990, 33,
2924                   Qnil, CONVERSION_94x94);
2925 #endif
2926   staticpro (&Vcharset_japanese_jisx0208_1978);
2927   Vcharset_japanese_jisx0208_1978 =
2928     make_charset (LEADING_BYTE_JAPANESE_JISX0208_1978,
2929                   Qjapanese_jisx0208_1978, 94, 2,
2930                   2, 0, '@', CHARSET_LEFT_TO_RIGHT,
2931                   build_string ("JIS X0208:1978"),
2932                   build_string ("JIS X0208:1978 (Japanese)"),
2933                   build_string
2934                   ("JIS X0208:1978 Japanese Kanji (so called \"old JIS\")"),
2935                   build_string ("\\(jisx0208\\|jisc6226\\)\\.1978"),
2936                   Qnil, 0, 0, 0, 33,
2937 #ifdef UTF2000
2938                   Vcharset_jis_x0208,
2939 #else
2940                   Qnil,
2941 #endif
2942                   CONVERSION_IDENTICAL);
2943   staticpro (&Vcharset_chinese_gb2312);
2944   Vcharset_chinese_gb2312 =
2945     make_charset (LEADING_BYTE_CHINESE_GB2312, Qchinese_gb2312, 94, 2,
2946                   2, 0, 'A', CHARSET_LEFT_TO_RIGHT,
2947                   build_string ("GB2312"),
2948                   build_string ("GB2312)"),
2949                   build_string ("GB2312 Chinese simplified"),
2950                   build_string ("gb2312"),
2951                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
2952   staticpro (&Vcharset_chinese_gb12345);
2953   Vcharset_chinese_gb12345 =
2954     make_charset (LEADING_BYTE_CHINESE_GB12345, Qchinese_gb12345, 94, 2,
2955                   2, 0, 0, CHARSET_LEFT_TO_RIGHT,
2956                   build_string ("G1"),
2957                   build_string ("GB 12345)"),
2958                   build_string ("GB 12345-1990"),
2959                   build_string ("GB12345\\(\\.1990\\)?-0"),
2960                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
2961   staticpro (&Vcharset_japanese_jisx0208);
2962   Vcharset_japanese_jisx0208 =
2963     make_charset (LEADING_BYTE_JAPANESE_JISX0208, Qjapanese_jisx0208, 94, 2,
2964                   2, 0, 'B', CHARSET_LEFT_TO_RIGHT,
2965                   build_string ("JISX0208"),
2966                   build_string ("JIS X0208:1983 (Japanese)"),
2967                   build_string ("JIS X0208:1983 Japanese Kanji"),
2968                   build_string ("jisx0208\\.1983"),
2969                   Qnil, 0, 0, 0, 33,
2970 #ifdef UTF2000
2971                   Vcharset_jis_x0208,
2972 #else
2973                   Qnil,
2974 #endif
2975                   CONVERSION_IDENTICAL);
2976 #ifdef UTF2000
2977   staticpro (&Vcharset_japanese_jisx0208_1990);
2978   Vcharset_japanese_jisx0208_1990 =
2979     make_charset (LEADING_BYTE_JAPANESE_JISX0208_1990,
2980                   Qmap_jis_x0208_1990, 94, 2,
2981                   2, 0, 0, CHARSET_LEFT_TO_RIGHT,
2982                   build_string ("JISX0208-1990"),
2983                   build_string ("JIS X0208:1990 (Japanese)"),
2984                   build_string ("JIS X0208:1990 Japanese Kanji"),
2985                   build_string ("jisx0208\\.1990"),
2986                   Qnil,
2987                   0x2121 /* MIN_CHAR_JIS_X0208_1990 */,
2988                   0x7426 /* MAX_CHAR_JIS_X0208_1990 */,
2989                   0 /* MIN_CHAR_JIS_X0208_1990 */, 33,
2990                   Vcharset_jis_x0208 /* Qnil */,
2991                   CONVERSION_IDENTICAL /* CONVERSION_94x94 */);
2992 #endif
2993   staticpro (&Vcharset_korean_ksc5601);
2994   Vcharset_korean_ksc5601 =
2995     make_charset (LEADING_BYTE_KOREAN_KSC5601, Qkorean_ksc5601, 94, 2,
2996                   2, 0, 'C', CHARSET_LEFT_TO_RIGHT,
2997                   build_string ("KSC5601"),
2998                   build_string ("KSC5601 (Korean"),
2999                   build_string ("KSC5601 Korean Hangul and Hanja"),
3000                   build_string ("ksc5601"),
3001                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
3002   staticpro (&Vcharset_japanese_jisx0212);
3003   Vcharset_japanese_jisx0212 =
3004     make_charset (LEADING_BYTE_JAPANESE_JISX0212, Qjapanese_jisx0212, 94, 2,
3005                   2, 0, 'D', CHARSET_LEFT_TO_RIGHT,
3006                   build_string ("JISX0212"),
3007                   build_string ("JISX0212 (Japanese)"),
3008                   build_string ("JISX0212 Japanese Supplement"),
3009                   build_string ("jisx0212"),
3010                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
3011
3012 #define CHINESE_CNS_PLANE_RE(n) "cns11643[.-]\\(.*[.-]\\)?" n "$"
3013   staticpro (&Vcharset_chinese_cns11643_1);
3014   Vcharset_chinese_cns11643_1 =
3015     make_charset (LEADING_BYTE_CHINESE_CNS11643_1, Qchinese_cns11643_1, 94, 2,
3016                   2, 0, 'G', CHARSET_LEFT_TO_RIGHT,
3017                   build_string ("CNS11643-1"),
3018                   build_string ("CNS11643-1 (Chinese traditional)"),
3019                   build_string
3020                   ("CNS 11643 Plane 1 Chinese traditional"),
3021                   build_string (CHINESE_CNS_PLANE_RE("1")),
3022                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
3023   staticpro (&Vcharset_chinese_cns11643_2);
3024   Vcharset_chinese_cns11643_2 =
3025     make_charset (LEADING_BYTE_CHINESE_CNS11643_2, Qchinese_cns11643_2, 94, 2,
3026                   2, 0, 'H', CHARSET_LEFT_TO_RIGHT,
3027                   build_string ("CNS11643-2"),
3028                   build_string ("CNS11643-2 (Chinese traditional)"),
3029                   build_string
3030                   ("CNS 11643 Plane 2 Chinese traditional"),
3031                   build_string (CHINESE_CNS_PLANE_RE("2")),
3032                   Qnil, 0, 0, 0, 33, Qnil, CONVERSION_IDENTICAL);
3033 #ifdef UTF2000
3034   staticpro (&Vcharset_latin_tcvn5712);
3035   Vcharset_latin_tcvn5712 =
3036     make_charset (LEADING_BYTE_LATIN_TCVN5712, Qlatin_tcvn5712, 96, 1,
3037                   1, 1, 'Z', CHARSET_LEFT_TO_RIGHT,
3038                   build_string ("TCVN 5712"),
3039                   build_string ("TCVN 5712 (VSCII-2)"),
3040                   build_string ("Vietnamese TCVN 5712:1983 (VSCII-2)"),
3041                   build_string ("tcvn5712\\(\\.1993\\)?-1"),
3042                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
3043   staticpro (&Vcharset_latin_viscii_lower);
3044   Vcharset_latin_viscii_lower =
3045     make_charset (LEADING_BYTE_LATIN_VISCII_LOWER, Qlatin_viscii_lower, 96, 1,
3046                   1, 1, '1', CHARSET_LEFT_TO_RIGHT,
3047                   build_string ("VISCII lower"),
3048                   build_string ("VISCII lower (Vietnamese)"),
3049                   build_string ("VISCII lower (Vietnamese)"),
3050                   build_string ("MULEVISCII-LOWER"),
3051                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
3052   staticpro (&Vcharset_latin_viscii_upper);
3053   Vcharset_latin_viscii_upper =
3054     make_charset (LEADING_BYTE_LATIN_VISCII_UPPER, Qlatin_viscii_upper, 96, 1,
3055                   1, 1, '2', CHARSET_LEFT_TO_RIGHT,
3056                   build_string ("VISCII upper"),
3057                   build_string ("VISCII upper (Vietnamese)"),
3058                   build_string ("VISCII upper (Vietnamese)"),
3059                   build_string ("MULEVISCII-UPPER"),
3060                   Qnil, 0, 0, 0, 32, Qnil, CONVERSION_IDENTICAL);
3061   staticpro (&Vcharset_latin_viscii);
3062   Vcharset_latin_viscii =
3063     make_charset (LEADING_BYTE_LATIN_VISCII, Qlatin_viscii, 256, 1,
3064                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
3065                   build_string ("VISCII"),
3066                   build_string ("VISCII 1.1 (Vietnamese)"),
3067                   build_string ("VISCII 1.1 (Vietnamese)"),
3068                   build_string ("VISCII1\\.1"),
3069                   Qnil, 0, 0, 0, 0, Qnil, CONVERSION_IDENTICAL);
3070   staticpro (&Vcharset_chinese_big5);
3071   Vcharset_chinese_big5 =
3072     make_charset (LEADING_BYTE_CHINESE_BIG5, Qchinese_big5, 256, 2,
3073                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
3074                   build_string ("Big5"),
3075                   build_string ("Big5"),
3076                   build_string ("Big5 Chinese traditional"),
3077                   build_string ("big5-0"),
3078                   Qnil,
3079                   MIN_CHAR_BIG5_CDP, MAX_CHAR_BIG5_CDP,
3080                   MIN_CHAR_BIG5_CDP, 0, Qnil, CONVERSION_IDENTICAL);
3081
3082   staticpro (&Vcharset_ethiopic_ucs);
3083   Vcharset_ethiopic_ucs =
3084     make_charset (LEADING_BYTE_ETHIOPIC_UCS, Qethiopic_ucs, 256, 2,
3085                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
3086                   build_string ("Ethiopic (UCS)"),
3087                   build_string ("Ethiopic (UCS)"),
3088                   build_string ("Ethiopic of UCS"),
3089                   build_string ("Ethiopic-Unicode"),
3090                   Qnil, 0x1200, 0x137F, 0, 0,
3091                   Qnil, CONVERSION_IDENTICAL);
3092 #endif
3093   staticpro (&Vcharset_chinese_big5_1);
3094   Vcharset_chinese_big5_1 =
3095     make_charset (LEADING_BYTE_CHINESE_BIG5_1, Qchinese_big5_1, 94, 2,
3096                   2, 0, '0', CHARSET_LEFT_TO_RIGHT,
3097                   build_string ("Big5"),
3098                   build_string ("Big5 (Level-1)"),
3099                   build_string
3100                   ("Big5 Level-1 Chinese traditional"),
3101                   build_string ("big5"),
3102                   Qnil, 0, 0, 0, 33, /* Qnil, CONVERSION_IDENTICAL */
3103                   Vcharset_chinese_big5, CONVERSION_BIG5_1);
3104   staticpro (&Vcharset_chinese_big5_2);
3105   Vcharset_chinese_big5_2 =
3106     make_charset (LEADING_BYTE_CHINESE_BIG5_2, Qchinese_big5_2, 94, 2,
3107                   2, 0, '1', CHARSET_LEFT_TO_RIGHT,
3108                   build_string ("Big5"),
3109                   build_string ("Big5 (Level-2)"),
3110                   build_string
3111                   ("Big5 Level-2 Chinese traditional"),
3112                   build_string ("big5"),
3113                   Qnil, 0, 0, 0, 33, /* Qnil, CONVERSION_IDENTICAL */
3114                   Vcharset_chinese_big5, CONVERSION_BIG5_2);
3115
3116 #ifdef ENABLE_COMPOSITE_CHARS
3117   /* #### For simplicity, we put composite chars into a 96x96 charset.
3118      This is going to lead to problems because you can run out of
3119      room, esp. as we don't yet recycle numbers. */
3120   staticpro (&Vcharset_composite);
3121   Vcharset_composite =
3122     make_charset (LEADING_BYTE_COMPOSITE, Qcomposite, 96, 2,
3123                   2, 0, 0, CHARSET_LEFT_TO_RIGHT,
3124                   build_string ("Composite"),
3125                   build_string ("Composite characters"),
3126                   build_string ("Composite characters"),
3127                   build_string (""));
3128
3129   /* #### not dumped properly */
3130   composite_char_row_next = 32;
3131   composite_char_col_next = 32;
3132
3133   Vcomposite_char_string2char_hash_table =
3134     make_lisp_hash_table (500, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
3135   Vcomposite_char_char2string_hash_table =
3136     make_lisp_hash_table (500, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
3137   staticpro (&Vcomposite_char_string2char_hash_table);
3138   staticpro (&Vcomposite_char_char2string_hash_table);
3139 #endif /* ENABLE_COMPOSITE_CHARS */
3140
3141 }